Spyros Papanastasiou
/
General_purpose_timer_TIM2__PWM_LED
Controlling PWM of LED through direct access of TIM2 timer's registers.
main.cpp@7:d93dcab712f1, 2019-08-02 (annotated)
- Committer:
- Ladon
- Date:
- Fri Aug 02 06:03:16 2019 +0000
- Revision:
- 7:d93dcab712f1
- Parent:
- 6:be045fed855f
- Child:
- 8:6464500cc838
Made more cpp friendly.
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 | 5:3ee6e0113b41 | 14 | GPIOA->MODER &= ~GPIO_MODER_MODER5; |
Ladon | 5:3ee6e0113b41 | 15 | GPIOA->MODER |= 1 << GPIO_MODER_MODER5_Pos; |
Ladon | 0:12efa8652054 | 16 | } |
Ladon | 0:12efa8652054 | 17 | |
Ladon | 5:3ee6e0113b41 | 18 | void inline reset_timer () |
Ladon | 0:12efa8652054 | 19 | { |
Ladon | 5:3ee6e0113b41 | 20 | // Peripheral Reset Register. |
Ladon | 5:3ee6e0113b41 | 21 | // - |
Ladon | 5:3ee6e0113b41 | 22 | RCC->APB1RSTR |= RCC_APB1RSTR_TIM2RST; |
Ladon | 5:3ee6e0113b41 | 23 | RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM2RST; |
Ladon | 0:12efa8652054 | 24 | } |
Ladon | 0:12efa8652054 | 25 | |
Ladon | 5:3ee6e0113b41 | 26 | void inline clock_enable_for_timer () |
Ladon | 0:12efa8652054 | 27 | { |
Ladon | 5:3ee6e0113b41 | 28 | // Peripheral Clock Enable Register. |
Ladon | 5:3ee6e0113b41 | 29 | // TIM2 Timer Clock Enable. |
Ladon | 5:3ee6e0113b41 | 30 | // - |
Ladon | 5:3ee6e0113b41 | 31 | reset_timer(); |
Ladon | 5:3ee6e0113b41 | 32 | RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; |
Ladon | 0:12efa8652054 | 33 | } |
Ladon | 0:12efa8652054 | 34 | |
Ladon | 4:c52637c8d084 | 35 | void inline timer_downscale_by (const unsigned short& v) |
Ladon | 0:12efa8652054 | 36 | { |
Ladon | 5:3ee6e0113b41 | 37 | // Prescaler. |
Ladon | 5:3ee6e0113b41 | 38 | // - |
Ladon | 2:7c45a714b991 | 39 | TIM2->PSC = v; |
Ladon | 0:12efa8652054 | 40 | } |
Ladon | 0:12efa8652054 | 41 | |
Ladon | 4:c52637c8d084 | 42 | void inline timer_limit_counter_to (const unsigned int& v) |
Ladon | 0:12efa8652054 | 43 | { |
Ladon | 5:3ee6e0113b41 | 44 | // Auto-Reload Register. |
Ladon | 5:3ee6e0113b41 | 45 | // - |
Ladon | 2:7c45a714b991 | 46 | TIM2->ARR = v; |
Ladon | 0:12efa8652054 | 47 | } |
Ladon | 0:12efa8652054 | 48 | |
Ladon | 5:3ee6e0113b41 | 49 | void inline timer_set_period_to (const double& T) |
Ladon | 0:12efa8652054 | 50 | { |
Ladon | 5:3ee6e0113b41 | 51 | // This function allows : 500us <= T <= 32.768 |
Ladon | 5:3ee6e0113b41 | 52 | // The ^former was found by solving : 0 <= 1999 + (T - 1) * 2e3 <= 0xFFFF, for the prescaler register. |
Ladon | 5:3ee6e0113b41 | 53 | // - |
Ladon | 4:c52637c8d084 | 54 | timer_limit_counter_to(36000); |
Ladon | 4:c52637c8d084 | 55 | timer_downscale_by(1999 + (T - 1) * 2e3); |
Ladon | 0:12efa8652054 | 56 | } |
Ladon | 0:12efa8652054 | 57 | |
Ladon | 5:3ee6e0113b41 | 58 | void inline timer_enable_interrupt () |
Ladon | 5:3ee6e0113b41 | 59 | { |
Ladon | 5:3ee6e0113b41 | 60 | // DMA/ Interrupt Enable Register. |
Ladon | 5:3ee6e0113b41 | 61 | // Update Interrupt Enable. |
Ladon | 5:3ee6e0113b41 | 62 | // - |
Ladon | 5:3ee6e0113b41 | 63 | TIM2->DIER = TIM_DIER_UIE; |
Ladon | 5:3ee6e0113b41 | 64 | } |
Ladon | 0:12efa8652054 | 65 | |
Ladon | 5:3ee6e0113b41 | 66 | void inline timer_enable () |
Ladon | 0:12efa8652054 | 67 | { |
Ladon | 5:3ee6e0113b41 | 68 | // Control Register 1. |
Ladon | 5:3ee6e0113b41 | 69 | // Update Request Source | Counter Enable. |
Ladon | 0:12efa8652054 | 70 | // - |
Ladon | 5:3ee6e0113b41 | 71 | TIM2->CR1 = TIM_CR1_URS | TIM_CR1_CEN; |
Ladon | 5:3ee6e0113b41 | 72 | } |
Ladon | 5:3ee6e0113b41 | 73 | |
Ladon | 5:3ee6e0113b41 | 74 | void inline timer_clear_status () |
Ladon | 5:3ee6e0113b41 | 75 | { |
Ladon | 5:3ee6e0113b41 | 76 | // Status Register. |
Ladon | 5:3ee6e0113b41 | 77 | // - |
Ladon | 5:3ee6e0113b41 | 78 | TIM2->SR = 0; |
Ladon | 0:12efa8652054 | 79 | } |
Ladon | 0:12efa8652054 | 80 | |
Ladon | 4:c52637c8d084 | 81 | void led_toggle () |
Ladon | 0:12efa8652054 | 82 | { |
Ladon | 5:3ee6e0113b41 | 83 | // Output Data Register. |
Ladon | 5:3ee6e0113b41 | 84 | // - |
Ladon | 2:7c45a714b991 | 85 | GPIOA->ODR ^= GPIO_ODR_5; |
Ladon | 0:12efa8652054 | 86 | } |
Ladon | 0:12efa8652054 | 87 | |
Ladon | 5:3ee6e0113b41 | 88 | /* |
Ladon | 5:3ee6e0113b41 | 89 | // I was unable to use the following handler : |
Ladon | 5:3ee6e0113b41 | 90 | // - |
Ladon | 5:3ee6e0113b41 | 91 | extern "C" void TIM2_IRQHandler (void) |
Ladon | 5:3ee6e0113b41 | 92 | { |
Ladon | 5:3ee6e0113b41 | 93 | cout << "Interrupt hit!" << endl; |
Ladon | 5:3ee6e0113b41 | 94 | clear_timer_status(); |
Ladon | 5:3ee6e0113b41 | 95 | toggle_LED(); |
Ladon | 5:3ee6e0113b41 | 96 | } |
Ladon | 5:3ee6e0113b41 | 97 | */ |
Ladon | 0:12efa8652054 | 98 | |
Ladon | 5:3ee6e0113b41 | 99 | // I couldn 't get TIM2_IRQHandler() to work; probably wrong name. Thus, I 'll use a custom handler |
Ladon | 5:3ee6e0113b41 | 100 | // and attach it using SetVector() from CMSIS : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html. |
Ladon | 4:c52637c8d084 | 101 | // - |
Ladon | 4:c52637c8d084 | 102 | void interrupt_handler () |
Ladon | 3:db424769ecca | 103 | { |
Ladon | 3:db424769ecca | 104 | cout << "Interrupt hit!" << endl; |
Ladon | 4:c52637c8d084 | 105 | timer_clear_status(); |
Ladon | 4:c52637c8d084 | 106 | led_toggle(); |
Ladon | 3:db424769ecca | 107 | } |
Ladon | 3:db424769ecca | 108 | |
Ladon | 4:c52637c8d084 | 109 | inline void interrupt_enable () |
Ladon | 0:12efa8652054 | 110 | { |
Ladon | 4:c52637c8d084 | 111 | // NVIC_SetPriority(TIM2_IRQn, 250); |
Ladon | 7:d93dcab712f1 | 112 | NVIC_SetVector(TIM2_IRQn, reinterpret_cast<uint32_t>(interrupt_handler)); |
Ladon | 2:7c45a714b991 | 113 | NVIC_EnableIRQ(TIM2_IRQn); |
Ladon | 5:3ee6e0113b41 | 114 | // ^Definition of NVIC_SetVector() : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html#gab43c1c59d5c081f1bc725237f4b1f916. |
Ladon | 5:3ee6e0113b41 | 115 | // - |
Ladon | 0:12efa8652054 | 116 | } |
Ladon | 0:12efa8652054 | 117 | |
Ladon | 0:12efa8652054 | 118 | // |
Ladon | 0:12efa8652054 | 119 | // - |
Ladon | 0:12efa8652054 | 120 | // |
Ladon | 0:12efa8652054 | 121 | |
Ladon | 0:12efa8652054 | 122 | int main () |
Ladon | 0:12efa8652054 | 123 | { |
Ladon | 0:12efa8652054 | 124 | cout << "Entered main()." << endl; |
Ladon | 4:c52637c8d084 | 125 | led_init(); |
Ladon | 4:c52637c8d084 | 126 | clock_enable_for_timer(); |
Ladon | 5:3ee6e0113b41 | 127 | timer_set_period_to(1.3); |
Ladon | 4:c52637c8d084 | 128 | timer_enable_interrupt(); |
Ladon | 4:c52637c8d084 | 129 | timer_enable(); |
Ladon | 4:c52637c8d084 | 130 | interrupt_enable(); |
Ladon | 5:3ee6e0113b41 | 131 | /* |
Ladon | 5:3ee6e0113b41 | 132 | while (true) |
Ladon | 5:3ee6e0113b41 | 133 | { |
Ladon | 5:3ee6e0113b41 | 134 | cout << hex |
Ladon | 5:3ee6e0113b41 | 135 | << "Status : 0x" << TIM2->SR << endl |
Ladon | 5:3ee6e0113b41 | 136 | << "Count : 0x" << TIM2->CNT << endl; |
Ladon | 5:3ee6e0113b41 | 137 | } |
Ladon | 5:3ee6e0113b41 | 138 | */ |
Ladon | 0:12efa8652054 | 139 | cout << "Exiting main().." << endl; |
Ladon | 0:12efa8652054 | 140 | } |