To All,
From reading the datasheet I understand that nfr52832 spi can only send/receive up to 255 bytes at once. And to work around this a list method is used. Because I am writing/reading to a NAND flash, which has a page size of 2076 bytes, to save power by minimizing the number of write/read operations I would need to implement this method.
To test this on a smaller dataset, I have set the max buffer for both tx and rx to be 10, then try and write/read a dataset that is 30 bytes long. However I just cant get it to work, I keep getting wierd data from the NAND flash when trying to read back the data stored on it. Below is my code to illustrate this.
What I have done is to separate the spi transfer into long read and long write functions, for sending/reading a lot of data. The spi handler is used to count how many frames have been sent so for example to send a data set of 30 bytes + instruction with a buffer size of 10, 4 frames would be required. So every time a SPI_END event triggers the spi handler, it increases the frame counter by one, then manually starts the next transfer. (the reason for the manual start is that I cant get spi_short to work).
Code For Spi Handler:
void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{
if( long_transfer) // If Long transfer enabled
{
transfer_cnt++; // Counter for number of frames transferred
if(transfer_cnt <= n_transfer) //if number of frames transferred = total length / Buffer size
{
nrf_spim_task_trigger(spi.p_registers, NRF_SPIM_TASK_START); // Manually start next transfer
SEGGER_RTT_printf(0, "In Spi Interrupt: \r\n");
}else{
//nrf_spim_shorts_disable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);
spi_xfer_done = true;
}
}else{
spi_xfer_done = true;
}
}
Code For Long Write:
SPI_STATUS Serialize_SPI_long(uint8_t* tx_buf,
uint8_t tx_len,
uint8_t* rx_buf,
uint8_t rx_len)
{
SEGGER_RTT_printf(0, "Long Write Transfer: \r\n");
transfer_cnt = 0; //Counter for number of frames transferred
long_transfer = true; //Enable long transfer
uint16_t total_len = rx_len + tx_len; // synchronous transfer, total length = rx len + tx len
SEGGER_RTT_printf(0, "length: %d\r\n", total_len );
SEGGER_RTT_printf(0, "Buffer Size: %d\r\n", BUFFERSIZE );
n_transfer = ceil((double)total_len/BUFFERSIZE); // Number of frames to transfer = total length/ buffer size
SEGGER_RTT_printf(0, "Total No tranfers: %d\r\n", n_transfer );
uint8_t tx_array[n_transfer][BUFFERSIZE]; // 2D array buffer
for(uint16_t i = 0; i < total_len; i++) // Set all elements to 0x00;
{
tx_array[i/BUFFERSIZE][i%BUFFERSIZE] = 0x00;
}
for(uint16_t i = 0; i < tx_len; i++) // Copy data form tx_buf to tx_array
{
tx_array[i/BUFFERSIZE][i%BUFFERSIZE] = tx_buf[i];
}
spi_xfer_done = false;
//nrf_spim_shorts_enable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);
nrf_drv_spi_xfer_desc_t spi_xfer_NAND_desc = NRF_DRV_SPI_SINGLE_XFER( tx_array[0], BUFFERSIZE, rx_buf, rx_len);
nrf_gpio_pin_clear( SPIM0_SS_PIN ); // Manually toggle select line
APP_ERROR_CHECK(nrf_drv_spi_xfer(&spi, &spi_xfer_NAND_desc, NRF_DRV_SPI_FLAG_TX_POSTINC)); //Start transfer with Tx postinc flag
while(!spi_xfer_done)
{
__WFE();
}
nrf_gpio_pin_set( SPIM0_SS_PIN ); //Manually toggle select line
memcpy(rx_buf, rx_buf+tx_len, rx_len); //Reformat rx buf to get rid of the packets received during tx transfer
return RetSpiSuccess;
}
Code For Long Read:
SPI_STATUS Serialize_SPI_long2(uint8_t* tx_buf,
uint8_t tx_len,
uint8_t* rx_buf,
uint8_t rx_len)
{
SEGGER_RTT_printf(0, "Long Read Transfer: \r\n");
transfer_cnt = 0; //Counter for number of frames transferred
long_transfer = true; //Enable long transfer
uint16_t total_len = rx_len + tx_len; // synchronous transfer, total length = rx len + tx len
SEGGER_RTT_printf(0, "length: %d\r\n", total_len );
SEGGER_RTT_printf(0, "Buffer Size: %d\r\n", BUFFERSIZE );
n_transfer = ceil((double)total_len/BUFFERSIZE); // Number of frames to transfer = total length/ buffer size
SEGGER_RTT_printf(0, "Total No tranfers: %d\r\n", n_transfer );
uint8_t rx_array[n_transfer][BUFFERSIZE]; // 2D array buffer
for(uint16_t i = 0; i < total_len; i++) // Set all elements to 0x00;
{
rx_array[i/BUFFERSIZE][i%BUFFERSIZE] = 0x00;
}
spi_xfer_done = false;
//nrf_spim_shorts_enable(spi.p_registers, NRF_SPIM_SHORT_END_START_MASK);
nrf_drv_spi_xfer_desc_t spi_xfer_NAND_desc = NRF_DRV_SPI_SINGLE_XFER( tx_buf, tx_len, rx_array[0], BUFFERSIZE);
nrf_gpio_pin_clear( SPIM0_SS_PIN ); //Manually toggle select line
APP_ERROR_CHECK(nrf_drv_spi_xfer(&spi, &spi_xfer_NAND_desc,NRF_DRV_SPI_FLAG_RX_POSTINC)); //Start transfer with Rx postinc flag
while(!spi_xfer_done)
{
__WFE();
}
nrf_gpio_pin_set( SPIM0_SS_PIN ); //Manually toggle select line
for(uint16_t i = 0; i < total_len; i++) //Flatten rx 2d array to 1D rx buf
{
rx_buf[i] = rx_array[i/BUFFERSIZE][i%BUFFERSIZE];
}
memcpy(rx_buf, rx_buf+tx_len, rx_len); //Reformat rx buf to get rid of the packets received during tx transfer
return RetSpiSuccess;
}
Output from RTT:
The data sent (written into the NAND) should match with data received( read from the NAND), if I increase the buffer size then the data match better, if buffersize > dataset then they match. Which I do not understand why.
Output from RTT buffersize 20 data size 30:
Output form RTT buffersize 50 data size 30:
I am pretty sure the problem is due to long read function, because if I use long transfer to write data to NAND flash, but normal spi transfer to read the data then I get the correct reading.
Thank you so much for the help.
Regards, Bryan