ESPHome 2026.5.0
Loading...
Searching...
No Matches
nau7802.cpp
Go to the documentation of this file.
1#include "nau7802.h"
2#include "esphome/core/log.h"
3#include "esphome/core/hal.h"
4
5namespace esphome::nau7802 {
6
7static const char *const TAG = "nau7802";
8
9// Only define what we need
10
11static const uint8_t READ_BIT = 0x01;
12
13static const uint8_t PU_CTRL_REG = 0x00;
14static const uint8_t PU_CTRL_REGISTER_RESET = 0x01;
15static const uint8_t PU_CTRL_POWERUP_DIGITAL = 0x02;
16static const uint8_t PU_CTRL_POWERUP_ANALOG = 0x04;
17static const uint8_t PU_CTRL_POWERUP_READY = 0x08;
18static const uint8_t PU_CTRL_CYCLE_START = 0x10;
19static const uint8_t PU_CTRL_CYCLE_READY = 0x20;
20static const uint8_t PU_CTRL_AVDD_EXTERNAL = 0x80;
21
22static const uint8_t CTRL1_REG = 0x01;
23static const uint8_t CTRL1_LDO_SHIFT = 3;
24static const uint8_t CTRL1_LDO_MASK = (0x7 << CTRL1_LDO_SHIFT);
25static const uint8_t CTRL1_GAIN_MASK = 0x7;
26
27static const uint8_t CTRL2_REG = 0x02;
28static const uint8_t CTRL2_CRS_SHIFT = 4;
29static const uint8_t CTRL2_CRS_MASK = (0x7 << CTRL2_CRS_SHIFT);
30static const uint8_t CTRL2_CALS = 0x04;
31static const uint8_t CTRL2_CAL_ERR = 0x08;
32static const uint8_t CTRL2_GAIN_CALIBRATION = 0x03;
33static const uint8_t CTRL2_CONFIG_MASK = 0xF0;
34
35static const uint8_t OCAL1_B2_REG = 0x03;
36static const uint8_t GCAL1_B3_REG = 0x06;
37static const uint8_t GCAL1_FRACTIONAL = 23;
38
39// only need the first data register for sequential read method
40static const uint8_t ADCO_B2_REG = 0x12;
41
42static const uint8_t ADC_REG = 0x15;
43static const uint8_t ADC_CHPS_DISABLE = 0x30;
44
45static const uint8_t PGA_REG = 0x1B;
46static const uint8_t PGA_LDOMODE_ESR = 0x40;
47
48static const uint8_t POWER_REG = 0x1C;
49static const uint8_t POWER_PGA_CAP_EN = 0x80;
50
51static const uint8_t DEVICE_REV = 0x1F;
52
54 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
55 uint8_t rev;
56
57 if (this->read_register(DEVICE_REV | READ_BIT, &rev, 1)) {
58 ESP_LOGE(TAG, "Failed I2C read during setup()");
59 this->mark_failed();
60 return;
61 }
62 ESP_LOGI(TAG, "Setting up NAU7802 Rev %d", rev);
63
64 // reset
65 pu_ctrl |= PU_CTRL_REGISTER_RESET;
66 delay(10);
67 pu_ctrl &= ~PU_CTRL_REGISTER_RESET;
68
69 // power up digital hw
70 pu_ctrl |= PU_CTRL_POWERUP_DIGITAL;
71
72 delay(1);
73 if (!(pu_ctrl.get() & PU_CTRL_POWERUP_READY)) {
74 ESP_LOGE(TAG, "Failed to reset sensor during setup()");
75 this->mark_failed();
76 return;
77 }
78
79 uint32_t gcal = (uint32_t) (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 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
128 return;
129 }
130 // Note these may differ from the values on the device if calbration has been run
131 ESP_LOGCONFIG(TAG,
132 " Offset Calibration: %" PRId32 "\n"
133 " Gain Calibration: %f",
135
136 std::string voltage = "unknown";
137 switch (this->ldo_) {
138 case NAU7802_LDO_2V4:
139 voltage = "2.4V";
140 break;
141 case NAU7802_LDO_2V7:
142 voltage = "2.7V";
143 break;
144 case NAU7802_LDO_3V0:
145 voltage = "3.0V";
146 break;
147 case NAU7802_LDO_3V3:
148 voltage = "3.3V";
149 break;
150 case NAU7802_LDO_3V6:
151 voltage = "3.6V";
152 break;
153 case NAU7802_LDO_3V9:
154 voltage = "3.9V";
155 break;
156 case NAU7802_LDO_4V2:
157 voltage = "4.2V";
158 break;
159 case NAU7802_LDO_4V5:
160 voltage = "4.5V";
161 break;
163 voltage = "External";
164 break;
165 }
166 ESP_LOGCONFIG(TAG, " LDO Voltage: %s", voltage.c_str());
167 int gain = 0;
168 switch (this->gain_) {
169 case NAU7802_GAIN_128:
170 gain = 128;
171 break;
172 case NAU7802_GAIN_64:
173 gain = 64;
174 break;
175 case NAU7802_GAIN_32:
176 gain = 32;
177 break;
178 case NAU7802_GAIN_16:
179 gain = 16;
180 break;
181 case NAU7802_GAIN_8:
182 gain = 8;
183 break;
184 case NAU7802_GAIN_4:
185 gain = 4;
186 break;
187 case NAU7802_GAIN_2:
188 gain = 2;
189 break;
190 case NAU7802_GAIN_1:
191 gain = 1;
192 break;
193 }
194 ESP_LOGCONFIG(TAG, " Gain: %dx", gain);
195 int sps = 0;
196 switch (this->sps_) {
197 case NAU7802_SPS_320:
198 sps = 320;
199 break;
200 case NAU7802_SPS_80:
201 sps = 80;
202 break;
203 case NAU7802_SPS_40:
204 sps = 40;
205 break;
206 case NAU7802_SPS_20:
207 sps = 20;
208 break;
209 case NAU7802_SPS_10:
210 sps = 10;
211 break;
212 }
213 ESP_LOGCONFIG(TAG, " Samples Per Second: %d", sps);
214 LOG_UPDATE_INTERVAL(this);
215}
216
217void NAU7802Sensor::write_value_(uint8_t start_reg, size_t size, int32_t value) {
218 uint8_t data[4];
219 for (size_t i = 0; i < size; i++) {
220 data[i] = 0xFF & (value >> (size - 1 - i) * 8);
221 }
222 this->write_register(start_reg, data, size);
223}
224
225int32_t NAU7802Sensor::read_value_(uint8_t start_reg, size_t size) {
226 uint8_t data[4];
227 this->read_register(start_reg, data, size);
228 int32_t result = 0;
229 for (size_t i = 0; i < size; i++) {
230 result |= data[i] << (size - 1 - i) * 8;
231 }
232 // extend sign bit
233 if (result & 0x800000 && size == 3) {
234 result |= 0xFF000000;
235 }
236 return result;
237}
238
240 // check if already calbrating
241 if (this->state_ != CalibrationState::INACTIVE) {
242 ESP_LOGW(TAG, "Calibration already in progress");
243 return false;
244 }
245
247
248 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
249 // clear calibraye registers
250 ctrl2 &= CTRL2_CONFIG_MASK;
251 // Calibrate
252 ctrl2 |= mode;
253 ctrl2 |= CTRL2_CALS;
254 return true;
255}
256
258 switch (this->state_) {
260 this->gain_calibration_failed_ = failed;
261 break;
263 this->offset_calibration_failed_ = failed;
264 break;
266 // shouldn't happen
267 break;
268 }
269}
270
272 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
273
274 if (this->state_ != CalibrationState::INACTIVE && !(ctrl2.get() & CTRL2_CALS)) {
275 if (ctrl2.get() & CTRL2_CAL_ERR) {
276 this->set_calibration_failure_(true);
277 this->state_ = CalibrationState::INACTIVE;
278 ESP_LOGE(TAG, "Failed to calibrate sensor");
279 this->status_set_error(LOG_STR("Calibration Failed"));
280 return;
281 }
282
283 this->set_calibration_failure_(false);
284 this->state_ = CalibrationState::INACTIVE;
285
287 this->status_clear_error();
288
289 int32_t ocal = this->read_value_(OCAL1_B2_REG, 3);
290 ESP_LOGI(TAG, "New Offset: %" PRId32, ocal);
291 uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4);
292 float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL));
293 ESP_LOGI(TAG, "New Gain: %f", gcal_f);
294 }
295}
296
298 if (!this->is_data_ready_()) {
299 ESP_LOGW(TAG, "No measurements ready!");
300 this->status_set_warning();
301 return;
302 }
303
304 this->status_clear_warning();
305
306 // Get the most recent sample to publish
307 int32_t result = this->read_value_(ADCO_B2_REG, 3);
308
309 ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), result);
310 this->publish_state(result);
311}
312
313bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; }
314
315} // namespace esphome::nau7802
BedjetMode mode
BedJet operating mode.
void mark_failed()
Mark this component as failed.
bool is_failed() const
Definition component.h:284
ESPDEPRECATED("Use const char* or uint32_t overload instead. Removed in 2026.7.0", "2026.1.0") void set_timeout(const std voi set_timeout)(const char *name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.h:510
void status_clear_error()
Definition component.h:312
void status_clear_warning()
Definition component.h:306
const StringRef & get_name() const
Definition entity_base.h:71
constexpr const char * c_str() const
Definition string_ref.h:73
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:34
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:152
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:25
This class is used to create I2CRegister objects that act as proxies to read/write internal registers...
Definition i2c.h:32
uint8_t get() const
returns the register value
Definition i2c.cpp:84
bool calibrate_(enum NAU7802CalibrationModes mode)
Definition nau7802.cpp:239
void write_value_(uint8_t start_reg, size_t size, int32_t value)
Definition nau7802.cpp:217
int32_t read_value_(uint8_t start_reg, size_t size)
Definition nau7802.cpp:225
void set_calibration_failure_(bool failed)
Definition nau7802.cpp:257
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:68
AlsGain501 gain
@ NAU7802_CALIBRATE_GAIN
Definition nau7802.h:47
uint16_t size
Definition helpers.cpp:25
void HOT delay(uint32_t ms)
Definition hal.cpp:82
static void uint32_t