2 #include <twr_scheduler.h>
4 #include <stm32l083xx.h>
7 #include <twr_system.h>
9 #define VREFINT_CAL_ADDR 0x1ff80078
11 #define TWR_ADC_CHANNEL_INTERNAL_REFERENCE 7
12 #define TWR_ADC_CHANNEL_NONE ((twr_adc_channel_t) (-1))
13 #define TWR_ADC_CHANNEL_COUNT ((twr_adc_channel_t) 8)
17 TWR_ADC_STATE_CALIBRATION_BY_INTERNAL_REFERENCE_BEGIN,
18 TWR_ADC_STATE_CALIBRATION_BY_INTERNAL_REFERENCE_END,
19 TWR_ADC_STATE_MEASURE_INPUT
40 float real_vdda_voltage;
41 twr_adc_state_t state;
48 .channel_in_progress = TWR_ADC_CHANNEL_NONE,
62 static void _twr_adc_task(
void *param);
68 if (_twr_adc.initialized !=
true)
71 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
77 ADC1->CFGR1 |= ADC_CFGR1_AUTOFF;
80 ADC1->CFGR2 = ADC_CFGR2_CKMODE_0 | ADC_CFGR2_CKMODE_1;
83 ADC1->SMPR |= ADC_SMPR_SMP_1 | ADC_SMPR_SMP_0;
86 ADC1->CR |= ADC_CR_ADVREGEN;
89 _twr_adc.vrefint = (*(uint16_t *) VREFINT_CAL_ADDR);
91 NVIC_EnableIRQ(ADC1_COMP_IRQn);
93 _twr_adc.initialized =
true;
103 _twr_adc.channel_table[channel].oversampling = oversampling;
108 _twr_adc.channel_table[channel].resolution = resolution;
113 ADC1->CFGR1 &= ~ADC_CFGR1_RES_Msk;
114 ADC1->CFGR1 |= resolution & ADC_CFGR1_RES_Msk;
120 ADC1->CFGR2 &= ~(ADC_CFGR2_OVSE_Msk | ADC_CFGR2_OVSR_Msk | ADC_CFGR2_OVSS_Msk);
122 static const uint16_t oversampling_register_lut[9] =
125 ADC_CFGR2_OVSE | ADC_CFGR2_OVSS_0,
126 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_1,
127 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0,
128 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_2,
129 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_2 | ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_0,
130 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_2 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1,
131 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSS_2 | ADC_CFGR2_OVSS_1 | ADC_CFGR2_OVSS_0,
132 ADC_CFGR2_OVSE | ADC_CFGR2_OVSR_2 | ADC_CFGR2_OVSR_1 | ADC_CFGR2_OVSR_0 | ADC_CFGR2_OVSS_3,
135 ADC1->CFGR2 |= oversampling_register_lut[oversampling];
140 uint16_t value = ADC1->DR;
142 switch (_twr_adc.channel_table[channel].resolution)
175 return _twr_adc.channel_in_progress == TWR_ADC_CHANNEL_NONE;
181 if (_twr_adc.channel_in_progress != TWR_ADC_CHANNEL_NONE)
187 ADC1->CHSELR = _twr_adc.channel_table[channel].chselr;
193 ADC1->ISR = ADC_ISR_EOS;
196 ADC1->ISR |= ADC_ISR_ADRDY;
198 _twr_adc_configure_oversampling(_twr_adc.channel_table[channel].oversampling);
199 _twr_adc_configure_resolution(_twr_adc.channel_table[channel].resolution);
202 ADC1->CR |= ADC_CR_ADSTART;
205 while ((ADC1->ISR & ADC_ISR_EOS) == 0)
212 *result = _twr_adc_get_measured_value(channel);
221 if (_twr_adc.channel_in_progress == channel)
228 adc->event_handler = event_handler;
229 adc->event_param = event_param;
237 if (_twr_adc.channel_in_progress != TWR_ADC_CHANNEL_NONE)
239 _twr_adc.channel_table[channel].pending =
true;
244 _twr_adc.channel_in_progress = channel;
245 _twr_adc.channel_table[channel].pending =
false;
249 _twr_adc.state = TWR_ADC_STATE_CALIBRATION_BY_INTERNAL_REFERENCE_END;
252 ADC->CCR |= ADC_CCR_VREFEN;
254 _twr_adc_configure_oversampling(_twr_adc.channel_table[TWR_ADC_CHANNEL_INTERNAL_REFERENCE].oversampling);
255 _twr_adc_configure_resolution(_twr_adc.channel_table[TWR_ADC_CHANNEL_INTERNAL_REFERENCE].resolution);
258 ADC1->CHSELR = _twr_adc.channel_table[TWR_ADC_CHANNEL_INTERNAL_REFERENCE].chselr;
261 ADC1->ISR = ADC_ISR_EOCAL;
264 ADC1->IER = ADC_IER_EOCIE;
267 ADC1->CR |= ADC_CR_ADSTART;
276 *result = _twr_adc.channel_table[channel].value;
282 *result = (_twr_adc.channel_table[channel].value * _twr_adc.real_vdda_voltage) / 65536.f;
288 if (_twr_adc.real_vdda_voltage == 0.f)
294 *vdda_voltage = _twr_adc.real_vdda_voltage;
300 void ADC1_COMP_IRQHandler(
void)
303 if (_twr_adc.state == TWR_ADC_STATE_CALIBRATION_BY_INTERNAL_REFERENCE_END)
306 _twr_adc.real_vdda_voltage = 3.f * ((float) _twr_adc.vrefint / (
float) ADC1->DR);
308 _twr_adc_configure_oversampling(_twr_adc.channel_table[_twr_adc.channel_in_progress].oversampling);
309 _twr_adc_configure_resolution(_twr_adc.channel_table[_twr_adc.channel_in_progress].resolution);
312 ADC1->CHSELR = _twr_adc.channel_table[_twr_adc.channel_in_progress].chselr;
314 _twr_adc.state = TWR_ADC_STATE_MEASURE_INPUT;
317 ADC1->ISR = ADC_ISR_EOC;
320 ADC1->CR |= ADC_CR_ADSTART;
324 else if (_twr_adc.state == TWR_ADC_STATE_MEASURE_INPUT)
327 ADC->CCR &= ~ADC_CCR_VREFEN;
329 _twr_adc.channel_table[_twr_adc.channel_in_progress].value = _twr_adc_get_measured_value(_twr_adc.channel_in_progress);
345 if (_twr_adc.channel_in_progress != TWR_ADC_CHANNEL_NONE)
350 if (ADC1->CR & ADC_CR_ADEN)
356 ADC1->CR |= ADC_CR_ADCAL;
357 while ((ADC1->ISR & ADC_ISR_EOCAL) == 0)
363 ADC->CCR |= ADC_CCR_VREFEN;
366 ADC1->CHSELR = _twr_adc.channel_table[TWR_ADC_CHANNEL_INTERNAL_REFERENCE].chselr;
369 ADC1->ISR = ADC_ISR_EOS;
372 ADC1->CR |= ADC_CR_ADSTART;
374 while ((ADC1->ISR & ADC_ISR_EOS) == 0)
380 _twr_adc.real_vdda_voltage = 3.f * ((float) _twr_adc.vrefint / (
float) ADC1->DR);
383 ADC->CCR &= ~ADC_CCR_VREFEN;
388 static void _twr_adc_task(
void *param)
399 pending_result_channel = _twr_adc.channel_in_progress;
402 _twr_adc.channel_in_progress = TWR_ADC_CHANNEL_NONE;
408 if (_twr_adc_get_pending(&next, pending_result_channel) ==
true)
417 if (adc->event_handler != NULL)
425 for (
int i = start + 1; i != start; i++)
427 if (i == TWR_ADC_CHANNEL_COUNT)
439 if (_twr_adc.channel_table[i].pending ==
true)
void twr_adc_resolution_set(twr_adc_channel_t channel, twr_adc_resolution_t resolution)
Set ADC resolution for specific channel.
bool twr_adc_async_measure(twr_adc_channel_t channel)
Begins reading the ADC channel voltage in asynchronous mode.
void twr_adc_oversampling_set(twr_adc_channel_t channel, twr_adc_oversampling_t oversampling)
Set ADC oversampling for specific channel.
bool twr_adc_set_event_handler(twr_adc_channel_t channel, void(*event_handler)(twr_adc_channel_t, twr_adc_event_t, void *), void *event_param)
Set callback function.
twr_adc_oversampling_t
ADC oversampling.
bool twr_adc_calibration(void)
Calibration.
bool twr_adc_async_get_voltage(twr_adc_channel_t channel, float *result)
Get asynchronous measurement result in volts.
twr_adc_event_t
ADC event.
bool twr_adc_get_vdda_voltage(float *vdda_voltage)
Get voltage on VDDA pin.
twr_adc_channel_t
ADC channel.
twr_adc_resolution_t
ADC resolution.
bool twr_adc_is_ready()
Check if ADC is ready for reading.
bool twr_adc_async_get_value(twr_adc_channel_t channel, uint16_t *result)
Get asynchronous measurement result.
bool twr_adc_get_value(twr_adc_channel_t channel, uint16_t *result)
Reads the ADC channel value.
void twr_adc_init()
Initialize ADC converter.
@ TWR_ADC_OVERSAMPLING_256
ADC 256x oversampling.
@ TWR_ADC_EVENT_DONE
ADC event.
@ TWR_ADC_CHANNEL_A2
ADC channel A2.
@ TWR_ADC_CHANNEL_A5
ADC channel A5.
@ TWR_ADC_CHANNEL_A0
ADC channel A0.
@ TWR_ADC_CHANNEL_A4
ADC channel A4.
@ TWR_ADC_CHANNEL_A6
ADC channel A6.
@ TWR_ADC_CHANNEL_A3
ADC channel A3.
@ TWR_ADC_CHANNEL_A1
ADC channel A1.
@ TWR_ADC_RESOLUTION_6_BIT
ADC 6 bit resolution.
@ TWR_ADC_RESOLUTION_10_BIT
ADC 10 bit resolution.
@ TWR_ADC_RESOLUTION_12_BIT
ADC 12 bit resolution.
@ TWR_ADC_RESOLUTION_8_BIT
ADC 8 bit resolution.
void twr_irq_disable(void)
Disable interrupt requests globally (call can be nested)
void twr_irq_enable(void)
Enable interrupt requests globally (call can be nested)
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
#define TWR_TICK_INFINITY
Maximum timestamp value.