#include "timer_driver.h" #include "gd32f4xx.h" #include struct timer_hw_config_t { uint32_t timer_periph; rcu_periph_enum rcu_clock; bool is_32bit; bool is_advanced; }; static constexpr timer_hw_config_t timer_hw_map[] = { {TIMER0, RCU_TIMER0, false, true }, {TIMER1, RCU_TIMER1, true, false}, {TIMER2, RCU_TIMER2, false, false}, {TIMER3, RCU_TIMER3, false, false}, {TIMER4, RCU_TIMER4, true, false}, {TIMER5, RCU_TIMER5, false, false}, {TIMER6, RCU_TIMER6, false, false}, {TIMER7, RCU_TIMER7, false, true }, {TIMER8, RCU_TIMER8, false, false}, {TIMER9, RCU_TIMER9, false, false}, {TIMER10, RCU_TIMER10, false, false}, {TIMER11, RCU_TIMER11, false, false}, {TIMER12, RCU_TIMER12, false, false}, {TIMER13, RCU_TIMER13, false, false}, }; static uint8_t timer_irq_map(uint32_t timer_periph) { if (timer_periph == TIMER0) return TIMER0_UP_TIMER9_IRQn; if (timer_periph == TIMER1) return TIMER1_IRQn; if (timer_periph == TIMER2) return TIMER2_IRQn; if (timer_periph == TIMER3) return TIMER3_IRQn; if (timer_periph == TIMER4) return TIMER4_IRQn; if (timer_periph == TIMER5) return 0; if (timer_periph == TIMER6) return TIMER6_IRQn; if (timer_periph == TIMER7) return TIMER7_UP_TIMER12_IRQn; if (timer_periph == TIMER8) return TIMER0_BRK_TIMER8_IRQn; if (timer_periph == TIMER9) return TIMER0_UP_TIMER9_IRQn; if (timer_periph == TIMER10) return TIMER0_TRG_CMT_TIMER10_IRQn; if (timer_periph == TIMER11) return TIMER7_BRK_TIMER11_IRQn; if (timer_periph == TIMER12) return TIMER7_UP_TIMER12_IRQn; if (timer_periph == TIMER13) return TIMER7_TRG_CMT_TIMER13_IRQn; return 0; } TimerBus::TimerBus(TimerPort port) : port_(port) { } TimerBus::~TimerBus() { if (initialized_) { deinit(); } } RetCode TimerBus::init(const TimerConfig &config) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return RET_INVALID_PARAM; } const timer_hw_config_t &hw = timer_hw_map[port_idx]; if (hw.timer_periph == 0) { return RET_NOT_SUPPORTED; } config_ = config; rcu_periph_clock_enable(hw.rcu_clock); timer_parameter_struct timer_para; timer_struct_para_init(&timer_para); timer_para.prescaler = static_cast(config.prescaler - 1); timer_para.period = config.period; timer_para.alignedmode = TIMER_COUNTER_EDGE; timer_para.counterdirection = TIMER_COUNTER_UP; timer_para.clockdivision = TIMER_CKDIV_DIV1; timer_para.repetitioncounter = 0U; timer_init(hw.timer_periph, &timer_para); if (config.mode == TimerMode::ONE_PULSE) { timer_single_pulse_mode_config(hw.timer_periph, TIMER_SP_MODE_SINGLE); } if (config.use_interrupt) { uint8_t irq = timer_irq_map(hw.timer_periph); if (irq != 0) { timer_interrupt_enable(hw.timer_periph, TIMER_INT_UP); nvic_irq_enable(irq, 0, 0); } } initialized_ = true; return RET_OK; } RetCode TimerBus::deinit() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return RET_INVALID_PARAM; } const timer_hw_config_t &hw = timer_hw_map[port_idx]; timer_disable(hw.timer_periph); timer_interrupt_disable(hw.timer_periph, TIMER_INT_UP); timer_deinit(hw.timer_periph); rcu_periph_clock_disable(hw.rcu_clock); initialized_ = false; return RET_OK; } RetCode TimerBus::start() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; const timer_hw_config_t &hw = timer_hw_map[port_idx]; timer_enable(hw.timer_periph); return RET_OK; } RetCode TimerBus::stop() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; const timer_hw_config_t &hw = timer_hw_map[port_idx]; timer_disable(hw.timer_periph); return RET_OK; } RetCode TimerBus::set_period(uint32_t period) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; const timer_hw_config_t &hw = timer_hw_map[port_idx]; timer_autoreload_value_config(hw.timer_periph, period); config_.period = period; return RET_OK; } uint32_t TimerBus::get_counter() const { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return 0; } if (!initialized_) return 0; const timer_hw_config_t &hw = timer_hw_map[port_idx]; return timer_counter_read(hw.timer_periph); } void timer_irq_handler(TimerPort port) { uint8_t port_idx = static_cast(port); if (port_idx >= sizeof(timer_hw_map) / sizeof(timer_hw_map[0])) { return; } const timer_hw_config_t &hw = timer_hw_map[port_idx]; if (hw.timer_periph == 0) return; if (timer_interrupt_flag_get(hw.timer_periph, TIMER_INT_UP) != RESET) { timer_interrupt_flag_clear(hw.timer_periph, TIMER_INT_UP); } } extern "C" { static TimerBus timer_0(TimerPort::_0); static TimerBus timer_1(TimerPort::_1); static TimerBus timer_2(TimerPort::_2); static TimerBus timer_3(TimerPort::_3); static TimerBus timer_4(TimerPort::_4); static TimerBus timer_5(TimerPort::_5); static TimerBus timer_6(TimerPort::_6); static TimerBus timer_7(TimerPort::_7); static TimerBus timer_8(TimerPort::_8); static TimerBus timer_9(TimerPort::_9); static TimerBus timer_10(TimerPort::_10); static TimerBus timer_11(TimerPort::_11); static TimerBus timer_12(TimerPort::_12); static TimerBus timer_13(TimerPort::_13); static TimerBus *timer_instances[] = { &timer_0, &timer_1, &timer_2, &timer_3, &timer_4, &timer_5, &timer_6, &timer_7, &timer_8, &timer_9, &timer_10, &timer_11, &timer_12, &timer_13, }; static uint8_t timer_inited[14] = {0}; int timer_bus_init(uint8_t port, uint32_t prescaler, uint32_t period) { if (port >= 14) return -1; TimerConfig cfg; cfg.prescaler = prescaler; cfg.period = period; RetCode ret = timer_instances[port]->init(cfg); timer_inited[port] = (ret == RET_OK) ? 1 : 0; return timer_inited[port] ? 0 : -1; } int timer_start(uint8_t port) { if (port >= 14 || !timer_inited[port]) return -1; return timer_instances[port]->start() == RET_OK ? 0 : -1; } int timer_stop(uint8_t port) { if (port >= 14 || !timer_inited[port]) return -1; return timer_instances[port]->stop() == RET_OK ? 0 : -1; } } /* extern "C" */