This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

RM57x DMA ADC Memory behavior

Other Parts Discussed in Thread: HALCOGEN

Hi Hercules experts,

I have an silly issue (I reckon) but spent hours to figure out without success.

I use DMA to continuously transfer 12 ADC results to a memory. The memory is defined as static in the adc.c module. ADC is configured to do the conversion continuously, and DMA is triggered when all 12 channels have been converted.

When debugging, the memory address monitored gave me expected results. See picture below.

However, when I read the memory in the application , it gave me the initialised data instead of the ADC data seen above. Insert a breakpoint to the reading adc function, the memory is automatically reset to my initialised data 0xA5, and this is the data I've got in the application instead of ADC data seen above. See picture below

If I cleared the breakpoint and let the the program run freely, then refresh the memory browser, I see the ADC data again in the debug window but not inside the application. Try continuous refreshing also gave me updated ADC results frequently in the debug window only.

I suspect the issue has something to do with memory mapping. Please anyone can explain and give me a suggestion to solve this?

Many thanks.

Phil

  • Hi Phil,

     What is your cache scheme selected? Is it write-through cache or write-back cache? if you choose write-back cache can you please change to write-through cache like below? Let me know if it makes a difference.

  • Hi Charles,

    Thank you for the answer, yes it was the issue, thanks for pointing it out.
    I would like to understand about this cache architecture a little bit deeper, please can you explain?

    Back to the issue, since getting the ADC results correctly written to the memory, I catch prefetchEntry abort (exception) at random time. I suspect it is because application and DMA tried to access the same memory at the same time. Is there a hardware mutex/locking mechanism inside the chip that I should use to protect this? At the moment I use:

    while (dmaIsChannelActive(DMA_CH1));
    x0 = get_adc_result(chan0);

    while (dmaIsChannelActive(DMA_CH1));
    x1 = get_adc_result(chan1);

    ...

    It seems to be ok but not ideal for a real-time application. Any suggestion?

    Regards,
    Phil
  • Hi Phil,
    First of all you have a cacheable memory that is shared by both the CPU and the DMA. Your code must have read the ADC destination buffer before the DMA started the transfer. Since the memory is declared cacheable, the buffer addresses have been stored in the cache tag RAM. In write-back cache scheme when the DMA transfers data to the L2SRAM, the CPU does not know that the external memory has become incoherent with respect to its cache content. You probably get an interrupt after the DMA transfer is complete. When CPU is notified to read the ADC buffer, it simply reads from the cache first since it thinks it is a cache hit. It does not know the data stored in the L2SRAM has been modified by the DMA. This is the reason for you problem. With write-through cache selected, it automatically enables an built-in snooping logic. The snooping logic detects if a L2SRAM is modified by any non-CPU master and if this is the case it will notify the CPU's cache controller to invalidate the cache lines. Since the cache lines corresponding to these ADC buffers have been invalidated, when CPU reads the ADC buffer it must read the external L2SRAM instead as if it is a cache miss. Reading the L2SRAM makes the cache and the L2RAM coherent again.

    As far as the exception you are getting, I'm not too sure the reason especially a prefetch abort rather a data abort. Prefetch abort is an exception due to CPU code fetch, not data access. The DMA transfer should not interfere with how CPU fetches it code. You can find out the cause of the prefetch abort exception by reading the Instruction Fault Status Register and Instruction Fault Address Register inside the CPU.
  • Hi Charles,

    Thank you for the explanation, it makes much more sense now. Thanks a lot!!

    I try to insert a breakpoint when CPU get into the prefetch abort, but it never get hit. By pausing the program I've got the following status

    The instruction fault address is right at the prefetch abort entry, and the instruction error status is zero.

    Is there something I missed when debugging?

    Kind regards,

    Phil

  • Hi Phil,
    You said if you place a breakpoint at prefetchEntry and it will never stop there. If you simply halt the CPU and you will find the PC already at prefetchEntry. Is this the correct understanding?

    Can you first place a breakpoint at prefetchEntry and do a system reset and then let it run?

    Can you also show the instruction fault status register? You only showed the auxilliary fault status register.
  • Hi Charles,

    You said if you place a breakpoint at prefetchEntry and it will never stop there. If you simply halt the CPU and you will find the PC already at prefetchEntry. Is this the correct understanding?

    Yes that was what I meant.

    Can you first place a breakpoint at prefetchEntry and do a system reset and then let it run?

    That is always the case how I debug. Tried to reset/restart and place a breakpoint at prefetchEntry, then run. However that breakpoint never gets hit.

    Can you also show the instruction fault status register? You only showed the auxilliary fault status register.

  • It looks like you have MPU fault for some reason. You have 0b01101 in your IFSR. First check your MPU setting to see if all the MPU regions are proper.

    Are you able to single step your code until the line that generates the prefetch abort? You might need to place breakpoints at various places to see how far you can run the code before prefetch abort is taken.
  • Hi Charles,

    Many thanks for your support.

    The abort, as said, occurs randomly and not consistent. I have a real-time tick running at 1ms to the control task. The control task runs fine in few seconds then stop. The durable time is very random, e.g. 3sec, 5sec, etc. Therefore I can not do step by step debugging.

    If I stopped the ADC, i.e. if I just read ADC from the memory without having DMA to update that memory, then it does not have problem.

    I will check the MPU settings. I let it to be default as HALCoGen suggested. Can you point me to a document discussing how to set the MPU correctly?

    Kind regards,
    Phil
  • I'm still puzzled as to how a prefetch abort is generated. I can understand better if it is a data abort exception. Prefetch abort means an error is detected while the CPU is fetching the code. Are you solely running code out of the flash? Can you show your MPU setting like below? You have shown the IFSR and IFAR. Can you also show the Data Fault Status Register and Data Fault Address Register? Are they zero or not-zero values?

  • That is always the case how I debug. Tried to reset/restart and place a breakpoint at prefetchEntry, then run. However that breakpoint never gets hit

    Rather than setting a breakpoint at the prefetchEntry, you can also try enabling "Break on Undefined Instruction", "Break on Prefetch Abort" and "Break on Data Abort" in the CCS debugger ARM Advanced Features. That causes the debugger to halt upon any of those exceptions.

    The following example is a program halting upon after a Data Abort exception caused by a test program which deliberately accessed an invalid pointer at address 0x1234DEAD as a result of "Break on Data Abort" being selected:

    The CCS debugger doesn't seem to remember the settings for "Break on Undefined Instruction", "Break on Prefetch Abort" and "Break on Data Abort", so you have to re-enable them every time a new debug session is started.

  • Hi Charles,

    I have changed a little bit of the MPU settings and now I get the dataEntry Abort. However the data fault address is very random. Please see attached recorded address when aborts happened

    S1:

    S2:

    S3:

    S4:

    Again, if I disabled the code to copy ADC result then it is ok.

    Kind regards,

    Phil

  • Hi Phil,

     For some reason you are writing to the flash as indicated by the Data Fault Status Register and Data Fault Address Register. Can you setup a watchpoint and watch for the address 0x37. 0x37 is what is indicated in the data fault address status. But I think you can watch any address that is in the address range of the flash memory. So once you setup the watchpoint then edit below breakpoint property when setting up the watchpoint. See the Range Mask is set to 0x3FFFFF. So the watchpoint is watching for any write to the first 4MB of CPU memory map.

    Are you running some type of RTOS?