#include "adc_driver.h" #include "gd32f4xx.h" #include struct adc_hw_config_t { uint32_t adc_periph; rcu_periph_enum rcu_clock; }; static constexpr adc_hw_config_t adc_hw_map[] = { {ADC0, RCU_ADC0}, {ADC1, RCU_ADC1}, {ADC2, RCU_ADC2}, }; static bool adc_clock_configured = false; static float adc_resolution_to_max_value(uint32_t resolution) { if (resolution == ADC_RESOLUTION_12B) return 4095.0f; if (resolution == ADC_RESOLUTION_10B) return 1023.0f; if (resolution == ADC_RESOLUTION_8B) return 255.0f; if (resolution == ADC_RESOLUTION_6B) return 63.0f; return 4095.0f; } AdcBus::AdcBus(AdcPort port) : port_(port) { } AdcBus::~AdcBus() { if (initialized_) { deinit(); } } RetCode AdcBus::init(const AdcConfig &config) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(adc_hw_map) / sizeof(adc_hw_map[0])) { return RET_INVALID_PARAM; } const adc_hw_config_t &hw = adc_hw_map[port_idx]; if (hw.adc_periph == 0) { return RET_NOT_SUPPORTED; } config_ = config; rcu_periph_clock_enable(hw.rcu_clock); if (!adc_clock_configured) { adc_clock_config(config.clock_prescaler); adc_clock_configured = true; } adc_resolution_config(hw.adc_periph, config.resolution); adc_data_alignment_config(hw.adc_periph, ADC_DATAALIGN_RIGHT); if (config.use_dma) { adc_dma_mode_enable(hw.adc_periph); } adc_special_function_config(hw.adc_periph, ADC_SCAN_MODE, DISABLE); adc_special_function_config(hw.adc_periph, ADC_CONTINUOUS_MODE, DISABLE); adc_enable(hw.adc_periph); for (volatile uint32_t i = 0; i < 10000; i++); adc_calibration_enable(hw.adc_periph); if (config.use_interrupt) { adc_interrupt_enable(hw.adc_periph, ADC_INT_EOC); nvic_irq_enable(ADC_IRQn, 0, 0); } initialized_ = true; return RET_OK; } RetCode AdcBus::deinit() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(adc_hw_map) / sizeof(adc_hw_map[0])) { return RET_INVALID_PARAM; } const adc_hw_config_t &hw = adc_hw_map[port_idx]; adc_disable(hw.adc_periph); rcu_periph_clock_disable(hw.rcu_clock); initialized_ = false; return RET_OK; } RetCode AdcBus::channel_config(uint8_t channel, uint8_t rank) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(adc_hw_map) / sizeof(adc_hw_map[0])) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; const adc_hw_config_t &hw = adc_hw_map[port_idx]; adc_channel_length_config(hw.adc_periph, ADC_ROUTINE_CHANNEL, rank + 1); adc_routine_channel_config(hw.adc_periph, rank, channel, config_.sample_time); return RET_OK; } RetCode AdcBus::start_conversion(uint8_t channel) { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(adc_hw_map) / sizeof(adc_hw_map[0])) { return RET_INVALID_PARAM; } if (!initialized_) return RET_NOT_INITIALIZED; const adc_hw_config_t &hw = adc_hw_map[port_idx]; adc_routine_channel_config(hw.adc_periph, 0, channel, config_.sample_time); adc_software_trigger_enable(hw.adc_periph, ADC_ROUTINE_CHANNEL); return RET_OK; } uint16_t AdcBus::read() { uint8_t port_idx = static_cast(port_); if (port_idx >= sizeof(adc_hw_map) / sizeof(adc_hw_map[0])) { return 0; } if (!initialized_) return 0; const adc_hw_config_t &hw = adc_hw_map[port_idx]; while (RESET == adc_flag_get(hw.adc_periph, ADC_FLAG_EOC)); uint16_t value = static_cast(adc_routine_data_read(hw.adc_periph)); adc_flag_clear(hw.adc_periph, ADC_FLAG_EOC); return value; } float AdcBus::read_voltage() { uint16_t raw = read(); float max_val = adc_resolution_to_max_value(config_.resolution); return static_cast(raw) * 3.3f / max_val; } void adc_irq_handler() { if (adc_interrupt_flag_get(ADC0, ADC_INT_FLAG_EOC) != RESET) { adc_interrupt_flag_clear(ADC0, ADC_INT_FLAG_EOC); } if (adc_interrupt_flag_get(ADC1, ADC_INT_FLAG_EOC) != RESET) { adc_interrupt_flag_clear(ADC1, ADC_INT_FLAG_EOC); } if (adc_interrupt_flag_get(ADC2, ADC_INT_FLAG_EOC) != RESET) { adc_interrupt_flag_clear(ADC2, ADC_INT_FLAG_EOC); } } extern "C" { static AdcBus adc_0(AdcPort::_0); static AdcBus adc_1(AdcPort::_1); static AdcBus adc_2(AdcPort::_2); static AdcBus *adc_instances[] = { &adc_0, &adc_1, &adc_2 }; static uint8_t adc_inited[3] = {0}; int adc_init(uint8_t port, uint32_t resolution) { if (port >= 3) return -1; AdcConfig cfg; cfg.resolution = resolution; cfg.clock_prescaler = ADC_ADCCK_PCLK2_DIV8; cfg.sample_time = ADC_SAMPLETIME_56; RetCode ret = adc_instances[port]->init(cfg); adc_inited[port] = (ret == RET_OK) ? 1 : 0; return adc_inited[port] ? 0 : -1; } uint16_t adc_read(uint8_t port, uint8_t channel) { if (port >= 3 || !adc_inited[port]) return 0; adc_instances[port]->channel_config(channel, 0); adc_instances[port]->start_conversion(channel); return adc_instances[port]->read(); } float adc_read_voltage(uint8_t port, uint8_t channel) { if (port >= 3 || !adc_inited[port]) return 0.0f; adc_instances[port]->channel_config(channel, 0); adc_instances[port]->start_conversion(channel); return adc_instances[port]->read_voltage(); } } /* extern "C" */