cancel
Showing results for 
Search instead for 
Did you mean: 

SCB_InvalidateDCache() hangs

fbar
Senior

I'm using a Nucleo-H437ZI2 board. Set up a simple project in STM32CubeIDE with the latest firmware for H7. I enabled both Icache and Dcache, no MPU

I create a uint16_t array of 12,900 elements as a buffer for an ADC conversion using DMA transfer into the bus. Since the Dcache is active, after the ADC/DMA conversion completes, I want to invalidate the cache, to ensure coherency between what the DMA transferred and what the CPU sees.

So, after having read all the available L1 documents (AN4839) and some examples, I added SCB_InvalidateDCache() right after the DMA completes, and before accessing the array. But the execution hangs, and if I interrupt the execution, I see that it loops forever in the code below in core_cm7.h

__STATIC_INLINE void SCB_InvalidateDCache (void)
{
  #if defined (__DCACHE_PRESENT) && (__DCACHE_PRESENT == 1U)
    uint32_t ccsidr;
    uint32_t sets;
    uint32_t ways;
 
    SCB->CSSELR = 0U; /*(0U << 1U) | 0U;*/  /* Level 1 data cache */
    __DSB();
 
    ccsidr = SCB->CCSIDR;
 
                                            /* invalidate D-Cache */
    sets = (uint32_t)(CCSIDR_SETS(ccsidr));
    do {
      ways = (uint32_t)(CCSIDR_WAYS(ccsidr));
      do {
        SCB->DCISW = (((sets << SCB_DCISW_SET_Pos) & SCB_DCISW_SET_Msk) |
                      ((ways << SCB_DCISW_WAY_Pos) & SCB_DCISW_WAY_Msk)  );
        #if defined ( __CC_ARM )
          __schedule_barrier();
        #endif
      } while (ways-- != 0U);
    } while(sets-- != 0U);
 
    __DSB();
    __ISB();
  #endif
}

sets starts from 127, decreases to 126, then jumps to 4294967294 and loops forever.

If instead I use the following SCB_InvalidateDCache_by_Addr((uint32_t *) &aADCxConvertedData[0], ADC_CONVERTED_DATA_BUFFER_SIZE * 2);, the memory used by the array is then read properly

I know I should probably disable Dcache for the memory used by DMA transfers (per the notes in AN4839), but only a small portion of my code relies on DMA, then there's an extensive set of operations on the data array, so I was thinking of disabling Dcache before the DMA section, perform all the ADC conversions, then re-enable Dcache

The problem is that SCB_DisableDCache(); also hangs, because before disabling the cache it will force an InvalidateDCache-like loop, and also loop forever. Same for SCB_EnableDCache();.

What I don't understand is why  SCB_EnableDCache(); works fine when invoked at the beginning the the code (before HAL_Init()), but fails in the main loop. I'm sure I'm missing something

Any pointer?

1 ACCEPTED SOLUTION

Accepted Solutions

Using the function blind will tend to trash any pending stack writes.

Use the by address variant, and remember that has 32-byte alignment expectations.

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

View solution in original post

4 REPLIES 4

Using the function blind will tend to trash any pending stack writes.

Use the by address variant, and remember that has 32-byte alignment expectations.

Tips, buy me a coffee, or three.. PayPal Venmo Up vote any posts that you find helpful, it shows what's working..
fbar
Senior

Thanks for the reply. And, yes, I did notice the 32 bit alignment so all my arrays are 32 bit aligned, to be on the safe side (the H7 has so much RAM, it's easy to get spoiled after years of fighting with mre kBytes for embedded CPUs :). But thanks for mentioning it, always good to be reminded of things like these

The "stack write trashing" sounds plausible for what I'm seeing. You mention "using the function blind", does it mean that there's a safer way to invoke it, or just that in general using SCB_InvalidateDCache() in the code is a bad idea, to be avoided?

Piranha
Chief II

> I'm using a Nucleo-H437ZI2 board.

Not 437, but 743.

> I did notice the 32 bit alignment so all my arrays are 32 bit aligned

Not bits, but bytes. Clive wrote clearly "32-byte" alignment. Plus buffer size also must be multiple of the same 32 bytes. And that is a requirement only for buffers on which you are doing cache invalidation, not all arrays in a project.

Additional recommendation - instead of magic numbers it's even better to use this define from core_cm7.h header file:

#define __SCB_DCACHE_LINE_SIZE  32U /*!< Cortex-M7 cache line size is fixed to 32 bytes (8 words). See also register SCB_CCSIDR */

More details here:

https://community.st.com/s/article/FAQ-DMA-is-not-working-on-STM32H7-devices

P.S. I hope you write code with more attention to details... 🙂

fbar
Senior

>P.S. I hope you write code with more attention to details... =)

I usually do :( Sometimes, though, my brain thinks one thing (e.g. bytes) and my fingers type another (bit). thanks for the __SCB_DCACHE_LINE_SIZE define (and all you rother points), good to know about that.