/** @file tim.c * Module handling general purpose and advances TIMers */ //--includes-------------------------------------------------------------------- #include "tim.h" #include "tim_regs.h" #include "nvic.h" #include "../srv/error.h" //--local definitions----------------------------------------------------------- static volatile struct TIM* regs[] = { (struct TIM*)TIM1_BASE_ADDRESS, (struct TIM*)TIM2_BASE_ADDRESS, (struct TIM*)TIM3_BASE_ADDRESS, (struct TIM*)TIM4_BASE_ADDRESS, }; static enum TimIRQSource computeIRQSource(enum TimPeriph periph); //--local variables------------------------------------------------------------- static TimCallback callbacks[4]; //--public functions------------------------------------------------------------ void tim_configure_master(enum TimPeriph periph, enum TimConfig config_mask, enum TimMasterConfig master_config_mask, TimCallback callback) { error_assert(periph <= TIM_PERIPH_4); //apply config mask directly while masking reserved areas. Masking is //important here since advanced timer may have additionnal config bits regs[periph]->cr1.word |= config_mask & 0x3FF; regs[periph]->cr2.word |= (config_mask >> 16) & 0x88; regs[periph]->cr2.word |= master_config_mask & 0x70; //if callback specified, configure IRQ if (callback != nullptr) { callbacks[periph] = callback; regs[periph]->dier.TIE = 1; regs[periph]->dier.UIE = 1; enum NvicIrq irq = 0; switch (periph) { case TIM_PERIPH_1: irq = NVIC_IRQ_TIM1_BRK | NVIC_IRQ_TIM1_UP | NVIC_IRQ_TIM1_TRG_COM | NVIC_IRQ_TIM1_CC; break; case TIM_PERIPH_2: irq = NVIC_IRQ_TIM2; break; case TIM_PERIPH_3: irq = NVIC_IRQ_TIM3; break; case TIM_PERIPH_4: irq = NVIC_IRQ_TIM4; break; } nvic_enable(irq); } //trigger update to force application of the config regs[periph]->egr.UG = 1; } void tim_start(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->cr1.CEN = 1; } void tim_stop(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->cr1.CEN = 0; } void tim_update(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->egr.UG = 1; } void tim_set_auto_reload(enum TimPeriph periph, uint16_t auto_reload) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->arr.ARR = auto_reload; } void tim_set_prescaler(enum TimPeriph periph, uint16_t prescaler) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->psc.PSC = prescaler; } void tim_set_counter(enum TimPeriph periph, uint16_t counter) { error_assert(periph <= TIM_PERIPH_4); regs[periph]->cnt.CNT = counter; } uint16_t tim_get_auto_reload(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); return regs[periph]->arr.ARR; } uint16_t tim_get_prescaler(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); return regs[periph]->psc.PSC; } uint16_t tim_get_counter(enum TimPeriph periph) { error_assert(periph <= TIM_PERIPH_4); return regs[periph]->cnt.CNT; } //--local functions------------------------------------------------------------- static enum TimIRQSource computeIRQSource(enum TimPeriph periph) { enum TimIRQSource src = (TIM_IRQ_SOURCE_TRIGGER & regs[periph]->sr.TIF) | (TIM_IRQ_SOURCE_UPDATE & regs[periph]->sr.UIF); regs[periph]->sr.TIF = 0; regs[periph]->sr.UIF = 0; return src; } //--ISRs------------------------------------------------------------------------ void hdr_tim1_brk(void) { nvic_clear_pending(NVIC_IRQ_TIM1_BRK); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_1); if (callbacks[TIM_PERIPH_1] != nullptr) { callbacks[TIM_PERIPH_1](src); } } void hdr_tim1_up(void) { nvic_clear_pending(NVIC_IRQ_TIM1_UP); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_1); if (callbacks[TIM_PERIPH_1] != nullptr) { callbacks[TIM_PERIPH_1](src); } } void hdr_tim1_trg_com(void) { nvic_clear_pending(NVIC_IRQ_TIM1_TRG_COM); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_1); if (callbacks[TIM_PERIPH_1] != nullptr) { callbacks[TIM_PERIPH_1](src); } } void hdr_tim1_cc(void) { nvic_clear_pending(NVIC_IRQ_TIM1_CC); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_1); if (callbacks[TIM_PERIPH_1] != nullptr) { callbacks[TIM_PERIPH_1](src); } } void hdr_tim2(void) { nvic_clear_pending(NVIC_IRQ_TIM2); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_2); callbacks[TIM_PERIPH_2](src); } void hdr_tim3(void) { nvic_clear_pending(NVIC_IRQ_TIM3); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_3); callbacks[TIM_PERIPH_3](src); } void hdr_tim4(void) { nvic_clear_pending(NVIC_IRQ_TIM4); enum TimIRQSource src = computeIRQSource(TIM_PERIPH_4); callbacks[TIM_PERIPH_4](src); }