Extend SysTick to 32 bit / Interrupt-safe DCACHE handling
In my software, I usually extend the 24bit SysTick handler to 32bit with the tricks shown in the code segment below. Using such a do-while construct as shown in "GetSysTickCompleteVal" I usually prefer for the fast access to volatile interrupt data, then I do not need to fight with disabling / enabling interrupts... .
This works in STM32F4 perfectly.
To my surprise this does NOT work in STM32H7 ... even if the DCACHE is disabled. I was very reliefed when I recognized that I can fix this by just adding __DSB() in my access function... . (but I needed several hours Googling around DCACHE... to get this idea...).
I looked for several hours through the STM32H7 Programming Manual cache description texts (+ ARM Cortex M7 TRM / Generic user guide, this morning I also found the arm AN321 ... but this all is terribly cumbersome and strangely described... ).
Generally I am happy now with my __DSB(). But I would like to know, whether there are other possiblities to solve this. Anybody knows this?
Alternatively to __DSB(), could I possibly use one of these strange (poorly described) instructions ICIMVAU, DCIMVAC, DCISW, DCCMVAU, DCCMVAC, DCCSW, DCCIMVAC, DCCISW for this purpose? In the ARM Cortec M7 Generic User Guide there is also discussed the possibility of "Forch Write Through" for data ... this sounds nice, but is this possible? (Could I e. g. define the volatile variable vuiSysTickValBase somehow such, that "write-through" / cache disabled is enforced for especially this varialbe ... or would this be efficient / complete nonsense?).
Code example to extend the SysTick timer to 32 bits (this example can easily be modified also for larger bit count, or for dropping e. g. the last 8 bits if nsec resolution for SysTick is not required... :(
volatile unsigned int vuiSysTickValBase;
void SysTickInit(){}
// 1.6M = 200MHz / 125kHz ... this generates Systick-Handler-Interrupt
// every 8ms (125kHz) (CPU AHB at maximum frequency of 200MHz)
#define SYSTICK_COUNTS 1600000
SysTick->LOAD = SYSTICK_COUNTS - 1;
NVIC_SetPriority (SysTick_IRQn, IP_SysTick);
// STM32H7: Y code chips do NOT allow AHB/8, see errata, better use AHB
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
SysTick_CTRL_TICKINT_Msk |
SysTick_CTRL_ENABLE_Msk;
}
void SysTick_Handler(void){
// use -! (SysTick running down...)
vuiSysTickValBase -= SYSTICK_COUNTS;
}
// To get the "Total 32 bit" value in "interrupt-safe" mode, in STM32F4 the
// following code was fine:
unsigned int GetSysTickCompleteVal(){
unsigned int uiBase, uiBase1, ui1;
do{
uiBase= vuiSysTickValBase;
ui1= SysTick->VAL;
uiBase1= vuiSysTickValBase;
} while (uiBase != uiBase1);
return uiBase + ui1;
}
// In STM32H7 this does NOT work ... if within the do loop the intterupt comes,
// this will very frequently give wrong values (old uiBase value combined with
// current SysTick Val ... ).
// In STM32H7 this even does not work, if DCACHE is not enabled... .
// This __DSB() construct is ultimately required for STM32H7!!!
unsigned int GetSysTickCompleteVal_H7(){
unsigned int uiBase, uiBase1, ui1;
do{
uiBase= vuiSysTickValBase;
ui1= SysTick->VAL;
__DSB();
uiBase1= vuiSysTickValBase;
} while (uiBase != uiBase1);
return uiBase + ui1;
}