lib/adc: SelectContinuousReadAdcs
- Adds Adc::SelectContinuousReadAdcs which allows setting which ADC
channels are sampled in continuous read mode.
- Fix missing static_cast in Adc::VoltageMeasurement()
- Correct continuous read mode order to vshunt followed by vbus.
Change-Id: I0590af949399b6d46fd930df7575bab9f2fa2222
Reviewed-on: https://pigweed-review.googlesource.com/c/gonk/+/189640
Commit-Queue: Anthony DiGirolamo <tonymd@google.com>
Reviewed-by: Umang Shah <umangshah@google.com>
Reviewed-by: Eric Holland <hollande@google.com>
diff --git a/applications/fpga_config/main.cc b/applications/fpga_config/main.cc
index 5c48e8d..6492d01 100644
--- a/applications/fpga_config/main.cc
+++ b/applications/fpga_config/main.cc
@@ -127,6 +127,8 @@
// Init ADCs
fpga_adc.InitAdcs();
fpga_adc.CheckAllAdcs();
+ // Select the first five ADC channels.
+ fpga_adc.SelectContinuousReadAdcs(0b11111);
PW_LOG_INFO("Switching to ADC binary log");
fpga_adc.SetContinuousReadMode();
diff --git a/lib/adc/adc.cc b/lib/adc/adc.cc
index 091513e..40ed56e 100644
--- a/lib/adc/adc.cc
+++ b/lib/adc/adc.cc
@@ -86,6 +86,7 @@
fpga_cs_(fpga_cs_pin),
spi_settings_(fpga_spi_baudrate, MSBFIRST, SPI_MODE1) {
sample_read_index_ = 0;
+ sampled_adc_count_ = kMaxStreamingAdcCount;
measurement_timestamp_ = 0;
previous_timestamp_ = 0;
sample_read_time_.fill(0);
@@ -199,6 +200,49 @@
| mode);
}
+uint32_t Adc::ADCAddressWriteSelection(uint16_t adc_selection,
+ uint8_t adc_command) {
+ return (
+ // Set adc selection bits
+ (adc_selection & 0x7FF) << 7
+ // ADC Register
+ | ((adc_command & 0x3f) << 1)
+ // 1=read, 0=write
+ | 0);
+}
+
+Status Adc::SelectContinuousReadAdcs(uint16_t adc_selection) {
+ // Count the number of selected ADCs.
+ uint16_t selected_bits = adc_selection;
+ uint16_t set_bits_count;
+ for (set_bits_count = 0; selected_bits; selected_bits >>= 1) {
+ set_bits_count += selected_bits & 1;
+ }
+ sampled_adc_count_ = set_bits_count;
+ if (sampled_adc_count_ > 11 || sampled_adc_count_ == 0) {
+ PW_LOG_ERROR("Invalid ADC channel selection: %x", adc_selection);
+ return pw::Status::OutOfRange();
+ }
+
+ PW_LOG_INFO("Selected ADC count: %d", sampled_adc_count_);
+
+ uint32_t adc_address =
+ ADCAddressWriteSelection(adc_selection, /*adc_command=*/0);
+
+ // Set bit 18 to signal to the FPGA to treat this as a continuous read mode
+ // update.
+ adc_address = 1 << 18 | adc_address;
+
+ StartSpiTransaction();
+ // Write the ADC address selection.
+ WriteAddress(adc_address);
+ // NOTE: The FPGA does not generate a valid signal for this write.
+ EndSpiTransaction();
+
+ // return wait_result;
+ return pw::OkStatus();
+}
+
uint32_t Adc::ADCAddressWrite(uint8_t adc_number, uint8_t adc_command) {
// Address with mode=0 for a write.
return ADCAddress(adc_number, adc_command, 0);
@@ -311,20 +355,8 @@
previous_timestamp_ = measurement_timestamp_;
measurement_timestamp_ = micros();
measurement_delta_micros_ = measurement_timestamp_ - previous_timestamp_;
- for (int i = 0; i < kMaxStreamingAdcCount; i++) {
- // Read VBUS
- std::array<std::byte, 3> vbus_read_buffer;
- const pw::Result<pw::ConstByteSpan> vbus_read_result =
- ReadData(pw::ByteSpan(vbus_read_buffer));
- if (!vbus_read_result.ok()) {
- PW_LOG_ERROR("vbus_read failed i=%d", i);
- return vbus_read_result.status();
- }
- int32_t vbus_value = VoltageMeasurement(vbus_read_result.value());
- PW_LOG_DEBUG("Continuous Read ADC #%02d: VBUS = %02x %02x %02x = %d", i,
- vbus_read_result.value()[0], vbus_read_result.value()[1],
- vbus_read_result.value()[2], vbus_value);
+ for (int i = 0; i < sampled_adc_count_; i++) {
// Read VSHUNT
std::array<std::byte, 3> vshunt_read_buffer;
const pw::Result<pw::ConstByteSpan> vshunt_read_result =
@@ -338,6 +370,19 @@
vshunt_read_result.value()[0], vshunt_read_result.value()[1],
vshunt_read_result.value()[2], vshunt_value);
+ // Read VBUS
+ std::array<std::byte, 3> vbus_read_buffer;
+ const pw::Result<pw::ConstByteSpan> vbus_read_result =
+ ReadData(pw::ByteSpan(vbus_read_buffer));
+ if (!vbus_read_result.ok()) {
+ PW_LOG_ERROR("vbus_read failed i=%d", i);
+ return vbus_read_result.status();
+ }
+ int32_t vbus_value = VoltageMeasurement(vbus_read_result.value());
+ PW_LOG_DEBUG("Continuous Read ADC #%02d: VBUS = %02x %02x %02x = %d", i,
+ vbus_read_result.value()[0], vbus_read_result.value()[1],
+ vbus_read_result.value()[2], vbus_value);
+
// Save this measurement.
measurements_[i].vbus_value_ = vbus_value;
measurements_[i].vshunt_value_ = vshunt_value;
@@ -382,7 +427,7 @@
PW_LOG_ERROR("WriteTimestamp: %d", status);
return status;
}
- for (size_t i = 0; i < kMaxStreamingAdcCount; i++) {
+ for (size_t i = 0; i < sampled_adc_count_; i++) {
auto adc_encoder = payload.GetAdcMeasurementsEncoder();
status = adc_encoder.WriteVbusValue(measurements_[i].vbus_value_);
if (!status.ok()) {
@@ -487,9 +532,9 @@
// read_buffer[2] >> 4 76543210--->
// result 98765432109876543210|
//
- return pw::bytes::SignExtend<20>((uint32_t)read_buffer[0] << 12 |
- (uint32_t)read_buffer[1] << 4 |
- (uint32_t)read_buffer[2] >> 4);
+ return pw::bytes::SignExtend<20>(static_cast<uint32_t>(read_buffer[0]) << 12 |
+ static_cast<uint32_t>(read_buffer[1]) << 4 |
+ static_cast<uint32_t>(read_buffer[2]) >> 4);
}
Status Adc::InitAdcs() {
diff --git a/lib/adc/public/gonk/adc.h b/lib/adc/public/gonk/adc.h
index ee0393f..9607fd6 100644
--- a/lib/adc/public/gonk/adc.h
+++ b/lib/adc/public/gonk/adc.h
@@ -45,6 +45,7 @@
Status WriteRegister(uint8_t adc_number, uint8_t adc_register,
pw::ByteSpan write_buffer);
Status WriteRegisterAll(uint8_t adc_register, pw::ByteSpan write_buffer);
+ Status SelectContinuousReadAdcs(uint16_t adc_selection);
// ADC Specific functions.
pw::Result<pw::ConstByteSpan> GetManufacturerID(uint8_t adc_number);
@@ -75,6 +76,7 @@
SPIClass &fpga_spi_;
SPISettings spi_settings_;
+ uint8_t sampled_adc_count_;
uint8_t sample_read_index_;
std::array<uint32_t, 16> sample_read_time_;
@@ -85,6 +87,8 @@
uint32_t ADCAddress(uint8_t adc_number, uint8_t adc_command, uint8_t mode);
uint32_t ADCAddressWrite(uint8_t adc_number, uint8_t adc_command);
uint32_t ADCAddressWriteAll(uint8_t adc_command);
+ uint32_t ADCAddressWriteSelection(uint16_t adc_selection,
+ uint8_t adc_command);
pw::Result<pw::ConstByteSpan> GetThreeBytes();