#ifndef STM32U5XX_HAL_ADC_HPP #define STM32U5XX_HAL_ADC_HPP #include "global_variable.h" #include "delay.h" #include "prepherials.h" #include "queue.hpp" #include "reg_adc_gen.h" #include "reg_nvic.h" #include "reg_rcc.h" #include "reg_uart.h" #include "stm32u5xx.h" typedef enum { ADC_RESOLUTION_12B = 0, ADC_RESOLUTION_10B = 1, ADC_RESOLUTION_8B = 2, ADC_RESOLUTION_6B = 3 } adc_resolution_e; // todo: check with rm0456 typedef enum { ADC_SINGLE_ENDED = 0, ADC_DIFFERENTIAL = 1 } adc_single_diff_e; // todo: check with rm0456 class Adc { private: ADC_TypeDef *ins = nullptr; reg_adc_t *reg = nullptr; ADC_Common_TypeDef *reg_common = nullptr; queue20u32 data_queue; public: Adc() = default; void setup(ADC_TypeDef *adc, ADC_Common_TypeDef *adc_common) { reg_common = adc_common, ins = adc, reg = (reg_adc_t *) ins; } hal_status_e init(int channel = 0, adc_resolution_e resolution = ADC_RESOLUTION_12B, adc_single_diff_e single_diff = ADC_SINGLE_ENDED) { rcc_enable_adc_clock(ins); // enable adc clock nvic_enable_adc_irq(); // enable adc irq reg->cr.advregen = 1; // enable adc voltage regulator delay_us(10, true); // todo: this delay may be removed, check with rm0456 { wait_for_true(reg->cr.advregen, 1); // wait for adc voltage regulator to be ready } reg->cfgr1.res = resolution; // set resolution reg->cfgr1.autdly = 0; // disable automatic delay (delay the start of conversion) // calibration for single-end mode // todo: add calibration for differential mode // todo: check set sampling time with rm0456 reg->difsel.difsel = single_diff; // set single ended mode reg->cr.adcal = 1; // start calibration { wait_for_true(reg->cr.adcal, 1); // wait for calibration to finish } reg->sqr1.l = 0; // set number of conversion reg->sqr1.sq1 = channel; // set channel reg->smpr1.smp1 = 0b111; // set sampling time to 640.5 adc clock cycles reg->cfgr1.exten = 0b00; // set trigger to software reg->cr.aden = 1; // enable adc return HAL_OK; } void start_conversion(int number_conversion = 1, bool continuous_conversion = false) { reg->cfgr1.cont = continuous_conversion; reg->sqr1.l = number_conversion - 1; // set number of conversion reg->cr.adstart = 1; // start conversion } void stop_conversion() { reg->cr.adstp = 1; // stop conversion } void interrupt_handler() { // read isr register reg_adc_isr_t isr = const_cast(reg->isr); // todo: end of sequence may not need to be checked if (isr.eoc || isr.eos) data_queue.push(reg->dr.rdata); // clear interrupt flag reg->isr.eoc = 0, reg->isr.eos = 0; // TODO: continuous conversion mode // single conversion mode and continuous conversion mode } hal_status_e read_last_conversion(uint32_t *data) { return data_queue.pop(data); } }; #endif // STM32U5XX_HAL_ADC_HPP