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

NRF52 not reading third SPI byte

Hi 

I am trying to port an SPI driver from a project for the NRF51822 to an NRF52832 and running into a problem reading more than two bytes. We are using SPI0 (not SPIM0) connected to an external flash chip.

Below is an image capturing an example of the problem. Here I am transmitting a command byte 0x9F (lower left) and then clocking in three bytes (lower right) from the flash chip. I expect the flash chip to transmit 0x9D 0x60 0x15 and that is exactly what I see in the waveform. However, the NRF52 only reads the 0x9D and 0x60 (which are double buffered), but it drops the 0x15. This same driver code works fine across multiple projects built for the NRF51.

Are there any known errata or issues regarding operation of the SPI peripheral on the NRF52? The only thing I can find in the documentation is the instantiation table in section 8.4 of the product specification where it says that the SPI peripheral is deprecated. But the rest of the document suggests the SPI peripheral is still supported. Are we supposed to move to the SPIM peripheral?

Parents
  • You should still be able to use the SPI module. I am guessing/hoping that you are using latest SDK drivers to communicate to your SPI module on nRF52832.  We have not known any other issue apart from the extra clock issue already mentioned in the Errata and this one does not match your symptoms.

    Try your communication using SDK15.2 nrfx_spi.c driver

  • Hi Susheel,

    We have our own driver, and like I said, it works on the NRF51.

    In section 48.1.3 of the product specification there are a couple paragraphs about the READY event and reading bytes B and C. It is difficult to interpret but on a whim I decided to add 15 nops before reading in the third byte and this fixed the issue. The 15 nops added another half clock cycle to the gap and now I can read the data. I have run tests reading thousands of bytes in 256 byte increments without failure.

  • Thanks for lettings us know about this. I do not understand why this fixes the issue. They should not have been needed if you are reading them on the condition of getting READY event.

    Just for future reference, can you please give us the code snippet to have a little more insights about the driver state at the time you add these nops.

  • // Refer to "Figure 58: SPI master transaction" in the nrf51 reference manual
    void spi_master_transfer(uint8_t const * p_tx_buf, size_t tx_buf_len, uint8_t * p_rx_buf, size_t rx_buf_len)
    {
        VERIFY_TRUE_VOID(spi_master.open);
        VERIFY_TRUE_VOID(BIT_IS_CLEAR(NRF_GPIO->OUT, spi_master.pin_slave_select));
    
        size_t const max_length = MAX(tx_buf_len, rx_buf_len);
    
        VERIFY_TRUE_VOID(max_length > 0);
    
        size_t bytes_sent = 0;
        size_t bytes_received = 0;
    
        // kick off the process by loading the double buffered TXD
        for (int i=0; i<2; i++)
        {
            if (bytes_sent < max_length)
            {
                if (p_tx_buf != NULL && bytes_sent < tx_buf_len)
                {
                    NRF_SPI->TXD = p_tx_buf[bytes_sent];
                }
                else
                {
                    // send a dummy byte in order to facilitate reading bytes we care about
                    NRF_SPI->TXD = SPI_DEFAULT_TX_BYTE;
                }
                bytes_sent++;
            }
        }
    
        uint8_t rx_byte;
    
        while (bytes_received < max_length)
        {
            while (!NRF_SPI->EVENTS_READY) {}   // TODO: driver locks up here with optimization at O3
    
            rx_byte = NRF_SPI->RXD;
    
            if (p_rx_buf != NULL && bytes_received < rx_buf_len)
            {
                p_rx_buf[bytes_received] = rx_byte;
            }
            bytes_received++;
    
            if (bytes_sent < max_length)
            {
                if (p_tx_buf != NULL && bytes_sent < tx_buf_len)
                {
                    NRF_SPI->TXD = p_tx_buf[bytes_sent];
                }
                else
                {
                    // send a dummy byte in order to facilitate reading bytes we care about
                    NRF_SPI->TXD = SPI_DEFAULT_TX_BYTE;
                }
                bytes_sent++;
            }
            
            // Note: Initial implementation for the nRF51 based modules did not require these nop's. However, the nRF52 was failing
            // the self-test and after some investigation I discovered that the third byte in the read_jedec_id command was being
            // transfered by the chip but was not being read into the rx buffer. After reading paragraph 48.1.3, SPI master transaction
            // sequence, of the product specification I attempted the nop's and was able to read in the third byte and pass the test.
            // I first attempted 5 nop's but saw no change. I then arbitrarily tried 15 nop's and saw success. I added 5 more for
            // good measure but the bootloader was not working so I increased to 40 and all issues were resolved.
            if(bytes_received == 2)
            {
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
                __asm("nop");
            }
        }
    
        NRF_SPI->EVENTS_READY = 0;
    }

  • Can use this SPI driver code as reference.  Same code works across nRF5x series with supports for both master/slave, IO or DMA.

Reply Children
No Data
Related