2019-12-15 05:43 AM
We are trying to use SPI1 as a slave to receive 11 bytes of data per transaction.
I.E. SPI1_RX --> my_data_array[11]
When an 11-byte transaction is received, we want the DMA to raise a flag that we will check (we can't afford to use interrupts, as this is for a motor control application, and other interrupts can mess with our 50usec current control loop).
When I try to configure this as a project in CubeMX, the "DMA Global Interrupt" checkbox comes in the project as pre-checked, and I cannot uncheck it. Does this mean that we MUST use an interrupt to signal that the DMA is done transferring?
2019-12-17 08:06 AM
No, you should not call any HAL functions at all. Here is the rule again: You can have either strict timing requirements or CubeMX/HAL in one project, but not both.
Setting up SPI with DMA is just a few lines of code.
That's it I think, 11 simple register writes. You don't even have to bother with masking the bits, as the reset state of each register is known (listed in the reference manual).
To re-enable DMA after receiving, write the appropriate values to LIFCR or HIFCR, and set the DMA stream control register again.
2019-12-20 08:02 AM
SO, we have most of it working! We have an external processor sending the 11 byte message to the ST (through DMA2-RX), and then the ST adds a 1 to all elements, and sends it back to the external processor (through DMA1-TX).
Now, the only issue that I see is that the main processor seems to always be "behind by 1", in terms of the samples that it currently has. Is there a "one-transaction delay" in the DMA in the ST? We do NOT have double-buffering enabled.
2019-12-20 10:44 AM
You might have an issue with the L1 cache.
The L1 cache sits between the CPU core and the memories, so all code and data accesses made by the program are going through the cache, but DMA accesses bypass this cache. The scenario might be something like this:
There are two ways to solve this.
Set some memory aside for DMA buffers, and mark it as non-cacheable. I prefer this one, because it has to be set up once, and requires almost no attention later, and its effects can be resticted to the necessary memory area.
struct {
dma_rx[16];
dma_tx[16];
} nochache __attribute__ ((aligned (32)));
MPU->RBAR = ((uint32_t)&nocache) | MPU_RBAR_VALID_Msk; // using region slot 0
MPU->RASR =
MPU_RASR_XN_Msk | // 1: Instruction fetches disabled
(3u << MPU_RASR_AP_Pos) | // Full access
(4u << MPU_RASR_SIZE_Pos) | // 32 bytes
MPU_RASR_ENABLE_Msk |
0; // TEX,C,B,S are 0 meaning strongly ordered, this is the safest thing
The struct holding the DMA buffers must be padded and aligned to a power of 2, and at least to 32 bytes. If the size is changed, adjust the alignment attribute and the MPU_RASR_SIZE field accordingly. The full documentation of the MPU registers is in the PM0253 STM32F7 Series and STM32H7 Series Cortex®-M7 processor programming manual.
Cleaning and invalidating the cache when needed. This one can get tricky, especially at a DMA receive transaction.
There are 2 basic operations.
Preparing for a transmit is straightforward, just clean the cache before starting DMA.
Receiving is tricky, because invalidating means that a couple of preceding memory writes are lost. Therefore the cache should be cleaned immediately before invalidating, and it must be ensured that the receive buffer does not get accidentally cached. It must be aligned and padded to cache lines, cleaned before starting to receive, and not touched during receive. There are lots of ways it can go wrong.
2020-02-18 06:05 PM
If change the size of dma_rx & tx to 128, How do it?
2020-02-18 09:44 PM
Just follow this, change the alignment in the struct declaration, and the value that goes into MPU_RASR_SIZE.
The struct holding the DMA buffers must be padded and aligned to a power of 2, and at least to 32 bytes. If the size is changed, adjust the alignment attribute and the MPU_RASR_SIZE field accordingly. The full documentation of the MPU registers is in the PM0253 STM32F7 Series and STM32H7 Series Cortex®-M7 processor programming manual.
2020-02-18 11:22 PM
How to change (4u << MPU_RASR_SIZE_Pos) ?
2020-02-18 11:33 PM
Find the documentation of the MPU RASR register in the programming manual.