Open
Description
Header
// nau7802.h
#ifndef NAU7802_H
#define NAU7802_H
#include "pico/stdlib.h"
#include "hardware/i2c.h"
// Register Map
#define NAU7802_PU_CTRL 0x00
#define NAU7802_CTRL1 0x01
#define NAU7802_CTRL2 0x02
#define NAU7802_OCAL1_B2 0x03
#define NAU7802_OCAL1_B1 0x04
#define NAU7802_OCAL1_B0 0x05
#define NAU7802_GCAL1_B3 0x06
#define NAU7802_GCAL1_B2 0x07
#define NAU7802_GCAL1_B1 0x08
#define NAU7802_GCAL1_B0 0x09
#define NAU7802_OCAL2_B2 0x0A
#define NAU7802_OCAL2_B1 0x0B
#define NAU7802_OCAL2_B0 0x0C
#define NAU7802_GCAL2_B3 0x0D
#define NAU7802_GCAL2_B2 0x0E
#define NAU7802_GCAL2_B1 0x0F
#define NAU7802_GCAL2_B0 0x10
#define NAU7802_I2C_CONTROL 0x11
#define NAU7802_ADCO_B2 0x12
#define NAU7802_ADCO_B1 0x13
#define NAU7802_ADCO_B0 0x14
#define NAU7802_ADC 0x15
#define NAU7802_OTP_B1 0x16
#define NAU7802_OTP_B0 0x17
#define NAU7802_PGA 0x1B
#define NAU7802_PGA_PWR 0x1C
#define NAU7802_DEVICE_REV 0x1F
// PU_CTRL Bits
#define NAU7802_PU_CTRL_RR 0
#define NAU7802_PU_CTRL_PUD 1
#define NAU7802_PU_CTRL_PUA 2
#define NAU7802_PU_CTRL_PUR 3
#define NAU7802_PU_CTRL_CS 4
#define NAU7802_PU_CTRL_CR 5
#define NAU7802_PU_CTRL_OSCS 6
#define NAU7802_PU_CTRL_AVDDS 7
// CTRL1 Bits
#define NAU7802_CTRL1_GAIN 2
#define NAU7802_CTRL1_VLDO 5
#define NAU7802_CTRL1_DRDY_SEL 6
#define NAU7802_CTRL1_CRP 7
// CTRL2 Bits
#define NAU7802_CTRL2_CALMOD 0
#define NAU7802_CTRL2_CALS 2
#define NAU7802_CTRL2_CAL_ERROR 3
#define NAU7802_CTRL2_CRS 4
#define NAU7802_CTRL2_CHS 7
// PGA Bits
#define NAU7802_PGA_CHP_DIS 0
#define NAU7802_PGA_INV 3
#define NAU7802_PGA_BYPASS_EN 4
#define NAU7802_PGA_OUT_EN 5
#define NAU7802_PGA_LDOMODE 6
#define NAU7802_PGA_RD_OTP_SEL 7
// PGA PWR Bits
#define NAU7802_PGA_PWR_PGA_CURR 0
#define NAU7802_PGA_PWR_ADC_CURR 2
#define NAU7802_PGA_PWR_MSTR_BIAS_CURR 4
#define NAU7802_PGA_PWR_PGA_CAP_EN 7
// LDO Values
#define NAU7802_LDO_2V4 0b111
#define NAU7802_LDO_2V7 0b110
#define NAU7802_LDO_3V0 0b101
#define NAU7802_LDO_3V3 0b100
#define NAU7802_LDO_3V6 0b011
#define NAU7802_LDO_3V9 0b010
#define NAU7802_LDO_4V2 0b001
#define NAU7802_LDO_4V5 0b000
// Gain Values
#define NAU7802_GAIN_128 0b111
#define NAU7802_GAIN_64 0b110
#define NAU7802_GAIN_32 0b101
#define NAU7802_GAIN_16 0b100
#define NAU7802_GAIN_8 0b011
#define NAU7802_GAIN_4 0b010
#define NAU7802_GAIN_2 0b001
#define NAU7802_GAIN_1 0b000
// Samples per second
#define NAU7802_SPS_320 0b111
#define NAU7802_SPS_80 0b011
#define NAU7802_SPS_40 0b010
#define NAU7802_SPS_20 0b001
#define NAU7802_SPS_10 0b000
// Channels
#define NAU7802_CHANNEL_1 0
#define NAU7802_CHANNEL_2 1
// Calibration Status
#define NAU7802_CAL_SUCCESS 0
#define NAU7802_CAL_IN_PROGRESS 1
#define NAU7802_CAL_FAILURE 2
// Calibration Mode
#define NAU7802_CALMOD_INTERNAL 0
#define NAU7802_CALMOD_OFFSET 2
#define NAU7802_CALMOD_GAIN 3
typedef struct {
i2c_inst_t* i2c;
uint8_t address;
int32_t zero_offset;
float calibration_factor;
uint32_t ldo_ramp_delay;
} NAU7802;
// Function prototypes
void nau7802_init(NAU7802* dev, i2c_inst_t* i2c, uint8_t address);
bool nau7802_begin(NAU7802* dev, bool initialize);
bool nau7802_is_connected(NAU7802* dev);
bool nau7802_available(NAU7802* dev);
int32_t nau7802_get_reading(NAU7802* dev);
int32_t nau7802_get_average(NAU7802* dev, uint8_t average_amount, uint32_t timeout_ms);
void nau7802_calculate_zero_offset(NAU7802* dev, uint8_t average_amount, uint32_t timeout_ms);
void nau7802_set_zero_offset(NAU7802* dev, int32_t new_zero_offset);
int32_t nau7802_get_zero_offset(NAU7802* dev);
void nau7802_calculate_calibration_factor(NAU7802* dev, float weight_on_scale, uint8_t average_amount, uint32_t timeout_ms);
void nau7802_set_calibration_factor(NAU7802* dev, float new_cal_factor);
float nau7802_get_calibration_factor(NAU7802* dev);
float nau7802_get_weight(NAU7802* dev, bool allow_negative_weights, uint8_t samples_to_take, uint32_t timeout_ms);
bool nau7802_set_gain(NAU7802* dev, uint8_t gain_value);
bool nau7802_set_ldo(NAU7802* dev, uint8_t ldo_value);
void nau7802_set_ldo_ramp_delay(NAU7802* dev, uint32_t delay);
uint32_t nau7802_get_ldo_ramp_delay(NAU7802* dev);
bool nau7802_set_sample_rate(NAU7802* dev, uint8_t rate);
bool nau7802_set_channel(NAU7802* dev, uint8_t channel_number);
bool nau7802_calibrate_afe(NAU7802* dev, uint8_t mode);
void nau7802_begin_calibrate_afe(NAU7802* dev, uint8_t mode);
bool nau7802_wait_for_calibrate_afe(NAU7802* dev, uint32_t timeout_ms);
uint8_t nau7802_cal_afe_status(NAU7802* dev);
bool nau7802_reset(NAU7802* dev);
bool nau7802_power_up(NAU7802* dev);
bool nau7802_power_down(NAU7802* dev);
bool nau7802_set_int_polarity_high(NAU7802* dev);
bool nau7802_set_int_polarity_low(NAU7802* dev);
uint8_t nau7802_get_revision_code(NAU7802* dev);
bool nau7802_set_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address);
bool nau7802_clear_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address);
bool nau7802_get_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address);
uint8_t nau7802_get_register(NAU7802* dev, uint8_t register_address);
bool nau7802_set_register(NAU7802* dev, uint8_t register_address, uint8_t value);
int32_t nau7802_get_24bit_register(NAU7802* dev, uint8_t register_address);
bool nau7802_set_24bit_register(NAU7802* dev, uint8_t register_address, int32_t value);
uint32_t nau7802_get_32bit_register(NAU7802* dev, uint8_t register_address);
bool nau7802_set_32bit_register(NAU7802* dev, uint8_t register_address, uint32_t value);
int32_t nau7802_get_channel1_offset(NAU7802* dev);
bool nau7802_set_channel1_offset(NAU7802* dev, int32_t value);
uint32_t nau7802_get_channel1_gain(NAU7802* dev);
bool nau7802_set_channel1_gain(NAU7802* dev, uint32_t value);
#endif // NAU7802_H
Source
// nau7802.c
#include "nau7802.h"
#include <string.h>
void nau7802_init(NAU7802* dev, i2c_inst_t* i2c, uint8_t address) {
dev->i2c = i2c;
dev->address = address;
dev->zero_offset = 0;
dev->calibration_factor = 1.0f;
dev->ldo_ramp_delay = 250;
}
bool nau7802_begin(NAU7802* dev, bool initialize) {
// Check if the device ack's over I2C
if (!nau7802_is_connected(dev)) {
// Try one more time
if (!nau7802_is_connected(dev)) {
return false;
}
}
bool result = true;
if (initialize) {
result &= nau7802_reset(dev);
result &= nau7802_power_up(dev);
result &= nau7802_set_ldo(dev, NAU7802_LDO_3V3);
result &= nau7802_set_gain(dev, NAU7802_GAIN_128);
result &= nau7802_set_sample_rate(dev, NAU7802_SPS_80);
// Turn off CLK_CHP
uint8_t adc = nau7802_get_register(dev, NAU7802_ADC);
adc |= 0x30;
result &= nau7802_set_register(dev, NAU7802_ADC, adc);
result &= nau7802_set_bit(dev, NAU7802_PGA_PWR_PGA_CAP_EN, NAU7802_PGA_PWR);
result &= nau7802_clear_bit(dev, NAU7802_PGA_LDOMODE, NAU7802_PGA);
sleep_ms(dev->ldo_ramp_delay);
nau7802_get_weight(dev, true, 10, 1000);
result &= nau7802_calibrate_afe(dev, NAU7802_CALMOD_INTERNAL);
}
return result;
}
bool nau7802_is_connected(NAU7802* dev) {
uint8_t dummy;
int ret = i2c_read_blocking(dev->i2c, dev->address, &dummy, 1, false);
return ret != PICO_ERROR_GENERIC;
}
bool nau7802_available(NAU7802* dev) {
return nau7802_get_bit(dev, NAU7802_PU_CTRL_CR, NAU7802_PU_CTRL);
}
bool nau7802_calibrate_afe(NAU7802* dev, uint8_t mode) {
nau7802_begin_calibrate_afe(dev, mode);
return nau7802_wait_for_calibrate_afe(dev, 1000);
}
void nau7802_begin_calibrate_afe(NAU7802* dev, uint8_t mode) {
uint8_t value = nau7802_get_register(dev, NAU7802_CTRL2);
value &= 0xFC; // Clear CALMOD bits
uint8_t cal_mode = mode & 0x03; // Limit mode to 2 bits
value |= cal_mode; // Set the mode
nau7802_set_register(dev, NAU7802_CTRL2, value);
nau7802_set_bit(dev, NAU7802_CTRL2_CALS, NAU7802_CTRL2);
}
uint8_t nau7802_cal_afe_status(NAU7802* dev) {
if (nau7802_get_bit(dev, NAU7802_CTRL2_CALS, NAU7802_CTRL2)) {
return NAU7802_CAL_IN_PROGRESS;
}
if (nau7802_get_bit(dev, NAU7802_CTRL2_CAL_ERROR, NAU7802_CTRL2)) {
return NAU7802_CAL_FAILURE;
}
return NAU7802_CAL_SUCCESS;
}
bool nau7802_wait_for_calibrate_afe(NAU7802* dev, uint32_t timeout_ms) {
uint32_t start_time = to_ms_since_boot(get_absolute_time());
uint8_t cal_ready;
while ((cal_ready = nau7802_cal_afe_status(dev)) == NAU7802_CAL_IN_PROGRESS) {
if (timeout_ms > 0 && (to_ms_since_boot(get_absolute_time()) - start_time > timeout_ms) {
break;
}
sleep_ms(1);
}
return cal_ready == NAU7802_CAL_SUCCESS;
}
bool nau7802_set_sample_rate(NAU7802* dev, uint8_t rate) {
if (rate > 0b111) rate = 0b111;
uint8_t value = nau7802_get_register(dev, NAU7802_CTRL2);
value &= 0b10001111; // Clear CRS bits
value |= rate << 4; // Mask in new CRS bits
return nau7802_set_register(dev, NAU7802_CTRL2, value);
}
bool nau7802_set_channel(NAU7802* dev, uint8_t channel_number) {
if (channel_number == NAU7802_CHANNEL_1) {
return nau7802_clear_bit(dev, NAU7802_CTRL2_CHS, NAU7802_CTRL2);
} else {
return nau7802_set_bit(dev, NAU7802_CTRL2_CHS, NAU7802_CTRL2);
}
}
bool nau7802_power_up(NAU7802* dev) {
nau7802_set_bit(dev, NAU7802_PU_CTRL_PUD, NAU7802_PU_CTRL);
nau7802_set_bit(dev, NAU7802_PU_CTRL_PUA, NAU7802_PU_CTRL);
// Wait for Power Up bit to be set
uint8_t counter = 0;
while (true) {
if (nau7802_get_bit(dev, NAU7802_PU_CTRL_PUR, NAU7802_PU_CTRL)) {
break;
}
sleep_ms(1);
if (counter++ > 100) {
return false;
}
}
return nau7802_set_bit(dev, NAU7802_PU_CTRL_CS, NAU7802_PU_CTRL);
}
bool nau7802_power_down(NAU7802* dev) {
nau7802_clear_bit(dev, NAU7802_PU_CTRL_PUD, NAU7802_PU_CTRL);
return nau7802_clear_bit(dev, NAU7802_PU_CTRL_PUA, NAU7802_PU_CTRL);
}
bool nau7802_reset(NAU7802* dev) {
nau7802_set_bit(dev, NAU7802_PU_CTRL_RR, NAU7802_PU_CTRL);
sleep_ms(1);
return nau7802_clear_bit(dev, NAU7802_PU_CTRL_RR, NAU7802_PU_CTRL);
}
bool nau7802_set_ldo(NAU7802* dev, uint8_t ldo_value) {
if (ldo_value > 0b111) ldo_value = 0b111;
uint8_t value = nau7802_get_register(dev, NAU7802_CTRL1);
value &= 0b11000111; // Clear LDO bits
value |= ldo_value << 3; // Mask in new LDO bits
nau7802_set_register(dev, NAU7802_CTRL1, value);
return nau7802_set_bit(dev, NAU7802_PU_CTRL_AVDDS, NAU7802_PU_CTRL);
}
void nau7802_set_ldo_ramp_delay(NAU7802* dev, uint32_t delay) {
dev->ldo_ramp_delay = delay;
}
uint32_t nau7802_get_ldo_ramp_delay(NAU7802* dev) {
return dev->ldo_ramp_delay;
}
bool nau7802_set_gain(NAU7802* dev, uint8_t gain_value) {
if (gain_value > 0b111) gain_value = 0b111;
uint8_t value = nau7802_get_register(dev, NAU7802_CTRL1);
value &= 0b11111000; // Clear gain bits
value |= gain_value; // Mask in new bits
return nau7802_set_register(dev, NAU7802_CTRL1, value);
}
uint8_t nau7802_get_revision_code(NAU7802* dev) {
uint8_t revision_code = nau7802_get_register(dev, NAU7802_DEVICE_REV);
return revision_code & 0x0F;
}
int32_t nau7802_get_reading(NAU7802* dev) {
return nau7802_get_24bit_register(dev, NAU7802_ADCO_B2);
}
int32_t nau7802_get_average(NAU7802* dev, uint8_t average_amount, uint32_t timeout_ms) {
int32_t total = 0;
uint8_t samples_acquired = 0;
uint32_t start_time = to_ms_since_boot(get_absolute_time());
while (true) {
if (nau7802_available(dev)) {
total += nau7802_get_reading(dev);
if (++samples_acquired == average_amount) {
break;
}
}
if (to_ms_since_boot(get_absolute_time()) - start_time > timeout_ms) {
return 0;
}
sleep_ms(1);
}
total /= average_amount;
return total;
}
void nau7802_calculate_zero_offset(NAU7802* dev, uint8_t average_amount, uint32_t timeout_ms) {
nau7802_set_zero_offset(dev, nau7802_get_average(dev, average_amount, timeout_ms));
}
void nau7802_set_zero_offset(NAU7802* dev, int32_t new_zero_offset) {
dev->zero_offset = new_zero_offset;
}
int32_t nau7802_get_zero_offset(NAU7802* dev) {
return dev->zero_offset;
}
void nau7802_calculate_calibration_factor(NAU7802* dev, float weight_on_scale, uint8_t average_amount, uint32_t timeout_ms) {
int32_t on_scale = nau7802_get_average(dev, average_amount, timeout_ms);
float new_cal_factor = ((float)(on_scale - dev->zero_offset)) / weight_on_scale;
nau7802_set_calibration_factor(dev, new_cal_factor);
}
void nau7802_set_calibration_factor(NAU7802* dev, float new_cal_factor) {
dev->calibration_factor = new_cal_factor;
}
float nau7802_get_calibration_factor(NAU7802* dev) {
return dev->calibration_factor;
}
float nau7802_get_weight(NAU7802* dev, bool allow_negative_weights, uint8_t samples_to_take, uint32_t timeout_ms) {
int32_t on_scale = nau7802_get_average(dev, samples_to_take, timeout_ms);
if (!allow_negative_weights) {
if (on_scale < dev->zero_offset) {
on_scale = dev->zero_offset;
}
}
float weight = ((float)(on_scale - dev->zero_offset)) / dev->calibration_factor;
return weight;
}
bool nau7802_set_int_polarity_high(NAU7802* dev) {
return nau7802_clear_bit(dev, NAU7802_CTRL1_CRP, NAU7802_CTRL1);
}
bool nau7802_set_int_polarity_low(NAU7802* dev) {
return nau7802_set_bit(dev, NAU7802_CTRL1_CRP, NAU7802_CTRL1);
}
bool nau7802_set_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address) {
uint8_t value = nau7802_get_register(dev, register_address);
value |= (1 << bit_number);
return nau7802_set_register(dev, register_address, value);
}
bool nau7802_clear_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address) {
uint8_t value = nau7802_get_register(dev, register_address);
value &= ~(1 << bit_number);
return nau7802_set_register(dev, register_address, value);
}
bool nau7802_get_bit(NAU7802* dev, uint8_t bit_number, uint8_t register_address) {
uint8_t value = nau7802_get_register(dev, register_address);
value &= (1 << bit_number);
return value;
}
uint8_t nau7802_get_register(NAU7802* dev, uint8_t register_address) {
uint8_t value;
i2c_write_blocking(dev->i2c, dev->address, ®ister_address, 1, true);
i2c_read_blocking(dev->i2c, dev->address, &value, 1, false);
return value;
}
bool nau7802_set_register(NAU7802* dev, uint8_t register_address, uint8_t value) {
uint8_t data[2] = {register_address, value};
return i2c_write_blocking(dev->i2c, dev->address, data, 2, false) == 2;
}
int32_t nau7802_get_24bit_register(NAU7802* dev, uint8_t register_address) {
uint8_t data[3];
i2c_write_blocking(dev->i2c, dev->address, ®ister_address, 1, true);
i2c_read_blocking(dev->i2c, dev->address, data, 3, false);
union {
uint32_t unsigned32;
int32_t signed32;
} result;
result.unsigned32 = (uint32_t)data[0] << 16;
result.unsigned32 |= (uint32_t)data[1] << 8;
result.unsigned32 |= (uint32_t)data[2];
if ((result.unsigned32 & 0x00800000) == 0x00800000) {
result.unsigned32 |= 0xFF000000;
}
return result.signed32;
}
bool nau7802_set_24bit_register(NAU7802* dev, uint8_t register_address, int32_t value) {
union {
uint32_t unsigned32;
int32_t signed32;
} data;
data.signed32 = value;
uint8_t buffer[4] = {
register_address,
(uint8_t)((data.unsigned32 >> 16) & 0xFF),
(uint8_t)((data.unsigned32 >> 8) & 0xFF),
(uint8_t)(data.unsigned32 & 0xFF)
};
return i2c_write_blocking(dev->i2c, dev->address, buffer, 4, false) == 4;
}
uint32_t nau7802_get_32bit_register(NAU7802* dev, uint8_t register_address) {
uint8_t data[4];
i2c_write_blocking(dev->i2c, dev->address, ®ister_address, 1, true);
i2c_read_blocking(dev->i2c, dev->address, data, 4, false);
uint32_t result = (uint32_t)data[0] << 24;
result |= (uint32_t)data[1] << 16;
result |= (uint32_t)data[2] << 8;
result |= (uint32_t)data[3];
return result;
}
bool nau7802_set_32bit_register(NAU7802* dev, uint8_t register_address, uint32_t value) {
uint8_t buffer[5] = {
register_address,
(uint8_t)((value >> 24) & 0xFF),
(uint8_t)((value >> 16) & 0xFF),
(uint8_t)((value >> 8) & 0xFF),
(uint8_t)(value & 0xFF)
};
return i2c_write_blocking(dev->i2c, dev->address, buffer, 5, false) == 5;
}
int32_t nau7802_get_channel1_offset(NAU7802* dev) {
return nau7802_get_24bit_register(dev, NAU7802_OCAL1_B2);
}
bool nau7802_set_channel1_offset(NAU7802* dev, int32_t value) {
return nau7802_set_24bit_register(dev, NAU7802_OCAL1_B2, value);
}
uint32_t nau7802_get_channel1_gain(NAU7802* dev) {
return nau7802_get_32bit_register(dev, NAU7802_GCAL1_B3);
}
bool nau7802_set_channel1_gain(NAU7802* dev, uint32_t value) {
return nau7802_set_32bit_register(dev, NAU7802_GCAL1_B3, value);
}
Can you check and correct it and publish it for raspberry pi pico c language?
Metadata
Metadata
Assignees
Labels
No labels