amiro-os / components / power / adconverter.cpp @ 1d9e5660
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 |
|