Implement ADS1115 register reading and writing
This commit is contained in:
172
src/bus/i2c.c
172
src/bus/i2c.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
17
src/main.c
17
src/main.c
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user