I am experimenting with timers and interrupts using STM32CubeIDE and STM32F411E development board. I am comfortable with working on microcontrollers. I noticed some anomalies in the behavior of the code.
The idea of the code is, after I introduce an external pulse on EXTI0, I'll start 2 counters, TIM1 and TIM9. TIM1 will run 10 times with period of 0.06 sec, each update interrupt will toggle PC7 to generate a square wave on the output. TIM9 will run once with period of 6 sec, at the update of TIM9, will re-activate EXTI0 interrupt.
here is part of main.c
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM1_Init();
MX_TIM9_Init();
/* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET);
halfPeriodCount = 0;
highFrequencyTogglerFlag = 0;
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(highFrequencyTogglerFlag == 1)
{
highFrequencyTogglerFlag = 0;
highFrequencyToggel();
}
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void highFrequencyToggel(void)
{
uint32_t odr;
/* get current Output Data Register value */
odr = GPIOC->ODR;
/* Set selected pins that were at low level, and reset ones that were high */
GPIOC->BSRR = ((odr & GPIO_PIN_7) << GPIO_NUMBER) | (~odr & GPIO_PIN_7);
halfPeriodCount = halfPeriodCount + 1;
if(halfPeriodCount >= MAX_HALF_PERIOD_COUNT)
{
htim1.Instance->CR1 &= ~(TIM_CR1_CEN);
}
}
void pulseDelay(void)
{
LD4_GPIO_Port->BSRR = (uint32_t)LD4_Pin << 16U;
htim9.Instance->CR1 &= ~(TIM_CR1_CEN);
}
void startTimers(void)
{
halfPeriodCount = 0;
LD4_GPIO_Port->BSRR = LD4_Pin;
// GPIOC->BSRR = GPIO_PIN_7;
GPIOC->BSRR = (uint32_t)GPIO_PIN_7 << 16U;
htim1.Instance->DIER |= TIM_IT_UPDATE;
uint32_t itflag = htim1.Instance->SR;
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
htim1.Instance->SR = ~TIM_FLAG_UPDATE;
}
htim1.Instance->CR1|= TIM_CR1_CEN;
htim9.Instance->DIER |= TIM_IT_UPDATE;
itflag = htim9.Instance->SR;
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
htim9.Instance->SR = ~TIM_FLAG_UPDATE;
}
htim9.Instance->CR1 |= TIM_CR1_CEN;
}
here is stm32f4xx_it.c
that does not work
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
HAL_NVIC_DisableIRQ(EXTI0_IRQn);
__HAL_GPIO_EXTI_CLEAR_IT(Start_Pin);
startTimers();
#ifdef RUN_HAL
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(Start_Pin);
/* USER CODE BEGIN EXTI0_IRQn 1 */
#endif
/* USER CODE END EXTI0_IRQn 1 */
}
/**
* @brief This function handles TIM1 break interrupt and TIM9 global interrupt.
*/
void TIM1_BRK_TIM9_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_BRK_TIM9_IRQn 0 */
#ifdef RUN_HAL
/* USER CODE END TIM1_BRK_TIM9_IRQn 0 */
HAL_TIM_IRQHandler(&htim1);
HAL_TIM_IRQHandler(&htim9);
/* USER CODE BEGIN TIM1_BRK_TIM9_IRQn 1 */
#endif
uint32_t itflag = htim9.Instance->SR;
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
htim9.Instance->SR = ~TIM_FLAG_UPDATE;
pulseDelay();
}
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
/* USER CODE END TIM1_BRK_TIM9_IRQn 1 */
}
/**
* @brief This function handles TIM1 update interrupt and TIM10 global interrupt.
*/
void TIM1_UP_TIM10_IRQHandler(void)
{
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 0 */
#ifdef RUN_HAL
/* USER CODE END TIM1_UP_TIM10_IRQn 0 */
HAL_TIM_IRQHandler(&htim1);
/* USER CODE BEGIN TIM1_UP_TIM10_IRQn 1 */
#endif
uint32_t itflag = htim1.Instance->SR;
if ((itflag & (TIM_FLAG_UPDATE)) == (TIM_FLAG_UPDATE))
{
htim1.Instance->SR = ~TIM_FLAG_UPDATE;
highFrequencyTogglerFlag = 1;
}
/* USER CODE END TIM1_UP_TIM10_IRQn 1 */
}
if I remove int8_t highFrequencyTogglerFlag = 1;
and replace it with highFrequencyToggel();
, the code works.
What is driving this anomaly? And how can I fix it?
The preprocessor directive #ifdef RUN_HAL
is to not use the default generic HAL functions.
1 Answer 1
Suggest definition is changed to qualify the variable as volatile. I.e.:
volatile int8_t highFrequencyTogglerFlag = 1;
That is because highFrequencyTogglerFlag
is shared between the main
function and an interrupt handler.
Without the volatile
qualifier the compiler optimiser may think there are no side-effects in the main
function which change highFrequencyTogglerFlag
, and not sample the updated value after has been modified by the interrupt handler. See this and this for some background information.
int8_t startTimerFlag = 0;
", looking at the posted code I can't see astartTimerFlag
variable. Has the correct code been posted? \$\endgroup\$highFrequencyTogglerFlag
\$\endgroup\$