Controlling PWM of LED through direct access of TIM2 timer's registers.

Dependencies:   mbed

Committer:
Ladon
Date:
Fri Aug 02 13:30:49 2019 +0000
Revision:
11:42d5cbbd0f3e
Parent:
10:f80370dd55f8
Controlling PWD of LED through direct access of TIM2 timer's registers.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Ladon 5:3ee6e0113b41 1 #include <mbed.h>
Ladon 0:12efa8652054 2 #include <iostream>
Ladon 0:12efa8652054 3
Ladon 0:12efa8652054 4 using namespace std;
Ladon 0:12efa8652054 5
Ladon 10:f80370dd55f8 6 void inline led_init ()
Ladon 0:12efa8652054 7 {
Ladon 5:3ee6e0113b41 8 // Led is at PA5.
Ladon 5:3ee6e0113b41 9 // -
Ladon 9:e65dd1ad537e 10 // Set PA5 as AF1 (TIM2_CH1).
Ladon 8:6464500cc838 11 // -
Ladon 11:42d5cbbd0f3e 12 // Alternate Function Low Register.
Ladon 11:42d5cbbd0f3e 13 // -
Ladon 8:6464500cc838 14 GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5;
Ladon 8:6464500cc838 15 GPIOA->AFR[0] |= 1 << GPIO_AFRL_AFRL5_Pos;
Ladon 11:42d5cbbd0f3e 16 // Port Output Speed Register.
Ladon 11:42d5cbbd0f3e 17 // -
Ladon 8:6464500cc838 18 GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5;
Ladon 11:42d5cbbd0f3e 19 // Port Mode Register.
Ladon 11:42d5cbbd0f3e 20 // -
Ladon 5:3ee6e0113b41 21 GPIOA->MODER &= ~GPIO_MODER_MODER5;
Ladon 8:6464500cc838 22 GPIOA->MODER |= 2 << GPIO_MODER_MODER5_Pos;
Ladon 0:12efa8652054 23 }
Ladon 0:12efa8652054 24
Ladon 5:3ee6e0113b41 25 void inline reset_timer ()
Ladon 0:12efa8652054 26 {
Ladon 5:3ee6e0113b41 27 // Peripheral Reset Register.
Ladon 11:42d5cbbd0f3e 28 // TIM2 timer reset.
Ladon 5:3ee6e0113b41 29 // -
Ladon 5:3ee6e0113b41 30 RCC->APB1RSTR |= RCC_APB1RSTR_TIM2RST;
Ladon 5:3ee6e0113b41 31 RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM2RST;
Ladon 0:12efa8652054 32 }
Ladon 0:12efa8652054 33
Ladon 5:3ee6e0113b41 34 void inline clock_enable_for_timer ()
Ladon 0:12efa8652054 35 {
Ladon 11:42d5cbbd0f3e 36 reset_timer();
Ladon 5:3ee6e0113b41 37 // Peripheral Clock Enable Register.
Ladon 5:3ee6e0113b41 38 // TIM2 Timer Clock Enable.
Ladon 5:3ee6e0113b41 39 // -
Ladon 5:3ee6e0113b41 40 RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
Ladon 0:12efa8652054 41 }
Ladon 0:12efa8652054 42
Ladon 11:42d5cbbd0f3e 43 void inline timer_setup_pwm ()
Ladon 11:42d5cbbd0f3e 44 {
Ladon 11:42d5cbbd0f3e 45 const double duty_cycle = 0.6;
Ladon 11:42d5cbbd0f3e 46 // Capture/ Compare Register 1.
Ladon 11:42d5cbbd0f3e 47 // -
Ladon 11:42d5cbbd0f3e 48 TIM2->CCR1 = TIM2->ARR * duty_cycle;
Ladon 11:42d5cbbd0f3e 49 // Capture/ Compare Mode Register 1.
Ladon 11:42d5cbbd0f3e 50 // Output Compare 1 Mode.
Ladon 11:42d5cbbd0f3e 51 // Output Compare 1 Preload Enable.
Ladon 11:42d5cbbd0f3e 52 // Output Compare 1 Fast Enable.
Ladon 11:42d5cbbd0f3e 53 // -
Ladon 11:42d5cbbd0f3e 54 TIM2->CCMR1 = (0b111 << TIM_CCMR1_OC1M_Pos) | TIM_CCMR1_OC1PE | TIM_CCMR1_OC1FE;
Ladon 11:42d5cbbd0f3e 55 // ^ 0b111 : PWM Mode 2 : On while CCR < ARR, OFF while >=.
Ladon 11:42d5cbbd0f3e 56 // -
Ladon 11:42d5cbbd0f3e 57 }
Ladon 11:42d5cbbd0f3e 58
Ladon 8:6464500cc838 59 void inline timer_enable_pwm ()
Ladon 8:6464500cc838 60 {
Ladon 11:42d5cbbd0f3e 61 timer_setup_pwm();
Ladon 11:42d5cbbd0f3e 62 // Capture/ Compare Enable Register.
Ladon 11:42d5cbbd0f3e 63 // Capture/ Compare 1 Output Enable.
Ladon 11:42d5cbbd0f3e 64 // -
Ladon 10:f80370dd55f8 65 TIM2->CCER = TIM_CCER_CC1E;
Ladon 8:6464500cc838 66 }
Ladon 8:6464500cc838 67
Ladon 4:c52637c8d084 68 void inline timer_downscale_by (const unsigned short& v)
Ladon 0:12efa8652054 69 {
Ladon 5:3ee6e0113b41 70 // Prescaler.
Ladon 5:3ee6e0113b41 71 // -
Ladon 2:7c45a714b991 72 TIM2->PSC = v;
Ladon 0:12efa8652054 73 }
Ladon 0:12efa8652054 74
Ladon 4:c52637c8d084 75 void inline timer_limit_counter_to (const unsigned int& v)
Ladon 0:12efa8652054 76 {
Ladon 5:3ee6e0113b41 77 // Auto-Reload Register.
Ladon 5:3ee6e0113b41 78 // -
Ladon 2:7c45a714b991 79 TIM2->ARR = v;
Ladon 0:12efa8652054 80 }
Ladon 0:12efa8652054 81
Ladon 5:3ee6e0113b41 82 void inline timer_set_period_to (const double& T)
Ladon 0:12efa8652054 83 {
Ladon 11:42d5cbbd0f3e 84 // Precondition : T <= 59 (= (2^32 - 1) / 72e6).
Ladon 5:3ee6e0113b41 85 // -
Ladon 8:6464500cc838 86 timer_limit_counter_to(72000000 * T);
Ladon 11:42d5cbbd0f3e 87 // ^Explanation : By limiting ARR to 72e6, the counter gets filled in 1sec (at 72Mhz).
Ladon 11:42d5cbbd0f3e 88 // -
Ladon 0:12efa8652054 89 }
Ladon 0:12efa8652054 90
Ladon 5:3ee6e0113b41 91 void inline timer_enable_interrupt ()
Ladon 5:3ee6e0113b41 92 {
Ladon 5:3ee6e0113b41 93 // DMA/ Interrupt Enable Register.
Ladon 5:3ee6e0113b41 94 // Update Interrupt Enable.
Ladon 5:3ee6e0113b41 95 // -
Ladon 10:f80370dd55f8 96 TIM2->DIER = TIM_DIER_UIE;
Ladon 5:3ee6e0113b41 97 }
Ladon 0:12efa8652054 98
Ladon 5:3ee6e0113b41 99 void inline timer_enable ()
Ladon 0:12efa8652054 100 {
Ladon 5:3ee6e0113b41 101 // Control Register 1.
Ladon 5:3ee6e0113b41 102 // Update Request Source | Counter Enable.
Ladon 0:12efa8652054 103 // -
Ladon 11:42d5cbbd0f3e 104 TIM2->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
Ladon 5:3ee6e0113b41 105 }
Ladon 5:3ee6e0113b41 106
Ladon 5:3ee6e0113b41 107 void inline timer_clear_status ()
Ladon 5:3ee6e0113b41 108 {
Ladon 5:3ee6e0113b41 109 // Status Register.
Ladon 5:3ee6e0113b41 110 // -
Ladon 5:3ee6e0113b41 111 TIM2->SR = 0;
Ladon 0:12efa8652054 112 }
Ladon 0:12efa8652054 113
Ladon 5:3ee6e0113b41 114 /*
Ladon 5:3ee6e0113b41 115 // I was unable to use the following handler :
Ladon 5:3ee6e0113b41 116 // -
Ladon 5:3ee6e0113b41 117 extern "C" void TIM2_IRQHandler (void)
Ladon 5:3ee6e0113b41 118 {
Ladon 5:3ee6e0113b41 119 cout << "Interrupt hit!" << endl;
Ladon 5:3ee6e0113b41 120 clear_timer_status();
Ladon 5:3ee6e0113b41 121 toggle_LED();
Ladon 5:3ee6e0113b41 122 }
Ladon 5:3ee6e0113b41 123 */
Ladon 0:12efa8652054 124
Ladon 5:3ee6e0113b41 125 // I couldn 't get TIM2_IRQHandler() to work; probably wrong name. Thus, I 'll use a custom handler
Ladon 5:3ee6e0113b41 126 // and attach it using SetVector() from CMSIS : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html.
Ladon 4:c52637c8d084 127 // -
Ladon 4:c52637c8d084 128 void interrupt_handler ()
Ladon 3:db424769ecca 129 {
Ladon 4:c52637c8d084 130 timer_clear_status();
Ladon 3:db424769ecca 131 }
Ladon 3:db424769ecca 132
Ladon 10:f80370dd55f8 133 void inline interrupt_enable ()
Ladon 0:12efa8652054 134 {
Ladon 4:c52637c8d084 135 // NVIC_SetPriority(TIM2_IRQn, 250);
Ladon 7:d93dcab712f1 136 NVIC_SetVector(TIM2_IRQn, reinterpret_cast<uint32_t>(interrupt_handler));
Ladon 2:7c45a714b991 137 NVIC_EnableIRQ(TIM2_IRQn);
Ladon 5:3ee6e0113b41 138 // ^Definition of NVIC_SetVector() : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html#gab43c1c59d5c081f1bc725237f4b1f916.
Ladon 5:3ee6e0113b41 139 // -
Ladon 0:12efa8652054 140 }
Ladon 0:12efa8652054 141
Ladon 11:42d5cbbd0f3e 142 void inline timer_init ()
Ladon 11:42d5cbbd0f3e 143 {
Ladon 11:42d5cbbd0f3e 144 clock_enable_for_timer();
Ladon 11:42d5cbbd0f3e 145 timer_set_period_to(0.1);
Ladon 11:42d5cbbd0f3e 146 timer_enable_interrupt();
Ladon 11:42d5cbbd0f3e 147 timer_enable_pwm();
Ladon 11:42d5cbbd0f3e 148 timer_enable();
Ladon 11:42d5cbbd0f3e 149 }
Ladon 0:12efa8652054 150
Ladon 0:12efa8652054 151 int main ()
Ladon 0:12efa8652054 152 {
Ladon 0:12efa8652054 153 cout << "Entered main()." << endl;
Ladon 4:c52637c8d084 154 led_init();
Ladon 11:42d5cbbd0f3e 155 timer_init();
Ladon 4:c52637c8d084 156 interrupt_enable();
Ladon 0:12efa8652054 157 cout << "Exiting main().." << endl;
Ladon 0:12efa8652054 158 }