Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52840 SPIM and Toshiba SPI Nand Flash

I am using Nordic SDK 15.3 and nRF52840 to interface to a NAND flash TC58CVG2S0HRAIG.
I'm new with the SDK and I have little experience with the SPI / SPIM functions.
I started with the SDK SPI example.  I possibly also could have started with the SPIM example, since both use the SPIM with DMA, as far as I understand. 
And I'm using the SPI_SS_PIN to select the Nand Flash device.  

 For my SPI communication  I'm using functions like 

nrf_drv_spi_init(&spiInst, &spi_config, NULL, NULL);

and 

nrf_drv_spi_transfer(&spiInst, &tx_buf, 2, rx_buf, 4);

This basically works fine and  I also verify what's happening on the bus with my Logic Analyzer. 

But for certain operations with the flash it seems not to be appropriate / efficient to use the nrf_drv_spi_transfer function. 
It does its job, but the timing will be far away from optimal. 

Example:

For many commands which are sent to the NAND Flash (e.g. erase a block of memory), the device takes some unknown / varying time to finish it. For this reason the device provides a status command, which returns one byte with the current busy status. This "can" be done by sending the complete 3 byte GETSTATUS command and receive just one single status byte with each call to nrf_drv_spi_transfer. 

But the better / faster way to do this is by sending the same  3 byte GETSTATUS command sequence only once, but keeping the SS PIN active, and then continue transferring dummy bytes (in order to read the status from the device)  until a specific BUSY bit is cleared. Only then the SS PIN is returned to inactive.
No need (and no easy way) to actually save all the received and unknown number of bytes in a buffer. Only the last read byte is of interest. 

I'm aware that I might implement this GETSTATUS function somehow with a lower API level or directly programming the SPIM registers.

But basically my question is, which API level should I use to interface with the Nand Flash then ? 

a) Is it possible to mix such a status query with other regular calls to nrf_drv_spi_transfer ?  Does the API allow that ?
b) Or does it mean, I have to drop the functions around nrf_drv_spi_transfer and do all SPI communication with a lower level ? 

Thanks for any pointer.

Parents
  • Hi,

    a) The SPIM peripheral does not allow you to control the clock separately. Rather, you have to set up transactions where data (dummy or not) is transferred in and out. That is regardless of whether you control it directly via registers or use the driver. I recommend you use the driver, as that simplifies and makes the code more readable. Moreover, it is properly tested, so you will probably both save time and achieve better quality compared to writing yourself. Regarding the chip select signal you can use a SW controlled GPIO pin that you handle yourself if you need to control it in a flexible way.

    b) No, not as far as I can see.

  • Well, I do not want explicitly control the "SPI clock".   I can imagine not to use the drivers support for the chip select

    spi_config.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;

    and instead set the CS pin manually.  Thus I could

    a) set Flash CS line active
    b) send my command 0x0F, 0xB0,   (using nrf_drv_spi_transfer)
    c)  do
           send dummy 0xff to receive one (status) byte  from the Nand Flash (using nrf_drv_spi_transfer)
         while ( status byte == busy)
    d) set Flash CS  line inactive 

    It does not make sense to setup a transfer to receive e.g. 128 status bytes, and afterwards find out, that after e.g. 42 status queries the Nand Flash already was no longer busy.  So the question only is, how can I optimize (speed) the looping around a 1 byte transfer.  I will try my above idea.

    Would it be different if I use the SPI peripheral instead of the SPIM ?

Reply
  • Well, I do not want explicitly control the "SPI clock".   I can imagine not to use the drivers support for the chip select

    spi_config.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;

    and instead set the CS pin manually.  Thus I could

    a) set Flash CS line active
    b) send my command 0x0F, 0xB0,   (using nrf_drv_spi_transfer)
    c)  do
           send dummy 0xff to receive one (status) byte  from the Nand Flash (using nrf_drv_spi_transfer)
         while ( status byte == busy)
    d) set Flash CS  line inactive 

    It does not make sense to setup a transfer to receive e.g. 128 status bytes, and afterwards find out, that after e.g. 42 status queries the Nand Flash already was no longer busy.  So the question only is, how can I optimize (speed) the looping around a 1 byte transfer.  I will try my above idea.

    Would it be different if I use the SPI peripheral instead of the SPIM ?

Children
  • Hi,

    rodims said:
    Would it be different if I use the SPI peripheral instead of the SPIM ?

    The SPI peripheral does not support DMA, do you would have to process every byte in and out continuously in SW. If that is what you want ("looping around a 1 byte transfer") then it might be simpler than using 1 byte transfers with the SPIM peripheral (it should not be a big difference though, as the driver anyway abstracts away any differences).

    Generally, SPI is just a standard way of transferring data, and any meaning you put into this data (for instance if it is command, status or just dummy data) is application specific and depend on the chip you communicate with (TC58CVG2S0HRAIG). Therefor you will not find explicit support for any of this in the nRF HW or driver, but you have to implement the protocol for the external flash chip yourself (as you are doing).

Related