This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Nordic SDK QSPI driver call

Hi all,

             We had implemented Nordic QSPI using "nrf_drv_qspi_write" and "nrf_drv_qspi_read" operation , however I am seeing for page to write in flash of 4096 bytes with 512 bytes of QSPI write size limitation its taking 8.6 milli sec , when many streams (sensor data at stretch to be written into system) streams are getting hanged when flash logging is enabled .

So, wanted to check basic operations "nrf_drv_qspi_write" and "nrf_drv_qspi_read" if it blocks other sensor operations to process data ? Is it blocking call? If so how do we configure into dma mode?

Please help

Parents
  • What's the write speed of the flash?

    The read and write functions are blocking or non-blocking depending on whether you supplied an event handler to nrfx_qspi_init or not. 

  • Hi ,

             Please find the driver code init.

    #define QSPI_NAND_FLASH_CONFIG                                        \
    {                                                                       \
        .xip_offset  = 0,                         \
        .pins = {                                                           \
           .sck_pin     = QSPI_NAND_FLASH_SCK_PIN,                                \
           .csn_pin     = QSPI_NAND_FLASH_CSN_PIN,                                \
           .io0_pin     = QSPI_NAND_FLASH_IO0_PIN,                                \
           .io1_pin     = QSPI_NAND_FLASH_IO1_PIN,                                \
           .io2_pin     = QSPI_NAND_FLASH_IO2_PIN,                                \
           .io3_pin     = QSPI_NAND_FLASH_IO3_PIN,                                \
        },                                                                  \
        .irq_priority   = (uint8_t)NRFX_QSPI_CONFIG_IRQ_PRIORITY,           \
        .prot_if = {                                                        \
            .readoc     = QSPI_IFCONFIG0_READOC_READ4O,       \
            .writeoc    = QSPI_IFCONFIG0_WRITEOC_PP4O,     \
            .addrmode   = (nrf_qspi_addrmode_t)NRFX_QSPI_CONFIG_ADDRMODE,   \
            .dpmconfig  = false,                                            \
        },                                                                  \
        .phy_if = {                                                         \
            .sck_freq   = NRF_QSPI_FREQ_32MDIV1, \
            .sck_delay  = (uint8_t)NRFX_QSPI_CONFIG_SCK_DELAY,              \
            .spi_mode   = (nrf_qspi_spi_mode_t)NRFX_QSPI_CONFIG_MODE,       \
            .dpmen      = false                                             \
        },                                                                  \
    }
    /*
        select: 1=512byte,0=256byte.
    */
    __STATIC_INLINE void nrf_qspi_ifconfig0_set_page_size(uint8_t select)
    {
        if(select == 0)
        {
            NRF_QSPI->IFCONFIG0 &= 0xffffefff;
        }
        else
        {
            NRF_QSPI->IFCONFIG0 |= 0x00001000;
        }
    }
    uint32_t nand_flash_qspi_init(void)
    {
        uint32_t err_code = NAND_SUCCESS;
        nrf_drv_qspi_config_t config = QSPI_NAND_FLASH_CONFIG;
        err_code = nrf_drv_qspi_init(&config, NULL, NULL);
        if(NRFX_SUCCESS != err_code)
        {
            NRF_LOG_INFO("QSPI init error,err_code=%d",err_code);
            return err_code;
        }
        nrf_qspi_ifconfig0_set_page_size(1);
        return NRFX_SUCCESS;
    }
  • Hi,

           Version is 

    nRF5_SDK_15.2.0

    I also see drivers are updated in nrfx_1.7.2 . Is it latest one ? Could I use nrfx_qspi.c from 1.7.2?

  • ARPITHA CHANDRASHEKAR said:

    nrf_drv_qspi_init is failing with below mentioned call back; inside 

    init function 

    m_cb.interrupt_driven = false; is set to false ; so it crashes when assigned call back.

     What do you mean it's failing? Where? What's the error code?



  • Sir, issue is not resolved yet. Are there any settings that has be changed to make it blocking call on sdk config 

  • This is what we tried to modify nrfx_qspi_driver file . PLs check.

    #include <nrfx.h>
    #if NRFX_CHECK(NRFX_QSPI_ENABLED)
    #include <nrfx_qspi.h>
    volatile uint8_t ISR_flag  =0;
    /**
     * @brief Command byte used to read status register.
     *
     */
    #define QSPI_STD_CMD_RDSR 0x05
    /**
     * @brief Byte used to mask status register and retrieve the write-in-progess bit.
     *
     */
    #define QSPI_MEM_STATUSREG_WIP_Pos 0x01
    /**
     * @brief Default time used in timeout function.
     */
    #define QSPI_DEF_WAIT_TIME_US 10
    /**
     * @brief Default number of tries in timeout function.
     */
    #define QSPI_DEF_WAIT_ATTEMPTS 100
    /**
      * @brief Control block - driver instance local data.
      */
    typedef struct
    {
        nrfx_qspi_handler_t handler;          /**< Handler. */
        nrfx_drv_state_t    state;            /**< Driver state. */
        volatile bool       interrupt_driven; /**< Information if the current operation is performed and is interrupt-driven. */
        void *              p_context;        /**< Driver context used in interrupt. */
    } qspi_control_block_t;
    static qspi_control_block_t m_cb;
    static nrfx_err_t qspi_task_perform(nrf_qspi_task_t task)
    {
        // Wait for peripheral
        if (m_cb.interrupt_driven)
        {
            return NRFX_ERROR_BUSY;
        }
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        if (m_cb.handler)
        {
            m_cb.interrupt_driven = true;
            nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
        }
      ISR_flag =0;
        nrf_qspi_task_trigger(NRF_QSPI, task);
        if (m_cb.handler == NULL)
        {
            while (!nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
            {};
        }
        while(!ISR_flag);
        return NRFX_SUCCESS;
    }
    static bool qspi_pins_configure(nrf_qspi_pins_t const * p_config)
    {
        // Check if the user set meaningful values to struct fields. If not, return false.
        if ((p_config->sck_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
            (p_config->csn_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
            (p_config->io0_pin == NRF_QSPI_PIN_NOT_CONNECTED) ||
            (p_config->io1_pin == NRF_QSPI_PIN_NOT_CONNECTED))
        {
            return false;
        }
        nrf_qspi_pins_set(NRF_QSPI, p_config);
        return true;
    }
    nrfx_err_t nrfx_qspi_init(nrfx_qspi_config_t const * p_config,
                              nrfx_qspi_handler_t        handler,
                              void *                     p_context)
    {
        NRFX_ASSERT(p_config);
        if (m_cb.state != NRFX_DRV_STATE_UNINITIALIZED)
        {
            return NRFX_ERROR_INVALID_STATE;
        }
        if (!qspi_pins_configure(&p_config->pins))
        {
            return NRFX_ERROR_INVALID_PARAM;
        }
        nrf_qspi_xip_offset_set(NRF_QSPI, p_config->xip_offset);
        nrf_qspi_ifconfig0_set(NRF_QSPI, &p_config->prot_if);
        nrf_qspi_ifconfig1_set(NRF_QSPI, &p_config->phy_if);
        m_cb.interrupt_driven = false;
        m_cb.handler = handler;
        m_cb.p_context = p_context;
        /* QSPI interrupt is disabled because the device should be enabled in polling mode (wait for activate
           task event ready)*/
        nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
        if (handler)
        {
            NRFX_IRQ_PRIORITY_SET(QSPI_IRQn, p_config->irq_priority);
            NRFX_IRQ_ENABLE(QSPI_IRQn);
        }
        m_cb.state = NRFX_DRV_STATE_INITIALIZED;
        nrf_qspi_enable(NRF_QSPI);
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_ACTIVATE);
        // Waiting for the peripheral to activate
        bool result;
        NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY),
                      QSPI_DEF_WAIT_ATTEMPTS,
                      QSPI_DEF_WAIT_TIME_US,
                      result);
        if (!result)
        {
            return NRFX_ERROR_TIMEOUT;
        }
        return NRFX_SUCCESS;
    }
    nrfx_err_t nrfx_qspi_cinstr_xfer(nrf_qspi_cinstr_conf_t const * p_config,
                                     void const *                   p_tx_buffer,
                                     void *                         p_rx_buffer)
    {
        NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
        if (m_cb.interrupt_driven)
        {
            return NRFX_ERROR_BUSY;
        }
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        /* In some cases, only opcode should be sent. To prevent execution, set function code is
         * surrounded by an if.
         */
        if (p_tx_buffer)
        {
            nrf_qspi_cinstrdata_set(NRF_QSPI, p_config->length, p_tx_buffer);
        }
        /* modify begin by Leo, 2020-06-28,not need to disable interrupt if no use it*/
        if(m_cb.handler)
        {
            nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
        }
        /* modify end by Leo, 2020-06-28 */
        nrf_qspi_cinstr_transfer_start(NRF_QSPI, p_config);
        bool result;
        NRFX_WAIT_FOR(nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY),
                      QSPI_DEF_WAIT_ATTEMPTS,
                      QSPI_DEF_WAIT_TIME_US,
                      result);
        if (!result)
        {
            // This timeout should never occur when WIPWAIT is not active, since in this
            // case the QSPI peripheral should send the command immediately, without any
            // waiting for previous write to complete.
            NRFX_ASSERT(p_config->wipwait);
            return NRFX_ERROR_TIMEOUT;
        }
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        /* modify begin by Leo, 2020-06-28 not need to disable interrupt if no use it*/
        if(m_cb.handler)
        {
            nrf_qspi_int_enable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
        }
        /* modify end by Leo, 2020-06-28 */
        if (p_rx_buffer)
        {
            nrf_qspi_cinstrdata_get(NRF_QSPI, p_config->length, p_rx_buffer);
        }
        return NRFX_SUCCESS;
    }
    nrfx_err_t nrfx_qspi_cinstr_quick_send(uint8_t               opcode,
                                           nrf_qspi_cinstr_len_t length,
                                           void const *          p_tx_buffer)
    {
        nrf_qspi_cinstr_conf_t config = NRFX_QSPI_DEFAULT_CINSTR(opcode, length);
        return nrfx_qspi_cinstr_xfer(&config, p_tx_buffer, NULL);
    }
    nrfx_err_t nrfx_qspi_mem_busy_check(void)
    {
        nrfx_err_t ret_code;
        uint8_t status_value = 0;
        nrf_qspi_cinstr_conf_t const config =
            NRFX_QSPI_DEFAULT_CINSTR(QSPI_STD_CMD_RDSR,
                                     NRF_QSPI_CINSTR_LEN_2B);
        ret_code = nrfx_qspi_cinstr_xfer(&config, &status_value, &status_value);
        if (ret_code != NRFX_SUCCESS)
        {
            return ret_code;
        }
        if ((status_value & QSPI_MEM_STATUSREG_WIP_Pos) != 0x00)
        {
            return NRFX_ERROR_BUSY;
        }
        return NRFX_SUCCESS;
    }
    void nrfx_qspi_uninit(void)
    {
        NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
        nrf_qspi_int_disable(NRF_QSPI, NRF_QSPI_INT_READY_MASK);
        nrf_qspi_task_trigger(NRF_QSPI, NRF_QSPI_TASK_DEACTIVATE);
        // Workaround for nRF52840 anomaly 122: Current consumption is too high.
        *(volatile uint32_t *)0x40029054ul = 1ul;
        nrf_qspi_disable(NRF_QSPI);
        NRFX_IRQ_DISABLE(QSPI_IRQn);
        nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
        m_cb.state = NRFX_DRV_STATE_UNINITIALIZED;
    }
    nrfx_err_t nrfx_qspi_write(void const * p_tx_buffer,
                               size_t       tx_buffer_length,
                               uint32_t     dst_address)
    {
        NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
        NRFX_ASSERT(p_tx_buffer != NULL);
        if (!nrfx_is_in_ram(p_tx_buffer))
        {
            return NRFX_ERROR_INVALID_ADDR;
        }
        nrf_qspi_write_buffer_set(NRF_QSPI, p_tx_buffer, tx_buffer_length, dst_address);
        return qspi_task_perform(NRF_QSPI_TASK_WRITESTART);
    }
    nrfx_err_t nrfx_qspi_read(void *   p_rx_buffer,
                              size_t   rx_buffer_length,
                              uint32_t src_address)
    {
        NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
        NRFX_ASSERT(p_rx_buffer != NULL);
        if (!nrfx_is_in_ram(p_rx_buffer))
        {
            return NRFX_ERROR_INVALID_ADDR;
        }
        nrf_qspi_read_buffer_set(NRF_QSPI, p_rx_buffer, rx_buffer_length, src_address);
        return qspi_task_perform(NRF_QSPI_TASK_READSTART);
    }
    nrfx_err_t nrfx_qspi_erase(nrf_qspi_erase_len_t length,
                               uint32_t             start_address)
    {
        NRFX_ASSERT(m_cb.state != NRFX_DRV_STATE_UNINITIALIZED);
        nrf_qspi_erase_ptr_set(NRF_QSPI, start_address, length);
        return qspi_task_perform(NRF_QSPI_TASK_ERASESTART);
    }
    nrfx_err_t nrfx_qspi_chip_erase(void)
    {
        return nrfx_qspi_erase(NRF_QSPI_ERASE_LEN_ALL, 0);
    }
    void nrfx_qspi_irq_handler(void)
    {
        // Catch Event ready interrupts
        if (nrf_qspi_event_check(NRF_QSPI, NRF_QSPI_EVENT_READY))
        {
            m_cb.interrupt_driven = false;
            nrf_qspi_event_clear(NRF_QSPI, NRF_QSPI_EVENT_READY);
            ISR_flag = 1;
            m_cb.handler(NRFX_QSPI_EVENT_DONE, m_cb.p_context);
        }
    }
Reply Children
No Data
Related