In Marlin we need to have access to the DWT CYCCNT register for short delays. On a STM32F7 you need to execute following code to gain access to these register:
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
This code is essential to not let the MCU halt when disconnecting the debugger probe (in my case Segger JLINK). After executing the above code, the program is then able to get the current cycle counter from the CYCCNT.
Right now we are calling the above code from the setup() methode as the first code. But sadly, this seems too late, since the MCU will halt when detaching the debugger probe and starting normally.
After some debugging I found out that I had to put the above code right after the SystemClock_Config() right after all clocks are configured. With that code change, I could now detach my debugger probe, the MCU didn't halt and the program got access to the CYCCNT register.
I need to look deeper into the issue and need to identify what between the SystemClock_Config() and the Setup() method is called, that results in this problem.
I would like to avoid putting the above code into the variant definition and I feel the setup() method is the right place to do so.
Hi @hasenbanck,
I've made a branch several months ago to perform some test around DWT.
Maybe this can help (rebased on top of the master):
https://github.com/fpistm/Arduino_Core_STM32/tree/DWT
It seems you also had to setup the DWT access directly after the clock setup and before initializing the other peripherals. Maybe this is the correct way to do.
Suggestion:
We could add a function call inside the cores/arduino/stm32/hw_config.c:
void hw_config_init(void)
{
//Initialize the HAL
HAL_Init();
// Configure the system clock
SystemClock_Config();
// Initialize optional debug peripheral
SystemDebug_Config();
}
Whereas the SystemDebug_Config() would be a weak function, that could be overwritten by the sketch. So when, for whatever reason, the developer wants to configure the debugging peripherals (ITM/DWT or other Core Debug stuff), then he could use that entry-point to do so.
@fpistm If you approve of such an idea, I would test such an implementation this evening and would open a PR.
Nils this make sense.
So agreed ;)
About where calling the DWT init, I think setup is too late as in main() stage.
hw_config_init() is called at the premain() stage which come early.
My first read raised that any debug event not properly handled will finish as an exception, probably your case
Useful docs:
ARM® v7-M Architecture Reference Manual
ARM® CoreSight™ Architecture Specification v3.0
Using the DWT stuff for timing doesn't seem like its best use. Why can't you use a real timer. Doesn't the STM32F7 have more than enough?
Regarding stuffing things into the main() function that you want to do early on in the c runtime setup, there are other ways to do this for your personal code. I reject the idea that the core main() function needs to be modified to handle your personal code needs . Check out the gcc specific attribute "constructor". You can use this attribute to force code to run before main().
https://stackoverflow.com/questions/2053029/how-exactly-does-attribute-constructor-work
@RickKimball The delay function is not STM32F7 specific, so timers are not an option right now. The delay function are designed to be compatible for Cortex-M7 in general. So DWT is currently the best fit.
I will look if using the "constructor" attribute could help in this case.
Since the current premain() also uses the "constructor" attribute, we can indeed the suggested method by @RickKimball .
This is how we can do the initialization between the premain() and main() function of the core:
__attribute__(( constructor (102)))
void HAL_preinit() {
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}
Just wondering where you guys are taking definitions of CoreDebug from?
I expected to find those in includes here, alas, no.
So I had to do this: https://github.com/FastLED/FastLED/pull/568/commits/c68b12ca003e0554f6
Perhaps there is a better way?
CoreDebug is a CMSIS definition. For STM32F1, it is in the cortex m3 include file provided by the CMSIS package.
https://github.com/stm32duino/ArduinoModule-CMSIS
And the core has CMSIS in its include path:
https://github.com/stm32duino/Arduino_Core_STM32/blob/e07c02a20a409120682c9367841377a6edd2ce5f/platform.txt#L65
Most helpful comment
It seems you also had to setup the DWT access directly after the clock setup and before initializing the other peripherals. Maybe this is the correct way to do.
Suggestion:
We could add a function call inside the
cores/arduino/stm32/hw_config.c:Whereas the
SystemDebug_Config()would be a weak function, that could be overwritten by the sketch. So when, for whatever reason, the developer wants to configure the debugging peripherals (ITM/DWT or other Core Debug stuff), then he could use that entry-point to do so.@fpistm If you approve of such an idea, I would test such an implementation this evening and would open a PR.