ESPHome 2025.9.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 auto f = std::bind(&NAU7802Sensor::complete_setup_, this);
87 this->set_timeout(600, f);
88}
89
91 i2c::I2CRegister pu_ctrl = this->reg(PU_CTRL_REG);
92 i2c::I2CRegister ctrl1 = this->reg(CTRL1_REG);
93 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
94 pu_ctrl |= PU_CTRL_CYCLE_START;
95
96 // set gain
97 ctrl1 &= ~CTRL1_GAIN_MASK;
98 ctrl1 |= this->gain_;
99
100 // enable internal LDO
101 if (this->ldo_ != NAU7802_LDO_EXTERNAL) {
102 pu_ctrl |= PU_CTRL_AVDD_EXTERNAL;
103 ctrl1 &= ~CTRL1_LDO_MASK;
104 ctrl1 |= this->ldo_ << CTRL1_LDO_SHIFT;
105 }
106
107 // set sps
108 ctrl2 &= ~CTRL2_CRS_MASK;
109 ctrl2 |= this->sps_ << CTRL2_CRS_SHIFT;
110
111 // disable ADC chopper clock
112 i2c::I2CRegister adc_reg = this->reg(ADC_REG);
113 adc_reg |= ADC_CHPS_DISABLE;
114
115 // use low ESR caps
116 i2c::I2CRegister pga_reg = this->reg(PGA_REG);
117 pga_reg &= ~PGA_LDOMODE_ESR;
118
119 // PGA stabilizer cap on output
120 i2c::I2CRegister pwr_reg = this->reg(POWER_REG);
121 pwr_reg |= POWER_PGA_CAP_EN;
122}
123
125 LOG_SENSOR("", "NAU7802", this);
126 LOG_I2C_DEVICE(this);
127
128 if (this->is_failed()) {
129 ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL_FOR, this->get_name().c_str());
130 return;
131 }
132 // Note these may differ from the values on the device if calbration has been run
133 ESP_LOGCONFIG(TAG,
134 " Offset Calibration: %s\n"
135 " Gain Calibration: %f",
136 to_string(this->offset_calibration_).c_str(), this->gain_calibration_);
137
138 std::string voltage = "unknown";
139 switch (this->ldo_) {
140 case NAU7802_LDO_2V4:
141 voltage = "2.4V";
142 break;
143 case NAU7802_LDO_2V7:
144 voltage = "2.7V";
145 break;
146 case NAU7802_LDO_3V0:
147 voltage = "3.0V";
148 break;
149 case NAU7802_LDO_3V3:
150 voltage = "3.3V";
151 break;
152 case NAU7802_LDO_3V6:
153 voltage = "3.6V";
154 break;
155 case NAU7802_LDO_3V9:
156 voltage = "3.9V";
157 break;
158 case NAU7802_LDO_4V2:
159 voltage = "4.2V";
160 break;
161 case NAU7802_LDO_4V5:
162 voltage = "4.5V";
163 break;
165 voltage = "External";
166 break;
167 }
168 ESP_LOGCONFIG(TAG, " LDO Voltage: %s", voltage.c_str());
169 int gain = 0;
170 switch (this->gain_) {
171 case NAU7802_GAIN_128:
172 gain = 128;
173 break;
174 case NAU7802_GAIN_64:
175 gain = 64;
176 break;
177 case NAU7802_GAIN_32:
178 gain = 32;
179 break;
180 case NAU7802_GAIN_16:
181 gain = 16;
182 break;
183 case NAU7802_GAIN_8:
184 gain = 8;
185 break;
186 case NAU7802_GAIN_4:
187 gain = 4;
188 break;
189 case NAU7802_GAIN_2:
190 gain = 2;
191 break;
192 case NAU7802_GAIN_1:
193 gain = 1;
194 break;
195 }
196 ESP_LOGCONFIG(TAG, " Gain: %dx", gain);
197 int sps = 0;
198 switch (this->sps_) {
199 case NAU7802_SPS_320:
200 sps = 320;
201 break;
202 case NAU7802_SPS_80:
203 sps = 80;
204 break;
205 case NAU7802_SPS_40:
206 sps = 40;
207 break;
208 case NAU7802_SPS_20:
209 sps = 20;
210 break;
211 case NAU7802_SPS_10:
212 sps = 10;
213 break;
214 }
215 ESP_LOGCONFIG(TAG, " Samples Per Second: %d", sps);
216 LOG_UPDATE_INTERVAL(this);
217}
218
219void NAU7802Sensor::write_value_(uint8_t start_reg, size_t size, int32_t value) {
220 uint8_t data[4];
221 for (int i = 0; i < size; i++) {
222 data[i] = 0xFF & (value >> (size - 1 - i) * 8);
223 }
224 this->write_register(start_reg, data, size);
225}
226
227int32_t NAU7802Sensor::read_value_(uint8_t start_reg, size_t size) {
228 uint8_t data[4];
229 this->read_register(start_reg, data, size);
230 int32_t result = 0;
231 for (int i = 0; i < size; i++) {
232 result |= data[i] << (size - 1 - i) * 8;
233 }
234 // extend sign bit
235 if (result & 0x800000 && size == 3) {
236 result |= 0xFF000000;
237 }
238 return result;
239}
240
242 // check if already calbrating
243 if (this->state_ != CalibrationState::INACTIVE) {
244 ESP_LOGW(TAG, "Calibration already in progress");
245 return false;
246 }
247
249
250 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
251 // clear calibraye registers
252 ctrl2 &= CTRL2_CONFIG_MASK;
253 // Calibrate
254 ctrl2 |= mode;
255 ctrl2 |= CTRL2_CALS;
256 return true;
257}
258
260 switch (this->state_) {
262 this->gain_calibration_failed_ = failed;
263 break;
265 this->offset_calibration_failed_ = failed;
266 break;
268 // shouldn't happen
269 break;
270 }
271}
272
274 i2c::I2CRegister ctrl2 = this->reg(CTRL2_REG);
275
276 if (this->state_ != CalibrationState::INACTIVE && !(ctrl2.get() & CTRL2_CALS)) {
277 if (ctrl2.get() & CTRL2_CAL_ERR) {
278 this->set_calibration_failure_(true);
279 this->state_ = CalibrationState::INACTIVE;
280 ESP_LOGE(TAG, "Failed to calibrate sensor");
281 this->status_set_error("Calibration Failed");
282 return;
283 }
284
285 this->set_calibration_failure_(false);
286 this->state_ = CalibrationState::INACTIVE;
287
289 this->status_clear_error();
290
291 int32_t ocal = this->read_value_(OCAL1_B2_REG, 3);
292 ESP_LOGI(TAG, "New Offset: %s", to_string(ocal).c_str());
293 uint32_t gcal = this->read_value_(GCAL1_B3_REG, 4);
294 float gcal_f = ((float) gcal / (float) (1 << GCAL1_FRACTIONAL));
295 ESP_LOGI(TAG, "New Gain: %f", gcal_f);
296 }
297}
298
300
302 if (!this->is_data_ready_()) {
303 ESP_LOGW(TAG, "No measurements ready!");
304 this->status_set_warning();
305 return;
306 }
307
308 this->status_clear_warning();
309
310 // Get the most recent sample to publish
311 int32_t result = this->read_value_(ADCO_B2_REG, 3);
312
313 ESP_LOGD(TAG, "'%s': Got value %" PRId32, this->name_.c_str(), result);
314 this->publish_state(result);
315}
316
317bool NAU7802Sensor::is_data_ready_() { return this->reg(PU_CTRL_REG).get() & PU_CTRL_CYCLE_READY; }
318
319} // namespace nau7802
320} // 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=nullptr)
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.
void status_set_error(const char *message=nullptr)
const StringRef & get_name() const
constexpr const char * c_str() const
Definition string_ref.h:69
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:241
float get_setup_priority() const override
Definition nau7802.cpp:299
void write_value_(uint8_t start_reg, size_t size, int32_t value)
Definition nau7802.cpp:219
int32_t read_value_(uint8_t start_reg, size_t size)
Definition nau7802.cpp:227
void set_calibration_failure_(bool failed)
Definition nau7802.cpp:259
void publish_state(float state)
Publish a new state to the front-end.
Definition sensor.cpp:45
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:50
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
void IRAM_ATTR HOT delay(uint32_t ms)
Definition core.cpp:29