Introduction
The STM32F103C6T6A microcontroller, part of the STM32F1 series, includes a versatile Capture and Compare (CC) module that enhances its functionality for timing and measurement applications. This module is integral to the advanced timer peripherals found on the microcontroller.
The compare module can compare the counter value to a predefined threshold. When the counter matches the threshold, it can trigger an event or generate a PWM signal. This is essential for generating precise output waveforms and controlling external devices.
In this post we will cover compare mode and the capture mode will be covered in the next post.
Exercise
Write a program to blink an LED in 4 sec delay using the Compare mode of Timer 1
Registers used
- APB2 peripheral clock enable register (RCC_APB2ENR) – Enable clock for TIM1 and GPIOA
- Port A configuration register high (GPIOA_CRH) – Enable the alternate function for the pin PA8 to work as TIM1_CH1 pin.
- TIM1 Prescaler register (TIMx_PSC) – The timer prescaler value
- TIM1 capture/compare mode register 1 (TIMx_CCMR1) – Select action on compare match and capture/compare mode.
- TIM1 capture/compare enable register (TIMx_CCER) – enable Compare mode
- TIM1 reak and dead-time register (TIMx_BDTR) – Enable output pin
- TIM1 control register 1 (TIM1_CR1) – Enable the timer
Solution
In compare mode, the LED should be connected to the pin that is connected to the OCx output. If you refer to Figure 52 in the reference manual RM0008 (Download link in my blog “Start with STM32F103C6T6A”), you will see that the OCn pins are connected to the TIMx_CHn pins on the right-hand side of the diagram. These TIMx_CHn pins are multiplexed with some GPIO pins, and you can find this mapping in the datasheet (refer to table 5 in my blog “Start with STM32F103C6T6A”). Specifically, TIM1_CH1 to TIM1_CH4 are multiplexed with PA8 to PA11. For this exercise, I will use TIM1_CH1 (PA8) as the pin to connect the LED.
Next, we need to enable the TIM1_CH1 pin. First, configure PA8 for the alternate function using the GPIOA_CRH register. For this, we need to configure the PA8 pin as an alternate function push-pull (refer to Table 22 of RM0008). The procedure to configure PA8 as an alternate function push-pull is explained in Table 20 of RM0008. Specifically, CNF1:CNF0 should be set to 10.
// Clear both CRH_MODE8 and CRH_CNF8.
GPIOA->CRH &= ~(GPIO_CRH_MODE8 | GPIO_CRH_CNF8);
// Output mode, max speed 10 MHz
GPIOA->CRH |= GPIO_CRH_MODE8_0;
// Alternate function output push-pull
GPIOA->CRH |= GPIO_CRH_CNF8_1;
The next step is to configure the CCMR register. Since we are using channel 1 in compare mode, we are interested only in TIM1_CCMR1[7:0]. The channel is configured as output compare by default. Set OC1M[2:0] to 011 to toggle the output when TIM1_CNT equals TIM1_CCR1.
// Toggle on compare match between TIM1_CNT and TIM1_CCR1
TIM1->CCMR1 &= ~(TIM_CCMR1_OC1M);
TIM1->CCMR1 |= (TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_0);
// Enable compare output
TIM1->CCMR1 &= ~(TIM_CCMR1_CC1S);
Now, configure the counter to make 64,000 counts, and each count should take 500 clock cycles (prescaler 499). No matter the value loaded in TIM1_CCR1, the pin will toggle whenever the counter register equals the CCR1 register. This setup will create a 4-second delay.
// Total 4 sec delay for on and off LED
TIM1->PSC = 499;
TIM1->ARR = 63999;
// No matter the value set here because the match will happen
// once only in every 0-63999 counting.
TIM1->CCR1 = 32767;
Enable the capture compare module, output pin, and timer.
// Capture compare enable
TIM1->CCER |= TIM_CCER_CC1E;
// Enable PA8 (OC) if corresponding OCxE is set in the CCER register
TIM1->BDTR |= TIM_BDTR_MOE;
// Start the timer
TIM1->CR1 |= TIM_CR1_CEN;
The compare module setup is now complete. We will call it from the main function and wait in an infinite loop. Whenever a match occurs, the TIM1_CH1 pin will toggle, and hence the LED connected to that pin will toggle.
Here is the link to see the code in my GitHub page: Click Here