diff --git a/drv/tim.c b/drv/tim.c index 813c4ee..7ebe184 100644 --- a/drv/tim.c +++ b/drv/tim.c @@ -6,13 +6,209 @@ #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); +} + diff --git a/drv/tim.h b/drv/tim.h index 92d6def..c10470f 100644 --- a/drv/tim.h +++ b/drv/tim.h @@ -46,14 +46,14 @@ enum TimConfig { }; enum TimMasterConfig { - TIM_MASTER_CONFIG_MODE_RESET = (0x0 << 20), - TIM_MASTER_CONFIG_MODE_ENABLE = (0x1 << 20), - TIM_MASTER_CONFIG_MODE_UPDATE = (0x2 << 20), - TIM_MASTER_CONFIG_MODE_COMP_PULSE = (0x3 << 20), - TIM_MASTER_CONFIG_MODE_COMP_1 = (0x4 << 20), - TIM_MASTER_CONFIG_MODE_COMP_2 = (0x5 << 20), - TIM_MASTER_CONFIG_MODE_COMP_3 = (0x6 << 20), - TIM_MASTER_CONFIG_MODE_COMP_4 = (0x7 << 20), + TIM_MASTER_CONFIG_MODE_RESET = (0x0 << 4), + TIM_MASTER_CONFIG_MODE_ENABLE = (0x1 << 4), + TIM_MASTER_CONFIG_MODE_UPDATE = (0x2 << 4), + TIM_MASTER_CONFIG_MODE_COMP_PULSE = (0x3 << 4), + TIM_MASTER_CONFIG_MODE_COMP_1 = (0x4 << 4), + TIM_MASTER_CONFIG_MODE_COMP_2 = (0x5 << 4), + TIM_MASTER_CONFIG_MODE_COMP_3 = (0x6 << 4), + TIM_MASTER_CONFIG_MODE_COMP_4 = (0x7 << 4), }; @@ -122,7 +122,12 @@ enum TimIntputConfig { TIM_INPUT_CONFIG_PRESCALER_8 = (0x3 << 2), }; -typedef void (*TimCallback)(void); +enum TimIRQSource { + TIM_IRQ_SOURCE_TRIGGER, + TIM_IRQ_SOURCE_UPDATE, +}; + +typedef void (*TimCallback)(enum TimIRQSource src); //--functions------------------------------------------------------------------- @@ -133,6 +138,10 @@ void tim_configure_master(enum TimPeriph periph, enum TimConfig config_mask, void tim_configure_slave(enum TimPeriph periph, enum TimConfig config_mask, enum TimSlaveConfig slave_config_mask, TimCallback callback); +void tim_start(enum TimPeriph periph); +void tim_stop(enum TimPeriph periph); +void tim_update(enum TimPeriph periph); + void tim_set_auto_reload(enum TimPeriph periph, uint16_t auto_reload); void tim_set_prescaler(enum TimPeriph periph, uint16_t prescaler); void tim_set_counter(enum TimPeriph periph, uint16_t counter);