This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Double buffered SPIM TXD and RXD registers on nrf5340

I am using SPIM4 with easyDMA in list mode to read a set of registers from an SPI device, and everything seemed to work great until I attempted to use the double buffered TXD and RXD registers. Am I missing something, or is the double buffered functionality limited when easyDMA is used in list mode?

Code examples and results are listed below. The working example does not rely on the TXD and RXD registers being double buffered, but the broken example does.

Working Example

In the example below I do not rely on the SPIM registers to be double buffered, and the result is in line with what I would expect.

  1. Paint the receive buffer with 0xAA
  2. Log the painted receive buffer
  3. Prepare SPIM for 9 transactions of 7 bytes using list mode and a counter
  4. Enable external data ready trigger
  5. Clear (old) counter compare event
  6. Wait for new counter compare event
  7. Log filled receive buffer
Test code Result
memset(result, 0xAA, RET_LEN * num_regs);
LOG_HEXDUMP_INF(result, RET_LEN*num_regs, "Flushed rx buff");

// Wait for first transaction to start
spim->TXD.PTR = (uint32_t)read_cmd_buff;
spim->RXD.PTR = (uint32_t)result;
nrfx_dppi_group_enable(drdy_event_group);

NRF_TIMER0->EVENTS_COMPARE[0] = 0;
while(!(NRF_TIMER0->EVENTS_COMPARE[0]));
LOG_HEXDUMP_INF(result, RET_LEN*num_regs, "Filled rx buff");
Running burst test
Burst test finished
[00:01:13.967,193] <inf> ADE7953: Flushed rx buff
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa    |........ .......
[00:01:13.967,498] <inf> ADE7953: Filled rx buff
                                  ff ff fe 00 0c c6 6b ff  ff ff ff f7 6f fd ff ff |......k. ....o...
                                  fe 00 27 15 2f ff ff fe  00 28 7a 9f ff ff fe 00 |..'./... .(z.....
                                  04 5e e9 ff ff ff ff fb  a2 56 ff ff fe 00 06 2e |.^...... .V......
                                  07 ff ff ff a5 78 a5 78  ff ff ff fd d0 fd d0    |.....x.x .......

Broken example

When I modify the code to prime for the next transaction after the first has started it seems like the last transaction is lost:

Test code Result
// Paint receive buffer with 0xAA
    memset(result, 0xAA, RET_LEN * num_regs);
    LOG_HEXDUMP_INF(result, RET_LEN*num_regs, "Flushed rx buff");

    // Prepare transaction
    spim->TXD.PTR = (uint32_t)read_cmd_buff;
    spim->RXD.PTR = (uint32_t)result;
    spim->EVENTS_STARTED = 0;
    nrfx_dppi_group_enable(drdy_event_group);

    // Wait for transaction to start
    while(!(spim->EVENTS_STARTED));

    // Prime for next transaction
    spim->TXD.PTR = (uint32_t)read_cmd_buff;
    spim->TXD.MAXCNT = CMD_LEN;
    spim->RXD.PTR = (uint32_t)result;
    spim->RXD.MAXCNT = RET_LEN;
    //nrfx_dppi_group_enable(drdy_event_group); // Not enabeling next ransfer

    // Wait for transaction to complete
    NRF_TIMER0->EVENTS_COMPARE[0] = 0;
    while(!(NRF_TIMER0->EVENTS_COMPARE[0]));

    // Log result
    LOG_HEXDUMP_INF(result, RET_LEN*num_regs, "Filled rx buff");
Running burst test
Burst test finished
[00:06:05.437,072] <inf> ADE7953: Flushed rx buff
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa aa |........ ........
                                  aa aa aa aa aa aa aa aa  aa aa aa aa aa aa aa    |........ .......
[00:06:05.437,255] <inf> ADE7953: Filled rx buff
                                  ff ff ff ff fb fb d5 ff  ff fe 00 11 0d 0b ff ff |........ ........
                                  fe 00 27 15 7f ff ff fe  00 28 7a 28 ff ff fe 00 |..'..... .(z(....
                                  04 5e b5 ff ff ff ff fb  a2 bf ff ff fe 00 06 2e |.^...... ........
                                  02 ff ff ff a5 7c a5 7c  aa aa aa aa aa aa aa    |.....|.| .......

Parents
  • I expanded the "broken example" from my original post to use two independent rx_buffers, rx_buff[0], rx_buff[1]

    As before all rx_buff memory is painted with 0xAA before SPIM transaction, and the buffers are logged before and after the transactions has completed. This gave the result captured below:

    Based on this result it seems like the double buffered registers are reloaded at the next TASK_START trigger, even though list mode is used.

    My hope was that the SPIM would hold off reloading until a TASK_STOP trigger has been received. I am using SPIM with a counter to implement a burst read from a chip that requires slave select to deactivate between every register access, and I was hoping to use double buffered RXD / TXD to prime for burst n+1 at the start for burst n.

    The obvious solution would be to start transactions from a drdy triggered ISR, or to prime the SPIM for the next burst at the end of every burst, but this will result in quite tight ISR latency requirements.

    Suggestions to alternative solutions are most welcome :)

Reply
  • I expanded the "broken example" from my original post to use two independent rx_buffers, rx_buff[0], rx_buff[1]

    As before all rx_buff memory is painted with 0xAA before SPIM transaction, and the buffers are logged before and after the transactions has completed. This gave the result captured below:

    Based on this result it seems like the double buffered registers are reloaded at the next TASK_START trigger, even though list mode is used.

    My hope was that the SPIM would hold off reloading until a TASK_STOP trigger has been received. I am using SPIM with a counter to implement a burst read from a chip that requires slave select to deactivate between every register access, and I was hoping to use double buffered RXD / TXD to prime for burst n+1 at the start for burst n.

    The obvious solution would be to start transactions from a drdy triggered ISR, or to prime the SPIM for the next burst at the end of every burst, but this will result in quite tight ISR latency requirements.

    Suggestions to alternative solutions are most welcome :)

Children
No Data
Related