1010#define POWER_REGISTER 0x03
1111#define I2C_ADDRESS 0x40
1212
13- #define ByteSwap ( u ) (uint16_t)((u << 8)|(u >> 8))
13+ #define CONFIG_REGISTER 0x00
1414
1515#ifndef RTC_CLOCK_SRC_GPIO_OUT
1616#define RTC_CLOCK_SRC_GPIO_OUT 21
1717#endif
1818
19+ // Averaging: number of samples the INA260 averages in hardware before updating
20+ // its registers (CONFIG register AVG field, bits 11:9). More = quieter readings
21+ // but slower updates. Helpful for low sleep currents.
22+ // Allowed values: 1, 4, 16, 64, 128, 256, 512, 1024.
23+ #define AVG_SAMPLES 128
24+
25+ #if AVG_SAMPLES == 1
26+ #define AVG_FIELD 0
27+ #elif AVG_SAMPLES == 4
28+ #define AVG_FIELD 1
29+ #elif AVG_SAMPLES == 16
30+ #define AVG_FIELD 2
31+ #elif AVG_SAMPLES == 64
32+ #define AVG_FIELD 3
33+ #elif AVG_SAMPLES == 128
34+ #define AVG_FIELD 4
35+ #elif AVG_SAMPLES == 256
36+ #define AVG_FIELD 5
37+ #elif AVG_SAMPLES == 512
38+ #define AVG_FIELD 6
39+ #elif AVG_SAMPLES == 1024
40+ #define AVG_FIELD 7
41+ #else
42+ #error "AVG_SAMPLES must be one of: 1, 4, 16, 64, 128, 256, 512, 1024"
43+ #endif
44+
45+ // CONFIG register value:
46+ // bit 15 reset (0)
47+ // bits 11:9 AVG = samples averaged
48+ // bits 8:6 VBUSCT, 5:3 ISHCT = conversion times (left at default 0b100 = 1.1 ms)
49+ // bits 2:0 MODE = 0b111 (continuous shunt + bus)
50+ #define CONFIG_VALUE ( ((AVG_FIELD & 0x7) << 9) \
51+ | (0x4 << 6) /* VBUSCT 1.1 ms */ \
52+ | (0x4 << 3 ) /* ISHCT 1.1 ms */ \
53+ | 0x7 ) /* continuous shunt + bus */
54+
55+ // Swap the byte order of a 16-bit value (INA260 returns big-endian over I2C).
56+ static inline uint16_t byte_swap (uint16_t u ) {
57+ return (uint16_t )((u << 8 ) | (u >> 8 ));
58+ }
59+
1960// Read register value
2061static uint16_t read_reg (uint8_t reg ) {
2162 // Set the register address
@@ -27,7 +68,15 @@ static uint16_t read_reg(uint8_t reg) {
2768 ret = i2c_read_blocking (i2c_default , I2C_ADDRESS , (uint8_t * )& data , 2 , false);
2869 assert (ret == 2 );
2970 if (ret != 2 ) return 0 ;
30- return ByteSwap (data );
71+ return byte_swap (data );
72+ }
73+
74+ // Write a 16-bit register value
75+ static void write_reg (uint8_t reg , uint16_t value ) {
76+ uint8_t buf [3 ] = { reg , (uint8_t )(value >> 8 ), (uint8_t )(value & 0xFF ) };
77+ int ret = i2c_write_blocking (i2c_default , I2C_ADDRESS , buf , 3 , false);
78+ assert (ret == 3 );
79+ (void )ret ;
3180}
3281
3382int main () {
@@ -53,23 +102,28 @@ int main() {
53102 gpio_pull_up (PICO_DEFAULT_I2C_SDA_PIN );
54103 gpio_pull_up (PICO_DEFAULT_I2C_SCL_PIN );
55104
105+ // Configure averaging + continuous mode (see CONFIG_VALUE above).
106+ write_reg (CONFIG_REGISTER , CONFIG_VALUE );
107+
56108 hard_assert (status_led_init ());
57109 while (true) {
58110 status_led_set_state (true);
59111
60- // Read current and convert to mA
61- float ma = read_reg (CURRENT_REGISTER ) * 1.250f ;
62- if (ma > 15000 ) ma = 0 ;
63- // Read the voltage
112+ // Read current and convert to mA. The CURRENT register is signed
113+ // (two's complement), so cast through int16_t before scaling -- otherwise
114+ // small negative or near-zero readings wrap to a huge positive number.
115+ float ma = (int16_t )read_reg (CURRENT_REGISTER ) * 1.25f ;
116+ // Read the voltage (1.25 mV/LSB, unsigned)
64117 float v = read_reg (VOLTAGE_REGISTER ) * 0.00125f ;
65- // Read power and convert to mW
66- uint16_t mw = read_reg (POWER_REGISTER ) * 10 ;
67-
118+ // Read power and convert to mW (10 mW/LSB). Use 32-bit: register x 10
119+ // exceeds uint16_t range.
120+ uint32_t mw = (uint32_t )read_reg (POWER_REGISTER ) * 10 ;
121+
68122 // Display results
69- printf ("current: %.2f mA voltage: %.2f V power: %u mW\n" , ma , v , mw );
123+ printf ("current: %.2f mA voltage: %.2f V power: %lu mW\n" , ma , v , ( unsigned long ) mw );
70124
71125 status_led_set_state (false);
72126 sleep_ms (1000 );
73127 }
74128 return 0 ;
75- }
129+ }
0 commit comments