cancel
Showing results for 
Search instead for 
Did you mean: 

STM32G431 FOC R3_2_TIMx_UP and ADC1_2 Interrupt handler lockup with FreeRTOS

Clive_S
Associate II

I have a strange problem with the ADC/TIM interrupts for a simple FOC motor application on STM32G431 on the B-B431B-ESC eval board. The build uses FreeRTOS.

There appears to be some strange behavior with R3_2_TIMx_UP_IRQHandler() and ADC1_2_IRQHandler() at startup under some conditions. An apparently benign code change (code that is not actually executed) causes a lockup in R3_2_TIMx_UP_IRQHandler() due to an aparent timing issue.

while (0x0u != pHandle->pParams_str->ADCDataReg1[pHandle->_Super.Sector]->JSQR)
{
    /* Nothing to do */
}

 

What appears to happen in the lockup case is

  • R3_2_TIMx_UP_IRQHandler() called for the 1st time and triggers an ADC JSQR conversion (T1).
  • R3_2_TIMx_UP_IRQHandler() called for the second time and triggers an ADC JSQR conversion (T2).
  • ADC1_2_IRQHandler() is called for the first time for T1, but we now loose T2
  • R3_2_TIMx_UP_IRQHandler() called for the third time and hangs because JSQR is not zero because the T2
    trigger was lost.

What should have happened is the first call to ADC1_2_IRQHandler() should have happened before the second call to R3_2_TIMx_UP_IRQHandler().

I can toggle between the correct and incorrect behavior by (for example) inserting a call to strtol() in a thread. However I have added a 5 second sleep to the start of all threads (including medium-frequency and safety) to ensure the thread code is present but the threads are effectively disabled initially. The lockup occurs quite early after the osKernelStart() call. FreeRTOS should take one pass through each thread and then they should all sleep leaving FreeRTOS in its idle loop. Adding the strtol moves things in memory a little but in this case the version that works
correctly has the strtol() call present. There is plenty flash and ram.

In the failing case I can re-trigger the ADC in R3_2_TIMx_UP_IRQHandler() but that just repeats the same cycle with the call to ADC1_2_IRQHandler being too late. However, if I then add one idle pass through R3_2_TIMx_UP_IRQHandler() (ie skip one tick) everything syncs up and the ADC1_2_IRQHandler() calls happen correctly before the next R3_2_TIMx_UP_IRQHandler() call and everything then works fine. That apears it could be a workaround, though I don't like it.

I'm struggling to work out what would cause these two interrupts to initially get out of sync. The behavior regarding adding or removing the one line of code has been 100% consistent through dozens of debug builds. I have seen other things flip between working and not working, this one just seems to be particularly stable. Adding that line of code will change memory locations but its existence may possibly also change startup timing and code alignment and there may be other minor knock-on effects but at the moment I don't have a solid root-cause.

Are there any specific startup constraints with the FreeRTOS build that I need to be aware of? There seems to be no timing constraint between R3_2_Init() and osKernelStart(), should there be?

Has anyone seen anything like this before, anything else I might have missed?

I also note that Inc/stm32g4xx_hal_conf.h defines TICK_INT_PRIORITY to be 0, with a comment that is lowest. 0 is usually highest in cortex. Is that intentional? Is there a requirement for TICK_INT_PRIORITY to be 0?

Thanks

Clive

 

0 REPLIES 0