ProtoCore v0.0.2
Deterministic, zero-heap network stack for embedded targets
Loading...
Searching...
No Matches
ads1115.cpp
Go to the documentation of this file.
1// Copyright (C) 2026 Douglas Quigg (dstroy0) <dquigg123@gmail.com>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4/**
5 * @file ads1115.cpp
6 * @brief TI ADS1115 16-bit ADC codec - implementation. See ads1115.h.
7 */
8
10#include "protocore_config.h"
11#include "services/system/clock.h" // pcdelay
12
13#if PC_ENABLE_ADS1115
14
15#if defined(ARDUINO)
17#include <Arduino.h>
18#include <Wire.h>
19#endif
20namespace
21{
22// Config-register field values (per the ADS1115 datasheet).
23const uint16_t OS_SINGLE = 0x8000; // start a single conversion
24const uint16_t MUX_SINGLE0 = 0x4000; // single-ended AIN0; AINx = this | (channel << 12)
25const uint16_t MODE_SINGLE = 0x0100; // single-shot
26const uint16_t COMP_DISABLE = 0x0003;
27
28// PGA bits and the matching full-scale range in microvolts, indexed by gain code.
29const uint16_t PGA_BITS[6] = {0x0000, 0x0200, 0x0400, 0x0600, 0x0800, 0x0A00};
30const int32_t FSR_UV[6] = {6144000, 4096000, 2048000, 1024000, 512000, 256000};
31} // namespace
32
33uint16_t pc_ads1115_config_single(uint8_t channel, uint8_t gain, uint8_t dr)
34{
35 if (channel > 3)
36 {
37 channel = 0;
38 }
40 {
41 gain = (uint8_t)PC_ADS1115_GAIN;
42 }
44 {
45 dr = (uint8_t)PC_ADS1115_DR;
46 }
47 uint16_t cfg = OS_SINGLE;
48#if PC_ADS1115_DIFFERENTIAL
49 cfg |= (uint16_t)((uint16_t)channel << 12); // differential pair: MUX 0=AIN0-1, 1=AIN0-3, 2=AIN1-3, 3=AIN2-3
50#else
51 cfg |= (uint16_t)(MUX_SINGLE0 | ((uint16_t)channel << 12)); // single-ended AINx
52#endif
53 cfg |= PGA_BITS[gain];
54 cfg |= MODE_SINGLE;
55 cfg |= (uint16_t)((uint16_t)dr << 5); // data-rate bits [7:5]
56 cfg |= COMP_DISABLE;
57 return cfg;
58}
59
60int32_t pc_ads1115_raw_to_uv(int16_t raw, uint8_t gain)
61{
63 {
64 gain = (uint8_t)PC_ADS1115_GAIN;
65 }
66 return (int32_t)((int64_t)raw * FSR_UV[gain] / 32768);
67}
68
69// ---------------------------------------------------------------------------
70// I2C binding
71// ---------------------------------------------------------------------------
72
73#if defined(ARDUINO)
74
75namespace
76{
77// All ADS1115 I2C-binding state, owned by one instance (internal linkage): the device
78// address, so it is one named owner, unreachable from any other translation unit.
79struct Ads1115Ctx
80{
81 uint8_t addr = PC_ADS1115_I2C_ADDR;
82};
83Ads1115Ctx s_ads;
84
85bool wr16(uint8_t reg, uint16_t v)
86{
87 Wire.beginTransmission(s_ads.addr);
88 Wire.write(reg);
89 Wire.write((uint8_t)(v >> 8)); // ADS1115 registers are big-endian
90 Wire.write((uint8_t)(v & 0xFF));
91 return Wire.endTransmission() == 0;
92}
93
94bool rd16(uint8_t reg, uint16_t *v)
95{
96 Wire.beginTransmission(s_ads.addr);
97 Wire.write(reg);
98 if (Wire.endTransmission(false) != 0)
99 {
100 return false;
101 }
102 if (Wire.requestFrom((int)s_ads.addr, 2) != 2)
103 {
104 return false;
105 }
106 uint8_t hi = (uint8_t)Wire.read();
107 uint8_t lo = (uint8_t)Wire.read();
108 *v = (uint16_t)(((uint16_t)hi << 8) | lo);
109 return true;
110}
111} // namespace
112
113bool pc_ads1115_begin(uint8_t addr)
114{
115 s_ads.addr = addr ? addr : (uint8_t)PC_ADS1115_I2C_ADDR;
116 pc_i2c_begin();
117 return true;
118}
119
120bool pc_ads1115_read_raw(uint8_t channel, uint8_t gain, int16_t *raw)
121{
122 if (!raw)
123 {
124 return false;
125 }
126 uint8_t dr = (uint8_t)PC_ADS1115_DR;
128 {
130 }
131 if (!wr16(ADS1115_REG_CONFIG, pc_ads1115_config_single(channel, gain, dr)))
132 {
133 return false;
134 }
135 // Single-shot conversion time tracks the data rate (~1000/SPS ms); wait it out plus a 1 ms margin.
136 static const uint16_t pc_ads1115_sps[8] = {8, 16, 32, 64, 128, 250, 475, 860};
137 pcdelay(1000u / pc_ads1115_sps[dr] + 1);
138 uint16_t v = 0;
139 if (!rd16(ADS1115_REG_CONVERSION, &v))
140 {
141 return false;
142 }
143 *raw = (int16_t)v;
144 return true;
145}
146
147bool pc_ads1115_read_uv(uint8_t channel, uint8_t gain, int32_t *microvolts)
148{
149 int16_t raw = 0;
150 if (!pc_ads1115_read_raw(channel, gain, &raw))
151 {
152 return false;
153 }
154 if (microvolts)
155 {
156 *microvolts = pc_ads1115_raw_to_uv(raw, gain);
157 }
158 return true;
159}
160
161#else // host build: no I2C. The config encoder + conversion above are host-tested.
162
163bool pc_ads1115_begin(uint8_t)
164{
165 return false;
166}
167bool pc_ads1115_read_raw(uint8_t, uint8_t, int16_t *)
168{
169 return false;
170}
171bool pc_ads1115_read_uv(uint8_t, uint8_t, int32_t *)
172{
173 return false;
174}
175
176#endif // ARDUINO
177
178#endif // PC_ENABLE_ADS1115
TI ADS1115 16-bit ADC codec (PC_ENABLE_ADS1115).
bool pc_ads1115_begin(uint8_t addr)
Initialize the I2C bus for the ADS1115 at addr.
int32_t pc_ads1115_raw_to_uv(int16_t raw, uint8_t gain)
Convert a signed 16-bit sample to microvolts for gain's full-scale range.
bool pc_ads1115_read_raw(uint8_t channel, uint8_t gain, int16_t *raw)
Single-shot read of channel (0..3) at gain into raw.
#define ADS1115_REG_CONVERSION
conversion result register
Definition ads1115.h:31
uint16_t pc_ads1115_config_single(uint8_t channel, uint8_t gain, uint8_t dr)
Build the 16-bit config word for a single-shot, single-ended reading of channel (0....
#define ADS1115_REG_CONFIG
configuration register
Definition ads1115.h:32
bool pc_ads1115_read_uv(uint8_t channel, uint8_t gain, int32_t *microvolts)
Single-shot read of channel at gain, converted to microvolts in microvolts.
Pluggable monotonic clock for all library timing.
void pcdelay(uint32_t ms)
Block for at least ms milliseconds - the library's single delay primitive.
Definition clock.h:89
The one owner of the shared I2C bus bring-up for the peripheral drivers.
void pc_i2c_begin()
Bring up the shared I2C bus on PC_I2C_SDA_PIN / PC_I2C_SCL_PIN (-1 = default).
Definition i2c.h:33
User-facing configuration for ProtoCore.
#define PC_ADS1115_I2C_ADDR
I2C address of the ADS1115 (0x48 with ADDR to GND; 0x49/0x4A/0x4B for VDD/SDA/SCL).
#define PC_ADS1115_DR
Default ADS1115 data-rate code (ADS1115_DR_*): 0=8, 1=16, 2=32, 3=64, 4=128 (default),...
#define PC_ADS1115_GAIN
Default ADS1115 PGA gain code (ADS1115_GAIN_*): 0=+/-6.144V, 1=+/-4.096V, 2=+/-2.048V (default),...
static constexpr uint8_t ADS1115_DR_128
128 SPS (default)
Definition ads1115.h:53
static constexpr uint8_t ADS1115_DR_860
860 SPS
Definition ads1115.h:56
static constexpr uint8_t ADS1115_GAIN_16
+/- 0.256 V
Definition ads1115.h:43