STM32 LED Pulse

From Stm32World
Jump to navigation Jump to search

Imagine you had the requirement to turn on a LED for a specific length of time at the press of a button (or some other event).

Obviously, responding to a button press could be easily handled by an external interrupt, so one could come up with something like:

// Warning, really idiotic code follows - don't _EVER_ do this!
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == BTN_Pin) // If the button
    {

        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // Switch LED ON
        HAL_Delay(500); // Wait 500 ms
        HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // Switch LED OFF

    }
}

It should be equally obvious why this is a really piss poor idea. The function will block for half a second, leaving the processor unable to do anything else for that period.

A much better idea would be to use a timer (of which most STM32 processors have quite a lot) to handle the delay.

First, let us configure a timer for this use.

One shot timer.png

In this example, the timer clock is 100 MHz.

Timer clock.png

And the User Variables LED_PRE and LED_CNT are configured like this:

User Constants.png

In other words, once started, the timer should count down from 9999 to 0 at a frequency of 100 MHz / 10000 = 10 kHz (10000 per second). Since the LED_CNT is set to 9999, the timer will run for exactly 1 second and then fire an interrupt.

We can now improve on the above code:

/* USER CODE BEGIN 0 */

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
	if (htim->Instance == TIM5) {
		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // Off LED
		HAL_TIM_Base_Stop(&htim5); // Kill the Timer
	}
}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
	if (GPIO_Pin == BTN_Pin) // If the button
	{

		HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // Switch LED ON

		if (__HAL_TIM_GET_COUNTER(&htim5) == LED_CNT) { // Check if Timer is running - sort of
			HAL_TIM_Base_Start_IT(&htim5); // Timer is NOT running - start it
		} else {
			__HAL_TIM_SET_COUNTER(&htim5, LED_CNT); // Timer IS running - reset it
		}
	}
}

/* USER CODE END 0 */

The HAL_TIM_PeriodElapsedCallback is pretty obvious. The button interrupt is a little more complex. We are only using one timer, so we have to check if it is already running and only start the timer if it is not. If the timer is running we simply reset it to a full second again.

And that is about it - no (or very few at least) CPU cycles wasted leaving the processor to do other thing while waiting to switch the LED off.

Source code is in github: https://github.com/lbthomsen/blackpill/tree/master/btnpulse