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