diff --git a/firmware/hw_layer/adc/ads1015.cpp b/firmware/hw_layer/adc/ads1015.cpp new file mode 100644 index 0000000000..e861a0b6d4 --- /dev/null +++ b/firmware/hw_layer/adc/ads1015.cpp @@ -0,0 +1,65 @@ +#include "ads1015.h" +#include "efilib.h" + +constexpr uint8_t addr = 0x48; + +#define ADS1015_CONV (0) +#define ADS1015_CONFIG (1) +#define ADS1015_LO_THRESH (2) +#define ADS1015_HI_THRESH (3) + +bool Ads1015::init(brain_pin_e scl, brain_pin_e sda) { + m_i2c.init(scl, sda); + + // ADS1015 has no ID register - so we read the Lo_thresh instead + uint16_t loThresh = readReg(ADS1015_LO_THRESH); + + if (loThresh != 0x8000) { + return false; + } + + m_hasInit = true; + return true; +} + +void Ads1015::readChannels(float (&result)[4]) { + for (size_t i = 0; i < 4; i++) { + result[i] = readChannel(i); + } +} + +float Ads1015::readChannel(uint8_t ch) { + // set the channel + // set to +-6.144v full scale, fastest sampling, manual conversion start + writeReg(ADS1015_CONFIG, 0xC1E0 | ch << 12); + + // Wait for conversion to complete + // Bit is cleared while conversion is ongoing, set when done + while ((readReg(ADS1015_CONFIG) & 0x8000) == 0) ; + + // Read the result + int16_t result = readReg(ADS1015_CONV); + // Result is 12 bits left aligned, so right align the result + result = result >> 4; + + // 2048 counts = positive 6.144 volts + constexpr float ratio = 6.144f / 2048; + return result * ratio; +} + +void Ads1015::writeReg(uint8_t reg, uint16_t data) { + uint8_t packet[3]; + + packet[0] = reg; + packet[1] = data >> 8; + packet[2] = data & 0xFF; + + m_i2c.write(addr, packet, 3); +} + +uint16_t Ads1015::readReg(uint8_t reg) { + uint16_t res; + m_i2c.write(addr, ®, 1); + m_i2c.read(addr, reinterpret_cast(&res), 2); + return SWAP_UINT16(res); +} diff --git a/firmware/hw_layer/adc/ads1015.h b/firmware/hw_layer/adc/ads1015.h new file mode 100644 index 0000000000..59dce7ee6e --- /dev/null +++ b/firmware/hw_layer/adc/ads1015.h @@ -0,0 +1,18 @@ +#pragma once + +#include "i2c_bb.h" + +class Ads1015 { +public: + bool init(brain_pin_e scl, brain_pin_e sda); + void readChannels(float (&result)[4]); + +private: + float readChannel(uint8_t ch); + + void writeReg(uint8_t reg, uint16_t data); + uint16_t readReg(uint8_t reg); + + bool m_hasInit = false; + BitbangI2c m_i2c; +}; diff --git a/firmware/hw_layer/hw_layer.mk b/firmware/hw_layer/hw_layer.mk index 3467a3788f..b3286193c0 100644 --- a/firmware/hw_layer/hw_layer.mk +++ b/firmware/hw_layer/hw_layer.mk @@ -31,6 +31,7 @@ HW_LAYER_EMS_CPP = $(HW_LAYER_EGT_CPP) \ $(PROJECT_DIR)/hw_layer/lcd/lcd_HD44780.cpp \ $(PROJECT_DIR)/hw_layer/adc/adc_inputs.cpp \ $(PROJECT_DIR)/hw_layer/adc/adc_subscription.cpp \ + $(PROJECT_DIR)/hw_layer/adc/ads1015.cpp \ $(PROJECT_DIR)/hw_layer/sensors/hip9011.cpp \ $(PROJECT_DIR)/hw_layer/sensors/hip9011_logic.cpp \ $(PROJECT_DIR)/hw_layer/mc33816.cpp \ diff --git a/firmware/hw_layer/i2c_bb.cpp b/firmware/hw_layer/i2c_bb.cpp index 96c8a35b57..b75fce2baa 100644 --- a/firmware/hw_layer/i2c_bb.cpp +++ b/firmware/hw_layer/i2c_bb.cpp @@ -188,8 +188,11 @@ void BitbangI2c::writeRead(uint8_t addr, const uint8_t* writeData, size_t writeS for (size_t i = 0; i < writeSize; i++) { writeByte(writeData[i]); } - - // Send a repeated start bit to indicate transition to read + + read(addr, readData, readSize); +} + +void BitbangI2c::read(uint8_t addr, uint8_t* readData, size_t readSize) { start(); // Address + read diff --git a/firmware/hw_layer/i2c_bb.h b/firmware/hw_layer/i2c_bb.h index 4c25c39e29..51a1ce093a 100644 --- a/firmware/hw_layer/i2c_bb.h +++ b/firmware/hw_layer/i2c_bb.h @@ -23,6 +23,8 @@ public: // Write a sequence of bytes to the specified device void write(uint8_t addr, const uint8_t* data, size_t size); + // Read a sequence of bytes from the device + void read(uint8_t addr, uint8_t* data, size_t size); // Write some bytes then read some bytes back after a repeated start bit void writeRead(uint8_t addr, const uint8_t* writeData, size_t writeSize, uint8_t* readData, size_t readSize);