ESPHome 2026.5.0-dev
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 {
6namespace nau7802 {
7
8static const char *const TAG = "nau7802";
9
10// Only define what we need
11
12static const uint8_t READ_BIT = 0x01;
13
14static const uint8_t PU_CTRL_REG = 0x00;
15static const uint8_t PU_CTRL_REGISTER_RESET = 0x01;
16static const uint8_t PU_CTRL_POWERUP_DIGITAL = 0x02;
17static const uint8_t PU_CTRL_POWERUP_ANALOG = 0x04;
18static const uint8_t PU_CTRL_POWERUP_READY = 0x08;
19static const uint8_t PU_CTRL_CYCLE_START = 0x10;
20static const uint8_t PU_CTRL_CYCLE_READY = 0x20;
21static const uint8_t PU_CTRL_AVDD_EXTERNAL = 0x80;
22
23static const uint8_t CTRL1_REG = 0x01;
24static const uint8_t CTRL1_LDO_SHIFT = 3;
25static const uint8_t CTRL1_LDO_MASK = (0x7 << CTRL1_LDO_SHIFT);
26static const uint8_t CTRL1_GAIN_MASK = 0x7;
27
28static const uint8_t CTRL2_REG = 0x02;
29static const uint8_t CTRL2_CRS_SHIFT = 4;
30static const uint8_t CTRL2_CRS_MASK = (0x7 << CTRL2_CRS_SHIFT);
31static const uint8_t CTRL2_CALS = 0x04;
32static const uint8_t CTRL2_CAL_ERR = 0x08;
33static const uint8_t CTRL2_GAIN_CALIBRATION = 0x03;
34static const uint8_t CTRL2_CONFIG_MASK = 0xF0;
35
36static const uint8_t OCAL1_B2_REG = 0x03;
37static const uint8_t GCAL1_B3_REG = 0x06;
38static const uint8_t GCAL1_FRACTIONAL = 23;
39
40// only need the first data register for sequential read method
41static const uint8_t ADCO_B2_REG = 0x12;
42
43static const uint8_t ADC_REG = 0x15;
44static const uint8_t ADC_CHPS_DISABLE = 0x30;
45
46static const uint8_t PGA_REG = 0x1B;
47static const uint8_t PGA_LDOMODE_ESR = 0x40;
48
49static const uint8_t POWER_REG = 0x1C;
50static const uint8_t POWER_PGA_CAP_EN = 0x80;
51
52static const uint8_t DEVICE_REV = 0x1F;
53
55 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
56 uint8_t rev;
57
58 if (this->read_register(DEVICE_REV | READ_BIT, &rev, 1)) {
59 ESP_LOGE(TAG, "Failed I2C read during setup()");
60 this->mark_failed();
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 ESP_LOGE(TAG, "Failed to reset sensor during setup()");
76 this->mark_failed();
77 return;
78 }
79
80 uint32_t gcal = (uint32_t) (round(this->gain_calibration_ * (1 << GCAL1_FRACTIONAL)));
81 this->write_value_(OCAL1_B2_REG, 3, this->offset_calibration_);
82 this->write_value_(GCAL1_B3_REG, 4, gcal);
83
84 // turn on AFE
85 pu_ctrl |= PU_CTRL_POWERUP_ANALOG;
86 this->set_timeout(600, [this]() { this->complete_setup_(); });
87}
88
90 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
91 i2c::I2CRegister ctrl1 = this->reg(CTRL1_REG);
92 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
93 pu_ctrl |= PU_CTRL_CYCLE_START;
94
95 // set gain
96 ctrl1 &= ~CTRL1_GAIN_MASK;
97 ctrl1 |= this->gain_;
98
99 // enable internal LDO
100 if (this->ldo_ != NAU7802_LDO_EXTERNAL) {
101 pu_ctrl |= PU_CTRL_AVDD_EXTERNAL;
102 ctrl1 &= ~CTRL1_LDO_MASK;
103 ctrl1 |= this->ldo_ << CTRL1_LDO_SHIFT;
104 }
105
106 // set sps
107 ctrl2 &= ~CTRL2_CRS_MASK;
108 ctrl2 |= this->sps_ << CTRL2_CRS_SHIFT;
109
110 // disable ADC chopper clock
111 i2c::I2CRegister adc_reg = this->reg(ADC_REG);
112 adc_reg |= ADC_CHPS_DISABLE;
113
114 // use low ESR caps
115 i2c::I2CRegister pga_reg = this->reg(PGA_REG);
116 pga_reg &= ~PGA_LDOMODE_ESR;
117
118 // PGA stabilizer cap on output
119 i2c::I2CRegister pwr_reg = this->reg(POWER_REG);
120 pwr_reg |= POWER_PGA_CAP_EN;
121}
122
124 LOG_SENSOR("", "NAU7802", this);
125 LOG_I2C_DEVICE(this);
126
127 if (this->is_failed()) {
128 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
129 return;
130 }
131 // Note these may differ from the values on the device if calbration has been run
132 ESP_LOGCONFIG(TAG,
133 " Offset Calibration: %" PRId32 "\n"
134 " Gain Calibration: %f",
136
137 std::string voltage = "unknown";
138 switch (this->ldo_) {
139 case NAU7802_LDO_2V4:
140 voltage = "2.4V";
141 break;
142 case NAU7802_LDO_2V7:
143 voltage = "2.7V";
144 break;
145 case NAU7802_LDO_3V0:
146 voltage = "3.0V";
147 break;
148 case NAU7802_LDO_3V3:
149 voltage = "3.3V";
150 break;
151 case NAU7802_LDO_3V6:
152 voltage = "3.6V";
153 break;
154 case NAU7802_LDO_3V9:
155 voltage = "3.9V";
156 break;
157 case NAU7802_LDO_4V2:
158 voltage = "4.2V";
159 break;
160 case NAU7802_LDO_4V5:
161 voltage = "4.5V";
162 break;
164 voltage = "External";
165 break;
166 }
167 ESP_LOGCONFIG(TAG, " LDO Voltage: %s", voltage.c_str());
168 int gain = 0;
169 switch (this->gain_) {
170 case NAU7802_GAIN_128:
171 gain = 128;
172 break;
173 case NAU7802_GAIN_64:
174 gain = 64;
175 break;
176 case NAU7802_GAIN_32:
177 gain = 32;
178 break;
179 case NAU7802_GAIN_16:
180 gain = 16;
181 break;
182 case NAU7802_GAIN_8:
183 gain = 8;
184 break;
185 case NAU7802_GAIN_4:
186 gain = 4;
187 break;
188 case NAU7802_GAIN_2:
189 gain = 2;
190 break;
191 case NAU7802_GAIN_1:
192 gain = 1;
193 break;
194 }
195 ESP_LOGCONFIG(TAG, " Gain: %dx", gain);
196 int sps = 0;
197 switch (this->sps_) {
198 case NAU7802_SPS_320:
199 sps = 320;
200 break;
201 case NAU7802_SPS_80:
202 sps = 80;
203 break;
204 case NAU7802_SPS_40:
205 sps = 40;
206 break;
207 case NAU7802_SPS_20:
208 sps = 20;
209 break;
210 case NAU7802_SPS_10:
211 sps = 10;
212 break;
213 }
214 ESP_LOGCONFIG(TAG, " Samples Per Second: %d", sps);
215 LOG_UPDATE_INTERVAL(this);
216}
217
218void NAU7802Sensor::write_value_(uint8_t start_reg, size_t size, int32_t value) {
219 uint8_t data[4];
220 for (size_t i = 0; i < size; i++) {
221 data[i] = 0xFF & (value >> (size - 1 - i) * 8);
222 }
223 this->write_register(start_reg, data, size);
224}
225
226int32_t NAU7802Sensor::read_value_(uint8_t start_reg, size_t size) {
227 uint8_t data[4];
228 this->read_register(start_reg, data, size);
229 int32_t result = 0;
230 for (size_t i = 0; i < size; i++) {
231 result |= data[i] << (size - 1 - i) * 8;
232 }
233 // extend sign bit
234 if (result & 0x800000 && size == 3) {
235 result |= 0xFF000000;
236 }
237 return result;
238}
239
241 // check if already calbrating
242 if (this->state_ != CalibrationState::INACTIVE) {
243 ESP_LOGW(TAG, "Calibration already in progress");
244 return false;
245 }
246
248
249 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
250 // clear calibraye registers
251 ctrl2 &= CTRL2_CONFIG_MASK;
252 // Calibrate
253 ctrl2 |= mode;
254 ctrl2 |= CTRL2_CALS;
255 return true;
256}
257
259 switch (this->state_) {
261 this->gain_calibration_failed_ = failed;
262 break;
264 this->offset_calibration_failed_ = failed;
265 break;
267 // shouldn't happen
268 break;
269 }
270}
271
273 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
274
275 if (this->state_ != CalibrationState::INACTIVE && !(ctrl2.get() & CTRL2_CALS)) {
276 if (ctrl2.get() & CTRL2_CAL_ERR) {
277 this->set_calibration_failure_(true);
278 this->state_ = CalibrationState::INACTIVE;
279 ESP_LOGE(TAG, "Failed to calibrate sensor");
280 this->status_set_error(LOG_STR("Calibration Failed"));
281 return;
282 }
283
284 this->set_calibration_failure_(false);
285 this->state_ = CalibrationState::INACTIVE;
286
288 this->status_clear_error();
289
290 int32_t ocal = this->read_value_(OCAL1_B2_REG, 3);
291 ESP_LOGI(TAG, "New Offset: %" PRId32, ocal);
292 uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4);
293 float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL));
294 ESP_LOGI(TAG, "New Gain: %f", gcal_f);
295 }
296}
297
299 if (!this->is_data_ready_()) {
300 ESP_LOGW(TAG, "No measurements ready!");
301 this->status_set_warning();
302 return;
303 }
304
305 this->status_clear_warning();
306
307 // Get the most recent sample to publish
308 int32_t result = this->read_value_(ADCO_B2_REG, 3);
309
310 ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), result);
311 this->publish_state(result);
312}
313
314bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; }
315
316} // namespace nau7802
317} // namespace esphome
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:240
void write_value_(uint8_t start_reg, size_t size, int32_t value)
Definition nau7802.cpp:218
int32_t read_value_(uint8_t start_reg, size_t size)
Definition nau7802.cpp:226
void set_calibration_failure_(bool failed)
Definition nau7802.cpp:258
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:48
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
uint16_t size
Definition helpers.cpp:25
void HOT delay(uint32_t ms)
Definition core.cpp:28
static void uint32_t