diff --git a/src/shared/sensors/ADS131M04/ADS131M04.cpp b/src/shared/sensors/ADS131M04/ADS131M04.cpp index 3b7387c4161e1a9e6c89add58510bb1137412a58..797d9ba46d3e0e720fc6cedac287c5855ec9ea41 100644 --- a/src/shared/sensors/ADS131M04/ADS131M04.cpp +++ b/src/shared/sensors/ADS131M04/ADS131M04.cpp @@ -26,6 +26,7 @@ #include <util/crc16.h> #include <utils/CRC.h> +using namespace miosix; using namespace Boardcore::ADS131M04RegisterBitMasks; namespace Boardcore @@ -100,32 +101,47 @@ bool ADS131M04::reset() void ADS131M04::calibrateOffset() { - int32_t averageValues[4] = {0}; + // Reset all offsets and gains + for (int i = 0; i < 8; i++) + { + setChannelOffset(static_cast<Channel>(i), 0); + } // Sample the channels and average the samples - for (int i = 0; i < 1000; i++) + int32_t averageValues[4] = {0}; + for (int i = 0; i < 250; i++) { - sample(); - miosix::delayUs(1); + Thread::sleep(4); - for (int ii = 0; ii < 4; ii++) - averageValues[ii] += - lastSample.voltage[ii] / - PGA_LSB_SIZE[static_cast<uint16_t>(channelsPGAGain[ii])]; - } + uint8_t data[18] = {0}; + + data[0] = static_cast<uint16_t>(Commands::NULL_CMD) >> 8; + data[1] = static_cast<uint16_t>(Commands::NULL_CMD); + + SPITransaction transaction(spiSlave); + transaction.transfer(data, sizeof(data)); + + for (int j = 0; j < 4; j++) + { + int32_t tmp = static_cast<uint32_t>(data[j * 3 + 3]) << 16 | + static_cast<uint32_t>(data[j * 3 + 4]) << 8 | + static_cast<uint32_t>(data[j * 3 + 5]); + // Check for the sign bit + if (tmp & 0x00800000) + tmp |= 0xFF000000; // Extend the sign bit + + averageValues[j] += tmp; + } + } for (int i = 0; i < 4; i++) - averageValues[i] /= 1000; + averageValues[i] /= 250; // Configure the offset registers - writeRegister(Registers::REG_CH0_OCAL_MSB, averageValues[0] >> 8); - writeRegister(Registers::REG_CH0_OCAL_LSB, averageValues[0] << 16); - writeRegister(Registers::REG_CH1_OCAL_MSB, averageValues[1] >> 8); - writeRegister(Registers::REG_CH1_OCAL_LSB, averageValues[1] << 16); - writeRegister(Registers::REG_CH2_OCAL_MSB, averageValues[2] >> 8); - writeRegister(Registers::REG_CH2_OCAL_LSB, averageValues[2] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[3] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[3] << 16); + for (int i = 0; i < 4; i++) + { + setChannelOffset(static_cast<Channel>(i), averageValues[i]); + } } void ADS131M04::setChannelPGA(Channel channel, PGA gain) @@ -162,8 +178,8 @@ void ADS131M04::setChannelOffset(Channel channel, uint32_t offset) break; } - writeRegister(regMSB, static_cast<uint16_t>(offset) >> 16); - writeRegister(regLSB, static_cast<uint16_t>(offset) << 8); + writeRegister(regMSB, offset >> 8); + writeRegister(regLSB, offset << 16); } void ADS131M04::setChannelGainCalibration(Channel channel, double gain) @@ -201,6 +217,32 @@ void ADS131M04::setChannelGainCalibration(Channel channel, double gain) writeRegister(regLSB, rawGain << 8); } +void ADS131M04::setChannelInput(Channel channel, Input input) +{ + // Set the correct register based on the selected channel + Registers reg; + switch (static_cast<int>(channel)) + { + case 0: + reg = Registers::REG_CH0_CFG; + break; + case 1: + reg = Registers::REG_CH1_CFG; + break; + case 2: + reg = Registers::REG_CH2_CFG; + break; + default: + reg = Registers::REG_CH3_CFG; + break; + } + + uint16_t value = readRegister(reg); + value &= REG_CHx_CFG_MUX; + value |= static_cast<uint16_t>(input); + writeRegister(reg, value); +} + void ADS131M04::enableChannel(Channel channel) { changeRegister(Registers::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), @@ -233,7 +275,65 @@ ADCData ADS131M04::getVoltage(Channel channel) bool ADS131M04::selfTest() { - // TODO + static constexpr float V_REF = 1.2; + static constexpr float TEST_SIGNAL_FACTOR = 2 / 15; + static constexpr float TEST_SIGNAL_SLACK = 0.1; // Not defined in DS + + float voltage[4] = {0}; + + // Connect all channels to the positive DC test signal + for (int i = 0; i < 4; i++) + { + setChannelInput(static_cast<Channel>(i), Input::POSITIVE_DC_TEST); + setChannelPGA(static_cast<Channel>(i), PGA::PGA_1); + } + + // Take some samples + for (int i = 0; i < 100; i++) + { + Thread::sleep(4); + auto newSample = sampleImpl(); + + for (int j = 0; j < 4; j++) + { + voltage[j] += newSample.voltage[j]; + } + } + + // Check values + for (int i = 0; i < 4; i++) + { + voltage[i] /= 100; + if (voltage[i] < V_REF * TEST_SIGNAL_FACTOR - TEST_SIGNAL_SLACK) + return false; + } + + // Connect all channels to the negative DC test signal + for (int i = 0; i < 4; i++) + { + setChannelInput(static_cast<Channel>(i), Input::NEGATIVE_DC_TEST); + } + + // Take some samples + for (int i = 0; i < 100; i++) + { + Thread::sleep(4); + auto newSample = sampleImpl(); + + for (int j = 0; j < 4; j++) + { + voltage[j] += newSample.voltage[j]; + } + } + + // Check values + for (int i = 0; i < 4; i++) + { + voltage[i] /= 100; + if (voltage[i] > -V_REF * TEST_SIGNAL_FACTOR + TEST_SIGNAL_SLACK) + return false; + } + return true; } @@ -250,18 +350,12 @@ ADS131M04Data ADS131M04::sampleImpl() // Extract each channel value int32_t rawValue[4]; - rawValue[0] = static_cast<uint32_t>(data[3]) << 16 | - static_cast<uint32_t>(data[4]) << 8 | - static_cast<uint32_t>(data[5]); - rawValue[1] = static_cast<uint32_t>(data[6]) << 16 | - static_cast<uint32_t>(data[7]) << 8 | - static_cast<uint32_t>(data[8]); - rawValue[2] = static_cast<uint32_t>(data[9]) << 16 | - static_cast<uint32_t>(data[10]) << 8 | - static_cast<uint32_t>(data[11]); - rawValue[3] = static_cast<uint32_t>(data[12]) << 16 | - static_cast<uint32_t>(data[13]) << 8 | - static_cast<uint32_t>(data[14]); + for (int i = 0; i < 4; i++) + { + rawValue[i] = static_cast<uint32_t>(data[i * 3 + 3]) << 16 | + static_cast<uint32_t>(data[i * 3 + 4]) << 8 | + static_cast<uint32_t>(data[i * 3 + 5]); + } // Extract and verify the CRC uint16_t dataCrc = @@ -281,7 +375,7 @@ ADS131M04Data ADS131M04::sampleImpl() for (int i = 0; i < 4; i++) { // Check for the sign bit - if (rawValue[i] & 0x800000) + if (rawValue[i] & 0x00800000) rawValue[i] |= 0xFF000000; // Extend the sign bit } diff --git a/src/shared/sensors/ADS131M04/ADS131M04.h b/src/shared/sensors/ADS131M04/ADS131M04.h index 9d948a2886550e06e5ae0e7c37e4261cf80ed9bb..c2857a4f8bb615094a091bee941787742d1084da 100644 --- a/src/shared/sensors/ADS131M04/ADS131M04.h +++ b/src/shared/sensors/ADS131M04/ADS131M04.h @@ -116,6 +116,14 @@ public: CHANNEL_3 = 3 }; + enum class Input : uint8_t + { + DEFAULT = 0, // AINxP and AINxN (default) + SHORTED = 1, // ADC inputs shorted + POSITIVE_DC_TEST = 2, // Positive DC test signal + NEGATIVE_DC_TEST = 3 // Negative DC test signal + }; + ADS131M04(SPIBusInterface &bus, miosix::GpioPin cs, SPIBusConfig config = getDefaultSPIConfig()); @@ -164,6 +172,8 @@ public: */ void setChannelGainCalibration(Channel channel, double gain); + void setChannelInput(Channel channel, Input input); + void enableChannel(Channel channel); void disableChannel(Channel channel); diff --git a/src/shared/sensors/ADS131M08/ADS131M08.cpp b/src/shared/sensors/ADS131M08/ADS131M08.cpp index 9ea5204cccc2725e6da333761032597720af0323..21c30d1e3de2647b6e427e532e8024c769969e24 100644 --- a/src/shared/sensors/ADS131M08/ADS131M08.cpp +++ b/src/shared/sensors/ADS131M08/ADS131M08.cpp @@ -26,6 +26,7 @@ #include <util/crc16.h> #include <utils/CRC.h> +using namespace miosix; using namespace Boardcore::ADS131M08RegisterBitMasks; namespace Boardcore @@ -79,7 +80,7 @@ bool ADS131M08::init() bool ADS131M08::reset() { // Write all the communication frame which is maximum 6 24bit words - uint8_t data[18] = {0}; + uint8_t data[30] = {0}; // Prepare the command data[1] = static_cast<uint16_t>(Commands::RESET); @@ -92,7 +93,7 @@ bool ADS131M08::reset() uint16_t response = data[0] << 8 | data[1]; // Check for the correct response - if (response != 0xFF24) + if (response != 0xFF28) { lastError = SensorErrors::COMMAND_FAILED; LOG_ERR(logger, "Reset command failed, response was {:X}", response); @@ -104,40 +105,47 @@ bool ADS131M08::reset() void ADS131M08::calibrateOffset() { - int32_t averageValues[8] = {0}; + // Reset all offsets and gains + for (int i = 0; i < 8; i++) + { + setChannelOffset(static_cast<Channel>(i), 0); + } // Sample the channels and average the samples - for (int i = 0; i < 1000; i++) + int32_t averageValues[8] = {0}; + for (int i = 0; i < 250; i++) { - sample(); - miosix::delayUs(1); + Thread::sleep(4); - for (int ii = 0; ii < 4; ii++) - averageValues[ii] += - lastSample.voltage[ii] / - PGA_LSB_SIZE[static_cast<uint16_t>(channelsPGAGain[ii])]; - } + uint8_t data[30] = {0}; + + data[0] = static_cast<uint16_t>(Commands::NULL_CMD) >> 8; + data[1] = static_cast<uint16_t>(Commands::NULL_CMD); + + SPITransaction transaction(spiSlave); + transaction.transfer(data, sizeof(data)); - for (int i = 0; i < 4; i++) - averageValues[i] /= 1000; + for (int j = 0; j < 8; j++) + { + int32_t tmp = static_cast<uint32_t>(data[j * 3 + 3]) << 16 | + static_cast<uint32_t>(data[j * 3 + 4]) << 8 | + static_cast<uint32_t>(data[j * 3 + 5]); + + // Check for the sign bit + if (tmp & 0x00800000) + tmp |= 0xFF000000; // Extend the sign bit + + averageValues[j] += tmp; + } + } + for (int i = 0; i < 8; i++) + averageValues[i] /= 250; // Configure the offset registers - writeRegister(Registers::REG_CH0_OCAL_MSB, averageValues[0] >> 8); - writeRegister(Registers::REG_CH0_OCAL_LSB, averageValues[0] << 16); - writeRegister(Registers::REG_CH1_OCAL_MSB, averageValues[1] >> 8); - writeRegister(Registers::REG_CH1_OCAL_LSB, averageValues[1] << 16); - writeRegister(Registers::REG_CH2_OCAL_MSB, averageValues[2] >> 8); - writeRegister(Registers::REG_CH2_OCAL_LSB, averageValues[2] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[3] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[3] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[4] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[4] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[5] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[5] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[6] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[6] << 16); - writeRegister(Registers::REG_CH3_OCAL_MSB, averageValues[7] >> 8); - writeRegister(Registers::REG_CH3_OCAL_LSB, averageValues[7] << 16); + for (int i = 0; i < 8; i++) + { + setChannelOffset(static_cast<Channel>(i), averageValues[i]); + } } void ADS131M08::setChannelPGA(Channel channel, PGA gain) @@ -200,8 +208,8 @@ void ADS131M08::setChannelOffset(Channel channel, uint32_t offset) break; } - writeRegister(regMSB, static_cast<uint16_t>(offset) >> 16); - writeRegister(regLSB, static_cast<uint16_t>(offset) << 8); + writeRegister(regMSB, offset >> 8); + writeRegister(regLSB, offset << 16); } void ADS131M08::setChannelGainCalibration(Channel channel, double gain) @@ -255,6 +263,44 @@ void ADS131M08::setChannelGainCalibration(Channel channel, double gain) writeRegister(regLSB, rawGain << 8); } +void ADS131M08::setChannelInput(Channel channel, Input input) +{ + // Set the correct register based on the selected channel + Registers reg; + switch (static_cast<int>(channel)) + { + case 0: + reg = Registers::REG_CH0_CFG; + break; + case 1: + reg = Registers::REG_CH1_CFG; + break; + case 2: + reg = Registers::REG_CH2_CFG; + break; + case 3: + reg = Registers::REG_CH3_CFG; + break; + case 4: + reg = Registers::REG_CH4_CFG; + break; + case 5: + reg = Registers::REG_CH5_CFG; + break; + case 6: + reg = Registers::REG_CH6_CFG; + break; + default: + reg = Registers::REG_CH7_CFG; + break; + } + + uint16_t value = readRegister(reg); + value &= REG_CHx_CFG_MUX; + value |= static_cast<uint16_t>(input); + writeRegister(reg, value); +} + void ADS131M08::enableChannel(Channel channel) { changeRegister(Registers::REG_CLOCK, 1 << (static_cast<int>(channel) + 8), @@ -287,7 +333,65 @@ ADCData ADS131M08::getVoltage(Channel channel) bool ADS131M08::selfTest() { - // TODO + static constexpr float V_REF = 1.2; + static constexpr float TEST_SIGNAL_FACTOR = 2 / 15; + static constexpr float TEST_SIGNAL_SLACK = 0.1; // Not defined in DS + + float voltage[8] = {0}; + + // Connect all channels to the positive DC test signal + for (int i = 0; i < 8; i++) + { + setChannelInput(static_cast<Channel>(i), Input::POSITIVE_DC_TEST); + setChannelPGA(static_cast<Channel>(i), PGA::PGA_1); + } + + // Take some samples + for (int i = 0; i < 100; i++) + { + Thread::sleep(4); + auto newSample = sampleImpl(); + + for (int j = 0; j < 8; j++) + { + voltage[j] += newSample.voltage[j]; + } + } + + // Check values + for (int i = 0; i < 8; i++) + { + voltage[i] /= 100; + if (voltage[i] < V_REF * TEST_SIGNAL_FACTOR - TEST_SIGNAL_SLACK) + return false; + } + + // Connect all channels to the negative DC test signal + for (int i = 0; i < 8; i++) + { + setChannelInput(static_cast<Channel>(i), Input::NEGATIVE_DC_TEST); + } + + // Take some samples + for (int i = 0; i < 100; i++) + { + Thread::sleep(4); + auto newSample = sampleImpl(); + + for (int j = 0; j < 8; j++) + { + voltage[j] += newSample.voltage[j]; + } + } + + // Check values + for (int i = 0; i < 8; i++) + { + voltage[i] /= 100; + if (voltage[i] > -V_REF * TEST_SIGNAL_FACTOR + TEST_SIGNAL_SLACK) + return false; + } + return true; } @@ -304,30 +408,12 @@ ADS131M08Data ADS131M08::sampleImpl() // Extract each channel value int32_t rawValue[8]; - rawValue[0] = static_cast<uint32_t>(data[3]) << 16 | - static_cast<uint32_t>(data[4]) << 8 | - static_cast<uint32_t>(data[5]); - rawValue[1] = static_cast<uint32_t>(data[6]) << 16 | - static_cast<uint32_t>(data[7]) << 8 | - static_cast<uint32_t>(data[8]); - rawValue[2] = static_cast<uint32_t>(data[9]) << 16 | - static_cast<uint32_t>(data[10]) << 8 | - static_cast<uint32_t>(data[11]); - rawValue[3] = static_cast<uint32_t>(data[12]) << 16 | - static_cast<uint32_t>(data[13]) << 8 | - static_cast<uint32_t>(data[14]); - rawValue[4] = static_cast<uint32_t>(data[15]) << 16 | - static_cast<uint32_t>(data[16]) << 8 | - static_cast<uint32_t>(data[17]); - rawValue[5] = static_cast<uint32_t>(data[18]) << 16 | - static_cast<uint32_t>(data[19]) << 8 | - static_cast<uint32_t>(data[20]); - rawValue[6] = static_cast<uint32_t>(data[21]) << 16 | - static_cast<uint32_t>(data[22]) << 8 | - static_cast<uint32_t>(data[23]); - rawValue[7] = static_cast<uint32_t>(data[24]) << 16 | - static_cast<uint32_t>(data[25]) << 8 | - static_cast<uint32_t>(data[26]); + for (int i = 0; i < 8; i++) + { + rawValue[i] = static_cast<uint32_t>(data[i * 3 + 3]) << 16 | + static_cast<uint32_t>(data[i * 3 + 4]) << 8 | + static_cast<uint32_t>(data[i * 3 + 5]); + } // Extract and verify the CRC uint16_t dataCrc = @@ -347,7 +433,7 @@ ADS131M08Data ADS131M08::sampleImpl() for (int i = 0; i < 8; i++) { // Check for the sign bit - if (rawValue[i] & 0x800000) + if (rawValue[i] & 0x00800000) rawValue[i] |= 0xFF000000; // Extend the sign bit } diff --git a/src/shared/sensors/ADS131M08/ADS131M08.h b/src/shared/sensors/ADS131M08/ADS131M08.h index 0d2d3c73385c2a0bf7c1b525b8cbbe50fe6c739c..6dca0801fd26aad599b42f4fd1ead87889e429d7 100644 --- a/src/shared/sensors/ADS131M08/ADS131M08.h +++ b/src/shared/sensors/ADS131M08/ADS131M08.h @@ -120,6 +120,14 @@ public: CHANNEL_7 = 3 }; + enum class Input : uint8_t + { + DEFAULT = 0, // AINxP and AINxN (default) + SHORTED = 1, // ADC inputs shorted + POSITIVE_DC_TEST = 2, // Positive DC test signal + NEGATIVE_DC_TEST = 3 // Negative DC test signal + }; + ADS131M08(SPIBusInterface &bus, miosix::GpioPin cs, SPIBusConfig config = getDefaultSPIConfig()); @@ -168,6 +176,8 @@ public: */ void setChannelGainCalibration(Channel channel, double gain); + void setChannelInput(Channel channel, Input input); + void enableChannel(Channel channel); void disableChannel(Channel channel); diff --git a/src/tests/sensors/test-ads131m08.cpp b/src/tests/sensors/test-ads131m08.cpp index 5deb400dac0aff30234582d7b4a7c39a1e532c9b..cd4dd482dc69676d10cc43b7870fe24c729f6496 100644 --- a/src/tests/sensors/test-ads131m08.cpp +++ b/src/tests/sensors/test-ads131m08.cpp @@ -59,7 +59,22 @@ int main() ADS131M08 ads131(spiSlave); // Initialize the device - ads131.init(); + if (!ads131.init()) + { + printf("Initialization failed!\n"); + } + else + { + printf("Initialization done\n"); + } + if (!ads131.selfTest()) + { + printf("Self test failed!\n"); + } + else + { + printf("Self test done\n"); + } ads131.enableGlobalChopMode(); ads131.setOversamplingRatio(ADS131M08::OversamplingRatio::OSR_16256); ads131.calibrateOffset();