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();