Implement ADS1115 register reading and writing

This commit is contained in:
2024-09-04 21:38:12 +02:00
parent 992899f0cb
commit 1602aa4297
3 changed files with 183 additions and 8 deletions

View File

@@ -20,6 +20,9 @@ static bool I2C_AHT20_IsCalibrated(void);
static void I2C_AHT20_Calibrate(void);
static void I2C_AHT20_Trigger(void);
static int I2C_ADS1115_WriteRegister(unsigned char reg, unsigned short data);
static unsigned short I2C_ADS1115_ReadRegister(unsigned char reg);
int I2C_Init(void)
{
// Set SCL bit rate to 400kHz
@@ -168,18 +171,18 @@ int I2C_SetChannel(int channel)
crb = (1 << channel);
// crb = 0x01; // Channel 0 | 00000001
// crb = 0x02 // Channel 1 | 00000010
// crb = 0x04 // Channel 2 | 00000100
// crb = 0x08 // Channel 3 | 00001000
// 0x02 // Channel 1 | 00000010
// 0x04 // Channel 2 | 00000100
// 0x08 // Channel 3 | 00001000
I2C_Write(crb);
I2C_Wait_ACK();
// When a channel is selected, the channel
// becomes active after a stop condition has been
// placed on the I2C bus. A stop condition always
// must occur right after the acknowledge cycle.
I2C_Wait_ACK();
I2C_Stop();
return 0;
@@ -352,3 +355,164 @@ static void I2C_AHT20_Trigger(void)
} while ((status & BIT(7)) == 1);
I2C_Stop();
}
static int I2C_ADS1115_WriteRegister(unsigned char reg, unsigned short data)
{
// The ADS111x have one address pin, ADDR, that
// configures the I2C address of the device. This
// pin can be connected to GND, VDD, SDA, or SCL,
// allowing for four different addresses to be
// selected with one pin:
// GND 1001000
// VDD 1001001
// SDA 1001010
// SCL 1001011
// In slave receive mode, the first byte transmitted
// from the master to the slave consists of the 7-bit
// device address followed by a low R/W bit.
I2C_Start(0x48, 0); // ADDR pin to GND
I2C_Wait_ACK();
// The next byte transmitted by the master is the
// Address Pointer register. The ADS111x then
// acknowledge receipt of the Address Pointer
// register byte.
I2C_Write(reg);
I2C_Wait_ACK();
// The next two bytes are written to the address
// given by the register address pointer bits P[1:0].
// The ADS111x acknowledge each byte sent. Register
// bytes are sent with the most significant byte
// first, followed by the least significant byte.
I2C_Write(data >> 8);
I2C_Wait_ACK();
I2C_Write(data & 0xFF);
I2C_Wait_ACK();
I2C_Stop();
return 0;
}
static unsigned short I2C_ADS1115_ReadRegister(unsigned char reg)
{
unsigned char data[2];
// To access a specific register from the ADS1115,
// the master must first write an appropriate value
// to register address pointer bits P[1:0] in the
// Address Pointer register.
// The Address Pointer register is written to
// directly after the slave address byte, low R/W bit,
// and a successful slave acknowledgment.
I2C_Start(0x48, 0);
I2C_Wait_ACK();
I2C_Write(reg);
// After the Address Pointer register
// is written, the slave acknowledges, and the master
// issues a STOP or a repeated START condition.
I2C_Wait_ACK();
I2C_Stop();
I2C_Start(0x48, 1);
I2C_Wait_ACK();
// The ADS111x provide 16 bits of data in binary
// two's complement format. A positive full-scale (+FS)
// input produces an output code of 7FFFh and a negative
// full-scale (FS) input produces an output code of
// 8000h. The output clips at these codes for signals
// that exceed full-scale. XXX: ???
data[0] = I2C_Read_ACK();
data[1] = I2C_Read_NACK();
I2C_Stop();
return data[0] << 8 | data[1];
}
unsigned short I2C_ADS1115_Read(int channel)
{
unsigned short config;
unsigned short rate, gain, mux, os;
// Operational status or single-shot conversion
// start: This bit determines the operational
// status of the device. OS can only be written
// when in power-down state and has no effect
// when a conversion is ongoing.
// When writing:
// 0 : No effect
// 1 : Start single conversion (power-down state)
// When reading:
// 0 : Device is performing a conversion
// 1 : Device is not performing a conversion
os = 0x8000; // Start single | 10000000 00000000
// Data rate: These bits control the data rate setting.
// 000 | 8 SPS
// 001 | 16 SPS
// 010 | 32 SPS
// 011 | 64 SPS
// 100 | 128 SPS
// 101 | 250 SPS
// 110 | 475 SPS
// 111 | 860 SPS
rate = 0x0080; // 128 SPS | 00000000 10000000
// Programmable gain amplifier configuration: These
// bits set the FSR of the programmable gain amplifier.
// 000 | ±6.144 V
// 001 | ±4.096 V
// 010 | ±2.048 V
// 011 | ±1.024 V
// 100 | ±0.512 V
// 101 | ±0.256 V
// 110 | ±0.256 V
// 111 | ±0.256 V
gain = 0x0400; // 2.048 V | 00000100 00000000
// Input multiplexer configuration: These bits
// configure the input multiplexer.
// 000 | AINP = AIN0, AINN = AIN1
// 001 | AINP = AIN0, AINN = AIN3
// 010 | AINP = AIN1, AINN = AIN3
// 011 | AINP = AIN2, AINN = AIN3
// 100 | AINP = AIN0, AINN = GND
// 101 | AINP = AIN1, AINN = GND
// 110 | AINP = AIN2, AINN = GND
// 111 | AINP = AIN3, AINN = GND
mux = 0;
if (channel == 0)
mux = 0x4000; // | 01000000 00000000
else if (channel == 1)
mux = 0x5000; // | 01010000 00000000
else if (channel == 2)
mux = 0x6000; // | 01100000 00000000
else if (channel == 3)
mux = 0x7000; // | 01110000 00000000
// Single-shot conversion, active low, continous mode
config = os | rate | gain | mux;
I2C_ADS1115_WriteRegister(0x01, config);
return I2C_ADS1115_ReadRegister(0x00);
}

View File

@@ -18,4 +18,6 @@ int I2C_Stop(void);
int I2C_AHT20_Init(void);
int I2C_AHT20_Read(float *temp, float *rhum);
unsigned short I2C_ADS1115_Read(int channel);
#endif // MAD_CORE_BUS_I2C_H

View File

@@ -6,7 +6,7 @@
#include <avr/interrupt.h>
// TODO: Get readings from ADC ADS1115 over I2C.
// TODO: Convert raw data from ADS1115 to usable values.
// TODO: Implement optional sensor value check with CRC8.
// TODO: Set timeouts for polling based things like I2C.
// TODO: Write an improved serial parser (low priority).
@@ -78,18 +78,27 @@ int Init(void)
void Update(void)
{
float temp, rhum;
short raw[4];
I2C_SetChannel(AHT01);
if (I2C_AHT20_Read(&temp, &rhum))
if (I2C_AHT20_Read(&temp, &rhum) == 0)
Info("TEMP=%.2fC, RHUM=%.2f%", temp, rhum);
I2C_SetChannel(AHT02);
if (I2C_AHT20_Read(&temp, &rhum))
if (I2C_AHT20_Read(&temp, &rhum) == 0)
Info("TEMP=%.2fC, RHUM=%.2f%", temp, rhum);
I2C_SetChannel(AHT03);
if (I2C_AHT20_Read(&temp, &rhum))
if (I2C_AHT20_Read(&temp, &rhum) == 0)
Info("TEMP=%.2fC, RHUM=%.2f%", temp, rhum);
raw[0] = I2C_ADS1115_Read(0);
raw[1] = I2C_ADS1115_Read(1);
raw[2] = I2C_ADS1115_Read(2);
raw[3] = I2C_ADS1115_Read(3);
Info("ADC0=%04X, ADC1=%04X, ADC2=%04X, ADC3=%04X",
raw[0], raw[1], raw[2], raw[3]);
}
int main(void)