Incrementing the TX buffer in PPI-driven SPI


I transfer data by ESB between send and receive.
And I want to transfer 2 bytes x 10 data that is received by ESB every T[s] to ESB receive (trigger) -> PPI->SPIM, 2 bytes every T/10[s].
We have already confirmed that the hardware can correctly drive the SPI SS, SCLK and MOSI every T/10[s] starting from the ESB receive timing.
However, as it is an ESB, it can be triggered, but I understand that the passing from the ESB receive buffer to the SPI TX buffer needs to be done via the CPU (interrupt processing).

So I first prepared an ESB receive buffer 2 bytes x 10 (payload) and a SPI TX buffer 2 bytes x 1. I then increment the read address of the ESB receive buffer for each SPI interrupt and copy the 2 bytes to the SPI TX buffer.

However, with this method, the 10/10th data may not be correctly transferred to the SPI's TX buffer.
It seems that the SPI interrupt has a lower priority than the ESB receive interrupt and the 10/10th SPI interrupt is delayed, thus delaying the 10/10th data transfer and not allowing the 10/10th SPI TX operation by PPI in time.

I would therefore like to transfer the data from the ESB receive buffer to the SPI TX buffer without involving the interrupt process.
Specifically, first prepare a 2 byte x 10 SPI TX buffer, which is the same as the ESB receive buffer. Then, each time an ESB receive interrupt occurs, the 2 byte x 10 data in the ESB receive buffer is copied to the SPI TX buffer at once.

After the n-th SPI transfer, the read address of the TX buffer is incremented without an SPI interrupt to prepare for the (n+1)st SPI transfer. How can I do this?
Can you tell me how to do this specifically?

<<Current programme>>

#define SPI_DA_SIZE 2
uint8_t spi_tx_buf[ SPI_DA_SIZE ]

void spi_init(void)
{
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.ss_pin = SPI_CONV;
spi_config.miso_pin = NRF_DRV_SPI_PIN_NOT_USED;
spi_config.mosi_pin = SPI_MOSI;
spi_config.sck_pin = SPI_SCK;
spi_config.frequency = NRF_DRV_SPI_FREQ_4M;
spi_config.mode = NRF_DRV_SPI_MODE_2;
nrf_drv_spi_init(&SPI_0, &spi_config, spi_event_handler, NULL);

nrf_drv_spi_xfer_desc_t spi_xfer;
spi_xfer.p_tx_buffer=spi_tx_buf;
spi_xfer.tx_length=SPI_DA_SIZE;
spi_xfer.p_rx_buffer=NULL;
spi_xfer.rx_length= NULL;
nrf_drv_spi_xfer(&SPI_0,&spi_xfer,NRF_DRV_SPI_FLAG_HOLD_XFER); //It is important NRF_DRV_SPI_FLAG_HOLD_XFER.
return;
}

Parents
  • Sounds to me that you need to look at array list, then each start task will increment the buffer pointer:
    https://infocenter.nordicsemi.com/topic/ps_nrf52840/easydma.html#arraylist 

    Then after executing the start task let's say 10 times, then you need to update the buffer array and set the pointer to the start of the buffer array again.

    Alternatively you need to look into giving the spi interrupt priority 0, but that may affect the real-time handling of the ESB protocol in a negative way (e.g. affect ack).

    In either case the CPU will need to do some CPU processing before/after e.g. 10 transfers.

    Kenneth

  • Reply, thanks.

    https://infocenter.nordicsemi.com/topic/ps_nrf52840/easydma.html#arraylist 
    in the EasyDMA array list for examples and Figure 3.
    So the questions are.

    (1) ’Then each start task will increment the buffer pointer:’
    What is a pointer in this case? Does the pointer here mean READER.PTR = &ReaderList = 0x20000000?

    (2) Read order
    In this example, does this mean that the address to be read is incremented as follows?
    RaderList[0]-buffer[0]--->RaderList[0]-buffer[1]--->RaderList[0]-buffer[2]--->RaderList[0]-buffer[3]--->RaderList[1]-buffer[0]--->RaderList[1]-buffer[1]--->--->--->--->--->--->--->--->--->--->--->----->--->--->--->--->--->--->--->--->--->RaderList[2]-buffer[2]--->RaderList[2]-buffer[3].

    (3) 'Then you need to update the buffer array and set the pointer to the start of the buffer array again.'
    The following is a list of the Specifically.
    --RaderList[0]-buffer[0] to RaderList[2]-buffer[3] then you need to update the contents of the buffer array.
    --READER.PTR = &ReaderList = 0x20000000, revert.
    Does this mean?

  • So you need to for intance set SPIM.TXD_MAXCNT and SPIM.TXD_PTR like any SPIM transfer, however if you also enable SPIM.TXD_LIST, then for each 'n' SPIM transfer that you call SPIM.TASKS_START then the TXD_PTR will point to the memory address TXD_PTR+MACNT*'n'.

    So that is why you need to define for instance:

    #define BUFFER_SIZE 2

    typedef struct ArrayList
    {
    uint8_t buffer[BUFFER_SIZE];
    } ArrayList_type;

    ArrayList_type TXDList[10] ;

    NRF_SPIM->TXD.MAXCNT = BUFFER_SIZE;
    NRF_SPIM->TXD.PTR = &TXDList;
    NRF_SPIM->TXD.LIST = 1;

    You may also need to do the same for RXD buffer if you want it to increment the same way.

    If you want to start from the beginning of the ArraList again then you need to write one time to NRF_SPIM->TXD.PTR before calling start task again.

    Best regards,
    Kenneth

Reply
  • So you need to for intance set SPIM.TXD_MAXCNT and SPIM.TXD_PTR like any SPIM transfer, however if you also enable SPIM.TXD_LIST, then for each 'n' SPIM transfer that you call SPIM.TASKS_START then the TXD_PTR will point to the memory address TXD_PTR+MACNT*'n'.

    So that is why you need to define for instance:

    #define BUFFER_SIZE 2

    typedef struct ArrayList
    {
    uint8_t buffer[BUFFER_SIZE];
    } ArrayList_type;

    ArrayList_type TXDList[10] ;

    NRF_SPIM->TXD.MAXCNT = BUFFER_SIZE;
    NRF_SPIM->TXD.PTR = &TXDList;
    NRF_SPIM->TXD.LIST = 1;

    You may also need to do the same for RXD buffer if you want it to increment the same way.

    If you want to start from the beginning of the ArraList again then you need to write one time to NRF_SPIM->TXD.PTR before calling start task again.

    Best regards,
    Kenneth

Children
Related