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

nRF52840 QSPI XIP read function,qspi can't reinit

We used qspi  xip read function.
If I uninit qspi and then init qspi again,the mcu halted。

ret = nrf_drv_qspi_init(p_qspi_cfg, qspi_handler, (void *)p_blk_dev);


u8_t tmp = *(__IO uint8_t*)(0x12000000);

nrf_drv_qspi_uninit();

ret = nrf_drv_qspi_init(p_qspi_cfg, qspi_handler, (void *)p_blk_dev);

Is there a problem with my use? What can i do now。

Parents
  • Hi

    First off, please make sure that all memory access by the QSPI peripheral to external memory devices are word-aligned, as you can only write/read in full words (usually 32 bits). What SDK version are you using?

    There was a bug in SDK v15.3 that would result in the CPU hanging without access to the SWD interface, which would be caused by either reading/writing from a specific register or calling the uninit function to reconfigure the QSPI.

    The workaround is to trigger the ACTIVATE task of the QSPI peripheral before calling the uninit function as such:

    NRF_QSPI->EVENTS_READY = 0;
    NRF_QSPI->TASKS_ACTIVATE = 1;
    while(NRF_QSPI->EVENTS_READY == 0) {};
    Both "done" and "end" is printed. I've included the code with the workaround implemented.
    /**
     * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     * @defgroup qspi_example_main main.c
     * @{
     * @ingroup qspi_example
     *
     * @brief QSPI Example Application main file.
     *
     * This file contains the source code for a sample application using QSPI.
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "nrf_drv_qspi.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    
    #include "crc32.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "sdk_config.h"
    
    #include "nrf_delay.h"
    
    
    #define QSPI_STD_CMD_WRSR   0x01
    #define QSPI_STD_CMD_RSTEN  0x66
    #define QSPI_STD_CMD_RST    0x99
    
    
    #define QSPI_FLASH_DPM_ENTER_DURATION                   3                              //Duration required to enter DPM, in units of 16us
    #define QSPI_FLASH_DPM_EXIT_DURATION                    3                              //Duration required to exit DPM, in units of 16us
    
    static void configure_memory()
    {
        uint8_t temporary = 0x40;
        uint32_t err_code;
        nrf_qspi_cinstr_conf_t cinstr_cfg = {
            .opcode    = QSPI_STD_CMD_RSTEN,
            .length    = NRF_QSPI_CINSTR_LEN_1B,
            .io2_level = true,
            .io3_level = true,
            .wipwait   = true,
            .wren      = true
        };
    
        // Send reset enable
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Send reset command
        cinstr_cfg.opcode = QSPI_STD_CMD_RST;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Switch to qspi mode
        cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
        cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    uint32_t GenerateCRC(void *data, uint32_t nSize)
    {
        NRF_LOG_INFO("crc of %lx size %d", data, nSize);
    
        uint32_t i = 0;
        uint32_t nSeg = 32;
        uint32_t nCRC = 0;
        while (i < nSize)
        {
            if ((i + nSeg) > nSize)
            {
                nSeg = nSize - i;
            }
    
            nCRC = crc32_compute((const uint8_t*)(data + i), nSeg, &nCRC);
            i += nSeg;
        }
    
        return nCRC;
    }
    
    int main(void)
    {
        uint32_t err_code;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO(""
                     "QSPI write and read example using 24bit addressing mode");
    
        nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;
    
    
    
        //This delay is to allow for nrfjprog to erase the device after a reboot, otherwise it locks out SWD access, DO NOT REMOVE!
        nrf_delay_ms(2000);
    
    
    
        //Setup QSPI to allow for DPM but with it turned off, set XIP offset to 0x0
        config.phy_if.dpmen = false;
        config.xip_offset = 0x0;
        config.prot_if.dpmconfig = true;
        NRF_QSPI->DPMDUR = (QSPI_FLASH_DPM_EXIT_DURATION << QSPI_DPMDUR_EXIT_Pos) | QSPI_FLASH_DPM_ENTER_DURATION;
        err_code = nrf_drv_qspi_init(&config, NULL, NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("QSPI example started.");
        configure_memory();
    
        uint8_t pBuf[64];
        nrf_drv_qspi_read(pBuf, 64, 0x0);
    
        uint32_t mycrc = GenerateCRC((uint32_t*)0x12000000, 0x1000);
        NRF_LOG_INFO("Got: %lx", mycrc);
        
        //Workaround
        NRF_QSPI->EVENTS_READY = 0;
        NRF_QSPI->TASKS_ACTIVATE = 1;
        while(NRF_QSPI->EVENTS_READY == 0) {};
     
    
    
        //This is what causes the issue
        uint32_t nConfig = NRF_QSPI->IFCONFIG1;
        nConfig |= 1U << QSPI_IFCONFIG1_DPMEN_Pos;
        NRF_QSPI->IFCONFIG1 = nConfig;
    
    
    
        //This never executes
        NRF_LOG_INFO("done");
    
        nrf_drv_qspi_uninit();
    
        NRF_LOG_INFO("end");
    
        for (;;)
        {
        }
    }
    
    /** @} */
    Best regards,
    Simon
Reply
  • Hi

    First off, please make sure that all memory access by the QSPI peripheral to external memory devices are word-aligned, as you can only write/read in full words (usually 32 bits). What SDK version are you using?

    There was a bug in SDK v15.3 that would result in the CPU hanging without access to the SWD interface, which would be caused by either reading/writing from a specific register or calling the uninit function to reconfigure the QSPI.

    The workaround is to trigger the ACTIVATE task of the QSPI peripheral before calling the uninit function as such:

    NRF_QSPI->EVENTS_READY = 0;
    NRF_QSPI->TASKS_ACTIVATE = 1;
    while(NRF_QSPI->EVENTS_READY == 0) {};
    Both "done" and "end" is printed. I've included the code with the workaround implemented.
    /**
     * Copyright (c) 2016 - 2018, Nordic Semiconductor ASA
     *
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     * 1. Redistributions of source code must retain the above copyright notice, this
     *    list of conditions and the following disclaimer.
     *
     * 2. Redistributions in binary form, except as embedded into a Nordic
     *    Semiconductor ASA integrated circuit in a product or a software update for
     *    such product, must reproduce the above copyright notice, this list of
     *    conditions and the following disclaimer in the documentation and/or other
     *    materials provided with the distribution.
     *
     * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
     *    contributors may be used to endorse or promote products derived from this
     *    software without specific prior written permission.
     *
     * 4. This software, with or without modification, must only be used with a
     *    Nordic Semiconductor ASA integrated circuit.
     *
     * 5. Any software provided in binary form under this license must not be reverse
     *    engineered, decompiled, modified and/or disassembled.
     *
     * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
     * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
     * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
     * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     */
    /** @file
     * @defgroup qspi_example_main main.c
     * @{
     * @ingroup qspi_example
     *
     * @brief QSPI Example Application main file.
     *
     * This file contains the source code for a sample application using QSPI.
     */
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include "nrf_drv_qspi.h"
    #include "nrf_delay.h"
    #include "app_util_platform.h"
    #include "app_error.h"
    #include "boards.h"
    
    #include "crc32.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "sdk_config.h"
    
    #include "nrf_delay.h"
    
    
    #define QSPI_STD_CMD_WRSR   0x01
    #define QSPI_STD_CMD_RSTEN  0x66
    #define QSPI_STD_CMD_RST    0x99
    
    
    #define QSPI_FLASH_DPM_ENTER_DURATION                   3                              //Duration required to enter DPM, in units of 16us
    #define QSPI_FLASH_DPM_EXIT_DURATION                    3                              //Duration required to exit DPM, in units of 16us
    
    static void configure_memory()
    {
        uint8_t temporary = 0x40;
        uint32_t err_code;
        nrf_qspi_cinstr_conf_t cinstr_cfg = {
            .opcode    = QSPI_STD_CMD_RSTEN,
            .length    = NRF_QSPI_CINSTR_LEN_1B,
            .io2_level = true,
            .io3_level = true,
            .wipwait   = true,
            .wren      = true
        };
    
        // Send reset enable
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Send reset command
        cinstr_cfg.opcode = QSPI_STD_CMD_RST;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
        APP_ERROR_CHECK(err_code);
    
        // Switch to qspi mode
        cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
        cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
        err_code = nrf_drv_qspi_cinstr_xfer(&cinstr_cfg, &temporary, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    uint32_t GenerateCRC(void *data, uint32_t nSize)
    {
        NRF_LOG_INFO("crc of %lx size %d", data, nSize);
    
        uint32_t i = 0;
        uint32_t nSeg = 32;
        uint32_t nCRC = 0;
        while (i < nSize)
        {
            if ((i + nSeg) > nSize)
            {
                nSeg = nSize - i;
            }
    
            nCRC = crc32_compute((const uint8_t*)(data + i), nSeg, &nCRC);
            i += nSeg;
        }
    
        return nCRC;
    }
    
    int main(void)
    {
        uint32_t err_code;
    
        err_code = NRF_LOG_INIT(NULL);
        APP_ERROR_CHECK(err_code);
    
        NRF_LOG_DEFAULT_BACKENDS_INIT();
    
        NRF_LOG_INFO(""
                     "QSPI write and read example using 24bit addressing mode");
    
        nrf_drv_qspi_config_t config = NRF_DRV_QSPI_DEFAULT_CONFIG;
    
    
    
        //This delay is to allow for nrfjprog to erase the device after a reboot, otherwise it locks out SWD access, DO NOT REMOVE!
        nrf_delay_ms(2000);
    
    
    
        //Setup QSPI to allow for DPM but with it turned off, set XIP offset to 0x0
        config.phy_if.dpmen = false;
        config.xip_offset = 0x0;
        config.prot_if.dpmconfig = true;
        NRF_QSPI->DPMDUR = (QSPI_FLASH_DPM_EXIT_DURATION << QSPI_DPMDUR_EXIT_Pos) | QSPI_FLASH_DPM_ENTER_DURATION;
        err_code = nrf_drv_qspi_init(&config, NULL, NULL);
        APP_ERROR_CHECK(err_code);
        NRF_LOG_INFO("QSPI example started.");
        configure_memory();
    
        uint8_t pBuf[64];
        nrf_drv_qspi_read(pBuf, 64, 0x0);
    
        uint32_t mycrc = GenerateCRC((uint32_t*)0x12000000, 0x1000);
        NRF_LOG_INFO("Got: %lx", mycrc);
        
        //Workaround
        NRF_QSPI->EVENTS_READY = 0;
        NRF_QSPI->TASKS_ACTIVATE = 1;
        while(NRF_QSPI->EVENTS_READY == 0) {};
     
    
    
        //This is what causes the issue
        uint32_t nConfig = NRF_QSPI->IFCONFIG1;
        nConfig |= 1U << QSPI_IFCONFIG1_DPMEN_Pos;
        NRF_QSPI->IFCONFIG1 = nConfig;
    
    
    
        //This never executes
        NRF_LOG_INFO("done");
    
        nrf_drv_qspi_uninit();
    
        NRF_LOG_INFO("end");
    
        for (;;)
        {
        }
    }
    
    /** @} */
    Best regards,
    Simon
Children
  • I tried your code,then it's ok.
    I find the nrf_drv_qspi_init must config without callback handler.
    nrf_drv_qspi_init(&config, NULL, NULL);//It's ok
    nrf_drv_qspi_init(p_qspi_cfg, qspi_handler, NULL);//It's will stop at while(NRF_QSPI->EVENTS_READY == 0) {};
     To make sure the words are aligned, I read the data like this:
    /*************************************************************************   
    **	function name:	qspi_read 
    **	input para:		
    **                  
    **	input para:		 	
    **	return:					                                         
    **************************************************************************/
    void qspi_read(u8_t *p_data, u32_t addr, u16_t len)
    {
        u16_t i;
    
        for(i=0; i<len; i += 4)
        {
            u32_t tmp_data = *(__IO uint32_t*)(0x12000000 + addr + i);
            if((i+4)>len)
            {
                if((len%4) >= 1)
                {
                    p_data[i] = (u8_t)(tmp_data);
                }
    
                if((len%4) >= 2)
                {
                    p_data[i+1] = (u8_t)(tmp_data >> 8);
                }      
    
                if((len%4) >= 3)
                {
                    p_data[i+2] = (u8_t)(tmp_data >> 16);
                }                 
            }
            else
            {
                p_data[i]   = (u8_t)(tmp_data);
                p_data[i+1] = (u8_t)(tmp_data >> 8);
                p_data[i+2] = (u8_t)(tmp_data >> 16);
                p_data[i+3] = (u8_t)(tmp_data >> 24);                
            }
        }   
    }
Related