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:
- 11:42d5cbbd0f3e
- Parent:
- 10:f80370dd55f8
File content as of revision 11:42d5cbbd0f3e:
#include <mbed.h> #include <iostream> using namespace std; void inline led_init () { // Led is at PA5. // - // Set PA5 as AF1 (TIM2_CH1). // - // Alternate Function Low Register. // - GPIOA->AFR[0] &= ~GPIO_AFRL_AFRL5; GPIOA->AFR[0] |= 1 << GPIO_AFRL_AFRL5_Pos; // Port Output Speed Register. // - GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR5; // Port Mode Register. // - GPIOA->MODER &= ~GPIO_MODER_MODER5; GPIOA->MODER |= 2 << GPIO_MODER_MODER5_Pos; } void inline reset_timer () { // Peripheral Reset Register. // TIM2 timer reset. // - RCC->APB1RSTR |= RCC_APB1RSTR_TIM2RST; RCC->APB1RSTR &= ~RCC_APB1RSTR_TIM2RST; } void inline clock_enable_for_timer () { reset_timer(); // Peripheral Clock Enable Register. // TIM2 Timer Clock Enable. // - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; } void inline timer_setup_pwm () { const double duty_cycle = 0.6; // Capture/ Compare Register 1. // - TIM2->CCR1 = TIM2->ARR * duty_cycle; // Capture/ Compare Mode Register 1. // Output Compare 1 Mode. // Output Compare 1 Preload Enable. // Output Compare 1 Fast Enable. // - TIM2->CCMR1 = (0b111 << TIM_CCMR1_OC1M_Pos) | TIM_CCMR1_OC1PE | TIM_CCMR1_OC1FE; // ^ 0b111 : PWM Mode 2 : On while CCR < ARR, OFF while >=. // - } void inline timer_enable_pwm () { timer_setup_pwm(); // Capture/ Compare Enable Register. // Capture/ Compare 1 Output Enable. // - TIM2->CCER = TIM_CCER_CC1E; } 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) { // Precondition : T <= 59 (= (2^32 - 1) / 72e6). // - timer_limit_counter_to(72000000 * T); // ^Explanation : By limiting ARR to 72e6, the counter gets filled in 1sec (at 72Mhz). // - } 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; } /* // 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 () { timer_clear_status(); } void inline 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. // - } void inline timer_init () { clock_enable_for_timer(); timer_set_period_to(0.1); timer_enable_interrupt(); timer_enable_pwm(); timer_enable(); } int main () { cout << "Entered main()." << endl; led_init(); timer_init(); interrupt_enable(); cout << "Exiting main().." << endl; }