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

Dependencies:   mbed

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?

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 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 }