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

Dependencies:   mbed

Committer:
Ladon
Date:
Fri Aug 02 12:18:17 2019 +0000
Revision:
8:6464500cc838
Parent:
7:d93dcab712f1
Child:
9:e65dd1ad537e
1st version.

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