ADC: replace ioctl with uorb message (#14087)

This commit is contained in:
SalimTerryLi
2020-03-20 18:23:32 +08:00
committed by GitHub
parent 40af5b0fbe
commit dc8e775d8f
30 changed files with 345 additions and 486 deletions
@@ -40,7 +40,6 @@ px4_add_module(
MODULE_CONFIG
module.yaml
DEPENDS
arch_adc
battery
conversion
drivers__device
+21 -35
View File
@@ -15,17 +15,11 @@ static constexpr int DEFAULT_V_CHANNEL[1] = {0};
static constexpr int DEFAULT_I_CHANNEL[1] = {0};
#endif
static constexpr float DEFAULT_VOLTS_PER_COUNT = 3.3f / 4096.0f;
AnalogBattery::AnalogBattery(int index, ModuleParams *parent) :
Battery(index, parent)
{
char param_name[17];
_analog_param_handles.cnt_v_volt = param_find("BAT_CNT_V_VOLT");
_analog_param_handles.cnt_v_curr = param_find("BAT_CNT_V_CURR");
_analog_param_handles.v_offs_cur = param_find("BAT_V_OFFS_CURR");
snprintf(param_name, sizeof(param_name), "BAT%d_V_DIV", index);
@@ -34,8 +28,11 @@ AnalogBattery::AnalogBattery(int index, ModuleParams *parent) :
snprintf(param_name, sizeof(param_name), "BAT%d_A_PER_V", index);
_analog_param_handles.a_per_v = param_find(param_name);
snprintf(param_name, sizeof(param_name), "BAT%d_ADC_CHANNEL", index);
_analog_param_handles.adc_channel = param_find(param_name);
snprintf(param_name, sizeof(param_name), "BAT%d_V_CHANNEL", index);
_analog_param_handles.v_channel = param_find(param_name);
snprintf(param_name, sizeof(param_name), "BAT%d_I_CHANNEL", index);
_analog_param_handles.i_channel = param_find(param_name);
_analog_param_handles.v_div_old = param_find("BAT_V_DIV");
_analog_param_handles.a_per_v_old = param_find("BAT_A_PER_V");
@@ -43,11 +40,11 @@ AnalogBattery::AnalogBattery(int index, ModuleParams *parent) :
}
void
AnalogBattery::updateBatteryStatusRawADC(hrt_abstime timestamp, int32_t voltage_raw, int32_t current_raw,
bool selected_source, int priority, float throttle_normalized)
AnalogBattery::updateBatteryStatusADC(hrt_abstime timestamp, float voltage_raw, float current_raw,
bool selected_source, int priority, float throttle_normalized)
{
float voltage_v = (voltage_raw * _analog_params.cnt_v_volt) * _analog_params.v_div;
float current_a = ((current_raw * _analog_params.cnt_v_curr) - _analog_params.v_offs_cur) * _analog_params.a_per_v;
float voltage_v = voltage_raw * _analog_params.v_div;
float current_a = (current_raw - _analog_params.v_offs_cur) * _analog_params.a_per_v;
bool connected = voltage_v > BOARD_ADC_OPEN_CIRCUIT_V &&
(BOARD_ADC_OPEN_CIRCUIT_V <= BOARD_VALID_UV || is_valid());
@@ -70,8 +67,8 @@ bool AnalogBattery::is_valid()
int AnalogBattery::get_voltage_channel()
{
if (_analog_params.adc_channel >= 0) {
return _analog_params.adc_channel;
if (_analog_params.v_channel >= 0) {
return _analog_params.v_channel;
} else {
return DEFAULT_V_CHANNEL[_index - 1];
@@ -80,8 +77,12 @@ int AnalogBattery::get_voltage_channel()
int AnalogBattery::get_current_channel()
{
// TODO: Possibly implement parameter for current sense channel
return DEFAULT_I_CHANNEL[_index - 1];
if (_analog_params.i_channel >= 0) {
return _analog_params.i_channel;
} else {
return DEFAULT_I_CHANNEL[_index - 1];
}
}
void
@@ -92,33 +93,18 @@ AnalogBattery::updateParams()
&_analog_params.v_div, _first_parameter_update);
migrateParam<float>(_analog_param_handles.a_per_v_old, _analog_param_handles.a_per_v, &_analog_params.a_per_v_old,
&_analog_params.a_per_v, _first_parameter_update);
migrateParam<int>(_analog_param_handles.adc_channel_old, _analog_param_handles.adc_channel,
&_analog_params.adc_channel_old, &_analog_params.adc_channel, _first_parameter_update);
migrateParam<int>(_analog_param_handles.adc_channel_old, _analog_param_handles.v_channel,
&_analog_params.adc_channel_old, &_analog_params.v_channel, _first_parameter_update);
} else {
param_get(_analog_param_handles.v_div, &_analog_params.v_div);
param_get(_analog_param_handles.a_per_v, &_analog_params.a_per_v);
param_get(_analog_param_handles.adc_channel, &_analog_params.adc_channel);
param_get(_analog_param_handles.v_channel, &_analog_params.v_channel);
}
param_get(_analog_param_handles.cnt_v_volt, &_analog_params.cnt_v_volt);
param_get(_analog_param_handles.cnt_v_curr, &_analog_params.cnt_v_curr);
param_get(_analog_param_handles.i_channel, &_analog_params.i_channel);
param_get(_analog_param_handles.v_offs_cur, &_analog_params.v_offs_cur);
/* scaling of ADC ticks to battery voltage */
if (_analog_params.cnt_v_volt < 0.0f) {
/* apply scaling according to defaults if set to default */
_analog_params.cnt_v_volt = (BOARD_ADC_POS_REF_V_FOR_VOLTAGE_CHAN / px4_arch_adc_dn_fullcount());
param_set_no_notification(_analog_param_handles.cnt_v_volt, &_analog_params.cnt_v_volt);
}
/* scaling of ADC ticks to battery current */
if (_analog_params.cnt_v_curr < 0.0f) {
/* apply scaling according to defaults if set to default */
_analog_params.cnt_v_curr = (BOARD_ADC_POS_REF_V_FOR_CURRENT_CHAN / px4_arch_adc_dn_fullcount());
param_set_no_notification(_analog_param_handles.cnt_v_curr, &_analog_params.cnt_v_curr);
}
if (_analog_params.v_div <= 0.0f) {
/* apply scaling according to defaults if set to default */
_analog_params.v_div = BOARD_BATTERY1_V_DIV;
+8 -10
View File
@@ -44,15 +44,15 @@ public:
/**
* Update current battery status message.
*
* @param voltage_raw Battery voltage read from ADC, in raw ADC counts
* @param current_raw Voltage of current sense resistor, in raw ADC counts
* @param voltage_raw Battery voltage read from ADC, volts
* @param current_raw Voltage of current sense resistor, volts
* @param timestamp Time at which the ADC was read (use hrt_absolute_time())
* @param selected_source This battery is on the brick that the selected source for selected_source
* @param priority: The brick number -1. The term priority refers to the Vn connection on the LTC4417
* @param throttle_normalized Throttle of the vehicle, between 0 and 1
*/
void updateBatteryStatusRawADC(hrt_abstime timestamp, int32_t voltage_raw, int32_t current_raw,
bool selected_source, int priority, float throttle_normalized);
void updateBatteryStatusADC(hrt_abstime timestamp, float voltage_raw, float current_raw,
bool selected_source, int priority, float throttle_normalized);
/**
* Whether the ADC channel for the voltage of this battery is valid.
@@ -73,12 +73,11 @@ public:
protected:
struct {
param_t cnt_v_volt;
param_t cnt_v_curr;
param_t v_offs_cur;
param_t v_div;
param_t a_per_v;
param_t adc_channel;
param_t v_channel;
param_t i_channel;
param_t v_div_old;
param_t a_per_v_old;
@@ -86,12 +85,11 @@ protected:
} _analog_param_handles;
struct {
float cnt_v_volt;
float cnt_v_curr;
float v_offs_cur;
float v_div;
float a_per_v;
int adc_channel;
int v_channel;
int i_channel;
float v_div_old;
float a_per_v_old;
@@ -31,30 +31,6 @@
*
****************************************************************************/
/**
* Scaling from ADC counts to volt on the ADC input (battery voltage)
*
* This is not the battery voltage, but the intermediate ADC voltage.
* A value of -1 signifies that the board defaults are used, which is
* highly recommended.
*
* @group Battery Calibration
* @decimal 8
*/
PARAM_DEFINE_FLOAT(BAT_CNT_V_VOLT, -1.0f);
/**
* Scaling from ADC counts to volt on the ADC input (battery current)
*
* This is not the battery current, but the intermediate ADC voltage.
* A value of -1 signifies that the board defaults are used, which is
* highly recommended.
*
* @group Battery Calibration
* @decimal 8
*/
PARAM_DEFINE_FLOAT(BAT_CNT_V_CURR, -1.0);
/**
* Offset in volt as seen by the ADC input of the current sensor.
*
+37 -47
View File
@@ -60,7 +60,7 @@
#include <uORB/Publication.hpp>
#include <uORB/topics/actuator_controls.h>
#include <uORB/topics/parameter_update.h>
#include <uORB/topics/battery_status.h>
#include <uORB/topics/adc_report.h>
#include <px4_platform_common/px4_work_queue/ScheduledWorkItem.hpp>
#include "analog_battery.h"
@@ -99,10 +99,9 @@ public:
private:
void Run() override;
int _adc_fd{-1}; /**< ADC file handle */
uORB::Subscription _actuator_ctrl_0_sub{ORB_ID(actuator_controls_0)}; /**< attitude controls sub */
uORB::Subscription _parameter_update_sub{ORB_ID(parameter_update)}; /**< notification of parameter updates */
uORB::Subscription _adc_report_sub{ORB_ID(adc_report)};
AnalogBattery _battery1;
@@ -167,21 +166,15 @@ BatteryStatus::parameter_update_poll(bool forced)
void
BatteryStatus::adc_poll()
{
/* make space for a maximum of twelve channels (to ensure reading all channels at once) */
px4_adc_msg_t buf_adc[PX4_MAX_ADC_CHANNELS];
/* read all channels available */
int ret = px4_read(_adc_fd, &buf_adc, sizeof(buf_adc));
/* For legacy support we publish the battery_status for the Battery that is
* associated with the Brick that is the selected source for VDD_5V_IN
* Selection is done in HW ala a LTC4417 or similar, or may be hard coded
* Like in the FMUv4
*/
* associated with the Brick that is the selected source for VDD_5V_IN
* Selection is done in HW ala a LTC4417 or similar, or may be hard coded
* Like in the FMUv4
*/
/* Per Brick readings with default unread channels at 0 */
int32_t bat_current_adc_readings[BOARD_NUMBER_BRICKS] {};
int32_t bat_voltage_adc_readings[BOARD_NUMBER_BRICKS] {};
float bat_current_adc_readings[BOARD_NUMBER_BRICKS] {};
float bat_voltage_adc_readings[BOARD_NUMBER_BRICKS] {};
/* Based on the valid_chan, used to indicate the selected the lowest index
* (highest priority) supply that is the source for the VDD_5V_IN
@@ -190,34 +183,40 @@ BatteryStatus::adc_poll()
int selected_source = -1;
if (ret >= (int)sizeof(buf_adc[0])) {
adc_report_s adc_report;
if (_adc_report_sub.update(&adc_report)) {
/* Read add channels we got */
for (unsigned i = 0; i < ret / sizeof(buf_adc[0]); i++) {
{
for (int b = 0; b < BOARD_NUMBER_BRICKS; b++) {
for (unsigned i = 0; i < PX4_MAX_ADC_CHANNELS; ++i) {
for (int b = 0; b < BOARD_NUMBER_BRICKS; b++) {
/* Once we have subscriptions, Do this once for the lowest (highest priority
* supply on power controller) that is valid.
/* Once we have subscriptions, Do this once for the lowest (highest priority
* supply on power controller) that is valid.
*/
if (selected_source < 0 && _analogBatteries[b]->is_valid()) {
/* Indicate the lowest brick (highest priority supply on power controller)
* that is valid as the one that is the selected source for the
* VDD_5V_IN
*/
if (selected_source < 0 && _analogBatteries[b]->is_valid()) {
/* Indicate the lowest brick (highest priority supply on power controller)
* that is valid as the one that is the selected source for the
* VDD_5V_IN
*/
selected_source = b;
selected_source = b;
}
/* look for specific channels and process the raw voltage to measurement data */
if (_analogBatteries[b]->get_voltage_channel() == buf_adc[i].am_channel) {
/* Voltage in volts */
bat_voltage_adc_readings[b] = buf_adc[i].am_data;
} else if (_analogBatteries[b]->get_current_channel() == buf_adc[i].am_channel) {
bat_current_adc_readings[b] = buf_adc[i].am_data;
}
}
/* look for specific channels and process the raw voltage to measurement data */
if (adc_report.channel_id[i] == _analogBatteries[b]->get_voltage_channel()) {
/* Voltage in volts */
bat_voltage_adc_readings[b] = adc_report.raw_data[i] *
adc_report.v_ref /
adc_report.resolution;
} else if (adc_report.channel_id[i] == _analogBatteries[b]->get_current_channel()) {
bat_current_adc_readings[b] = adc_report.raw_data[i] *
adc_report.v_ref /
adc_report.resolution;
}
}
}
@@ -226,7 +225,7 @@ BatteryStatus::adc_poll()
actuator_controls_s ctrl{};
_actuator_ctrl_0_sub.copy(&ctrl);
_analogBatteries[b]->updateBatteryStatusRawADC(
_analogBatteries[b]->updateBatteryStatusADC(
hrt_absolute_time(),
bat_voltage_adc_readings[b],
bat_current_adc_readings[b],
@@ -249,15 +248,6 @@ BatteryStatus::Run()
perf_begin(_loop_perf);
if (_adc_fd < 0) {
_adc_fd = px4_open(ADC0_DEVICE_PATH, O_RDONLY);
if (_adc_fd < 0) {
PX4_ERR("unable to open ADC: %s", ADC0_DEVICE_PATH);
return;
}
}
/* check parameters for updates */
parameter_update_poll();
+17 -4
View File
@@ -9,7 +9,7 @@ parameters:
description:
short: Battery ${i} voltage divider (V divider)
long: |
This is the divider from battery ${i} voltage to 3.3V ADC voltage.
This is the divider from battery ${i} voltage to ADC voltage.
If using e.g. Mauch power modules the value from the datasheet
can be applied straight here. A value of -1 means to use
the board default.
@@ -25,7 +25,7 @@ parameters:
description:
short: Battery ${i} current per volt (A/V)
long: |
The voltage seen by the 3.3V ADC multiplied by this factor
The voltage seen by the ADC multiplied by this factor
will determine the battery current. A value of -1 means to use
the board default.
@@ -36,9 +36,9 @@ parameters:
instance_start: 1
default: [-1.0, -1.0]
BAT${i}_ADC_CHANNEL:
BAT${i}_V_CHANNEL:
description:
short: Battery ${i} ADC Channel
short: Battery ${i} Voltage ADC Channel
long: |
This parameter specifies the ADC channel used to monitor voltage of main power battery.
A value of -1 means to use the board default.
@@ -48,3 +48,16 @@ parameters:
num_instances: *max_num_config_instances
instance_start: 1
default: [-1, -1]
BAT${i}_I_CHANNEL:
description:
short: Battery ${i} Current ADC Channel
long: |
This parameter specifies the ADC channel used to monitor current of main power battery.
A value of -1 means to use the board default.
type: int32
reboot_required: true
num_instances: *max_num_config_instances
instance_start: 1
default: [-1, -1]
+17 -37
View File
@@ -144,10 +144,10 @@ private:
DataValidator _airspeed_validator; /**< data validator to monitor airspeed */
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
int _adc_fd {-1}; /**< ADC driver handle */
hrt_abstime _last_adc{0}; /**< last time we took input from the ADC */
uORB::Subscription _adc_report_sub{ORB_ID(adc_report)}; /**< adc_report sub */
differential_pressure_s _diff_pres {};
uORB::PublicationMulti<differential_pressure_s> _diff_pres_pub{ORB_ID(differential_pressure)}; /**< differential_pressure */
#endif /* ADC_AIRSPEED_VOLTAGE_CHANNEL */
@@ -183,11 +183,6 @@ private:
*/
void parameter_update_poll(bool forced = false);
/**
* Do adc-related initialisation.
*/
int adc_init();
/**
* Poll the ADC and update readings to suit.
*
@@ -254,23 +249,6 @@ int Sensors::parameters_update()
return PX4_OK;
}
int Sensors::adc_init()
{
if (!_hil_enabled) {
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
_adc_fd = px4_open(ADC0_DEVICE_PATH, O_RDONLY);
if (_adc_fd == -1) {
PX4_ERR("no ADC found: %s", ADC0_DEVICE_PATH);
return PX4_ERROR;
}
#endif // ADC_AIRSPEED_VOLTAGE_CHANNEL
}
return OK;
}
void Sensors::diff_pres_poll()
{
differential_pressure_s diff_pres{};
@@ -365,37 +343,40 @@ Sensors::parameter_update_poll(bool forced)
void Sensors::adc_poll()
{
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
/* only read if not in HIL mode */
if (_hil_enabled) {
return;
}
#ifdef ADC_AIRSPEED_VOLTAGE_CHANNEL
if (_parameters.diff_pres_analog_scale > 0.0f) {
hrt_abstime t = hrt_absolute_time();
/* rate limit to 100 Hz */
if (t - _last_adc >= 10000) {
/* make space for a maximum of twelve channels (to ensure reading all channels at once) */
px4_adc_msg_t buf_adc[PX4_MAX_ADC_CHANNELS];
/* read all channels available */
int ret = px4_read(_adc_fd, &buf_adc, sizeof(buf_adc));
if (ret >= (int)sizeof(buf_adc[0])) {
adc_report_s adc;
if (_adc_report_sub.update(&adc)) {
/* Read add channels we got */
for (unsigned i = 0; i < ret / sizeof(buf_adc[0]); i++) {
if (ADC_AIRSPEED_VOLTAGE_CHANNEL == buf_adc[i].am_channel) {
for (unsigned i = 0; i < PX4_MAX_ADC_CHANNELS; i++) {
if (adc.channel_id[i] == -1) {
continue; // skip non-exist channels
}
if (ADC_AIRSPEED_VOLTAGE_CHANNEL == adc.channel_id[i]) {
/* calculate airspeed, raw is the difference from */
const float voltage = (float)(buf_adc[i].am_data) * 3.3f / 4096.0f * 2.0f; // V_ref/4096 * (voltage divider factor)
const float voltage = (float)(adc.raw_data[i]) * adc.v_ref / adc.resolution * ADC_DP_V_DIV;
/**
* The voltage divider pulls the signal down, only act on
* a valid voltage from a connected sensor. Also assume a non-
* zero offset from the sensor if its connected.
*
* Notice: This won't work on devices which have PGA controlled
* vref. Those devices require no divider at all.
*/
if (voltage > 0.4f) {
const float diff_pres_pa_raw = voltage * _parameters.diff_pres_analog_scale - _parameters.diff_pres_offset_pa;
@@ -410,9 +391,9 @@ void Sensors::adc_poll()
}
}
}
_last_adc = t;
}
_last_adc = t;
}
}
@@ -465,7 +446,6 @@ void Sensors::Run()
// run once
if (_last_config_update == 0) {
adc_init();
_voted_sensors_update.init(_sensor_combined);
parameter_update_poll(true);
}