Spyros Papanastasiou
/
General_purpose_timer_TIM2__PWM_LED
Controlling PWM of LED through direct access of TIM2 timer's registers.
main.cpp
- Committer:
- Ladon
- Date:
- 2019-08-02
- Revision:
- 7:d93dcab712f1
- Parent:
- 6:be045fed855f
- Child:
- 8:6464500cc838
File content as of revision 7:d93dcab712f1:
#include <mbed.h> #include <iostream> using namespace std; void led_init () { // Led is at PA5. // - // Set PA5 as output. // - // Port Mode Register. // - GPIOA->MODER &= ~GPIO_MODER_MODER5; GPIOA->MODER |= 1 << GPIO_MODER_MODER5_Pos; } void inline reset_timer () { // Peripheral Reset Register. // - RCC->APB1RSTR |= RCC_APB1RSTR_TIM2RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM2RST; } void inline clock_enable_for_timer () { // Peripheral Clock Enable Register. // TIM2 Timer Clock Enable. // - reset_timer(); RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; } void inline timer_downscale_by (const unsigned short& v) { // Prescaler. // - TIM2->PSC = v; } void inline timer_limit_counter_to (const unsigned int& v) { // Auto-Reload Register. // - TIM2->ARR = v; } void inline timer_set_period_to (const double& T) { // This function allows : 500us <= T <= 32.768 // The ^former was found by solving : 0 <= 1999 + (T - 1) * 2e3 <= 0xFFFF, for the prescaler register. // - timer_limit_counter_to(36000); timer_downscale_by(1999 + (T - 1) * 2e3); } void inline timer_enable_interrupt () { // DMA/ Interrupt Enable Register. // Update Interrupt Enable. // - TIM2->DIER = TIM_DIER_UIE; } void inline timer_enable () { // Control Register 1. // Update Request Source | Counter Enable. // - TIM2->CR1 = TIM_CR1_URS | TIM_CR1_CEN; } void inline timer_clear_status () { // Status Register. // - TIM2->SR = 0; } void led_toggle () { // Output Data Register. // - GPIOA->ODR ^= GPIO_ODR_5; } /* // I was unable to use the following handler : // - extern "C" void TIM2_IRQHandler (void) { cout << "Interrupt hit!" << endl; clear_timer_status(); toggle_LED(); } */ // I couldn 't get TIM2_IRQHandler() to work; probably wrong name. Thus, I 'll use a custom handler // and attach it using SetVector() from CMSIS : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html. // - void interrupt_handler () { cout << "Interrupt hit!" << endl; timer_clear_status(); led_toggle(); } inline void interrupt_enable () { // NVIC_SetPriority(TIM2_IRQn, 250); NVIC_SetVector(TIM2_IRQn, reinterpret_cast<uint32_t>(interrupt_handler)); NVIC_EnableIRQ(TIM2_IRQn); // ^Definition of NVIC_SetVector() : https://arm-software.github.io/CMSIS_5/Core/html/group__NVIC__gr.html#gab43c1c59d5c081f1bc725237f4b1f916. // - } // // - // int main () { cout << "Entered main()." << endl; led_init(); clock_enable_for_timer(); timer_set_period_to(1.3); timer_enable_interrupt(); timer_enable(); interrupt_enable(); /* while (true) { cout << hex << "Status : 0x" << TIM2->SR << endl << "Count : 0x" << TIM2->CNT << endl; } */ cout << "Exiting main().." << endl; }