Skip to content

Commit 1d0786e

Browse files
committed
add new i2c example ina228 to pico examples
1 parent 664cdda commit 1d0786e

File tree

8 files changed

+175
-154
lines changed

8 files changed

+175
-154
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ App|Description
159159
[ht16k33_i2c](i2c/ht16k33_i2c) | Drive a 4 digit 14 segment LED with an HT16K33.
160160
[slave_mem_i2c](i2c/slave_mem_i2c) | i2c slave example where the slave implements a 256 byte memory.
161161
[slave_mem_i2c_burst](i2c/slave_mem_i2c) | i2c slave example where the slave implements a 256 byte memory. This version inefficiently writes each byte in a separate call to demonstrate read and write burst mode.
162+
[ina228_i2c](i2c/ina228) | Read voltage, current, temperature, power, energy and charge from INA228 sensor, via I2C.
162163

163164
### Interpolator
164165

examples_tests.json

Lines changed: 0 additions & 154 deletions
This file was deleted.

i2c/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ if (TARGET hardware_i2c)
1212
add_subdirectory_exclude_platforms(pcf8523_i2c)
1313
add_subdirectory_exclude_platforms(ht16k33_i2c)
1414
add_subdirectory_exclude_platforms(slave_mem_i2c)
15+
add_subdirectory_exclude_platforms(ina228_i2c)
16+
else()
1517
else()
1618
message("Skipping I2C examples as hardware_i2c is unavailable on this platform")
1719
endif()

i2c/ina228_i2c/CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
add_executable(ina228_i2c ina228_i2c.c)
2+
3+
# pull in common dependencies and additional i2c hardware support
4+
target_link_libraries(ina228_i2c
5+
pico_stdlib
6+
hardware_i2c)
7+
8+
# create map/bin/hex file etc.
9+
pico_add_extra_outputs(ina228_i2c)
10+
11+
# add url via pico_set_program_url
12+
example_auto_set_url(lcd_1602_i2c)
13+

i2c/ina228_i2c/README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
= Reading an INA228 power sensor via I2C
2+
3+
This example code shows how to interface the Raspberry Pi Pico with the INA228 current/voltage/power/temperature/energy/charge sensor. The sensor features a 20 bit ADC and supports up to 85V DC, making it a great choice for high preccision measurments. It is capable of high-side and low-side measurments (which can be configured by soldering the jumper on the back of the board), but this example focuses on low-side measurments.
4+
5+
The sensor breakout board has an integrated 0.015 ohm, high precision shunt resistor, which is used for measuring voltage drop, which also gives current since the resistor value is known. This current, combined with the load voltage vbus, allows load power and energy to be calculated.
6+
7+
[TIP]
8+
======
9+
The INA228 is highly configurable. Find the datasheet online (https://www.ti.com/lit/ds/symlink/ina228.pdf) to explore all of its capabilities beyond the simple example given here.
10+
======
11+
12+
== Wiring information
13+
14+
[[bmp280_i2c_wiring]]
15+
[pdfwidth=75%]
16+
.Wiring Diagram for BMP280 sensor via I2C.
17+
image::bmp280_i2c_bb.png[]
18+
19+
== List of Files
20+
21+
CMakeLists.txt:: CMake file to incorporate the example into the examples build tree.
22+
ina228_i2c.c:: The example code.
23+
24+
== Bill of Materials
25+
26+
.A list of materials required for the example
27+
[[ina228_i2c-bom-table]]
28+
[cols=3]
29+
|===
30+
| *Item* | *Quantity* | Details
31+
| Breadboard | 1 | generic part
32+
| Raspberry Pi Pico 2 | 1 | https://www.raspberrypi.com/products/raspberry-pi-pico-2/
33+
| INA228-based breakout board | 1 | https://www.adafruit.com/product/5832?srsltid=AfmBOoq8cjiUxn01ClOriCxHK3rMMtswYVhzd2tTkiLdjysj2CJZE-RX[from Adafruit]
34+
| M/M Jumper wires | 9 | generic part
35+
| LED | 1 | generic part
36+
| 330 ohm resistor | 1 | generic part
37+
|===

i2c/ina228_i2c/ina228_i2c.c

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
#include <stdio.h>
2+
#include "pico/stdlib.h"
3+
#include "hardware/i2c.h"
4+
#include <math.h>
5+
6+
// GPIOs, see circuit diagram
7+
#define I2C_SDA 8
8+
#define I2C_SCL 9
9+
#define EXT_LED_GPIO 2
10+
11+
// Shunt resistor values in ohms
12+
#define R_SHUNT 0.015
13+
14+
// Max expected current through shunt resistor
15+
#define MAX_EXPECTED_CURRENT 0.1
16+
#define I2C_ADDR 0x40
17+
18+
// ina228 registers (see datasheet)
19+
uint8_t VSHUNT_REG = 0x04;
20+
uint8_t VBUS_REG = 0x05;
21+
uint8_t DIETEMP_REG = 0x06;
22+
uint8_t CURRENT_REG = 0x07;
23+
uint8_t POWER_REG = 0x08;
24+
uint8_t ENERGY_REG = 0x09;
25+
uint8_t CHARGE_REG = 0x0A;
26+
27+
uint8_t ADC_CONFIG_REG = 0x01;
28+
uint8_t SHUNT_CAL_REG = 0x02;
29+
30+
// conversion factors (see datasheet)
31+
// note: VSHUNT_FACTOR assumes ADCRANGE = 0
32+
const double VSHUNT_FACTOR = 312.5 * 1e-9;
33+
const double VBUS_FACTOR = 195.3125 * 1e-6;
34+
const double DIETEMP_FACTOR = 7.8125 * 1e-3;
35+
const double CURRENT_FACTOR = MAX_EXPECTED_CURRENT / (1<<19);
36+
const double POWER_FACTOR = 3.2 * CURRENT_FACTOR ;
37+
const double ENERGY_FACTOR = 16 * 3.2 * CURRENT_FACTOR;
38+
const double CHARGE_FACTOR = CURRENT_FACTOR;
39+
40+
const uint16_t SHUNT_CAL = 13107.2 * 1e6 * CURRENT_FACTOR * R_SHUNT;
41+
42+
float vshunt, vbus, dietemp, current, power, energy, charge;
43+
44+
static void ina228_init() {
45+
// Write to shunt register
46+
uint8_t shunt_msb = (SHUNT_CAL >> 8) & 0xFF;
47+
uint8_t shunt_lsb = SHUNT_CAL & 0xff;
48+
uint8_t shunt_buf[3] = {SHUNT_CAL_REG, shunt_msb, shunt_lsb};
49+
i2c_write_blocking(i2c_default, I2C_ADDR, shunt_buf, 3, false);
50+
51+
// Write to ADC config register (need to enable continuous mode to access accumilation variables energy and charge)
52+
// To enable contintinuous vbus, vshunt and temp, write 0x0F to bits 15-12
53+
uint8_t adc_msb = 0xF1;
54+
uint8_t adc_lsb = 0x11;
55+
uint8_t adc_buf[3] = {ADC_CONFIG_REG, adc_msb, adc_lsb};
56+
i2c_write_blocking(i2c_default, I2C_ADDR, adc_buf, 3, false);
57+
}
58+
59+
static void ina228_read(float *vshunt, float *vbus, float *dietemp, float *current, float *power, float *energy, float *charge) {
60+
// Buffers for writing register measurments to
61+
// Some registers are 2 byte, some are 3 byte, the accumilation registers are 5 byte
62+
uint8_t buffer_2[2];
63+
uint8_t buffer_3[3];
64+
uint8_t buffer_5[5];
65+
66+
// For some of the registers the 4 least significant bits are reserved and always read zero, which is why we shift right 12, 4, then left 4 for vshunt, vbus and current
67+
i2c_write_blocking(i2c_default, I2C_ADDR, &VSHUNT_REG, 1, true);
68+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_3, 3, false);
69+
*vshunt = ((buffer_3[0] << 12) | (buffer_3[1] << 4) | (buffer_3[2] >> 4)) * VSHUNT_FACTOR;
70+
71+
i2c_write_blocking(i2c_default, I2C_ADDR, &VBUS_REG, 1, true);
72+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_3, 3, false);
73+
*vbus = ((buffer_3[0] << 12) | (buffer_3[1] << 4) | (buffer_3[2] >> 4)) * VBUS_FACTOR;
74+
75+
i2c_write_blocking(i2c_default, I2C_ADDR, &DIETEMP_REG, 1, true);
76+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_2, 2, false);
77+
*dietemp = ((buffer_2[0] << 8) + buffer_2[1]) * DIETEMP_FACTOR;
78+
79+
i2c_write_blocking(i2c_default, I2C_ADDR, &CURRENT_REG, 1, true);
80+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_3, 3, false);
81+
*current = ((buffer_3[0] << 12) | (buffer_3[1] << 4) | (buffer_3[2] >> 4)) * CURRENT_FACTOR;
82+
83+
i2c_write_blocking(i2c_default, I2C_ADDR, &POWER_REG, 1, true);
84+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_3, 3, false);
85+
*power = ((buffer_3[0] << 16) | (buffer_3[1] << 8) | buffer_3[2]) * POWER_FACTOR;
86+
87+
i2c_write_blocking(i2c_default, I2C_ADDR, &ENERGY_REG, 1, true);
88+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_5, 5, false);
89+
*energy = (((uint64_t) buffer_5[0] << 32) | (buffer_5[1] << 24) | (buffer_5[2] << 16) | (buffer_5[3] << 8) | buffer_5[4]) * ENERGY_FACTOR;
90+
91+
i2c_write_blocking(i2c_default, I2C_ADDR, &CHARGE_REG, 1, true);
92+
i2c_read_blocking(i2c_default, I2C_ADDR, buffer_5, 5, false);
93+
*charge = (((uint64_t) buffer_5[0] << 32) | (buffer_5[1] << 24) | (buffer_5[2] << 16) | (buffer_5[3] << 8) | buffer_5[4]) * CHARGE_FACTOR;
94+
}
95+
96+
int main()
97+
{
98+
stdio_init_all();
99+
100+
// Initialise external LED and turn it on (so we can measure some current)
101+
gpio_init(EXT_LED_GPIO);
102+
gpio_set_dir(EXT_LED_GPIO, GPIO_OUT);
103+
gpio_put(EXT_LED_GPIO, true);
104+
105+
// I2C initialisation
106+
i2c_init(i2c_default, 400*1000);
107+
108+
// GPIO initialisiation
109+
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
110+
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
111+
gpio_pull_up(I2C_SDA);
112+
gpio_pull_up(I2C_SCL);
113+
114+
// Initialise ina228
115+
ina228_init();
116+
117+
while (true) {
118+
ina228_read(&vshunt, &vbus, &dietemp, &current, &power, &energy, &charge);
119+
printf("INA228 Measurments:\nVSHUNT: %f\nVBUS: %f\nDIETEMP: %f\nCURRENT: %f\nPOWER: %f\nENERGY: %.9f\nCHARGE: %.9f\n-----------------\n", vshunt, vbus, dietemp, current, power, energy, charge);
120+
sleep_ms(3000);
121+
}
122+
}

i2c/ina228_i2c/ina228_i2c.fzz

87.7 KB
Binary file not shown.

i2c/ina228_i2c/ina228_i2c.png

258 KB
Loading

0 commit comments

Comments
 (0)