STM32 Timers #9. One Pulse Mode
This is the 9th tutorial in the STM32 Timer series and today we will see another timer feature, i.e the one pulse mode.
One-pulse mode is used to generate a pulse of a programmable length in response to an external event. The pulse can start as soon as the input trigger arrives or after a programmable delay. We can control the start of the pulse as well as the pulse width.
The waveform can be programmed to have a single pulse generated by the trigger, or to have a continuous pulse train started by a single trigger.
One-pulse mode also offers a retriggerable option. In this case, a new trigger arriving before the end of the pulse will cause the counter to be reset and the pulse width to be extended accordingly.
CubeMX Setup
Clock configuration
I have configured the 8 MHz external crystal to provide the clock. The system is running at 90MHz and note that both the APB timer clocks are also running at 90MHz. This will make us easier to configure the timer as we don’t have to worry which timer is connected to which APB bus.
Timer configuration
I am using timer 1 for this application. The setup is shown below.
- The timer must be configured in the slave mode with trigger mode.
- I have selected the trigger source as TI2FP2, i.e the channel 2 of the timer. Here we will connect the signal pin.
- The channel 1 is used for the output compare. Here we will get the output from the timer.
- Make sure to select the one pulse mode.
- The prescalar of 90 will bring down the clock to 1MHz. This is the rate at which the counter counts and each count will take 1us.
- I have set the ARR to 50000, so the maximum width of the pulse can be 50ms.
- Also note that the Repetition counter is set to 0, which means we only want a single pulse. If you set this value to 10 (11-1), there will be 11 pulses for each trigger.
- The Mode in output compare will be changed later in the code.
- The pulse value (the CCR1 value) is set to 10000. This means the pulse will be delayed by 10000 counts, i.e. 10ms after the trigger.
The above configuration will generate a pulse of 40ms (ARR – CCR) on each trigger on channel 2 of the timer 1.
We are using 2 channels for the timer 1,below is the pinout for the same.
Here the pin PA9 (TIM1_CH2) will be used as the input pin, where we will send the external signal. And the pin PA8 (TIM1_CH1) will be used as the output pin, where the one pulse will be generated. We will monitor this on the oscilloscope.
Additional Setting
Generating Multiple pulses
The above configuration will only generate a single pulse of the predefined delay and pulse width. If you want to generate a pulse train on a single trigger signal, you have to write the value in the Repetition counter. This is shown below.
The rest of the configuration is still the same. I have only modified the Repetition counter value to 5 (6-1). This arrangement will generate the 6 pulses of the same width upon receiving a trigger signal on the channel 2.
Retriggerable One Pulse Mode
In the Retriggerable mode, a new trigger arriving before the end of the pulse will cause the counter to be reset and the pulse width to be extended accordingly. The setup for the Retriggerable mode is shown below.
Note:- All the STM32 MCUs don’t have the retriggerable option. I am using STM32F750 discovery board and it have the retriggerable mode.
- The timer must be configured in the slave mode with Combine Reset and trigger mode. The reset of the configuration is same as what we configured earlier.
- Make sure to select the one pulse mode.
- The Prescalar and ARR configuration is same as what we configured earlier.
- The Mode in output compare is set to Retriggerable One pulse mode 2.
- The pulse value must be set to 0.
Connection
In the picture above you can see that the BLACK wire is connected between the button and the pin PA9, the TIM_CH2 Pin. The PURPLE wire is connected between the button and the 3.3V pin on the MCU.
When the button is pressed, the input pin, PA9, is pulled up to 3.3V and the Timer will see this as the trigger signal.
The BLUE wire is connected between the pin PA8, TIM_CH1, and the Logic analyzer. This is the output pin, so we will use it to see the one pulse generated on the Logic Analyzer.
Some Insight into the CODE
Single Pulse
static void MX_TIM1_Init(void)
{
........................
........................
........................
sConfigOC.OCMode = TIM_OCMODE_PWM2;
sConfigOC.Pulse = 10000-1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
........................
........................
........................
}
First of all in the Timer initialization function, change the output compare mode to PWM 2. This is updated in Line no 7.
The PWM2 mode will generate a pulse whose width will be equal to ARR-CCR as we set up in the timer initialization. For the rest of the time, the signal will remain low.
/* USER CODE BEGIN 2 */
HAL_TIM_OnePulse_Start(&htim1, TIM_CHANNEL_1);
/* USER CODE END 2 */
In the main function, after the timer initialization is over, start the timer in one pulse mode.
Below is he image showing the output on the logic analyzer.
The image above shows a single pulse of 40ms was generated when the button was pressed.
This is as per the setup we did in the cubeMX for the timer, with ARR at 50000(50ms) and CCR at 10000(10ms). The difference between them is 40ms and that’s what the width of the pulse is.
Multiple Pulses
Let’s assume that I want to generate 8 pulses with single trigger from an external signal. We need to make a small modification for this to work.
static void MX_TIM1_Init(void)
{
....................
....................
htim1.Instance = TIM1;
htim1.Init.Prescaler = 90-1;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 50000-1;
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 8-1;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
....................
....................
sConfigOC.OCMode = TIM_OCMODE_PWM2;
sConfigOC.Pulse = 10000-1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_OC_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
....................
....................
}
Since I want to generate the 8 pulses, I have set the RepetitionCounter value to 7 (Line no 11).
The rest of the configuration is unchanged. We will see the output below for this configuration.
The first image shows there are a total of 8 pulses in the output. They are generated with a single trigger provided by the button.
The second image shows the pulse width is 40ms and this is same for all the 8 pulses. The pulse remains low for 10ms, as we set the start time of 10ms (CCR value).
Retriggerable Mode
In the Retriggerable mode, the pulse width will extend if another trigger comes while the pulse is still high.
I am using the STM32F750 discovery board as this mode is not available in all the MCUs.
Also The trigger signal will be provided by the another pin, PA0, which is connected to the TIM_CH2 (input pin on channel 2). We can control the toggle delay for the pin PA0 and therefore control the trigger time.
The configuration for the Retriggerable mode is shown below.
- The timer must be configured in the slave mode with Combine Reset and trigger mode. The reset of the configuration is same as what we configured earlier.
- Make sure to select the one pulse mode.
- The Prescalar and ARR configuration is same as what we configured earlier.
- The Mode in output compare is set to Retriggerable One pulse mode 2.
- The pulse value must be set to 0.
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 1);
HAL_Delay(5);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, 0);
HAL_Delay(40);
}
Remember that pin PA0 is connected to the TIM_CH2 pin. SO when this is pulled high, the trigger pin on the timer is also high.
Also since the ARR is set to 50000(50ms) and the pulse value is 0, the output pulse width is going to be 50ms.
In the while loop I have configured the pin to go high every 45ms. This time is lower than the time for which the output pulse remains high (50ms). That means the trigger is happening before the pulse goes low and in the retriggerable mode, the pulse width should now extend.
You can see in the image above, the pulse width has been extended. This is because the new trigger signal is arriving before the pulse can even go low, so it simply keep extending.