NVM process on SPI bus seems to be interfered with during BLE_GATTS_EVT_WRITE event

During an execution of a  winbond w25q64jv command (any command) during a BLE_GATTS_EVT_WRITE event the SPI bus goes inactive after the command is sent:

There is apparently no issue if I do any NVM operation outside a BLE_GATTS_EVT_WRITE event. 

  • Hello,

    What does the logic analyzer look like if you do it outside the BLE_GATTS_EVT_WRITE?

    And what does it look like in your implementation? Can you please share the snippet where you are using the SPI? Are you trying to send more data than the 0x66, 0xE6 directly from the interrupt? Or are you waiting for some sort of callback before you are trying to send the rest of the data?

    Best regards,

    Edvin

  • Hello Edvin,

    I am rewriting my code because of this strange issue.  But, the 0xE6 byte after the 0x66 was not intended to be sent to NVM,  The code for the NVM command is only intended to send the 0x66 (Enable Reset) on the SPI bus and nothing else for that command.  I think that's why there is NVM issue, because that 2nd byte is probably putting the NVM in a bad state.  I am not waiting for a callback.  Snippet below (ENABLE_RESET_CMND_LEN = 1, W25_ENABLE_RESET_REG = 0x66, and  W25_RESET_DEVICE_REG = 0x99):

    void w25_reset(void)
    {
        ret_code_t err_code;
        uint8_t spi_command[ENABLE_RESET_CMND_LEN] = {0};
        uint8_t spi_response[ENABLE_RESET_CMND_LEN] = {0};
    
        //Enable Reset Test
        spi_command[CMND_BYTE_0] = W25_ENABLE_RESET_REG;    //Write enable register address
        err_code = spi_transfer(spi_command, spi_response, ENABLE_RESET_CMND_LEN, 0, MEM_CS);  //Enable writing to NVM
        APP_ERROR_CHECK(err_code);
        //Send SW Reset
        spi_command[CMND_BYTE_0] = W25_RESET_DEVICE_REG;    //Write enable register address
        err_code = spi_transfer(spi_command, spi_response, RESET_CMND_LEN, 0, MEM_CS);  //Enable writing to NVM
        APP_ERROR_CHECK(err_code);
    }

    Here is a snippet of working code and SPI bus capture:

    bool Test_write_and_read_of_NVM()
    {
        uint8_t mydata[18] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 
                              0x0D, 0x0E, 0x0F, 0x55, 0x00, 0x10};  //test data
        ret_code_t err_code;
        uint8_t spi_command[TEST_WR_RD_CMND_LEN] = {0};
        uint8_t spi_response[TEST_WR_RD_CMND_LEN] = {0};
        uint8_t buffer[18] = {0};
        int WR_RD_check = 0;
        uint8_t SectorAddr[TRIPLE_BYTES];
        spi_command[CMND_BYTE_0] = W25_PAGE_PROGRAM_REG;         //Page Program Command
        spi_command[CMND_BYTE_1] = NVM_MEM_START_BYTE2;          //Address to write MSByte 1st
        spi_command[CMND_BYTE_2] = NVM_MEM_START_BYTE1;          //Address to write
        spi_command[CMND_BYTE_3] = NVM_MEM_START_BYTE0;          //Address to write
        //
        SectorAddr[CMND_BYTE_0] = NVM_MEM_START_BYTE2;          //Address to read MSByte 1st
        SectorAddr[CMND_BYTE_1] = NVM_MEM_START_BYTE1;          //Address to read
        SectorAddr[CMND_BYTE_2] = NVM_MEM_START_BYTE0;          //Address to read
    
        //Load up SPI command rest of data
        for (uint8_t ii = 0; ii < 18; ii++)
        {
          spi_command[ii + 4] = mydata[ii];
        }
    
        w25_write_enable();
        //Write test data to NVM
        err_code = spi_transfer(spi_command, spi_response, TEST_WR_RD_CMND_LEN, TEST_WR_RD_CMND_LEN, MEM_CS);
        APP_ERROR_CHECK(err_code);
        //Now Read Data back to compare to expected values.  First check if NVM is busy
        //while(Check_NVM_Busy() != false) {}
        //Read data
       // Check_NVM_Busy();
        err_code = w25_read_data(SectorAddr, buffer, 18);
        NRF_LOG_INFO("Read Test Data from NVM %u, %u, %u\n\r",buffer[0], buffer[1], buffer[2], buffer[3]);
        //Compare data with test data with what was read in
        WR_RD_check = memcmp(mydata, buffer, sizeof(buffer));
        if(WR_RD_check != 0)
        {
          return (false);
        }
        else
        {
          return (true);
        } 
    }

    The code writes to NVM and reads the data back and compares it to original data to check it.  Outside the BLE_GATTS_EVT_WRITE event it works, but not inside it.

  • Hello,

    Sorry for the late reply. I was out of office yesterday.

    I don't understand. Those two snippets are very different. What do you expect to see in your first snippet? 

    Is this something I will be able to reproduce on a DK? Obviously I will not be able to read back the data, but I should be able to see the same output data from the nRF. If so, can you please zip and send a project (or a minimum project) that can replicate the issue?

    Best regards,

    Edvin

  • In the first snippet the 0xE6 shouldn't be there.  I'll capture data where the 2nd snippet is executed within the BLE_GATTS_EVT_WRITE event.

  • I added a call to the NVM function (Test_write_and_read_of_NVM();) that is known to work was added here:

    static void on_Command_write(ble_Status_cus_t *stat_cus, ble_Cmnd_cus_t *cmnd_cus, ble_cus_data_t *p_cus, ble_evt_t const * p_ble_evt)
    {
        ble_gatts_evt_write_t const *p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
        uint8_t SOBRSafe_comnd = 0;
        uint32_t err_code;
        uint8_t SOBRSafe_err = SOBRSAFE_NO_ERROR;
        uint8_t rcvd_payload[PING_DATA_LENGTH]; 
        uint16_t rcvd_data_lngth = p_evt_write->len;
        timestamp_s curr_time;
        app_source_data *pull_strt_time;
        uint16_t ii = 0;
        Test_write_and_read_of_NVM();
        // Command Value Characteristic Written to.
        if (p_evt_write->handle == cmnd_cus->custom_value_handles.value_handle)
        {

    When I pause execution is shows it is running here:

    ret_code_t spi_transfer(uint8_t *txBuff, uint8_t *rxBuff, size_t tx_length, size_t rx_length, uint8_t cs)
    {
        nrfx_spim_xfer_desc_t xferDesc = NRFX_SPIM_XFER_TRX(txBuff, tx_length, rxBuff, rx_length);
    
        // Reset rx buffer and transfer flag
        memset(rxBuff, 0, rx_length);
        spi_xfer_done = false;
    
        /*NOTE: Below manual operation of CS pin is necessary because driver does not 
                natively handle multiple spi slaves on one spi instance */
        nrf_gpio_pin_clear(cs);
    
        //TODO: use nonblocking mode
        ret_code_t ret_err = nrfx_spim_xfer(&m_spi, &xferDesc, 0);
        
        while (!spi_xfer_done) 
        {
            __WFE();
        }
    
        /*NOTE: Below manual operation of CS pin is necessary because driver does not 
                natively handle multiple spi slaves on one spi instance */    
        nrf_gpio_pin_set(cs);
        
        return ret_err;
    }

    SPI communication during the Test_write_and_read_of_NVM() execution:

    So, it's appears calling the function during a BLE_GATTS_EVT_WRITE event is a problem.  I've have since rewritten code to not do any NVM processing during the BLE_GATTS_EVT_WRITE event, but it would be good to know why the results are different. 

Related