{"id":1004,"date":"2025-09-25T04:54:53","date_gmt":"2025-09-25T00:54:53","guid":{"rendered":"https:\/\/seriyps.com\/blog\/?p=1004"},"modified":"2025-10-03T22:25:39","modified_gmt":"2025-10-03T20:25:39","slug":"pair-ina226-and-raspberry-pi-ina2xx-kernel-driver","status":"publish","type":"post","link":"https:\/\/seriyps.com\/blog\/2025\/09\/25\/pair-ina226-and-raspberry-pi-ina2xx-kernel-driver\/","title":{"rendered":"How to pair INA226 current and voltage sensor and Raspberry Pi using ina2xx kernel driver"},"content":{"rendered":"\n<p><a href=\"https:\/\/www.ti.com\/product\/INA226\">INA226<\/a> is a popular microchip to measure the voltage and power consumption that uses i2c digital interface. There are a lot of articles describing how to make it work with Arduino, much fewer about how it can be connected and read using generic Linux i2c tools and seems to be none explaining how can it be paired with Linux <a href=\"https:\/\/www.kernel.org\/doc\/html\/v6.12\/hwmon\/ina2xx.html\">ina2xx kernel driver<\/a> so it can be manipulated via hwmon subsystem. Let&#8217;s fix ths!<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>In this example we are going to:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Enable i2c interface in Raspberry Pi OS<\/li>\n\n\n\n<li>Connect <a href=\"https:\/\/www.aliexpress.com\/item\/1005006572888455.html\">INA226 breakout board<\/a> to <a href=\"https:\/\/www.raspberrypi.com\/products\/raspberry-pi-zero-2-w\/\">Raspberry Pi zero 2w<\/a><\/li>\n\n\n\n<li>Create and enable a custom Device Tree overlay for OS to recognize the sensor<\/li>\n\n\n\n<li>Explore the sysfs entries provided by ina2xx kernel driver<\/li>\n<\/ol>\n\n\n\n<h2 class=\"wp-block-heading\">Enable i2c interface<\/h2>\n\n\n\n<p>In Raspberry Pi OS (Debian) i2c interface is disabled by-default, so we obviously need to enable it first. To do that, open the shell on Raspberry and run<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">sudo raspi config<\/code><\/pre>\n\n\n\n<p>In UI select &#8220;3 Interface Options&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"385\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-1024x385.png\" alt=\"\" class=\"wp-image-1005\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-1024x385.png 1024w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-768x289.png 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-624x235.png 624w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image.png 1129w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>then I5 I2C<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-6.png\"><img loading=\"lazy\" decoding=\"async\" width=\"731\" height=\"418\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-6.png\" alt=\"\" class=\"wp-image-1046\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-6.png 731w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-6-624x357.png 624w\" sizes=\"auto, (max-width: 731px) 100vw, 731px\" \/><\/a><\/figure>\n\n\n\n<p>And in the next screen select &#8220;yes&#8221;<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-7.png\"><img loading=\"lazy\" decoding=\"async\" width=\"594\" height=\"414\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-7.png\" alt=\"\" class=\"wp-image-1048\"\/><\/a><\/figure>\n\n\n\n<p>When done, you should be able to see at least 2 i2c devices:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">$ ls \/dev\/i2c*\n\/dev\/i2c-1  \/dev\/i2c-2<\/code><\/pre>\n\n\n\n<p>One of them is system internal, but <code>i2c-1<\/code> is the one that is accessible via the <a href=\"https:\/\/pinout.xyz\/pinout\/i2c\">GPIO pins 3 and 5<\/a>.<\/p>\n\n\n\n<p>You can now install the tools to inspect the i2c on Linux:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">sudo apt install i2c-tools<\/code><\/pre>\n\n\n\n<p>And try to see if there are any devices connected to i2c bus:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">$ sudo i2cdetect -y 1\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:                         -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n70: -- -- -- -- -- -- -- --<\/code><\/pre>\n\n\n\n<p>If it looks this way, it means no devices are connected which is expected.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Connecting the INA226 brealout board<\/h2>\n\n\n\n<p>The board we are going to use looks like this:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3.png\"><img loading=\"lazy\" decoding=\"async\" width=\"800\" height=\"800\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3.png\" alt=\"\" class=\"wp-image-1008\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3.png 800w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3-150x150.png 150w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3-768x768.png 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-3-624x624.png 624w\" sizes=\"auto, (max-width: 800px) 100vw, 800px\" \/><\/a><\/figure>\n\n\n\n<p>it has the shunt resistor that says <a href=\"https:\/\/kiloohm.info\/smd4-resistor\/R100\">&#8220;R100&#8221; which means 0,1 Ohm<\/a> and it has following outputs:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>VCC &#8211; the + of the voltage that&#8217;s going to power the microchip. We are going to connect it to Raspberry pin nr <a href=\"https:\/\/pinout.xyz\/pinout\/3v3_power\">1 (3,3 V)<\/a> or <a href=\"https:\/\/pinout.xyz\/pinout\/5v_power\">2 or 4 (5 V)<\/a>. This chip can be powered by any of them since it can be powered by a voltage in range 2.7 &#8211; 5.5V<\/li>\n\n\n\n<li>GND &#8211; should be connected to the ground of both Raspberry and device under test. You can use <a href=\"https:\/\/pinout.xyz\/pinout\/ground\">any ground pin<\/a>, say 6 or 9 or 14.<\/li>\n\n\n\n<li>SCL &#8211; the &#8220;clock&#8221; lane of i2c interface, should be connected to <a href=\"https:\/\/pinout.xyz\/pinout\/pin5_gpio3\/\">pin nr 5<\/a><\/li>\n\n\n\n<li>SDA &#8211; the &#8220;data&#8221; lane of i2c, should be connected to <a href=\"https:\/\/pinout.xyz\/pinout\/pin3_gpio2\/\">pin nr 3<\/a><\/li>\n\n\n\n<li>ALE &#8211; alert trigger &#8211; we leave not connected for now<\/li>\n\n\n\n<li>VBS &#8211; the Vbus &#8211; should be connected to the + of the power supply of the device under test, it is used to measure the power source supply voltage<\/li>\n\n\n\n<li>IN+ and IN- &#8211; will be installed sequentially in the supply line of the device under test (IN+ closer to the &#8220;+&#8221; of the power supply and IN- closer to the &#8220;-&#8220;). The INA226 can be installed in both high (between the device and &#8220;+&#8221; of power supply) and low (between the device and &#8220;-&#8221; of the power supply \/ ground)<\/li>\n<\/ul>\n\n\n\n<figure class=\"wp-block-gallery has-nested-images columns-default is-cropped wp-block-gallery-1 is-layout-flex wp-block-gallery-is-layout-flex\">\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"1014\" data-id=\"1009\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y-1024x1014.jpg\" alt=\"\" class=\"wp-image-1009\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y-1024x1014.jpg 1024w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y-150x150.jpg 150w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y-768x761.jpg 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y-624x618.jpg 624w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375199_y.jpg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y.jpg\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"830\" data-id=\"1010\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y-1024x830.jpg\" alt=\"\" class=\"wp-image-1010\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y-1024x830.jpg 1024w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y-768x623.jpg 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y-624x506.jpg 624w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/photo_5379885029087375198_y.jpg 1280w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n<\/figure>\n\n\n\n<p>As soon as GND, VCC, SCL and SDA are connected (on this picurre &#8211; to the pins 6, 4, 3, 2 accordingly), Linux should be able to detect a new device on i2c bus:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">$ sudo i2cdetect -y 1\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:                         -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- \n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n70: -- -- -- -- -- -- -- --<\/code><\/pre>\n\n\n\n<p>We can see that the i2c device address on this case is <code>0x44<\/code>. We need to remeber this &#8211; we are going to use it on the next step.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Custom Device Tree overlay<\/h2>\n\n\n\n<p>We can already use the i2c device as-is using generic i2c or SMBUS using, eg this python tool: <a href=\"https:\/\/github.com\/e71828\/pi_ina226\">https:\/\/github.com\/e71828\/pi_ina226<\/a>. However, Linux kernel already includes a special kernel driver for ina2xx series of chips (<a href=\"https:\/\/www.kernel.org\/doc\/html\/v6.12\/hwmon\/ina2xx.html\">docs<\/a>, <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/master\/drivers\/hwmon\/ina2xx.c\">source<\/a>, <a href=\"https:\/\/github.com\/torvalds\/linux\/blob\/master\/Documentation\/devicetree\/bindings\/hwmon\/ti%2Cina2xx.yaml\">bindings<\/a>) which is exposed via <code>hwmon<\/code> subsystem. However, we would have to define the i2c-connected INA226 in the Device Tree overlay for it to be recognized by kernel.<\/p>\n\n\n\n<p>Devicetree is a way to describe all the hardware so operaing system can see what hardware is available on the current machine. Those trees are declared using a declarative language and compiled to a binary form using <code>dtc<\/code> compiler. The device tree binary that describes the current machine lies in the <code>\/boot\/firmware<\/code> directory as one of <code>.dtb<\/code> files. For Raspberry pi Zero 2w it is in the <code>bcm2710-rpi-zero-2-w.dtb<\/code> file.<\/p>\n\n\n\n<p>The binary dtb file can be decompiled to a dts format (some meta-info would be lost though):<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-\">dtc -I dtb -O dts  \/boot\/firmware\/bcm2710-rpi-zero-2-w.dtb | less<\/code><\/pre>\n\n\n\n<p>In the output of the decompiler, you should find the entries describing i2c interface:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-nginx\">\/ {\n        compatible = &quot;raspberrypi,model-zero-2-w\\0brcm,bcm2837&quot;;\n&lt;..&gt;\n        aliases {\n&lt;..&gt;\n                i2c0 = &quot;\/soc\/i2c0mux\/i2c@0&quot;;\n                i2c1 = &quot;\/soc\/i2c@7e804000&quot;;\n                i2c10 = &quot;\/soc\/i2c0mux\/i2c@1&quot;;\n                i2c = &quot;\/soc\/i2c@7e804000&quot;;\n&lt;..&gt;\n                i2c2 = &quot;\/soc\/i2c@7e805000&quot;;\n        };\n\n        soc {\n&lt;..&gt;\n                i2c@7e205000 {\n                        compatible = &quot;brcm,bcm2835-i2c&quot;;\n                        reg = &lt;0x7e205000 0x200&gt;;\n                        interrupts = &lt;0x02 0x15&gt;;\n                        clocks = &lt;0x08 0x14&gt;;\n                        #address-cells = &lt;0x01&gt;;\n                        #size-cells = &lt;0x00&gt;;\n                        status = &quot;disabled&quot;;\n                        clock-frequency = &lt;0x186a0&gt;;\n                        phandle = &lt;0x1b&gt;;\n                };\n&lt;..&gt;\n                i2c@7e804000 {\n                        compatible = &quot;brcm,bcm2835-i2c&quot;;\n                        reg = &lt;0x7e804000 0x1000&gt;;\n                        interrupts = &lt;0x02 0x15&gt;;\n                        clocks = &lt;0x08 0x14&gt;;\n                        #address-cells = &lt;0x01&gt;;\n                        #size-cells = &lt;0x00&gt;;\n                        status = &quot;disabled&quot;;\n                        pinctrl-names = &quot;default&quot;;\n                        pinctrl-0 = &lt;0x15&gt;;\n                        clock-frequency = &lt;0x186a0&gt;;\n                        phandle = &lt;0x2a&gt;;\n                };\n&lt;..&gt;\n                i2c@7e805000 {\n                        compatible = &quot;brcm,bcm2835-i2c&quot;;\n                        reg = &lt;0x7e805000 0x1000&gt;;\n                        interrupts = &lt;0x02 0x15&gt;;\n                        clocks = &lt;0x08 0x14&gt;;\n                        #address-cells = &lt;0x01&gt;;\n                        #size-cells = &lt;0x00&gt;;\n                        status = &quot;disabled&quot;;\n                        clock-frequency = &lt;0x186a0&gt;;\n                        phandle = &lt;0x19&gt;;\n                };\n&lt;..&gt;\n                i2c0mux {\n&lt;..&gt;\n                };<\/code><\/pre>\n\n\n\n<p>If you can&#8217;t find the right &#8220;dtb&#8221; file, you can try to browse the sysfs representation of currently active device tree:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">ls \/sys\/firmware\/devicetree\/base\/<\/code><\/pre>\n\n\n\n<p>Since we remember from the <code>i2cdetect<\/code> that INA226 resides on i2c bus number 1, we see in aliases section that <code>i2c1 = &quot;\/soc\/i2c@7e804000&quot;<\/code> it has address <code>i2c@7e804000<\/code>. So, let&#8217;s write and device tree overlay for the <code>i2c@7e804000<\/code> section, given we know from i2cdetect that it has address &#8220;44&#8221;:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-nginx\">$ nano ~\/ina226-overlay.dts\n\n\/dts-v1\/;\n\/ {\n    fragment@0 {\n        target-path = &quot;\/soc\/i2c@7e804000&quot;; \/\/ Target the I2C bus\n        __overlay__ {\n            ina226@44 {\n                compatible = &quot;ti,ina226&quot;;\n                reg = &lt;0x44&gt;; \/\/ I2C address of the INA226 from i2cdetect\n                shunt-resistor = &lt;100000&gt;; \/\/ Shunt resistor value in micro-ohms (0.1 ohm)\n            };\n        };\n    };\n};<\/code><\/pre>\n\n\n\n<p>Now let&#8217;s compile this overlay<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">dtc -I dts -O dtb -o ina226-overlay.dtbo ina226-overlay.dts<\/code><\/pre>\n\n\n\n<p>Move it to the <code>\/boot<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">sudo cp ina226-overlay.dtbo \/boot\/firmware\/overlays\/<\/code><\/pre>\n\n\n\n<p>And make sure this overlay is enabled:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">sudo nano \/boot\/firmware\/config.txt<\/code><\/pre>\n\n\n\n<p>And add the following to config.txt: <code>dtoverlay=ina226-overlay<\/code>.<\/p>\n\n\n\n<p>Now reboot. After it starts, you can check from kernel logs that it was recognized well:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ journalctl -k -g ina2xx\nSep 24 22:12:16 raspberrypi kernel: ina2xx 1-0044: supply vs not found, using dummy regulator\nSep 24 22:12:16 raspberrypi kernel: ina2xx 1-0044: power monitor ina226 (Rshunt = 100000 uOhm)<\/code><\/pre>\n\n\n\n<p>The &#8220;supply vs not found&#8221; warning is nothing serious, it can be ignored (it complains that the &#8220;supply-vs&#8221; parameter that says what voltage the INA226 s supplied &#8211; 5 or 3.3 V, however it doesn&#8217;t really important and this warning is removed in the newer kernels). But the &#8220;power monitor&#8221; log means that the ina226 was successfully recognized and initialized.<\/p>\n\n\n\n<p>If your Pi doesn&#8217;t boot after your changes, you&#8217;d need to edit the contents of SD card manually, removing the overlay from <code>\/boot\/overlays<\/code> and from <code>config.txt<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Exploring it via sysfs<\/h2>\n\n\n\n<p>The <code>ina2xx<\/code> kernel driver exports the INA226 sensor via the <code>hwmon<\/code> subsystem and it can be managed via the sysfs:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ cat \/sys\/class\/hwmon\/hwmon2\/name \nina226\n$ ls \/sys\/class\/hwmon\/hwmon2\/\ncurr1_crit         in0_crit_alarm   in1_lcrit          power1_input\ncurr1_crit_alarm   in0_input        in1_lcrit_alarm    shunt_resistor\ncurr1_input        in0_lcrit        name               subsystem\ncurr1_lcrit        in0_lcrit_alarm  of_node            uevent\ncurr1_lcrit_alarm  in1_crit         power              update_interval\ndevice             in1_crit_alarm   power1_crit\nin0_crit           in1_input        power1_crit_alarm<\/code><\/pre>\n\n\n\n<p>The most important fields for us now are the ones with <code>_input<\/code> suffix:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>curr1_input &#8211; the current that passes through the IN+ &#8212; IN- line (in milliamperes, mA)<\/li>\n\n\n\n<li>in0_input &#8211; voltage drop on R100 shunt (not really important for us)<\/li>\n\n\n\n<li>in1_input &#8211; voltage between VBS and GND (should show the voltage of the power source if connected correctly, mV)<\/li>\n\n\n\n<li>power1_input &#8211; the power of the device (roughly, curr1_input * in1_input, in uW)<\/li>\n<\/ul>\n\n\n\n<p>For debugging purposes can be monitored using, eg<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ cd \/sys\/class\/hwmon\/hwmon2\/\n$ watch &#039;for name in `ls *_input`; do echo $name `cat $name`; done&#039;<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Radxa Zero 3w<\/h2>\n\n\n\n<p>The filesystem and hardware layout of Radxa Zero 3W (based on Rockchip RK3566 processor) is slightly different. The <code>.dtb<\/code> file can&#8217;t be found in <code>\/boot\/<\/code> partition, instead one can find it in Kernel&#8217;s directory:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ ls \/usr\/lib\/linux-image-$(uname -r)\/rockchip\/ | grep radxa-zero\nrk3566-radxa-zero-3e.dtb\nrk3566-radxa-zero-3w-aic8800ds2.dtb\nrk3566-radxa-zero-3w-ap6212.dtb<\/code><\/pre>\n\n\n\n<p>According to <a href=\"https:\/\/forum.radxa.com\/t\/wifi-driver-for-radxa-zero-3w\/20507\/2\">this post<\/a>, to find out what device tree you should use, you should check what wifi driver your system loads: if the driver is <code>brcmfmac<\/code>, then it is ap6212, and if the driver is <code>aic8800<\/code>, then you should use <code>aic8800ds2<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">radxa@radxa-zero3:~$ sudo lsmod | grep brcmfmac\nradxa@radxa-zero3:~$ sudo lsmod | grep aic8800\naic8800_fdrv          438272  0\naic8800_bsp            77824  1 aic8800_fdrv<\/code><\/pre>\n\n\n\n<p>In this case the driver is <code>aic8800<\/code>, so we open the <code>rk3566-radxa-zero-3w-aic8800ds2.dtb<\/code> device tree:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-nginx\">$ dtc -I dtb -O dts  \/usr\/lib\/linux-image-$(uname -r)\/rockchip\/rk3566-radxa-zero-3w-aic8800ds2.dtb | less\n    aliases {\n&lt;..&gt;\n            i2c0 = &quot;\/i2c@fdd40000&quot;;\n            i2c1 = &quot;\/i2c@fe5a0000&quot;;\n            i2c2 = &quot;\/i2c@fe5b0000&quot;;\n            i2c3 = &quot;\/i2c@fe5c0000&quot;;\n            i2c4 = &quot;\/i2c@fe5d0000&quot;;\n            i2c5 = &quot;\/i2c@fe5e0000&quot;;\n&lt;..&gt;\n    };<\/code><\/pre>\n\n\n\n<p>Most of i2c buses are internal to Radxa system. Unfortunately the <a href=\"https:\/\/docs.radxa.com\/en\/zero\/zero3\/hardware-design\/hardware-interface#gpio-interface\">GPIO schema in the &#8220;docs&#8221; section<\/a> is incomplete. The correct one can be found <a href=\"https:\/\/dl.radxa.com\/zero3\/docs\/hw\/3w\/radxa_zero_3w_product_brief.pdf\">in detailed PDF<\/a>:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-4.png\"><img loading=\"lazy\" decoding=\"async\" width=\"798\" height=\"493\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-4.png\" alt=\"\" class=\"wp-image-1037\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-4.png 798w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-4-768x474.png 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-4-624x386.png 624w\" sizes=\"auto, (max-width: 798px) 100vw, 798px\" \/><\/a><\/figure>\n\n\n\n<p>So pins 3 and 5 correspond to I2C3. To enable it, we use <code>rsetup<\/code> tool, &#8220;Overlays&#8221; =&gt; &#8220;Manage overlays&#8221;, select &#8220;Enable I2C3-M0&#8221;, then &#8220;ok&#8221; and reboot:<\/p>\n\n\n\n<figure class=\"wp-block-image size-large\"><a href=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5.png\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"569\" src=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5-1024x569.png\" alt=\"\" class=\"wp-image-1038\" srcset=\"https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5-1024x569.png 1024w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5-768x427.png 768w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5-624x347.png 624w, https:\/\/seriyps.com\/blog\/wp-content\/uploads\/2025\/09\/image-5.png 1034w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/a><\/figure>\n\n\n\n<p>Connect the INA226 i2c to pins 3 (sda) and 5 (scl), then test if it was detected by the bus:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">$ sudo i2cdetect -y 3\n     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f\n00:                         -- -- -- -- -- -- -- -- \n10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n20: -- -- UU -- -- -- -- -- -- -- -- -- -- -- -- -- \n30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n40: -- -- -- -- 44 -- -- -- -- -- -- -- -- -- -- -- \n50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- \n70: -- -- -- -- -- -- -- --<\/code><\/pre>\n\n\n\n<p>And use the following overlay:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-nginx\">$ nano ~\/ina226-overlay.dts\n\n\/dts-v1\/;\n\/ {\n    fragment@0 {\n        target-path = &quot;\/i2c@fe5c0000&quot;; \/\/ Target the I2C bus that corresponds to i2c3\n        __overlay__ {\n            ina226@44 {\n                compatible = &quot;ti,ina226&quot;;\n                reg = &lt;0x44&gt;; \/\/ I2C address of the INA226 from i2cdetect\n                shunt-resistor = &lt;100000&gt;; \/\/ Shunt resistor value in micro-ohms (0.1 ohm)\n            };\n        };\n    };\n};<\/code><\/pre>\n\n\n\n<p>Compile and move it to <code>\/boot\/dtbo\/<\/code> directory and then run the following comand to turn it on:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">rsetup enable_overlays ina226-overlay.dtbo $(cd \/boot\/dtbo\/ &amp;&amp; ls *.dtbo)<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Radxa Zero 3W kernel driver<\/h2>\n\n\n\n<p>By default, as of September 2025, Radxa don&#8217;t include the <code>ina2xx<\/code> driver in their kernel build. To find out if your system has this driver, try to run <code>sudo modprobe ina2xx<\/code> and if it fails, it means you don&#8217;t have the driver in your system. To build it:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-bash\">sudo apt install linux-source-6.1 libssl-dev\nsudo su\ncd \/usr\/src\ntar -xaf linux-source-6.1.tar.xz\ncd linux-source-6.1\ncp \/boot\/config-$(uname -r) .config  # or maybe `make oldconfig` ?\necho &quot;CONFIG_SENSORS_INA2XX=m&quot; &gt;&gt; .config\nmake prepare\nmake modules_prepare\nmake -j3 M=drivers\/hwmon\ncp drivers\/hwmon\/ina2xx.ko \/lib\/modules\/$(uname -r)\/kernel\/drivers\/hwmon\/\nsudo depmod -a<\/code><\/pre>\n","protected":false},"excerpt":{"rendered":"<p>INA226 is a popular microchip to measure the voltage and power consumption that uses i2c digital interface. There are a lot of articles describing how to make it work with Arduino, much fewer about how it can be connected and read using generic Linux i2c tools and seems to be none explaining how can it [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[250],"tags":[253,254,251,252],"class_list":["post-1004","post","type-post","status-publish","format-standard","hentry","category-electronics","tag-electronics","tag-i2c","tag-linux-2","tag-raspberry"],"_links":{"self":[{"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/posts\/1004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/comments?post=1004"}],"version-history":[{"count":22,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/posts\/1004\/revisions"}],"predecessor-version":[{"id":1062,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/posts\/1004\/revisions\/1062"}],"wp:attachment":[{"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/media?parent=1004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/categories?post=1004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/seriyps.com\/blog\/wp-json\/wp\/v2\/tags?post=1004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}