cancel
Showing results for 
Search instead for 
Did you mean: 

different cache behavior between stm32H7 and stm32F7

Franzi.Edo
Senior

Hi,

I am facing a strange cache problem. I use the DCMI coupled to the DMA in order to acquire an image into the external SDRAM. As indicated in the application note AN4839, I proceed in this way.

  1. before to start the DMA transfer I clean the cache (cache_D_Clean();)
  2. At the end of the transfer (in the DMA interruption indicating the end), I invalidate the cache (cache_D_Invalidate();)

Everything work perfectly on the stm32H7.

On the stm32F7, as soon as the cache invalidation routine is called, the CPU generates a bus error.

On the stm32F7, in the DMA interruption indicating the end of the transfer, I replaced the cache invalidation (cache_D_Invalidate()😉 by the cache clean followed by the cache invalidation (cache_D_Clean(); cache_D_Invalidate();). Adding a clean (cache_D_Clean();) seems to avoid the bus error but I cannot understand why.

Why the behavior of the H7 and the F7 caches are different on the same code?

Thank you for your feedbacks.

Any idea why ?

1 ACCEPTED SOLUTION

Accepted Solutions
Piranha
Chief II

The functions, which clean/invalidate the whole cache, normally should not be used at all and are almost useless. Typically I-cache can just be enabled and doesn't require any further management. For D-cache a proper management has to follow 3 basic rules:

  1. Make the address and size of all receive buffer instances aligned to __SCB_DCACHE_LINE_SIZE.
  2. Call SCB_InvalidateDCache_by_Addr() before passing the receive buffers to DMA.
  3. Call SCB_CleanDCache_by_Addr() before passing the transmit buffers to DMA.

Yes, even for receive part the invalidation must be done before passing buffers to DMA, because otherwise cache eviction can damage the receive buffers by writing back dirty lines during reception. A cite from AN4839:

If all the lines are allocated, the cache controller runs the line eviction process, where a line is selected (depending on replacement algorithm) cleaned/invalidated, and reallocated. The data cache and Instruction cache implement a pseudo-random replacement algorithm.

AN4838 is also closely related.

View solution in original post

4 REPLIES 4

Use the By Address variant of Invalidate DCache, lest very bad things happen...

Why? Because it trashes data pending to the stack, among other things, and that's hard to unwind and will cause unpredictable behaviour.

https://www.keil.com/pack/doc/CMSIS/Core/html/group__Dcache__functions__m7.html

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
Piranha
Chief II

The functions, which clean/invalidate the whole cache, normally should not be used at all and are almost useless. Typically I-cache can just be enabled and doesn't require any further management. For D-cache a proper management has to follow 3 basic rules:

  1. Make the address and size of all receive buffer instances aligned to __SCB_DCACHE_LINE_SIZE.
  2. Call SCB_InvalidateDCache_by_Addr() before passing the receive buffers to DMA.
  3. Call SCB_CleanDCache_by_Addr() before passing the transmit buffers to DMA.

Yes, even for receive part the invalidation must be done before passing buffers to DMA, because otherwise cache eviction can damage the receive buffers by writing back dirty lines during reception. A cite from AN4839:

If all the lines are allocated, the cache controller runs the line eviction process, where a line is selected (depending on replacement algorithm) cleaned/invalidated, and reallocated. The data cache and Instruction cache implement a pseudo-random replacement algorithm.

AN4838 is also closely related.

#ifndef __SCB_DCACHE_LINE_SIZE
#define __SCB_DCACHE_LINE_SIZE 32U
#endif
 
void flush_cache(bool is_TX, void *ptr, unsigned len)
{
    if (!ptr || (len == 0))
        __BKPT(0);
    // ptr, len may be not cacheline aligned: see impl. of SCB_CleanDCache_by_Addr
    // but we require alignment to be sure
    if ( len & (__SCB_DCACHE_LINE_SIZE - 1))
        __BKPT(0);
    if ((uintptr_t)ptr & (__SCB_DCACHE_LINE_SIZE - 1))
        __BKPT(0);
    if (is_TX) {
        SCB_CleanDCache_by_Addr(ptr, len);
    } else {
        SCB_InvalidateDCache_by_Addr(ptr, len);
    }
}

Franzi.Edo
Senior

Hi All,

thank you for all your input.

I implemented the clean/invalidation by address and on all my hardware (M7 and H7) and things run well.

Great support, thank you.

Edo