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.

RM57L843: Cache problem with DMA (FreeRTOS project)

Part Number: RM57L843
Other Parts Discussed in Thread: HALCOGEN

Hello,

I'm experiencing a weird problem in a FreeRTOS project in which I'm trying to send data through SPI in combination with the DMA (similar to this).


Problem:

The DMA is fetching data from RAM and copying it into the SPI TX buffer. Even though that specific piece of RAM is configured as non-cacheable, the DMA seems to be reading old data in RAM. This hypothesis is confirmed by the following counterexamples:

  • the problem disappears when completely disabling the cache in the system
  • the problem disappears if, with cache enabled, I explicitly clean the section of cache corresponding to the memory where the DMA is fetching data from, before triggering the DMA


HALCoGen configuration:

The project configuration in HALCoGen is as follows:

  • Project
    • FreeRTOS (RM57L843ZWT_FREERTOS)
    • GCC tools
  • Driver Enable
    • enable GIO and SPI3 drivers
  • R5-MPU-PMU
    • enable Region 8 (to be used by DMA)
    • Base: 0x08007C00
    • Size: 1 KB
    • Type: NORMAL_OINC_SHARED (shared and non-cacheable)
    • Permission: PRIV_RW_USER_RW_NOEXEC
  • RAM
    • Length: 0x00007C00 (leave 1 KB at the end for the shared section)
  • OS
    • uncheck all boxes
    • change Min Stack Size to 256
  • VIM RAM
    • change channel 2's name to vPortNonPreemptiveTick (workaround for HALCoGen bug)

When generating files with HALCoGen, two files need to be changed to solve some issues of HALCoGen:

  • in os_port.c, define the following
#define __interrupt __attribute__((interrupt("IRQ")))
  • in os_portmacro.h, change the definition of portYIELD_WITHIN_API to
#define portYIELD_WITHIN_API() { portSYS_SSIR1_REG = portSYS_SSIR1_SSKEY; ( void ) portSYS_SSIR1_REG; }


Project description:

After initializing SPI and DMA, I create one periodic FreeRTOS task to send data over the SPI3 peripheral using the DMA. RAM buffers that are to be accessed by the DMA are placed within the shared/non-cacheable section of the RAM using a customized linker script. The periodic task simply increments a variable, fills in the buffer to be read by the DMA, and triggers a DMA block transfer.

In this case, the DMA does not read the updated values from the shared RAM, and the SPI spits out all-zero words. As said above, if I clean the section of cache corresponding to the memory where the DMA is fetching data from, the SPI spits out the correct words. I checked many things around the initialization scripts generated by HALCoGen, and they seem to be fine. This issue is really driving me crazy, how can cleaning the cache of a non-cacheable memory section make any difference?


To reproduce:

I'm attaching the sample project I'm using, so that you can check it. It's been tested on Ubuntu 18.04. To use it, make sure you have the ARM GCC compiler and CMake on your machine. Then, download my project and run the following:

$ tar xf dmacache-rm57l.tar
$ cd dmacache-rm57l
$ mkdir build
$ cd build
$ export GCC_ARM_NONE_EABI_INSTALL_DIR=/path/to/gcc-arm-none-eabi-X-Y-Y-Z
$ cmake ..
$ make

The bin file will be build/dmacache-rm57l.out. I am using a Logic Analyzer to inspect SPI data.


Thanks in advance for your help,

Carlo

5265.dmacache-rm57l.tar

  • Hello Carlo,

    I don't see the shared the section in HL_sys_link.ld file.

    Is there overlapping of two MPU regions? Each region has its own priority, with region 0 having the lowest priority and region 11 having the highest. The MPU returns access permissions and attributes for the highest priority region where the address hits.

    Can you try to use write-through for the shared region?

  • Hi QJ,

    I'm using the ldscript.ld linker script located at the root of the project, as the HALCoGen-generated HL_sys_link.ld would be overwritten at any new code generation.

    As for the MPU configuration, as I said, I'm using region 8 for the shared section, that should take higher priority then region 3 (memory protection on RAM is defined in region 3). So this should not be a problem.

    I have tried to set the shared region as write-through, but that makes no difference. And, in any case, I would expect non-cacheability to be a safer option.

    Thanks, and looking forward to some other input,

    Carlo

  • Hi Carlo,

    I remember only several MPU regions are configured in freeRTOS (os_port.c). Please make sure that the region 8 is configured properly.

  • Hi QJ,

    Your input was useful. Inside os_port.c I found this in a comment

    Note: By default, all the RAM regions are configured to be cached (write-back, write-through) for better performance. This configuration is not suited in case multiple bus masters access the RAM, for example, DMA or EMAC master. Please use the USERCODE section below to change the default MPU settings

    To be honest I really wish this were more documented, I shouldn't have to look into port code to find out that some init function is overriding my HALCoGen settings.

    The solution I now adopted is to not configure MPU through HALCoGen, and use vTaskAllocateMPURegions() instead to allocate MPU regions per task at run-time.

    Best,

    Carlo

  • Hello Carlo,

    My colleague is working on a application note to address this. I am sorry for any inconvenience caused by the shortage of guideline.