fc10ef2e10
GD32F470ZGT6 based project with full peripheral support: - SDRAM (W9825G6KH) via EXMC - LCD NT35510 (480x800) via EXMC NOR/PSRAM - Flash (W25Q64) via SPI - UART (USART0) debug console - LED indicators - CMSIS-DAP debug interface - CMake + ARM GCC toolchain build system
235 lines
6.8 KiB
C++
235 lines
6.8 KiB
C++
#include "timer_driver.h"
|
|
#include "gd32f4xx.h"
|
|
#include <cstddef>
|
|
|
|
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<uint8_t>(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<uint16_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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<uint8_t>(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" */
|