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

NRF52832 DMA HALF TRANSFER INTERRUPT AND EASYDMA ARRAYLIST

Hi ,

1-) Is there any dma half transfer interrupt ? if there is where it is in documents ? ( i check this link but i couldnt see anything about this https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.nrf52832.ps.v1.1%2Feasydma.html

2-) How is that ArrayList organised by EasyDma? 

Lets assume that i am reading 32bytes from spi to ram . i have prepared 2 array with 16bytes in size. So how is it organized by dma ;

 - 1,3,5,7,9... byte will go 1st array and 2,4,6,8... to second array ?

-OR 1-16th Bytes will be stored in  1st array and 17-32th will be in second array ?

- or what ?

 Thank you all.

Best regards.

    1. There are no half transfer interrupt

    OR 1-16th Bytes will be stored in  1st array and 17-32th will be in second array ?

     Yes. The Array List feature is fairly simple, the pointer register in f.ex. the SPIM: RXD.PTR, is incremented by the RXD.MAXCNT size after the EVENTS_END has been fired. It is then up to you to trigger another TASKS_START in order to fill the next array of RXD.MAXCNT size. 

    You have to track how many EVENTS_END has been fired in order to know when to stop triggering the TASKS_START. This can be done either in SW or HW. With HW you can connect the EVENTS_END with the TASKS_START event via a PPI channel, and fork the EVENTS_END event to a TIMER — Timer/counter's TASKS_COUNT in order to increment the said counter. Then you can control the number of arrays you want by using the TIMER's EVENTS_COMPARE[x] event to trigger the TASKS_CHG[0].DIS of a channel group that includes the PPI channel of the EVENTS_END->TASKS_START channel. This will then turn off the PPI channel that keeps the SPIM in a perpetual loop, thereby stopping it after x iterations where x is set in the TIMER's CC[0] register.

    To break it down:

    1. Create a PPI channel between EVENTS_END and TASKS_START to set up the perpetual triggering of TASKS_START.
    2. Create a PPI channel group that only includes the PPI channel we're going to use. By triggering this channel group's TASKS_CHG[x].DIS you will disable the ppi channel we use to perpetually trigger TASKS_START.
    3. Set up a TIMER in COUNTER mode, with a CC[0] of how many buffers you want to transfer.
    4. Fork the PPI channel to connect the EVENTS_END with the TIMER's TASKS_COUNT, in order to increment it.
    5. Connect the TIMER's EVENTS_COMPARE[0] to the PPI's TASKS_CHG[x].DIS via a second PPI channel. This will disable the END->START ppi channel.
    6. Fork the second PPI channel to the TIMER's TASKS_CLEAR, in order to reset the TIMER for the next burst of transfers.



    If you're only interested in transferring 32 bytes then you do not need to use the array list feature as the maximum buffer size allowed by RXD.MAXCNT is 255 bytes.

  • You have to track how many EVENTS_END has been fired in order to know when to stop triggering the TASKS_START. This can be done either in SW or HW. With HW you can connect the EVENTS_END with the TASKS_START event via a PPI channel, and fork the EVENTS_END event to a TIMER — Timer/counter's TASKS_COUNT in order to increment the said counter. Then you can control the number of arrays you want by using the TIMER's EVENTS_COMPARE[x] event to trigger the TASKS_CHG[0].DIS of a channel group that includes the PPI channel of the EVENTS_END->TASKS_START channel. This will then turn off the PPI channel that keeps the SPIM in a perpetual loop, thereby stopping it after x iterations where x is set in the TIMER's CC[0] register.

    Actually i want to port my stm32 code in to nrf52 , i was using half transfer int this was "like" circular buffer. So i dont understand your example 100% ,since i did not realize PPI yet .So first i need to read about it ....

    But before reading it from your answer i have an idea if i understood you correctly.

    I need 1024 sample 32bit each ram area to store my samples. While cpu makes some calculation on the first 512 sample , dma should write samples to remaining area then so on.... 

    if i will inspire from your message , can i say i need to ;

    1-) create  16x256 byte array list 

    2-) connect the EVENTS_END with the TASKS_START event via a PPI (is this some kind of  for auto start of dma ??)

    3-)and fork the EVENTS_END event to a TIMER — Timer/counter's TASKS_COUNT in order to increment the said counter.

    (this will count how many array has been filled in array list righ ? is this fork hw fork or sw fork?)

    4-) TIMER's EVENTS_COMPARE[x] event (i will set this to 8 to get half transfer  ,right ?)

    if my assumes are correct i will get some kind of emulated half transfer event but by hw, is this correct ? 

  • I updated my previous post before I noticed that you had answered, I suggest you read it.

    1) The Maximum buffer size is 255 bytes, therefore I suggest 32 x 128bytes (4096bytes), or 17 x 241(4097bytes).

    2) Since the list feature auto-increment the DMA address pointer, we can immediately start another transfer. DMA is handled by the SPIM HW automatically. 

    3) Correct, this will keep track of how many arrays have been filled. The "fork" is a feature of a PPI — Programmable peripheral interconnect channel where one EVENT can trigger one additional TASK without having to create an additional channel. 

    4)You can set up another compare event. By setting the CC[1] register to half of CC0, and enabling the interrupt for CC1 by writing to the INTENSET register. The TIMER driver should forward an event to the application's TIMER callback after half the arrays have been transferred. The callback is provided as the event handler in nrfx_timer_init.

  •  Yes. The Array List feature is fairly simple, the pointer register in f.ex. the SPIM: RXD.PTR, is incremented by the RXD.MAXCNT size after the EVENTS_END has been fired. It is then up to you to trigger another TASKS_START in order to fill the next array of RXD.MAXCNT size. 

    i read whole Saadc section in document but i couldnt see such specification. i have also tested it by real code. But RESULT.PTR did not changed after END event .Is there any specific bit to activate auto increment  of  xxx.PTR ?

    Sorry , does this  auto increment  of  xxx.PTR behavior belong to only some peripherals such as spi ? or any peripheral with EasyDma?

  • The ArrayList feature is only enabled for the TWIM and SPIM peripherals. 

    From SAADC's EasyDMA chapter: 
    "The Result buffer is located at the address specified in the RESULT.PTR register. The RESULT.PTR register is double-buffered and it can be updated and prepared for the next START task immediately after the STARTED event is generated. "

    If you update the RESULT.PTR register after each STARTED event, then you can connect the END event to the START task, connected the STARTED event to a TIMER's START task, and a TIMERs COMPARE event to the SAADC's SAMPLE task. 
    That way the SAADC can run with as little delay as possible when switching buffers. 
    You will also need to fork the SAADC's END event to the TIMER's STOP task, in order to prevent the TIMER from triggering a SAMPLE task when the SAADC is reading the RESULT registers. 


Related