ESPHome 2025.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 {
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 ESP_LOGCONFIG(TAG, "Setting up NAU7802 '%s'...", this->name_.c_str());
57 uint8_t rev;
58
59 if (this->read_register(DEVICE_REV | READ_BIT, &rev, 1)) {
60 ESP_LOGE(TAG, "Failed I2C read during setup()");
61 this->mark_failed();
62 return;
63 }
64 ESP_LOGI(TAG, "Setting up NAU7802 Rev %d", rev);
65
66 // reset
67 pu_ctrl |= PU_CTRL_REGISTER_RESET;
68 delay(10);
69 pu_ctrl &= ~PU_CTRL_REGISTER_RESET;
70
71 // power up digital hw
72 pu_ctrl |= PU_CTRL_POWERUP_DIGITAL;
73
74 delay(1);
75 if (!(pu_ctrl.get() & PU_CTRL_POWERUP_READY)) {
76 ESP_LOGE(TAG, "Failed to reset sensor during setup()");
77 this->mark_failed();
78 return;
79 }
80
81 uint32_t gcal = (uint32_t) (round(this->gain_calibration_ * (1 << GCAL1_FRACTIONAL)));
82 this->write_value_(OCAL1_B2_REG, 3, this->offset_calibration_);
83 this->write_value_(GCAL1_B3_REG, 4, gcal);
84
85 // turn on AFE
86 pu_ctrl |= PU_CTRL_POWERUP_ANALOG;
87 auto f = std::bind(&NAU7802Sensor::complete_setup_, this);
88 this->set_timeout(600, f);
89}
90
92 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
93 i2c::I2CRegister ctrl1 = this->reg(CTRL1_REG);
94 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
95 pu_ctrl |= PU_CTRL_CYCLE_START;
96
97 // set gain
98 ctrl1 &= ~CTRL1_GAIN_MASK;
99 ctrl1 |= this->gain_;
100
101 // enable internal LDO
102 if (this->ldo_ != NAU7802_LDO_EXTERNAL) {
103 pu_ctrl |= PU_CTRL_AVDD_EXTERNAL;
104 ctrl1 &= ~CTRL1_LDO_MASK;
105 ctrl1 |= this->ldo_ << CTRL1_LDO_SHIFT;
106 }
107
108 // set sps
109 ctrl2 &= ~CTRL2_CRS_MASK;
110 ctrl2 |= this->sps_ << CTRL2_CRS_SHIFT;
111
112 // disable ADC chopper clock
113 i2c::I2CRegister adc_reg = this->reg(ADC_REG);
114 adc_reg |= ADC_CHPS_DISABLE;
115
116 // use low ESR caps
117 i2c::I2CRegister pga_reg = this->reg(PGA_REG);
118 pga_reg &= ~PGA_LDOMODE_ESR;
119
120 // PGA stabilizer cap on output
121 i2c::I2CRegister pwr_reg = this->reg(POWER_REG);
122 pwr_reg |= POWER_PGA_CAP_EN;
123}
124
126 LOG_SENSOR("", "NAU7802", this);
127 LOG_I2C_DEVICE(this);
128
129 if (this->is_failed()) {
130 ESP_LOGE(TAG, "Communication with NAU7802 failed earlier, during setup");
131 return;
132 }
133 // Note these may differ from the values on the device if calbration has been run
134 ESP_LOGCONFIG(TAG, " Offset Calibration: %s", to_string(this->offset_calibration_).c_str());
135 ESP_LOGCONFIG(TAG, " Gain Calibration: %f", this->gain_calibration_);
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 (int 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 (int 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("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: %s", to_string(ocal).c_str());
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
301 if (!this->is_data_ready_()) {
302 ESP_LOGW(TAG, "No measurements ready!");
303 this->status_set_warning();
304 return;
305 }
306
307 this->status_clear_warning();
308
309 // Get the most recent sample to publish
310 int32_t result = this->read_value_(ADCO_B2_REG, 3);
311
312 ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), result);
313 this->publish_state(result);
314}
315
316bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; }
317
318} // namespace nau7802
319} // namespace esphome
BedjetMode mode
BedJet operating mode.
virtual void mark_failed()
Mark this component as failed.
bool is_failed() const
void status_set_warning(const char *message="unspecified")
void status_set_error(const char *message="unspecified")
void status_clear_warning()
void set_timeout(const std::string &name, uint32_t timeout, std::function< void()> &&f)
Set a timeout function with a unique name.
Definition component.cpp:72
constexpr const char * c_str() const
Definition string_ref.h:68
ErrorCode write_register(uint8_t a_register, const uint8_t *data, size_t len, bool stop=true)
writes an array of bytes to a specific register in the I²C device
Definition i2c.cpp:25
I2CRegister reg(uint8_t a_register)
calls the I2CRegister constructor
Definition i2c.h:153
ErrorCode read_register(uint8_t a_register, uint8_t *data, size_t len, bool stop=true)
reads an array of bytes from a specific register in the I²C device
Definition i2c.cpp:10
This class is used to create I2CRegister objects that act as proxies to read/write internal registers...
Definition i2c.h:33
uint8_t get() const
returns the register value
Definition i2c.cpp:75
bool calibrate_(enum NAU7802CalibrationModes mode)
Definition nau7802.cpp:240
float get_setup_priority() const override
Definition nau7802.cpp:298
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:39
AlsGain501 gain
@ NAU7802_CALIBRATE_GAIN
Definition nau7802.h:48
const float DATA
For components that import data from directly connected sensors like DHT.
Definition component.cpp:19
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string to_string(int value)
Definition helpers.cpp:82
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:28