ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
nau7802.cpp
Go to the documentation of this file.
1#include "nau7802.h"
2#include <cmath>
4#include "esphome/core/log.h"
5#include "esphome/core/hal.h"
6
7namespace esphome::nau7802 {
8
9ESPHOME_LOG_TAG(TAG, "nau7802");
10
11// Only define what we need
12
13static const uint8_t READ_BIT = 0x01;
14
15static const uint8_t PU_CTRL_REG = 0x00;
16static const uint8_t PU_CTRL_REGISTER_RESET = 0x01;
17static const uint8_t PU_CTRL_POWERUP_DIGITAL = 0x02;
18static const uint8_t PU_CTRL_POWERUP_ANALOG = 0x04;
19static const uint8_t PU_CTRL_POWERUP_READY = 0x08;
20static const uint8_t PU_CTRL_CYCLE_START = 0x10;
21static const uint8_t PU_CTRL_CYCLE_READY = 0x20;
22static const uint8_t PU_CTRL_AVDD_EXTERNAL = 0x80;
23
24static const uint8_t CTRL1_REG = 0x01;
25static const uint8_t CTRL1_LDO_SHIFT = 3;
26static const uint8_t CTRL1_LDO_MASK = (0x7 << CTRL1_LDO_SHIFT);
27static const uint8_t CTRL1_GAIN_MASK = 0x7;
28
29static const uint8_t CTRL2_REG = 0x02;
30static const uint8_t CTRL2_CRS_SHIFT = 4;
31static const uint8_t CTRL2_CRS_MASK = (0x7 << CTRL2_CRS_SHIFT);
32static const uint8_t CTRL2_CALS = 0x04;
33static const uint8_t CTRL2_CAL_ERR = 0x08;
34static const uint8_t CTRL2_GAIN_CALIBRATION = 0x03;
35static const uint8_t CTRL2_CONFIG_MASK = 0xF0;
36
37static const uint8_t OCAL1_B2_REG = 0x03;
38static const uint8_t GCAL1_B3_REG = 0x06;
39static const uint8_t GCAL1_FRACTIONAL = 23;
40
41// only need the first data register for sequential read method
42static const uint8_t ADCO_B2_REG = 0x12;
43
44static const uint8_t ADC_REG = 0x15;
45static const uint8_t ADC_CHPS_DISABLE = 0x30;
46
47static const uint8_t PGA_REG = 0x1B;
48static const uint8_t PGA_LDOMODE_ESR = 0x40;
49
50static const uint8_t POWER_REG = 0x1C;
51static const uint8_t POWER_PGA_CAP_EN = 0x80;
52
53static const uint8_t DEVICE_REV = 0x1F;
54
56 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
57 uint8_t rev;
58
59 if (this->read_register(DEVICE_REV | READ_BIT, &rev, 1)) {
60 this->mark_failed(LOG_STR("Failed I2C read during setup()"));
61 return;
62 }
63 ESP_LOGI(TAG, "Setting up NAU7802 Rev %d", rev);
64
65 // reset
66 pu_ctrl |= PU_CTRL_REGISTER_RESET;
67 delay(10);
68 pu_ctrl &= ~PU_CTRL_REGISTER_RESET;
69
70 // power up digital hw
71 pu_ctrl |= PU_CTRL_POWERUP_DIGITAL;
72
73 delay(1);
74 if (!(pu_ctrl.get() & PU_CTRL_POWERUP_READY)) {
75 this->mark_failed(LOG_STR("Failed to reset sensor during setup()"));
76 return;
77 }
78
79 uint32_t gcal = (uint32_t) (std::round(this->gain_calibration_ * (1 << GCAL1_FRACTIONAL)));
80 this->write_value_(OCAL1_B2_REG, 3, this->offset_calibration_);
81 this->write_value_(GCAL1_B3_REG, 4, gcal);
82
83 // turn on AFE
84 pu_ctrl |= PU_CTRL_POWERUP_ANALOG;
85 this->set_timeout(600, [this]() { this->complete_setup_(); });
86}
87
89 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
90 i2c::I2CRegister ctrl1 = this->reg(CTRL1_REG);
91 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
92 pu_ctrl |= PU_CTRL_CYCLE_START;
93
94 // set gain
95 ctrl1 &= ~CTRL1_GAIN_MASK;
96 ctrl1 |= this->gain_;
97
98 // enable internal LDO
99 if (this->ldo_ != NAU7802_LDO_EXTERNAL) {
100 pu_ctrl |= PU_CTRL_AVDD_EXTERNAL;
101 ctrl1 &= ~CTRL1_LDO_MASK;
102 ctrl1 |= this->ldo_ << CTRL1_LDO_SHIFT;
103 }
104
105 // set sps
106 ctrl2 &= ~CTRL2_CRS_MASK;
107 ctrl2 |= this->sps_ << CTRL2_CRS_SHIFT;
108
109 // disable ADC chopper clock
110 i2c::I2CRegister adc_reg = this->reg(ADC_REG);
111 adc_reg |= ADC_CHPS_DISABLE;
112
113 // use low ESR caps
114 i2c::I2CRegister pga_reg = this->reg(PGA_REG);
115 pga_reg &= ~PGA_LDOMODE_ESR;
116
117 // PGA stabilizer cap on output
118 i2c::I2CRegister pwr_reg = this->reg(POWER_REG);
119 pwr_reg |= POWER_PGA_CAP_EN;
120}
121
123 LOG_SENSOR("", "NAU7802", this);
124 LOG_I2C_DEVICE(this);
125
126 if (this->is_failed())
127 return;
128 // Note these may differ from the values on the device if calbration has been run
129 ESP_LOGCONFIG(TAG,
130 " Offset Calibration: %" PRId32 "\n"
131 " Gain Calibration: %f",
133
134 std::string voltage = "unknown";
135 switch (this->ldo_) {
136 case NAU7802_LDO_2V4:
137 voltage = "2.4V";
138 break;
139 case NAU7802_LDO_2V7:
140 voltage = "2.7V";
141 break;
142 case NAU7802_LDO_3V0:
143 voltage = "3.0V";
144 break;
145 case NAU7802_LDO_3V3:
146 voltage = "3.3V";
147 break;
148 case NAU7802_LDO_3V6:
149 voltage = "3.6V";
150 break;
151 case NAU7802_LDO_3V9:
152 voltage = "3.9V";
153 break;
154 case NAU7802_LDO_4V2:
155 voltage = "4.2V";
156 break;
157 case NAU7802_LDO_4V5:
158 voltage = "4.5V";
159 break;
161 voltage = "External";
162 break;
163 }
164 ESP_LOGCONFIG(TAG, " LDO Voltage: %s", voltage.c_str());
165 int gain = 0;
166 switch (this->gain_) {
167 case NAU7802_GAIN_128:
168 gain = 128;
169 break;
170 case NAU7802_GAIN_64:
171 gain = 64;
172 break;
173 case NAU7802_GAIN_32:
174 gain = 32;
175 break;
176 case NAU7802_GAIN_16:
177 gain = 16;
178 break;
179 case NAU7802_GAIN_8:
180 gain = 8;
181 break;
182 case NAU7802_GAIN_4:
183 gain = 4;
184 break;
185 case NAU7802_GAIN_2:
186 gain = 2;
187 break;
188 case NAU7802_GAIN_1:
189 gain = 1;
190 break;
191 }
192 ESP_LOGCONFIG(TAG, " Gain: %dx", gain);
193 int sps = 0;
194 switch (this->sps_) {
195 case NAU7802_SPS_320:
196 sps = 320;
197 break;
198 case NAU7802_SPS_80:
199 sps = 80;
200 break;
201 case NAU7802_SPS_40:
202 sps = 40;
203 break;
204 case NAU7802_SPS_20:
205 sps = 20;
206 break;
207 case NAU7802_SPS_10:
208 sps = 10;
209 break;
210 }
211 ESP_LOGCONFIG(TAG, " Samples Per Second: %d", sps);
212 LOG_UPDATE_INTERVAL(this);
213}
214
215void NAU7802Sensor::write_value_(uint8_t start_reg, size_t size, int32_t value) {
216 uint8_t data[4];
217 for (size_t i = 0; i < size; i++) {
218 data[i] = 0xFF & (value >> (size - 1 - i) * 8);
219 }
220 this->write_register(start_reg, data, size);
221}
222
223int32_t NAU7802Sensor::read_value_(uint8_t start_reg, size_t size) {
224 uint8_t data[4];
225 this->read_register(start_reg, data, size);
226 int32_t result = 0;
227 for (size_t i = 0; i < size; i++) {
228 result |= data[i] << (size - 1 - i) * 8;
229 }
230 return size == 3 ? sign_extend<24>(result) : result;
231}
232
234 // check if already calbrating
235 if (this->state_ != CalibrationState::INACTIVE) {
236 ESP_LOGW(TAG, "Calibration already in progress");
237 return false;
238 }
239
241
242 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
243 // clear calibraye registers
244 ctrl2 &= CTRL2_CONFIG_MASK;
245 // Calibrate
246 ctrl2 |= mode;
247 ctrl2 |= CTRL2_CALS;
248 return true;
249}
250
252 switch (this->state_) {
254 this->gain_calibration_failed_ = failed;
255 break;
257 this->offset_calibration_failed_ = failed;
258 break;
260 // shouldn't happen
261 break;
262 }
263}
264
266 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
267
268 if (this->state_ != CalibrationState::INACTIVE && !(ctrl2.get() & CTRL2_CALS)) {
269 if (ctrl2.get() & CTRL2_CAL_ERR) {
270 this->set_calibration_failure_(true);
271 this->state_ = CalibrationState::INACTIVE;
272 ESP_LOGE(TAG, "Failed to calibrate sensor");
273 this->status_set_error(LOG_STR("Calibration Failed"));
274 return;
275 }
276
277 this->set_calibration_failure_(false);
278 this->state_ = CalibrationState::INACTIVE;
279
281 this->status_clear_error();
282
283 int32_t ocal = this->read_value_(OCAL1_B2_REG, 3);
284 ESP_LOGI(TAG, "New Offset: %" PRId32, ocal);
285 uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4);
286 float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL));
287 ESP_LOGI(TAG, "New Gain: %f", gcal_f);
288 }
289}
290
292 if (!this->status_comm_result(this->is_data_ready_(), nullptr)) {
293 ESP_LOGW(TAG, "No measurements ready!");
294 return;
295 }
296
297 // Get the most recent sample to publish
298 int32_t result = this->read_value_(ADCO_B2_REG, 3);
299
300 ESP_LOGD(TAG, "'%s': Got value %" PRId32, LOG_STR_ARG(this->get_log_name()), result);
301 this->publish_state(result);
302}
303
304bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; }
305
306} // namespace esphome::nau7802
BedjetMode mode
BedJet operating mode.
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:274
void status_clear_error()
Definition component.h:302
bool status_comm_result(bool ok)
Clears the warning when ok, else sets it with message (default "Communication failed"); returns ok.
void set_timeout(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a const char* name.
Definition component.cpp:96
const LogString * get_log_name() const
Get the name for a "%s" log argument (LOG_STR_ARG).
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len) const
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:37
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:164
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:28
This class is used to create I2CRegister objects that act as proxies to read/write internal registers...
Definition i2c.h:44
uint8_t get() const
returns the register value
Definition i2c.cpp:126
bool calibrate_(enum NAU7802CalibrationModes mode)
Definition nau7802.cpp:233
void write_value_(uint8_t start_reg, size_t size, int32_t value)
Definition nau7802.cpp:215
int32_t read_value_(uint8_t start_reg, size_t size)
Definition nau7802.cpp:223
void set_calibration_failure_(bool failed)
Definition nau7802.cpp:251
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:65
AlsGain501 gain
ESPHOME_LOG_TAG(TAG, "nau7802")
@ NAU7802_CALIBRATE_GAIN
Definition nau7802.h:46
uint16_t size
Definition helpers.cpp:34
constexpr int32_t sign_extend(uint32_t value)
Sign-extend the low BITS bits of value, e.g. sign_extend<24>(0xFFFFFE) == -2. Higher bits are ignored...
Definition helpers.h:1012
void HOT delay(uint32_t ms)
Definition hal.cpp:85
static void uint32_t