diff --git a/CMakeLists.txt b/CMakeLists.txt index 56309e4d6f92f5c10bb689b5cb7f14354b3d54e3..5352d725ddc0f3e19aa9932c03a262cc4933a085 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -327,7 +327,7 @@ add_executable(test-ads1118 src/tests/sensors/test-ads1118.cpp) sbs_target(test-ads1118 stm32f407vg_stm32f4discovery) add_executable(test-ads131m04 src/tests/sensors/test-ads131m04.cpp) -sbs_target(test-ads131m04 stm32f429zi_stm32f4discovery) +sbs_target(test-ads131m04 stm32f429zi_skyward_death_stack_v3) add_executable(test-ads131m08 src/tests/sensors/test-ads131m08.cpp) sbs_target(test-ads131m08 stm32f767zi_compute_unit) diff --git a/src/shared/sensors/ADS131M04/ADS131M04.cpp b/src/shared/sensors/ADS131M04/ADS131M04.cpp index 727ed16a8371926cc7f6d2d3816a46f743acd72c..2f5f7dfda2095b4aff8ffbefd32c37215e6fcd31 100644 --- a/src/shared/sensors/ADS131M04/ADS131M04.cpp +++ b/src/shared/sensors/ADS131M04/ADS131M04.cpp @@ -33,37 +33,26 @@ namespace Boardcore { ADS131M04::ADS131M04(SPIBusInterface &bus, miosix::GpioPin cs, - SPIBusConfig config) - : ADS131M04(SPISlave(bus, cs, config)) + SPIBusConfig spiConfig, const Config &config) + : spiSlave(bus, cs, spiConfig), config(config) { + // Impose the correct spi mode + spiSlave.config.mode = SPI::Mode::MODE_1; } -ADS131M04::ADS131M04(SPISlave spiSlave) : spiSlave(spiSlave) +bool ADS131M04::init() { - // Initialize the channel configurations to the default values - for (int i = 0; i < CHANNELS_NUM; i++) - { - channelsPGAGain[i] = PGA::PGA_1; - channelsOffset[i] = 0; - channelsGain[i] = 1.0; - } -} + reset(); + applyConfig(config); -SPIBusConfig ADS131M04::getDefaultSPIConfig() -{ - SPIBusConfig spiConfig{}; - spiConfig.clockDivider = SPI::ClockDivider::DIV_64; - spiConfig.mode = SPI::Mode::MODE_1; - return spiConfig; + return true; } -bool ADS131M04::init() { return true; } - bool ADS131M04::reset() { SPITransaction transaction(spiSlave); - uint8_t data[ADS131M04Defs::FULL_FRAME_SIZE] = {0}; + uint8_t data[FULL_FRAME_SIZE] = {0}; sendCommand(transaction, Command::RESET, data); // The reset command takes typically 5us to reload the register contents. @@ -85,21 +74,44 @@ bool ADS131M04::reset() return true; } -void ADS131M04::calibrateOffset() +void ADS131M04::applyConfig(Config config) { - // The device internal data chain firsts subtracts the offset and then - // multiplies for the gain. To calibrate the offset we first reset it, then - // take some samples and apply the average as the new offset. - // So we need to reset the offset and gain for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelOffsetImpl(static_cast<Channel>(i), 0); - setChannelGainCalibrationImpl(static_cast<Channel>(i), 1.0); + applyChannelConfig(static_cast<Channel>(i), config.channelsConfig[i]); } - // Sample the channels and average the samples - int32_t averageValues[CHANNELS_NUM] = {0}; - int realSampleCount = 0; + setOversamplingRatio(config.oversamplingRatio); + if (config.globalChopModeEnabled) + { + enableGlobalChopMode(); + } + else + { + disableGlobalChopMode(); + } + + // Save the newly applied configuration + this->config = config; +} + +void ADS131M04::calibrateOffset(Channel channel) +{ + // The device internal data chain firsts subtracts the offset and then + // multiplies for the gain. To calibrate the offset we first reset it, then + // take some samples and apply the average as the new offset. + // So we need to reset the offset and gain + Config::ChannelConfig calibrationConfig{ + .enabled = true, + .pga = PGA::PGA_1, + .offset = 0, + .gain = 1.0, + }; + applyChannelConfig(channel, calibrationConfig); + + // Sample the channel and average the samples + int32_t averageValue = 0; + int realSampleCount = 0; for (int i = 0; i < CALIBRATION_SAMPLES; i++) { // Wait for a sample to be ready @@ -113,10 +125,7 @@ void ADS131M04::calibrateOffset() continue; } - for (int j = 0; j < CHANNELS_NUM; j++) - { - averageValues[j] += rawValues[j]; - } + averageValue += rawValues[static_cast<int>(channel)]; realSampleCount++; } @@ -127,88 +136,43 @@ void ADS131M04::calibrateOffset() } else { - for (int i = 0; i < CHANNELS_NUM; i++) + // Compute the average + averageValue /= realSampleCount; + LOG_INFO(logger, "Channel {} average offset: {}", + static_cast<int>(channel), + averageValue * getLSBSizeFromGain(calibrationConfig.pga)); + + // Set the new offset only if valid, otherwise keep the old one + if (averageValue != 0) { - // Compute the average - averageValues[i] /= realSampleCount; - LOG_INFO(logger, "Channel {} average offset: {}", i, - averageValues[i] * getLSBSizeFromGain(channelsPGAGain[i])); - - // Set the new offset only if valid, otherwise keep the old one - if (averageValues[i] != 0) - { - channelsOffset[i] = averageValues[i]; - } + config.channelsConfig[static_cast<int>(channel)].offset = + averageValue; } } - // Update the offset values and reset the gain as it was before - for (int i = 0; i < CHANNELS_NUM; i++) - { - setChannelOffset(static_cast<Channel>(i), channelsOffset[i]); - setChannelGainCalibrationImpl(static_cast<Channel>(i), channelsGain[i]); - } -} - -void ADS131M04::setOversamplingRatio(OversamplingRatio ratio) -{ - changeRegister(Register::REG_CLOCK, static_cast<uint16_t>(ratio), - RegClockMasks::OSR); -} - -void ADS131M04::setChannelPGA(Channel channel, PGA gain) -{ - setChannelPGAImpl(channel, gain); - channelsPGAGain[static_cast<int>(channel)] = gain; -} - -void ADS131M04::setChannelOffset(Channel channel, uint32_t offset) -{ - setChannelOffsetImpl(channel, offset); - channelsOffset[static_cast<int>(channel)] = offset; -} - -void ADS131M04::setChannelGainCalibration(Channel channel, double gain) -{ - setChannelGainCalibrationImpl(channel, gain); - channelsGain[static_cast<int>(channel)] = gain; -} - -void ADS131M04::enableChannel(Channel channel) -{ - changeRegister(Register::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), - 1 << (static_cast<int>(channel) + 8)); -} - -void ADS131M04::disableChannel(Channel channel) -{ - changeRegister(Register::REG_CLOCK, 0, - 1 << (static_cast<int>(channel) + 8)); -} - -void ADS131M04::enableGlobalChopMode() -{ - changeRegister(Register::REG_CFG, RegConfigurationMasks::GC_EN, - RegConfigurationMasks::GC_EN); -} - -void ADS131M04::disableGlobalChopMode() -{ - changeRegister(Register::REG_CFG, 0, RegConfigurationMasks::GC_EN); + // Reset the original configuration with the new offset value + applyChannelConfig(channel, + config.channelsConfig[static_cast<int>(channel)]); } bool ADS131M04::selfTest() { bool success = true; - // Reset PGA, offsets and gains and connect the positive test signal + // Reset configuration and connect the positive test signal + Config::ChannelConfig selfTestConfig{ + .enabled = true, + .pga = PGA::PGA_1, + .offset = 0, + .gain = 1.0, + }; for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelPGAImpl(static_cast<Channel>(i), PGA::PGA_1); - setChannelOffsetImpl(static_cast<Channel>(i), 0); - setChannelGainCalibrationImpl(static_cast<Channel>(i), 1.0); + applyChannelConfig(static_cast<Channel>(i), selfTestConfig); setChannelInput(static_cast<Channel>(i), Input::POSITIVE_DC_TEST); } + setOversamplingRatio(OversamplingRatio::OSR_16256); + disableGlobalChopMode(); // Take some samples int32_t averageValues[CHANNELS_NUM] = {0}; @@ -249,7 +213,8 @@ bool ADS131M04::selfTest() averageValues[i] /= realSampleCount; // Convert the value to Volts - float volts = averageValues[i] * getLSBSizeFromGain(PGA::PGA_1); + float volts = + averageValues[i] * getLSBSizeFromGain(selfTestConfig.pga); // Check if the value is in the acceptable range if (volts < V_REF * TEST_SIGNAL_FACTOR - TEST_SIGNAL_SLACK) @@ -311,7 +276,8 @@ bool ADS131M04::selfTest() averageValues[i] /= realSampleCount; // Convert the value to Volts - float volts = averageValues[i] * getLSBSizeFromGain(PGA::PGA_1); + float volts = + averageValues[i] * getLSBSizeFromGain(selfTestConfig.pga); // Check if the value is in the acceptable range if (volts > -V_REF * TEST_SIGNAL_FACTOR + TEST_SIGNAL_SLACK) @@ -326,15 +292,15 @@ bool ADS131M04::selfTest() } } - // Reset channels previous configuration + // Reset channels input to default for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelPGAImpl(static_cast<Channel>(i), channelsPGAGain[i]); - setChannelOffsetImpl(static_cast<Channel>(i), channelsOffset[i]); - setChannelGainCalibrationImpl(static_cast<Channel>(i), channelsGain[i]); setChannelInput(static_cast<Channel>(i), Input::DEFAULT); } + // Reset to previous configuration + applyConfig(config); + // We fail even if one channel didn't pass the test return success; } @@ -355,26 +321,42 @@ ADS131M04Data ADS131M04::sampleImpl() for (int i = 0; i < CHANNELS_NUM; i++) { adcData.voltage[i] = - rawValues[i] * getLSBSizeFromGain(channelsPGAGain[i]); + rawValues[i] * getLSBSizeFromGain(config.channelsConfig[i].pga); } return adcData; } -void ADS131M04::setChannelInput(Channel channel, Input input) +void ADS131M04::applyChannelConfig(Channel channel, + Config::ChannelConfig config) { - Register reg = getChannelConfigRegister(channel); - changeRegister(reg, static_cast<uint16_t>(input), RegChannelMasks::CFG_MUX); + if (config.enabled) + { + setChannelPGA(channel, config.pga); + setChannelOffset(channel, config.offset); + setChannelGain(channel, config.gain); + enableChannel(channel); + } + else + { + disableChannel(channel); + } } -void ADS131M04::setChannelPGAImpl(Channel channel, PGA gain) +void ADS131M04::setOversamplingRatio(OversamplingRatio ratio) +{ + changeRegister(Register::REG_CLOCK, static_cast<uint16_t>(ratio), + RegClockMasks::OSR); +} + +void ADS131M04::setChannelPGA(Channel channel, PGA gain) { int shift = static_cast<int>(channel) * 4; changeRegister(Register::REG_GAIN, static_cast<uint16_t>(gain) << shift, RegGainMasks::PGA_GAIN_0 << shift); } -void ADS131M04::setChannelOffsetImpl(Channel channel, uint32_t offset) +void ADS131M04::setChannelOffset(Channel channel, uint32_t offset) { // The offset is a 24 bit value. Its two most significant bytes are stored // in the MSB register, and the least significant in the LSB register, like @@ -392,7 +374,7 @@ void ADS131M04::setChannelOffsetImpl(Channel channel, uint32_t offset) writeRegister(getChannelOffsetRegisterLSB(channel), offset << 8); } -void ADS131M04::setChannelGainCalibrationImpl(Channel channel, double gain) +void ADS131M04::setChannelGain(Channel channel, double gain) { // If the user passes a value outside the range [0, 2] we cap it. if (gain < 0) @@ -404,7 +386,7 @@ void ADS131M04::setChannelGainCalibrationImpl(Channel channel, double gain) gain = 2; } - // The ADS131M08 corrects for gain errors by multiplying the ADC conversion + // The ADS131M04 corrects for gain errors by multiplying the ADC conversion // result using the gain calibration registers. // The contents of the gain calibration registers are interpreted by the // dives as 24-bit unsigned values corresponding to linear steps from 0 to @@ -430,6 +412,35 @@ void ADS131M04::setChannelGainCalibrationImpl(Channel channel, double gain) writeRegister(getChannelGainRegisterLSB(channel), rawGain << 8); } +void ADS131M04::enableChannel(Channel channel) +{ + changeRegister(Register::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), + 1 << (static_cast<int>(channel) + 8)); +} + +void ADS131M04::disableChannel(Channel channel) +{ + changeRegister(Register::REG_CLOCK, 0, + 1 << (static_cast<int>(channel) + 8)); +} + +void ADS131M04::enableGlobalChopMode() +{ + changeRegister(Register::REG_CFG, RegConfigurationMasks::GC_EN, + RegConfigurationMasks::GC_EN); +} + +void ADS131M04::disableGlobalChopMode() +{ + changeRegister(Register::REG_CFG, 0, RegConfigurationMasks::GC_EN); +} + +void ADS131M04::setChannelInput(Channel channel, Input input) +{ + Register reg = getChannelConfigRegister(channel); + changeRegister(reg, static_cast<uint16_t>(input), RegChannelMasks::CFG_MUX); +} + Register ADS131M04::getChannelConfigRegister(Channel channel) { switch (static_cast<int>(channel)) diff --git a/src/shared/sensors/ADS131M04/ADS131M04.h b/src/shared/sensors/ADS131M04/ADS131M04.h index c5ac7068f0699efc9bde3edcd39ff392bad77699..d8142f18c33e9e28e3321f82f4158fcf02985bc4 100644 --- a/src/shared/sensors/ADS131M04/ADS131M04.h +++ b/src/shared/sensors/ADS131M04/ADS131M04.h @@ -75,27 +75,69 @@ namespace Boardcore class ADS131M04 : public Sensor<ADS131M04Data> { public: - ADS131M04(SPIBusInterface& bus, miosix::GpioPin cs, - SPIBusConfig config = getDefaultSPIConfig()); + struct Config + { + struct ChannelConfig + { + bool enabled = true; + ADS131M04Defs::PGA pga = ADS131M04Defs::PGA::PGA_1; + int32_t offset = 0; + double gain = 1.0; + }; + + ChannelConfig channelsConfig[ADS131M04Defs::CHANNELS_NUM]; + + ADS131M04Defs::OversamplingRatio oversamplingRatio = + ADS131M04Defs::OversamplingRatio::OSR_16256; + bool globalChopModeEnabled = false; + }; + + ADS131M04(SPIBusInterface& bus, miosix::GpioPin cs, SPIBusConfig spiConfig, + const Config& config); - explicit ADS131M04(SPISlave spiSlave); + bool init() override; + + bool reset(); /** - * Constructs the default config for SPI Bus. + * @brief Overwrites the sensor settings. * - * @returns The default SPIBusConfig. + * Writes a certain config to the sensor registers. This method is + * automatically called in ADS131M04::init() using as parameter the + * configuration given in the constructor. + * + * @param config The configuration to be applied. */ - static SPIBusConfig getDefaultSPIConfig(); - - bool init() override; - - bool reset(); + void applyConfig(Config config); /** * @brief Samples each channel, averages the samples and applies offset * compensation in the device. */ - void calibrateOffset(); + void calibrateOffset(ADS131M04Defs::Channel channel); + + /** + * @brief The self test samples internally connects each channel to known + * test signals and verifies if the sampled values are in an expected range. + * + * @returns True if the self test is successful, false otherwise. + */ + bool selfTest() override; + +private: + ADS131M04Data sampleImpl() override; + + /** + * @brief Overwrites the channel settings. + * + * Writes a certain configuration to the sensor registers. This method is + * automatically called in ADS131M04::applyConfig and in other routines. + * + * @param channel Specific channel where the configuration will be applied. + * @param config The configuration to be applied. + */ + void applyChannelConfig(ADS131M04Defs::Channel channel, + Config::ChannelConfig config); /** * @brief changes the oversampling ratio. @@ -130,7 +172,7 @@ public: * @param gain Gain value between 0 and 2. Values outside this range will be * capped. */ - void setChannelGainCalibration(ADS131M04Defs::Channel channel, double gain); + void setChannelGain(ADS131M04Defs::Channel channel, double gain); void enableChannel(ADS131M04Defs::Channel channel); @@ -159,40 +201,9 @@ public: */ void disableGlobalChopMode(); - /** - * @brief The self test samples internally connects each channel to known - * test signals and verifies if the sampled values are in an expected range. - * - * @returns True if the self test is successful, false otherwise. - */ - bool selfTest() override; - -private: - ADS131M04Data sampleImpl() override; - void setChannelInput(ADS131M04Defs::Channel channel, ADS131M04Defs::Input input); - /** - * setChannelPGS() implementation without saving the gain value in - * the local variable. - */ - void setChannelPGAImpl(ADS131M04Defs::Channel channel, - ADS131M04Defs::PGA gain); - - /** - * setChannelOffset() implementation without saving the offset value in - * the local variable. - */ - void setChannelOffsetImpl(ADS131M04Defs::Channel channel, uint32_t offset); - - /** - * setChannelGainCalibration() implementation without saving the gain value - * in the local variable. - */ - void setChannelGainCalibrationImpl(ADS131M04Defs::Channel channel, - double gain); - ADS131M04Defs::Register getChannelConfigRegister( ADS131M04Defs::Channel channel); @@ -234,12 +245,8 @@ private: SPISlave spiSlave; - // Saving the current configuration of the device - // This is necessary because the selfTest and calibrateOffset functions - // temporarily resets the channels configuration - ADS131M04Defs::PGA channelsPGAGain[ADS131M04Defs::CHANNELS_NUM]; - uint32_t channelsOffset[ADS131M04Defs::CHANNELS_NUM]; - double channelsGain[ADS131M04Defs::CHANNELS_NUM]; + // Current device configuration + Config config; PrintLogger logger = Logging::getLogger("ads131m04"); }; diff --git a/src/shared/sensors/ADS131M04/ADS131M04Data.h b/src/shared/sensors/ADS131M04/ADS131M04Data.h index d04b55a3d560f4c26b307e42af91525ef40cab5d..57057fde47c8402c5c2b2c1a99ba74323730149f 100644 --- a/src/shared/sensors/ADS131M04/ADS131M04Data.h +++ b/src/shared/sensors/ADS131M04/ADS131M04Data.h @@ -22,10 +22,13 @@ #pragma once +#include <sensors/SensorData.h> #include <stdint.h> #include <ostream> +#include "ADS131M04Defs.h" + namespace Boardcore { @@ -57,6 +60,12 @@ struct ADS131M04Data os << timestamp << "," << voltage[0] << "," << voltage[1] << "," << voltage[2] << "," << voltage[3] << "\n"; } + + const ADCData getVoltage(ADS131M04Defs::Channel channel) + { + return {timestamp, static_cast<uint8_t>(channel), + voltage[static_cast<uint8_t>(channel)]}; + } }; } // namespace Boardcore diff --git a/src/shared/sensors/ADS131M08/ADS131M08.cpp b/src/shared/sensors/ADS131M08/ADS131M08.cpp index 4dbff38b1a83d647e844b082c98cbf80630b719b..a1e10248313ac0d7b2c309b175a870a550231b93 100644 --- a/src/shared/sensors/ADS131M08/ADS131M08.cpp +++ b/src/shared/sensors/ADS131M08/ADS131M08.cpp @@ -33,37 +33,26 @@ namespace Boardcore { ADS131M08::ADS131M08(SPIBusInterface &bus, miosix::GpioPin cs, - SPIBusConfig config) - : ADS131M08(SPISlave(bus, cs, config)) + SPIBusConfig spiConfig, const Config &config) + : spiSlave(bus, cs, spiConfig), config(config) { + // Impose the correct spi mode + spiSlave.config.mode = SPI::Mode::MODE_1; } -ADS131M08::ADS131M08(SPISlave spiSlave) : spiSlave(spiSlave) +bool ADS131M08::init() { - // Initialize the channel configurations to the default values - for (int i = 0; i < CHANNELS_NUM; i++) - { - channelsPGAGain[i] = PGA::PGA_1; - channelsOffset[i] = 0; - channelsGain[i] = 1.0; - } -} + reset(); + applyConfig(config); -SPIBusConfig ADS131M08::getDefaultSPIConfig() -{ - SPIBusConfig spiConfig{}; - spiConfig.clockDivider = SPI::ClockDivider::DIV_64; - spiConfig.mode = SPI::Mode::MODE_1; - return spiConfig; + return true; } -bool ADS131M08::init() { return true; } - bool ADS131M08::reset() { SPITransaction transaction(spiSlave); - uint8_t data[ADS131M08Defs::FULL_FRAME_SIZE] = {0}; + uint8_t data[FULL_FRAME_SIZE] = {0}; sendCommand(transaction, Command::RESET, data); // The reset command takes typically 5us to reload the register contents. @@ -85,21 +74,44 @@ bool ADS131M08::reset() return true; } -void ADS131M08::calibrateOffset() +void ADS131M08::applyConfig(Config config) { - // The device internal data chain firsts subtracts the offset and then - // multiplies for the gain. To calibrate the offset we first reset it, then - // take some samples and apply the average as the new offset. - // So we need to reset the offset and gain for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelOffsetImpl(static_cast<Channel>(i), 0); - setChannelGainCalibrationImpl(static_cast<Channel>(i), 1.0); + applyChannelConfig(static_cast<Channel>(i), config.channelsConfig[i]); } - // Sample the channels and average the samples - int32_t averageValues[CHANNELS_NUM] = {0}; - int realSampleCount = 0; + setOversamplingRatio(config.oversamplingRatio); + if (config.globalChopModeEnabled) + { + enableGlobalChopMode(); + } + else + { + disableGlobalChopMode(); + } + + // Save the newly applied configuration + this->config = config; +} + +void ADS131M08::calibrateOffset(Channel channel) +{ + // The device internal data chain firsts subtracts the offset and then + // multiplies for the gain. To calibrate the offset we first reset it, then + // take some samples and apply the average as the new offset. + // So we need to reset the offset and gain + Config::ChannelConfig calibrationConfig{ + .enabled = true, + .pga = PGA::PGA_1, + .offset = 0, + .gain = 1.0, + }; + applyChannelConfig(channel, calibrationConfig); + + // Sample the channel and average the samples + int32_t averageValue = 0; + int realSampleCount = 0; for (int i = 0; i < CALIBRATION_SAMPLES; i++) { // Wait for a sample to be ready @@ -113,10 +125,7 @@ void ADS131M08::calibrateOffset() continue; } - for (int j = 0; j < CHANNELS_NUM; j++) - { - averageValues[j] += rawValues[j]; - } + averageValue += rawValues[static_cast<int>(channel)]; realSampleCount++; } @@ -127,88 +136,43 @@ void ADS131M08::calibrateOffset() } else { - for (int i = 0; i < CHANNELS_NUM; i++) + // Compute the average + averageValue /= realSampleCount; + LOG_INFO(logger, "Channel {} average offset: {}", + static_cast<int>(channel), + averageValue * getLSBSizeFromGain(calibrationConfig.pga)); + + // Set the new offset only if valid, otherwise keep the old one + if (averageValue != 0) { - // Compute the average - averageValues[i] /= realSampleCount; - LOG_INFO(logger, "Channel {} average offset: {}", i, - averageValues[i] * getLSBSizeFromGain(channelsPGAGain[i])); - - // Set the new offset only if valid, otherwise keep the old one - if (averageValues[i] != 0) - { - channelsOffset[i] = averageValues[i]; - } + config.channelsConfig[static_cast<int>(channel)].offset = + averageValue; } } - // Update the offset values and reset the gain as it was before - for (int i = 0; i < CHANNELS_NUM; i++) - { - setChannelOffset(static_cast<Channel>(i), channelsOffset[i]); - setChannelGainCalibrationImpl(static_cast<Channel>(i), channelsGain[i]); - } -} - -void ADS131M08::setOversamplingRatio(OversamplingRatio ratio) -{ - changeRegister(Register::REG_CLOCK, static_cast<uint16_t>(ratio), - RegClockMasks::OSR); -} - -void ADS131M08::setChannelPGA(Channel channel, PGA gain) -{ - setChannelPGAImpl(channel, gain); - channelsPGAGain[static_cast<int>(channel)] = gain; -} - -void ADS131M08::setChannelOffset(Channel channel, uint32_t offset) -{ - setChannelOffsetImpl(channel, offset); - channelsOffset[static_cast<int>(channel)] = offset; -} - -void ADS131M08::setChannelGainCalibration(Channel channel, double gain) -{ - setChannelGainCalibrationImpl(channel, gain); - channelsGain[static_cast<int>(channel)] = gain; -} - -void ADS131M08::enableChannel(Channel channel) -{ - changeRegister(Register::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), - 1 << (static_cast<int>(channel) + 8)); -} - -void ADS131M08::disableChannel(Channel channel) -{ - changeRegister(Register::REG_CLOCK, 0, - 1 << (static_cast<int>(channel) + 8)); -} - -void ADS131M08::enableGlobalChopMode() -{ - changeRegister(Register::REG_CFG, RegConfigurationMasks::GC_EN, - RegConfigurationMasks::GC_EN); -} - -void ADS131M08::disableGlobalChopMode() -{ - changeRegister(Register::REG_CFG, 0, RegConfigurationMasks::GC_EN); + // Reset the original configuration with the new offset value + applyChannelConfig(channel, + config.channelsConfig[static_cast<int>(channel)]); } bool ADS131M08::selfTest() { bool success = true; - // Reset PGA, offsets and gains and connect the positive test signal + // Reset configuration and connect the positive test signal + Config::ChannelConfig selfTestConfig{ + .enabled = true, + .pga = PGA::PGA_1, + .offset = 0, + .gain = 1.0, + }; for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelPGAImpl(static_cast<Channel>(i), PGA::PGA_1); - setChannelOffsetImpl(static_cast<Channel>(i), 0); - setChannelGainCalibrationImpl(static_cast<Channel>(i), 1.0); + applyChannelConfig(static_cast<Channel>(i), selfTestConfig); setChannelInput(static_cast<Channel>(i), Input::POSITIVE_DC_TEST); } + setOversamplingRatio(OversamplingRatio::OSR_16256); + disableGlobalChopMode(); // Take some samples int32_t averageValues[CHANNELS_NUM] = {0}; @@ -249,7 +213,8 @@ bool ADS131M08::selfTest() averageValues[i] /= realSampleCount; // Convert the value to Volts - float volts = averageValues[i] * getLSBSizeFromGain(PGA::PGA_1); + float volts = + averageValues[i] * getLSBSizeFromGain(selfTestConfig.pga); // Check if the value is in the acceptable range if (volts < V_REF * TEST_SIGNAL_FACTOR - TEST_SIGNAL_SLACK) @@ -311,7 +276,8 @@ bool ADS131M08::selfTest() averageValues[i] /= realSampleCount; // Convert the value to Volts - float volts = averageValues[i] * getLSBSizeFromGain(PGA::PGA_1); + float volts = + averageValues[i] * getLSBSizeFromGain(selfTestConfig.pga); // Check if the value is in the acceptable range if (volts > -V_REF * TEST_SIGNAL_FACTOR + TEST_SIGNAL_SLACK) @@ -326,15 +292,15 @@ bool ADS131M08::selfTest() } } - // Reset channels previous configuration + // Reset channels input to default for (int i = 0; i < CHANNELS_NUM; i++) { - setChannelPGAImpl(static_cast<Channel>(i), channelsPGAGain[i]); - setChannelOffsetImpl(static_cast<Channel>(i), channelsOffset[i]); - setChannelGainCalibrationImpl(static_cast<Channel>(i), channelsGain[i]); setChannelInput(static_cast<Channel>(i), Input::DEFAULT); } + // Reset to previous configuration + applyConfig(config); + // We fail even if one channel didn't pass the test return success; } @@ -355,19 +321,35 @@ ADS131M08Data ADS131M08::sampleImpl() for (int i = 0; i < CHANNELS_NUM; i++) { adcData.voltage[i] = - rawValues[i] * getLSBSizeFromGain(channelsPGAGain[i]); + rawValues[i] * getLSBSizeFromGain(config.channelsConfig[i].pga); } return adcData; } -void ADS131M08::setChannelInput(Channel channel, Input input) +void ADS131M08::applyChannelConfig(Channel channel, + Config::ChannelConfig config) { - Register reg = getChannelConfigRegister(channel); - changeRegister(reg, static_cast<uint16_t>(input), RegChannelMasks::CFG_MUX); + if (config.enabled) + { + setChannelPGA(channel, config.pga); + setChannelOffset(channel, config.offset); + setChannelGain(channel, config.gain); + enableChannel(channel); + } + else + { + disableChannel(channel); + } +} + +void ADS131M08::setOversamplingRatio(OversamplingRatio ratio) +{ + changeRegister(Register::REG_CLOCK, static_cast<uint16_t>(ratio), + RegClockMasks::OSR); } -void ADS131M08::setChannelPGAImpl(Channel channel, PGA gain) +void ADS131M08::setChannelPGA(Channel channel, PGA gain) { if (channel <= Channel::CHANNEL_3) { @@ -385,7 +367,7 @@ void ADS131M08::setChannelPGAImpl(Channel channel, PGA gain) } } -void ADS131M08::setChannelOffsetImpl(Channel channel, uint32_t offset) +void ADS131M08::setChannelOffset(Channel channel, int32_t offset) { // The offset is a 24 bit value. Its two most significant bytes are stored // in the MSB register, and the least significant in the LSB register, like @@ -403,7 +385,7 @@ void ADS131M08::setChannelOffsetImpl(Channel channel, uint32_t offset) writeRegister(getChannelOffsetRegisterLSB(channel), offset << 8); } -void ADS131M08::setChannelGainCalibrationImpl(Channel channel, double gain) +void ADS131M08::setChannelGain(Channel channel, double gain) { // If the user passes a value outside the range [0, 2] we cap it. if (gain < 0) @@ -441,6 +423,35 @@ void ADS131M08::setChannelGainCalibrationImpl(Channel channel, double gain) writeRegister(getChannelGainRegisterLSB(channel), rawGain << 8); } +void ADS131M08::enableChannel(Channel channel) +{ + changeRegister(Register::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), + 1 << (static_cast<int>(channel) + 8)); +} + +void ADS131M08::disableChannel(Channel channel) +{ + changeRegister(Register::REG_CLOCK, 0, + 1 << (static_cast<int>(channel) + 8)); +} + +void ADS131M08::enableGlobalChopMode() +{ + changeRegister(Register::REG_CFG, RegConfigurationMasks::GC_EN, + RegConfigurationMasks::GC_EN); +} + +void ADS131M08::disableGlobalChopMode() +{ + changeRegister(Register::REG_CFG, 0, RegConfigurationMasks::GC_EN); +} + +void ADS131M08::setChannelInput(Channel channel, Input input) +{ + Register reg = getChannelConfigRegister(channel); + changeRegister(reg, static_cast<uint16_t>(input), RegChannelMasks::CFG_MUX); +} + Register ADS131M08::getChannelConfigRegister(Channel channel) { switch (static_cast<int>(channel)) diff --git a/src/shared/sensors/ADS131M08/ADS131M08.h b/src/shared/sensors/ADS131M08/ADS131M08.h index 01ad2c733f0883054976fa1e03209ce33415ef7a..a83fdaf0978013227e8990c83a7540ce7268cf9d 100644 --- a/src/shared/sensors/ADS131M08/ADS131M08.h +++ b/src/shared/sensors/ADS131M08/ADS131M08.h @@ -75,27 +75,69 @@ namespace Boardcore class ADS131M08 : public Sensor<ADS131M08Data> { public: - ADS131M08(SPIBusInterface& bus, miosix::GpioPin cs, - SPIBusConfig config = getDefaultSPIConfig()); + struct Config + { + struct ChannelConfig + { + bool enabled = true; + ADS131M08Defs::PGA pga = ADS131M08Defs::PGA::PGA_1; + int32_t offset = 0; + double gain = 1.0; + }; + + ChannelConfig channelsConfig[ADS131M08Defs::CHANNELS_NUM]; + + ADS131M08Defs::OversamplingRatio oversamplingRatio = + ADS131M08Defs::OversamplingRatio::OSR_16256; + bool globalChopModeEnabled = false; + }; + + ADS131M08(SPIBusInterface& bus, miosix::GpioPin cs, SPIBusConfig spiConfig, + const Config& config); - explicit ADS131M08(SPISlave spiSlave); + bool init() override; + + bool reset(); /** - * Constructs the default config for SPI Bus. + * @brief Overwrites the sensor settings. * - * @returns The default SPIBusConfig. + * Writes a certain config to the sensor registers. This method is + * automatically called in ADS131M08::init() using as parameter the + * configuration given in the constructor. + * + * @param config The configuration to be applied. */ - static SPIBusConfig getDefaultSPIConfig(); - - bool init() override; - - bool reset(); + void applyConfig(Config config); /** * @brief Samples each channel, averages the samples and applies offset * compensation in the device. */ - void calibrateOffset(); + void calibrateOffset(ADS131M08Defs::Channel channel); + + /** + * @brief The self test samples internally connects each channel to known + * test signals and verifies if the sampled values are in an expected range. + * + * @returns True if the self test is successful, false otherwise. + */ + bool selfTest() override; + +private: + ADS131M08Data sampleImpl() override; + + /** + * @brief Overwrites the channel settings. + * + * Writes a certain configuration to the sensor registers. This method is + * automatically called in ADS131M08::applyConfig and in other routines. + * + * @param channel Specific channel where the configuration will be applied. + * @param config The configuration to be applied. + */ + void applyChannelConfig(ADS131M08Defs::Channel channel, + Config::ChannelConfig config); /** * @brief changes the oversampling ratio. @@ -122,7 +164,7 @@ public: * * Note that the device offset is a 24bit two complement. */ - void setChannelOffset(ADS131M08Defs::Channel channel, uint32_t offset); + void setChannelOffset(ADS131M08Defs::Channel channel, int32_t offset); /** * @brief Sets the channel gain calibration. @@ -130,7 +172,7 @@ public: * @param gain Gain value between 0 and 2. Values outside this range will be * capped. */ - void setChannelGainCalibration(ADS131M08Defs::Channel channel, double gain); + void setChannelGain(ADS131M08Defs::Channel channel, double gain); void enableChannel(ADS131M08Defs::Channel channel); @@ -159,40 +201,9 @@ public: */ void disableGlobalChopMode(); - /** - * @brief The self test samples internally connects each channel to known - * test signals and verifies if the sampled values are in an expected range. - * - * @returns True if the self test is successful, false otherwise. - */ - bool selfTest() override; - -private: - ADS131M08Data sampleImpl() override; - void setChannelInput(ADS131M08Defs::Channel channel, ADS131M08Defs::Input input); - /** - * setChannelPGS() implementation without saving the gain value in - * the local variable. - */ - void setChannelPGAImpl(ADS131M08Defs::Channel channel, - ADS131M08Defs::PGA gain); - - /** - * setChannelOffset() implementation without saving the offset value in - * the local variable. - */ - void setChannelOffsetImpl(ADS131M08Defs::Channel channel, uint32_t offset); - - /** - * setChannelGainCalibration() implementation without saving the gain value - * in the local variable. - */ - void setChannelGainCalibrationImpl(ADS131M08Defs::Channel channel, - double gain); - ADS131M08Defs::Register getChannelConfigRegister( ADS131M08Defs::Channel channel); @@ -234,12 +245,8 @@ private: SPISlave spiSlave; - // Saving the current configuration of the device - // This is necessary because the selfTest and calibrateOffset functions - // temporarily resets the channels configuration - ADS131M08Defs::PGA channelsPGAGain[ADS131M08Defs::CHANNELS_NUM]; - uint32_t channelsOffset[ADS131M08Defs::CHANNELS_NUM]; - double channelsGain[ADS131M08Defs::CHANNELS_NUM]; + // Current device configuration + Config config; PrintLogger logger = Logging::getLogger("ads131m08"); }; diff --git a/src/shared/sensors/ADS131M08/ADS131M08Data.h b/src/shared/sensors/ADS131M08/ADS131M08Data.h index ac28f168b6dc248e23f5e5ebfa566ced2353c17a..35ab9fe02e543594c2ecaca4ae384a7a85dc78ec 100644 --- a/src/shared/sensors/ADS131M08/ADS131M08Data.h +++ b/src/shared/sensors/ADS131M08/ADS131M08Data.h @@ -22,6 +22,7 @@ #pragma once +#include <sensors/SensorData.h> #include <stdint.h> #include <ostream> @@ -67,7 +68,7 @@ struct ADS131M08Data << voltage[5] << "," << voltage[6] << "," << voltage[7] << "\n"; } - ADCData getVoltage(ADS131M08Defs::Channel channel) + const ADCData getVoltage(ADS131M08Defs::Channel channel) { return {timestamp, static_cast<uint8_t>(channel), voltage[static_cast<uint8_t>(channel)]}; diff --git a/src/tests/sensors/test-ads131m04.cpp b/src/tests/sensors/test-ads131m04.cpp index cda44e9bc792c530de52472beecf5f095163a90b..1e073ee6ecd1ade54b7697fb307433c22a9d9519 100644 --- a/src/tests/sensors/test-ads131m04.cpp +++ b/src/tests/sensors/test-ads131m04.cpp @@ -28,10 +28,10 @@ using namespace miosix; using namespace Boardcore; -GpioPin sckPin = GpioPin(GPIOE_BASE, 2); -GpioPin misoPin = GpioPin(GPIOE_BASE, 5); -GpioPin mosiPin = GpioPin(GPIOE_BASE, 6); -GpioPin csPin = GpioPin(GPIOE_BASE, 4); +GpioPin sckPin = GpioPin(GPIOA_BASE, 5); +GpioPin misoPin = GpioPin(GPIOA_BASE, 6); +GpioPin mosiPin = GpioPin(GPIOA_BASE, 7); +GpioPin csPin = GpioPin(GPIOA_BASE, 4); void initBoard() { @@ -51,21 +51,17 @@ int main() // Enable SPI clock and set gpios initBoard(); - // SPI configuration setup - SPIBus spiBus(SPI4); - SPISlave spiSlave(spiBus, csPin, ADS131M04::getDefaultSPIConfig()); + // ADC configuration + ADS131M04::Config config{ + .oversamplingRatio = ADS131M04Defs::OversamplingRatio::OSR_8192, + .globalChopModeEnabled = true, + }; // Device initialization - ADS131M04 ads131(spiSlave); + SPIBus spiBus(SPI1); + ADS131M04 ads131(spiBus, csPin, {}, config); - ads131.reset(); - - ads131.enableGlobalChopMode(); - ads131.setOversamplingRatio(ADS131M04Defs::OversamplingRatio::OSR_16256); - - // WARNING: After changing the OSR the device needs some time to settle - delayMs(20); - ads131.calibrateOffset(); + ads131.init(); printf("Now performing self test...\n"); if (ads131.selfTest()) @@ -77,13 +73,18 @@ int main() printf("Self test failed!\n"); } + // ads131.calibrateOffset(ADS131M04Defs::Channel::CHANNEL_0); + // ads131.calibrateOffset(ADS131M04Defs::Channel::CHANNEL_1); + // ads131.calibrateOffset(ADS131M04Defs::Channel::CHANNEL_2); + // ads131.calibrateOffset(ADS131M04Defs::Channel::CHANNEL_3); + while (true) { ads131.sample(); ADS131M04Data data = ads131.getLastSample(); - printf("% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\n", data.voltage[0], + printf("% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\n", data.voltage[0], data.voltage[1], data.voltage[2], data.voltage[3]); delayMs(50); diff --git a/src/tests/sensors/test-ads131m08.cpp b/src/tests/sensors/test-ads131m08.cpp index ee199d39c61f76a303429d0b08f83c93ae261c70..ea36065dc7d26525788b7ad0fddfda30f779a43f 100644 --- a/src/tests/sensors/test-ads131m08.cpp +++ b/src/tests/sensors/test-ads131m08.cpp @@ -51,21 +51,17 @@ int main() // Enable SPI clock and set gpios initBoard(); - // SPI configuration setup - SPIBus spiBus(SPI4); - SPISlave spiSlave(spiBus, csPin, ADS131M08::getDefaultSPIConfig()); + // ADC configuration + ADS131M08::Config config{ + .oversamplingRatio = ADS131M08Defs::OversamplingRatio::OSR_8192, + .globalChopModeEnabled = true, + }; // Device initialization - ADS131M08 ads131(spiSlave); - - ads131.reset(); - - ads131.enableGlobalChopMode(); - ads131.setOversamplingRatio(ADS131M08Defs::OversamplingRatio::OSR_16256); + SPIBus spiBus(SPI4); + ADS131M08 ads131(spiBus, csPin, {}, config); - // WARNING: After changing the OSR the device needs some time to settle - delayMs(20); - ads131.calibrateOffset(); + ads131.init(); printf("Now performing self test...\n"); if (ads131.selfTest()) @@ -77,6 +73,15 @@ int main() printf("Self test failed!\n"); } + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_0); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_1); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_2); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_3); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_4); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_5); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_6); + ads131.calibrateOffset(ADS131M08Defs::Channel::CHANNEL_7); + while (true) { ads131.sample(); @@ -84,10 +89,10 @@ int main() ADS131M08Data data = ads131.getLastSample(); printf( - "% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\t% 2.5f\n", + "% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\t% 2.8f\n", data.voltage[0], data.voltage[1], data.voltage[2], data.voltage[3], data.voltage[4], data.voltage[5], data.voltage[6], data.voltage[7]); - delayMs(50); + delayMs(100); } }