Spyros Papanastasiou
/
General_purpose_timer_TIM2__PWM_LED
Controlling PWM of LED through direct access of TIM2 timer's registers.
main.cpp@8:6464500cc838, 2019-08-02 (annotated)
- 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?
User | Revision | Line number | New 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 | } |