amiro-os / components / power / adconverter.cpp @ a07a7a1c
History | View | Annotate | Download (5.165 KB)
1 |
#include <amiro/power/adconverter.hpp> |
---|---|
2 |
|
3 |
#include <global.hpp> |
4 |
#include <amiro/Constants.h> |
5 |
#include <amiro/power/ina219.hpp> |
6 |
#include <amiro/util/util.h> |
7 |
|
8 |
#include <chprintf.h> |
9 |
|
10 |
using namespace amiro; |
11 |
|
12 |
extern Global global;
|
13 |
|
14 |
void adcVsysErrorCallback(ADCDriver *adcp, adcerror_t err)
|
15 |
{ |
16 |
if (err == ADC_ERR_WATCHDOG) {
|
17 |
chSysLockFromIsr(); |
18 |
if (adcp->thread != NULL) { |
19 |
chEvtSignalI(adcp->thread, EVENT_MASK(ADConverter::EVT_WATCHDOG)); |
20 |
adcp->thread = NULL;
|
21 |
} |
22 |
chSysUnlockFromIsr(); |
23 |
} |
24 |
|
25 |
return;
|
26 |
} |
27 |
|
28 |
void adcTimerCallback(Thread *tp)
|
29 |
{ |
30 |
if (tp != NULL) { |
31 |
chEvtSignal(tp, EVENT_MASK(ADConverter::EVT_TIMER)); |
32 |
} |
33 |
return;
|
34 |
} |
35 |
|
36 |
uint16_t |
37 |
ADConverter::uV2Adc(const uint32_t uV)
|
38 |
{ |
39 |
// NOTE: The factor 5.33 is an approximation of the voltage divider.
|
40 |
// Its value should be 5.0, but due to too large resistors the factor is shifted.
|
41 |
// TODO: 5.33 should be replaced by a non linear function, which needs to be optained from the system.
|
42 |
|
43 |
// get the current VDD voltage
|
44 |
global.ina219[constants::PowerManagement::INA_VDD].update(); |
45 |
INA219::BusVoltage vdd = global.ina219[constants::PowerManagement::INA_VDD].getVoltage(); |
46 |
return float(uV)/1000000 / 5.33f / (float(vdd.voltage_uV)/1000000) * 4096; |
47 |
} |
48 |
|
49 |
uint32_t ADConverter::adc2uV(const uint16_t adc)
|
50 |
{ |
51 |
// NOTE: The factor 5.33 is an approximation of the voltage divider.
|
52 |
// Its value should be 5.0, but due to too large resistors the factor is shifted.
|
53 |
// TODO: 5.33 should be replaced by a non linear function, which needs to be optained from the system.
|
54 |
|
55 |
// get the current VDD voltage
|
56 |
global.ina219[constants::PowerManagement::INA_VDD].update(); |
57 |
INA219::BusVoltage vdd = global.ina219[constants::PowerManagement::INA_VDD].getVoltage(); |
58 |
return float(adc)/4096 * (float(vdd.voltage_uV)/1000000) * 5.33f * 1000000; |
59 |
} |
60 |
|
61 |
ADConverter::ADConverter(ADCDriver& adcdrv, ADCConversionGroup& adccgrp, const uint32_t threshold_uV) :
|
62 |
driver(adcdrv), conversion_group(adccgrp), watchdog_threshold_uV(threshold_uV) |
63 |
{ |
64 |
} |
65 |
|
66 |
|
67 |
ADConverter::~ADConverter() |
68 |
{ |
69 |
} |
70 |
|
71 |
msg_t |
72 |
ADConverter::main() |
73 |
{ |
74 |
// initialize a timer event for later use
|
75 |
evtInit(&this->evt_timer, MS2ST(1)); |
76 |
this->evt_source = reinterpret_cast<EvtSource*>(&this->evt_timer.et_es); |
77 |
this->evt_source->registerOne(&this->evt_listener, EVT_TIMER); |
78 |
|
79 |
// initialize the watchdog
|
80 |
this->enableWatchdog(true); |
81 |
this->conversion_group.htr = ADC_HTR(uV2Adc(this->watchdog_threshold_uV)); |
82 |
this->conversion_group.ltr = 0; |
83 |
this->driver.thread = this->thread_ref; |
84 |
|
85 |
adcStartConversion(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer)); |
86 |
|
87 |
while (!this->shouldTerminate()) |
88 |
{ |
89 |
eventmask_t event = this->waitOneEventTimeout(ALL_EVENTS, MS2ST(1000)); |
90 |
|
91 |
switch (event)
|
92 |
{ |
93 |
// watchdog event (fired by ADC interrupt)
|
94 |
case EVENT_MASK(EVT_WATCHDOG):
|
95 |
{ |
96 |
// disable the chargers
|
97 |
global.bq24103a[constants::PowerManagement::BAT_P7]->enable(false);
|
98 |
global.bq24103a[constants::PowerManagement::BAT_P8]->enable(false);
|
99 |
|
100 |
// to avoid multiple interrupts because of noise, wait 1ms before setting the chargers and ADC
|
101 |
this->enableWatchdog(false); |
102 |
evtStart(&this->evt_timer);
|
103 |
break;
|
104 |
} |
105 |
|
106 |
// timer event
|
107 |
case EVENT_MASK(EVT_TIMER):
|
108 |
{ |
109 |
evtStop(&this->evt_timer);
|
110 |
|
111 |
// read the current voltage
|
112 |
this->conversion_group.circular = FALSE;
|
113 |
adcConvert(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer)); |
114 |
this->conversion_group.circular = TRUE;
|
115 |
this->enableWatchdog(true); // Watchdog was disabled in ISR |
116 |
|
117 |
if (global.adc1_buffer[0] > uV2Adc(this->watchdog_threshold_uV)) |
118 |
{ |
119 |
chprintf((BaseSequentialStream*)&global.sercanmux1, "%f > 9V detected: now charging\n", ((float)adc2uV(global.adc1_buffer[0]))/1000000.0f); |
120 |
global.robot.getPowerStatus().charging_flags.content.vsys_higher_than_9V = true;
|
121 |
global.bq24103a[constants::PowerManagement::BAT_P7]->enable(true);
|
122 |
global.bq24103a[constants::PowerManagement::BAT_P8]->enable(true);
|
123 |
this->conversion_group.htr = ADC_HTR_HT;
|
124 |
this->conversion_group.ltr = ADC_LTR(uV2Adc(this->watchdog_threshold_uV)); |
125 |
} else {
|
126 |
chprintf((BaseSequentialStream*)&global.sercanmux1, "%f < 9V detected: not charging\n", ((float)adc2uV(global.adc1_buffer[0]))/1000000.0f); |
127 |
global.robot.getPowerStatus().charging_flags.content.vsys_higher_than_9V = false;
|
128 |
this->conversion_group.htr = ADC_HTR(uV2Adc(this->watchdog_threshold_uV)); |
129 |
this->conversion_group.ltr = 0; |
130 |
} |
131 |
this->driver.thread = this->thread_ref; |
132 |
adcStartConversion(&this->driver, &this->conversion_group, global.adc1_buffer, ARRAY_SIZE(global.adc1_buffer)); |
133 |
break;
|
134 |
} |
135 |
|
136 |
// timeout
|
137 |
case 0: |
138 |
|
139 |
default:
|
140 |
break;
|
141 |
} |
142 |
} |
143 |
|
144 |
return RDY_RESET;
|
145 |
} |
146 |
|
147 |
void
|
148 |
ADConverter::enableWatchdog(const bool enable) |
149 |
{ |
150 |
if (enable) {
|
151 |
this->conversion_group.cr1 |= ADC_CR1_AWDEN | ADC_CR1_AWDIE;
|
152 |
this->conversion_group.error_cb = &adcVsysErrorCallback;
|
153 |
} else {
|
154 |
this->conversion_group.cr1 &= ~(ADC_CR1_AWDEN | ADC_CR1_AWDIE);
|
155 |
this->conversion_group.error_cb = NULL; |
156 |
} |
157 |
} |
158 |
|
159 |
|