<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniel Guerrero</title>
    <description>The latest articles on Forem by Daniel Guerrero (@danielmx).</description>
    <link>https://forem.com/danielmx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3420880%2F2ad63621-f20a-42ac-b3bc-a5f09fb6f533.png</url>
      <title>Forem: Daniel Guerrero</title>
      <link>https://forem.com/danielmx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/danielmx"/>
    <language>en</language>
    <item>
      <title>CH341 with python</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Fri, 03 Apr 2026 22:02:02 +0000</pubDate>
      <link>https://forem.com/danielmx/ch341-with-python-52en</link>
      <guid>https://forem.com/danielmx/ch341-with-python-52en</guid>
      <description>&lt;p&gt;Some time ago I found the CH341a programmer.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntt3wx8hssnreqksauat.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fntt3wx8hssnreqksauat.jpg" alt="CH341a Programmer" width="800" height="800"&gt;&lt;/a&gt;&lt;br&gt;
The board seems a bit intimidating with its ZIF socket, but once you realize the low component count, it becomes more approachable. When I found a CH341 "dev" board, I started looking for documentation on how to develop with it.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98qeywsle2bo6h8zgcia.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F98qeywsle2bo6h8zgcia.jpg" alt="CH341a Dev Board" width="800" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The first step was, of course, finding the &lt;a href="https://www.wch-ic.com/downloads/CH341DS1_PDF.html" rel="noopener noreferrer"&gt;datasheet&lt;/a&gt;, but it turned out to be quite short. After checking the basics, there was nothing more - no programming guide, no registers, nothing.&lt;br&gt;
Looking for a programming manual, I could only find drivers for Linux, Windows, and Android.&lt;/p&gt;

&lt;p&gt;The good news is that this chip has been extensively reverse engineered, so there is a lot of code available. This post is more about the journey of finding all the details.&lt;/p&gt;

&lt;p&gt;If you just want to check the code, jump to: &lt;a href="https://github.com/danguer/pych341" rel="noopener noreferrer"&gt;https://github.com/danguer/pych341&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  The Three Modes of CH341
&lt;/h2&gt;

&lt;p&gt;The first thing you will notice is that the CH341 behaves as three different devices depending on some pin configuration.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17fsjcfwoqevhjnjwix8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17fsjcfwoqevhjnjwix8.png" alt="Pin Configuration" width="800" height="487"&gt;&lt;/a&gt;&lt;br&gt;
The modes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;UART&lt;/strong&gt; — in this mode the device shows up as a VCOM or Serial Port adapter. There is not much interest in this mode; aside from the full signals available, everything is transparent: you plug it in and it is recognized as a serial device, so no extra work is needed.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PRINT&lt;/strong&gt; — in this mode it behaves as a "standard Centronics printer interface" and should appear as a parallel printer. This also seems to be a transparent mode, so there is not much interesting here (for now).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EPP/MEM&lt;/strong&gt; — this is the most interesting mode, as you can use the device as an I2C master, SPI interface, or GPIO controller (it was apparently also designed to read/write parallel memory chips).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The datasheet shows how the pins have different uses under each mode.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz84wlxlqq4yqzm7fjnhe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fz84wlxlqq4yqzm7fjnhe.png" alt="The three modes of CH341" width="800" height="320"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Starting with USB Programming
&lt;/h2&gt;

&lt;p&gt;Accessing the USB with &lt;code&gt;pyusb&lt;/code&gt; is quite straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Find a device using the vendor ID and product ID (for EPP/MEM, &lt;code&gt;vendor_id=0x1A86, product_id=0x5512&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;List the endpoints.&lt;/li&gt;
&lt;li&gt;Find a bulk input (to read) and output (to write).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The write operation is usually wrapped in some special opcodes (more on this later), and the read is transparent - the data you receive comes from GPIO/I2C/SPI without extra frames or opcodes.&lt;/p&gt;
&lt;h2&gt;
  
  
  Reverse Engineering
&lt;/h2&gt;

&lt;p&gt;Here is where the fun starts. The WCH website contains this file: &lt;a href="https://www.wch-ic.com/downloads/CH341PAR_LINUX_ZIP.html" rel="noopener noreferrer"&gt;https://www.wch-ic.com/downloads/CH341PAR_LINUX_ZIP.html&lt;/a&gt;, and searching further leads to this repository:&lt;br&gt;
&lt;a href="https://github.com/WCHSoftGroup/ch341par_linux" rel="noopener noreferrer"&gt;https://github.com/WCHSoftGroup/ch341par_linux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code is basically:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A demo (testing all functions)&lt;/li&gt;
&lt;li&gt;A library&lt;/li&gt;
&lt;li&gt;A kernel driver/module&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The library calls the kernel driver and passes some arguments. It contains a lot of functions, some for different chips like CH347, and others that seem to not work at all (for example, calls to write/read from parallel memory chips).&lt;br&gt;
This looked like it would just be a matter of reading the source code and following along — except there is no source code for the library.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;README.md&lt;/code&gt; from the zip file points to: &lt;a href="https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux" rel="noopener noreferrer"&gt;https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This repository contains a much simpler and more straightforward implementation. My first guess was that this was all that was needed, so I started with the I2C implementation.&lt;/p&gt;
&lt;h2&gt;
  
  
  I2C Implementation
&lt;/h2&gt;

&lt;p&gt;The implementation is based on the &lt;code&gt;ch341_i2c_stream&lt;/code&gt; function. The sequence in the original is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;CH341_CMD_I2C_STREAM&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CH341_CMD_I2C_STM_STA&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;CH341_CMD_I2C_STM_OUT&lt;/code&gt; (&lt;code&gt;OR&lt;/code&gt; with the length of data)&lt;/li&gt;
&lt;li&gt;If reading: &lt;code&gt;CH341_CMD_I2C_STM_IN&lt;/code&gt; (&lt;code&gt;OR&lt;/code&gt; with the length of data)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CH341_CMD_I2C_STM_STO&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CH341_CMD_I2C_STM_END&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first thing to note is that there is a "packet" wrapped between &lt;code&gt;CH341_CMD_I2C_STREAM&lt;/code&gt; and &lt;code&gt;CH341_CMD_I2C_STM_END&lt;/code&gt;, meaning those opcodes are for the chip itself.&lt;br&gt;
After verifying with a logic analyzer and the I2C protocol, &lt;code&gt;CH341_CMD_I2C_STM_STA&lt;/code&gt; sends a &lt;strong&gt;Start&lt;/strong&gt; signal and &lt;code&gt;CH341_CMD_I2C_STM_STO&lt;/code&gt; sends a &lt;strong&gt;Stop&lt;/strong&gt; signal.&lt;/p&gt;

&lt;p&gt;The next thing to note is how you send/receive I2C data. The tricky part is that you must always send the address, which is defined as a 7-bit address plus an &lt;code&gt;R/W&lt;/code&gt; bit (&lt;code&gt;Read=1&lt;/code&gt;, &lt;code&gt;Write=0&lt;/code&gt;). Most libraries handle this automatically, but here you handle the sending and receiving of data directly.&lt;/p&gt;

&lt;p&gt;To write data to a device is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# send a 0xFF as message to address 0xC0
&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xC0&lt;/span&gt;
&lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xFF&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MODE_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# start signal
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DIR_OUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# sending just 1 byte of data plus 1 byte of address
&lt;/span&gt;  &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# sending 7-bit address and 0 as R/W bit
&lt;/span&gt;  &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;# stop signal
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To read data is a bit different, since you first need to write the address to the device and then read from it. For example, to read 1 byte from the device:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mh"&gt;0xC0&lt;/span&gt;
&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MODE_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;       &lt;span class="c1"&gt;# start signal
&lt;/span&gt;  &lt;span class="c1"&gt;# write the address
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DIR_OUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# sending just 1 byte of address
&lt;/span&gt;  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# sending 7-bit address and 1 as R/W bit
&lt;/span&gt;  &lt;span class="c1"&gt;# now actually read data from device
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DIR_IN&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# just read 1 byte
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;        &lt;span class="c1"&gt;# stop signal
&lt;/span&gt;  &lt;span class="n"&gt;I2CCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;i2c.py&lt;/code&gt; module follows the &lt;code&gt;Arduino Wire&lt;/code&gt; library approach.&lt;/p&gt;

&lt;p&gt;More information about I2C: &lt;a href="https://www.ti.com/lit/an/sbaa565/sbaa565.pdf" rel="noopener noreferrer"&gt;https://www.ti.com/lit/an/sbaa565/sbaa565.pdf&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  GPIO Implementation
&lt;/h2&gt;

&lt;p&gt;This is probably the trickiest part. The first implementation appears to target CH347 and uses a control endpoint instead of bulk:&lt;br&gt;
&lt;a href="https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux/blob/main/driver/ch34x_mphsi_master_gpio.c#L345" rel="noopener noreferrer"&gt;https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux/blob/main/driver/ch34x_mphsi_master_gpio.c#L345&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The driver has &lt;code&gt;CH34xSetOutput&lt;/code&gt; and &lt;code&gt;CH34xSet_D5_D0&lt;/code&gt;, so I decided to cross-reference this against the older library source code: &lt;a href="https://github.com/zoobab/ch341-parport/blob/master/CH341PAR_LINUX/lib/ch34x_lib.c#L593" rel="noopener noreferrer"&gt;https://github.com/zoobab/ch341-parport/blob/master/CH341PAR_LINUX/lib/ch34x_lib.c#L593&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also a simpler implementation here: &lt;a href="https://github.com/frank-zago/ch341-i2c-spi-gpio/blob/master/gpio-ch341.c#L198" rel="noopener noreferrer"&gt;https://github.com/frank-zago/ch341-i2c-spi-gpio/blob/master/gpio-ch341.c#L198&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Writing GPIO
&lt;/h3&gt;

&lt;p&gt;There are some undocumented values, but here is the packet structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[byte0] 0xA1 (output command)
[byte1] 0x6A (magic value)
[byte2] enable mask
[byte3] Byte 1 Data (0 for LOW, 1 for HIGH)
[byte4] Byte 1 Direction (0 for INPUT, 1 for OUTPUT)
[byte5] Byte 0 Data (0 for LOW, 1 for HIGH)
[byte6] Byte 0 Direction (0 for INPUT, 1 for OUTPUT)
[byte7] Byte 2 Data (0 for LOW, 1 for HIGH)
[byte8] Byte 2 Direction (should be 0x00)
[byte9] Byte 3 Data (0 for LOW, 1 for HIGH)
[byte10] Byte 3 Direction (should be 0x00)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The packet must be exactly 11 bytes.&lt;/p&gt;

&lt;h4&gt;
  
  
  GPIO Bytes
&lt;/h4&gt;

&lt;p&gt;There are 4 GPIO bytes in the following order:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Byte 1 (bits 8–15), pins: &lt;code&gt;ERR, PEMP, INT, SLCT, unknown, WAIT, READ, ADDR&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Byte 0 (bits 0–7), pins: &lt;code&gt;D0–D7&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Byte 2 (bits 16–23), pins: &lt;code&gt;WRITE, SCL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Byte 3 (bits 24–31), pins: &lt;code&gt;SDA&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Enable Mask
&lt;/h4&gt;

&lt;p&gt;The enable mask consists of pairs of bits that enable output and direction. Since this function is only for writing outputs, you need to always set both to 1. It follows the same order as the GPIO bytes, meaning the first two bits control enable and data direction for Byte 1 (bits 8–15):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bits 0,1 = Byte 1 Enable, Direction
bits 2,3 = Byte 0 Enable, Direction
bits 4,5 = Byte 2 Enable, Direction
bits 6,7 = Byte 3 Enable, Direction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that Byte 2 and Byte 3 only allow output direction, but you need to set Enable=0, Direction=1. The documentation is not very clear about the meaning of "enable" here.&lt;/p&gt;

&lt;h3&gt;
  
  
  Writing with &lt;code&gt;CH34xSet_D5_D0&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;A special message exists to set only pins D0–D5. The packet is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;GPIOCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UIO_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              &lt;span class="c1"&gt;# 0xAB
&lt;/span&gt;    &lt;span class="n"&gt;GPIOCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UIO_DIR&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="mh"&gt;0x3F&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# 0x40
&lt;/span&gt;    &lt;span class="n"&gt;GPIOCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UIO_OUT&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x3F&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="c1"&gt;# 0x80
&lt;/span&gt;    &lt;span class="n"&gt;GPIOCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UIO_STREAM_END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;          &lt;span class="c1"&gt;# 0x20
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;mask&lt;/code&gt; bits represent the pins to set HIGH. For example, to set &lt;code&gt;D0&lt;/code&gt; HIGH use &lt;code&gt;0x1&lt;/code&gt;, and to set &lt;code&gt;D0&lt;/code&gt; and &lt;code&gt;D2&lt;/code&gt; HIGH use &lt;code&gt;0x5&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reading
&lt;/h3&gt;

&lt;p&gt;Reading is simple, though it involves some undocumented behavior:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GPIOCmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INPUT&lt;/span&gt; &lt;span class="c1"&gt;# 0xA0
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After sending the command, read 6 bytes of data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[byte0] Byte 0 Data
[byte1] Byte 1 Data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All other bytes are undocumented or represent output pins.&lt;br&gt;
To read the value of &lt;code&gt;D0&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;d0_value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="mh"&gt;0x1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  SPI Implementation
&lt;/h2&gt;

&lt;p&gt;This is the simplest implementation, but it does require some understanding of SPI. The implementation needs to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Send X bytes&lt;/li&gt;
&lt;li&gt;Read X bytes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is because SPI is full-duplex, meaning that when you send data you also receive data within the same clock cycle. You must send and read simultaneously, or the buffers will overflow.&lt;/p&gt;

&lt;p&gt;The implementation is based on: &lt;a href="https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux/blob/main/driver/ch34x_mphsi_master_spi.c#L511" rel="noopener noreferrer"&gt;https://github.com/WCHSoftGroup/ch34x_mphsi_master_linux/blob/main/driver/ch34x_mphsi_master_spi.c#L511&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The command is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;bytes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
  &lt;span class="n"&gt;data_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SPICmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MODE_STREAM&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# 0xA8
&lt;/span&gt;  &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

  &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;# after writing, read the controller response
&lt;/span&gt;  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is all there is to it. To read from SPI, simply call &lt;code&gt;data = write(0xFF)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The one tricky part is that the chip always transmits in LSB-first order, so sending &lt;code&gt;1&lt;/code&gt; is transmitted as &lt;code&gt;1 0 0 0 0 0 0 0&lt;/code&gt;. Most devices expect MSB-first (&lt;code&gt;0 0 0 0 0 0 0 1&lt;/code&gt;), so you can use a lookup table to convert between the two.&lt;/p&gt;

&lt;h3&gt;
  
  
  Chip Select
&lt;/h3&gt;

&lt;p&gt;The board has &lt;code&gt;CS0&lt;/code&gt;, &lt;code&gt;CS1&lt;/code&gt;, and &lt;code&gt;CS2&lt;/code&gt;, but there is no dedicated command for chip select. Instead, you enable it through GPIO using &lt;code&gt;CH34xSet_D5_D0&lt;/code&gt;. For example, set &lt;code&gt;D0&lt;/code&gt; HIGH before a transaction and LOW after to use it as a chip select signal.&lt;/p&gt;

</description>
      <category>wch</category>
      <category>python</category>
    </item>
    <item>
      <title>Zephyr on Arduino UNO Q MCU</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Fri, 02 Jan 2026 19:53:20 +0000</pubDate>
      <link>https://forem.com/danielmx/zephyr-on-arduino-uno-q-mcu-5974</link>
      <guid>https://forem.com/danielmx/zephyr-on-arduino-uno-q-mcu-5974</guid>
      <description>&lt;p&gt;The Arduino UNO Q have a &lt;a href="https://www.st.com/en/microcontrollers-microprocessors/stm32u575-585.html" rel="noopener noreferrer"&gt;STM32U585&lt;/a&gt; inside doing all the Arduino stuff, it communicates with main processor and GPIO pins on board; it seems the only way to get a pinout is the schematics:&lt;br&gt;
&lt;a href="https://docs.arduino.cc/resources/schematics/ABX00162-schematics.pdf" rel="noopener noreferrer"&gt;https://docs.arduino.cc/resources/schematics/ABX00162-schematics.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The pinout image have brief information about the MCU pins&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F057pus6kjj26qsn284xj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F057pus6kjj26qsn284xj.png" alt="Arduino UNO Q Pinout" width="800" height="755"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://docs.arduino.cc/tutorials/uno-q/user-manual/#pinout" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But only shows that pins belong to MCU, and the only indication are on RGB LED 3 and 4 that shows the GPIO used for the MCU.&lt;/p&gt;

&lt;p&gt;For this example it will be needed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Zephyr (on the PC Host, probably can be reused the version in UNO Q)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://developer.android.com/tools/releases/platform-tools" rel="noopener noreferrer"&gt;ADB tools&lt;/a&gt; (to connect to the device from PC Host)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Zephyr
&lt;/h2&gt;

&lt;p&gt;You need to &lt;a href="https://docs.zephyrproject.org/latest/develop/getting_started/index.html" rel="noopener noreferrer"&gt;install&lt;/a&gt; / update Zephyr. Is important to have at least &lt;a href="https://github.com/zephyrproject-rtos/zephyr/tree/v4.3.0/boards/arduino/uno_q" rel="noopener noreferrer"&gt;version 4.3.0&lt;/a&gt; as that is the first version with support&lt;/p&gt;
&lt;h2&gt;
  
  
  Compile example
&lt;/h2&gt;

&lt;p&gt;It can be used the &lt;code&gt;blinky&lt;/code&gt; &lt;a href="https://docs.zephyrproject.org/latest/develop/getting_started/index.html#build-the-blinky-sample" rel="noopener noreferrer"&gt;example directly from documentation&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# use the path to your zephyr setup
cd ~/zephyrproject/zephyr
west build -p always -b arduino_uno_q samples/basic/blinky
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Upload to device
&lt;/h2&gt;

&lt;p&gt;Once compiled it needs to be copied to UNO Q device using adb:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb push build/zephyr/zephyr.elf /tmp/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Flash MCU
&lt;/h2&gt;

&lt;p&gt;The only remaining step is to flash the STM32 MCU this can be done with the tools already installed in the UNO Q&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb shell

# following commands must be in the UNO Q
# paths are hardcoded but should work
# probably some paths needs to be updated with proper versions
/home/arduino/.arduino15/packages/arduino/tools/remoteocd/0.0.4-rc.4/remoteocd \
    upload \
    --adb-path "/home/arduino/.arduino15/packages/arduino/tools/adb/32.0.0/adb" \
    -s "{upload.port.properties.serialNumber}" \
    -f "/home/arduino/.arduino15/packages/arduino/hardware/zephyr/0.52.0/variants/arduino_uno_q_stm32u585xx/flash_bootloader.cfg" \
    "--verbose" \
    /tmp/zephyr.elf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If everything is fine, the &lt;code&gt;LED3&lt;/code&gt; will blink with a green color&lt;/p&gt;

&lt;h2&gt;
  
  
  Restoring Sketch Bootloader
&lt;/h2&gt;

&lt;p&gt;If you use Arduino App Lab and try to upload a new sketch, you will notice there will be error on uploading, this is because the MCU contains a called "Sketch Bootloader" and the sketch code is added on top of that. &lt;br&gt;
But the Arduino UNO Q have the commands to restore:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;arduino-cli burn-bootloader -b arduino:zephyr:unoq -P jlink
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command will upload the Sketch Bootloader so you can upload code from the App Lab. Nice!&lt;/p&gt;

&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.zephyrproject.org/latest/boards/arduino/uno_q/doc/index.html" rel="noopener noreferrer"&gt;https://docs.zephyrproject.org/latest/boards/arduino/uno_q/doc/index.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/arduino/remoteocd" rel="noopener noreferrer"&gt;https://github.com/arduino/remoteocd&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>arduino</category>
    </item>
    <item>
      <title>MAX7219 Example (8 digit segment driver)</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Wed, 31 Dec 2025 20:35:00 +0000</pubDate>
      <link>https://forem.com/danielmx/max7219-example-8-digit-segment-driver-52m8</link>
      <guid>https://forem.com/danielmx/max7219-example-8-digit-segment-driver-52m8</guid>
      <description>&lt;p&gt;The MAX7219 is a 8 digit segment driver, it can also work as standard 8x8 LED driver, but since there is BCD support, it works much better with 7-segment parts.&lt;/p&gt;

&lt;p&gt;The board I used have 8 segments and the MAX7219&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7tcvmp74kotqlhb9iev.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7tcvmp74kotqlhb9iev.jpg" alt="MAX7219 8 digit 7-segment" width="600" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The inputs are just Power(&lt;code&gt;GND&lt;/code&gt;, &lt;code&gt;VCC&lt;/code&gt;), &lt;code&gt;DIN&lt;/code&gt; (Serial Data Input), &lt;code&gt;CLK&lt;/code&gt; and &lt;code&gt;LOAD/CS&lt;/code&gt;&lt;br&gt;
Even it looks like a SPI module, only the MAX7221 supports it, so the input for MAX7219 is serial and is simple to use.&lt;/p&gt;

&lt;p&gt;It needs to be sent 16 bit data which are split into lower 8 bits for the data and higher 8 bits for register.&lt;/p&gt;

&lt;p&gt;The datasheet is very clear and helpful about all parts, my only complain is the functional diagram suggest the data is loaded with LSB first which is not the case.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwd83go68xrsp676yvjm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwd83go68xrsp676yvjm.png" alt="Serial Data Format" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the address, there are few commands:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faulx9324yalt3xwcl7t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faulx9324yalt3xwcl7t0.png" alt="Register Address Map" width="439" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digit 0-7 data (&lt;code&gt;0x1&lt;/code&gt; to &lt;code&gt;0x8&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Decode mode &lt;code&gt;0x9&lt;/code&gt; (Disable / Enable BCD for each digit)&lt;/li&gt;
&lt;li&gt;Intensity &lt;code&gt;0xA&lt;/code&gt; (16  levels of intensity going from &lt;code&gt;0x0&lt;/code&gt; to &lt;code&gt;0xF&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Scan Limit &lt;code&gt;0xB&lt;/code&gt; (Disable / Enable digit output)&lt;/li&gt;
&lt;li&gt;Shutdown &lt;code&gt;0xC&lt;/code&gt; (Disable / Enable output)&lt;/li&gt;
&lt;li&gt;Display Test &lt;code&gt;0xF&lt;/code&gt; (Disable / Enable test mode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Display Test&lt;/code&gt; just enable all segments and all digits at full intensity.&lt;br&gt;
For &lt;code&gt;Shutdown&lt;/code&gt; if data is &lt;code&gt;0x1&lt;/code&gt; will enable output (TBH a bit odd to use that naming) &lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Scan Limit
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Scan Limit&lt;/code&gt; allows to how many digits to be display, so it can be up to &lt;code&gt;0x7&lt;/code&gt; (to display 8 digits). As note, the reset value of &lt;code&gt;0x0&lt;/code&gt; means that will show first digit; if you want to disable all output then you need to use the &lt;code&gt;Shutdown&lt;/code&gt; command, or just set the first digit to &lt;code&gt;0x0&lt;/code&gt; (no segment on) for &lt;code&gt;No Decode&lt;/code&gt; mode, or &lt;code&gt;0xF&lt;/code&gt; for &lt;code&gt;BCD&lt;/code&gt; mode&lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Digit
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Digit&lt;/code&gt; data will store 8 bits for the specific digit, the data can be stored in two ways: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard (No BCD / No Decode)&lt;/li&gt;
&lt;li&gt;BCD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the Standard, you need to select through bits which part to show from the 7-segment, so for example to display a &lt;code&gt;1&lt;/code&gt; you can store &lt;code&gt;0x30&lt;/code&gt; or &lt;code&gt;D5=1,D4=1&lt;/code&gt; (&lt;code&gt;B=1,C=1&lt;/code&gt;)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n2kzr8a7qdpfgwn16ga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n2kzr8a7qdpfgwn16ga.png" alt="No Decode Mode" width="446" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the BCD mode, the value from &lt;code&gt;0x0&lt;/code&gt; to &lt;code&gt;0x9&lt;/code&gt; (or &lt;code&gt;0-9&lt;/code&gt;) will be converted into the proper segments on, so if a &lt;code&gt;0x1&lt;/code&gt; is stored, the driver will properly convert to show segments &lt;code&gt;B=1,C=1&lt;/code&gt;.&lt;br&gt;
There are some special characters going from &lt;code&gt;0xA&lt;/code&gt; to &lt;code&gt;0xF&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0xA = dash(-)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xB = E&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xC = H&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xD = L&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xE = P&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0xF&lt;/code&gt; blank, so no output, the same as &lt;code&gt;0x0&lt;/code&gt; in &lt;code&gt;No Decode Mode&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Yes you can send a &lt;code&gt;HELP&lt;/code&gt; message with &lt;code&gt;0x040C 0x030B 0x020D 0x010E&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Decode Mode
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Decode Mode&lt;/code&gt;register allows to use the &lt;code&gt;No Decode/BCD&lt;/code&gt; mode, and the register is a bit interesting since is a mask, if the value is &lt;code&gt;0x0&lt;/code&gt; means no decode so the data are just the segment to set on.&lt;br&gt;
But if you want a specific digit to use BCD, you can use as mask, so for example to enable BCD on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digit 0 &lt;code&gt;0x1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Digit 1 &lt;code&gt;0x2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Digit 0 and 1 &lt;code&gt;0x3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Register: Loading Data
&lt;/h2&gt;

&lt;p&gt;The loading data is very simple, when you rise the &lt;code&gt;CLK&lt;/code&gt; it will read the &lt;code&gt;DIN&lt;/code&gt; and add to serial buffer (&lt;code&gt;MSB&lt;/code&gt; to &lt;code&gt;LSB&lt;/code&gt; order).&lt;br&gt;
So sending a bit is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;digitalWrite(PIN_CLK, LOW);
// check if MSB bit is on
if (cmd &amp;amp; 0x8000) {
    digitalWrite(PIN_DIN, HIGH);
} else {
    digitalWrite(PIN_DIN, LOW);
}
digitalWrite(PIN_CLK, HIGH);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to send a 16 bit value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// enable test mode
// 0x0F is test mode register
// 0x01 is enable data
uint16_t cmd = 0x0F01;
for (int i = 0; i &amp;lt; 16; i++) {
    digitalWrite(PIN_CLK, LOW);
    // check if MSB bit is on
    if (cmd &amp;amp; 0x8000) {
        digitalWrite(PIN_DIN, HIGH);
    } else {
        digitalWrite(PIN_DIN, LOW);
    }
    digitalWrite(PIN_CLK, HIGH);
    // shift one bit
    cmd &amp;lt;&amp;lt;= 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of the MAX7219 when &lt;code&gt;LOAD&lt;/code&gt; rises, it will load the last 16 bits from the &lt;code&gt;DIN&lt;/code&gt; input into the decoder and run the command.&lt;br&gt;
So this is achieved after sending the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// latch the data
// rise the LOAD pin from low to high and go back into low after that
digitalWrite(PIN_LOAD, LOW);
digitalWrite(PIN_LOAD, HIGH);
digitalWrite(PIN_LOAD, LOW);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;p&gt;Everything is a 16 bit data, so there is a helper function to build the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uint16_t buildCmd(uint8_t registerAddress, uint8_t data)
{
    return ((uint16_t)registerAddress &amp;lt;&amp;lt; 8) | data;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this can be converted into a macro if is needed better performance.&lt;/p&gt;

&lt;p&gt;So the commands are very easy to build, for example to send a number 6 to digit 0 (using BCD):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 0x1 is the register for digit 0
uint16_t cmd = buildCmd(0x1, 6);
// this is the function using code previously 
// posted to send data to module
sendCmd(cmd);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if not using BCD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 0x1 is the register for digit 0
// 6 uses A,C,D,E,F,G so is 
// 0101 1111 or 0x5F
uint16_t cmd = buildCmd(0x1, 0x5F);
// this is the function using code previously 
// posted to send data to module
sendCmd(cmd);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;The example uses the test mode, but later sets all the registers to "reset" most of them, note that this is not really needed if you only reset the module and never use the test mode.&lt;br&gt;
But I think is good to have it so you can configure everything before use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmdSetScanLimit(7); // Enable all 8 digits
cmdSetIntensity(0); // lowest intensity
cmdSetDecodeMode(0xFF); // all digits will use BCD

// set all segments to blank
for (uint8_t i = 0; i &amp;lt; 8; i++) {
  uint16_t cmd = buildCmd(REGISTER_DIGIT0 + i, 0xF);
  sendCmd(cmd);
}

// send all the possible values on BCD, finishing with blank
for (uint8_t i = 0; i &amp;lt; 8; i++) {
  for (uint8_t j = 0; j &amp;lt; 16; j++) {
    uint16_t cmd = buildCmd(REGISTER_DIGIT0 + i, j); 
    sendCmd(cmd);
    delay(200);
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example url
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/danguer/arduino-examples/tree/main/max7219" rel="noopener noreferrer"&gt;https://github.com/danguer/arduino-examples/tree/main/max7219&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Datasheet
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.analog.com/media/en/technical-documentation/data-sheets/max7219-max7221.pdf" rel="noopener noreferrer"&gt;https://www.analog.com/media/en/technical-documentation/data-sheets/max7219-max7221.pdf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
    </item>
    <item>
      <title>MAX7219 Example (8 digit segment driver)</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Wed, 31 Dec 2025 20:35:00 +0000</pubDate>
      <link>https://forem.com/danielmx/max7219-example-8-digit-segment-driver-1dfa</link>
      <guid>https://forem.com/danielmx/max7219-example-8-digit-segment-driver-1dfa</guid>
      <description>&lt;p&gt;The MAX7219 is a 8 digit segment driver, it can also work as standard 8x8 LED driver, but since there is BCD support, it works much better with 7-segment parts.&lt;/p&gt;

&lt;p&gt;The board I used have 8 segments and the MAX7219&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7tcvmp74kotqlhb9iev.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg7tcvmp74kotqlhb9iev.jpg" alt="MAX7219 8 digit 7-segment" width="600" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The inputs are just Power(&lt;code&gt;GND&lt;/code&gt;, &lt;code&gt;VCC&lt;/code&gt;), &lt;code&gt;DIN&lt;/code&gt; (Serial Data Input), &lt;code&gt;CLK&lt;/code&gt; and &lt;code&gt;LOAD/CS&lt;/code&gt;&lt;br&gt;
Even it looks like a SPI module, only the MAX7221 supports it, so the input for MAX7219 is serial and is simple to use.&lt;/p&gt;

&lt;p&gt;It needs to be sent 16 bit data which are split into lower 8 bits for the data and higher 8 bits for register.&lt;/p&gt;

&lt;p&gt;The datasheet is very clear and helpful about all parts, my only complain is the functional diagram suggest the data is loaded with LSB first which is not the case.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwd83go68xrsp676yvjm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwwd83go68xrsp676yvjm.png" alt="Serial Data Format" width="800" height="90"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the address, there are few commands:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faulx9324yalt3xwcl7t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faulx9324yalt3xwcl7t0.png" alt="Register Address Map" width="439" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digit 0-7 data (&lt;code&gt;0x1&lt;/code&gt; to &lt;code&gt;0x8&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Decode mode &lt;code&gt;0x9&lt;/code&gt; (Disable / Enable BCD for each digit)&lt;/li&gt;
&lt;li&gt;Intensity &lt;code&gt;0xA&lt;/code&gt; (16  levels of intensity going from &lt;code&gt;0x0&lt;/code&gt; to &lt;code&gt;0xF&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Scan Limit &lt;code&gt;0xB&lt;/code&gt; (Disable / Enable digit output)&lt;/li&gt;
&lt;li&gt;Shutdown &lt;code&gt;0xC&lt;/code&gt; (Disable / Enable output)&lt;/li&gt;
&lt;li&gt;Display Test &lt;code&gt;0xF&lt;/code&gt; (Disable / Enable test mode).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;Display Test&lt;/code&gt; just enable all segments and all digits at full intensity.&lt;br&gt;
For &lt;code&gt;Shutdown&lt;/code&gt; if data is &lt;code&gt;0x1&lt;/code&gt; will enable output (TBH a bit odd to use that naming) &lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Scan Limit
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Scan Limit&lt;/code&gt; allows to how many digits to be display, so it can be up to &lt;code&gt;0x7&lt;/code&gt; (to display 8 digits). As note, the reset value of &lt;code&gt;0x0&lt;/code&gt; means that will show first digit; if you want to disable all output then you need to use the &lt;code&gt;Shutdown&lt;/code&gt; command, or just set the first digit to &lt;code&gt;0x0&lt;/code&gt; (no segment on) for &lt;code&gt;No Decode&lt;/code&gt; mode, or &lt;code&gt;0xF&lt;/code&gt; for &lt;code&gt;BCD&lt;/code&gt; mode&lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Digit
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Digit&lt;/code&gt; data will store 8 bits for the specific digit, the data can be stored in two ways: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard (No BCD / No Decode)&lt;/li&gt;
&lt;li&gt;BCD&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the Standard, you need to select through bits which part to show from the 7-segment, so for example to display a &lt;code&gt;1&lt;/code&gt; you can store &lt;code&gt;0x30&lt;/code&gt; or &lt;code&gt;D5=1,D4=1&lt;/code&gt; (&lt;code&gt;B=1,C=1&lt;/code&gt;)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n2kzr8a7qdpfgwn16ga.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1n2kzr8a7qdpfgwn16ga.png" alt="No Decode Mode" width="446" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the BCD mode, the value from &lt;code&gt;0x0&lt;/code&gt; to &lt;code&gt;0x9&lt;/code&gt; (or &lt;code&gt;0-9&lt;/code&gt;) will be converted into the proper segments on, so if a &lt;code&gt;0x1&lt;/code&gt; is stored, the driver will properly convert to show segments &lt;code&gt;B=1,C=1&lt;/code&gt;.&lt;br&gt;
There are some special characters going from &lt;code&gt;0xA&lt;/code&gt; to &lt;code&gt;0xF&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;0xA = dash(-)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xB = E&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xC = H&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xD = L&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;0xE = P&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;0xF&lt;/code&gt; blank, so no output, the same as &lt;code&gt;0x0&lt;/code&gt; in &lt;code&gt;No Decode Mode&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(Yes you can send a &lt;code&gt;HELP&lt;/code&gt; message with &lt;code&gt;0x040C 0x030B 0x020D 0x010E&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Register: Decode Mode
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;Decode Mode&lt;/code&gt;register allows to use the &lt;code&gt;No Decode/BCD&lt;/code&gt; mode, and the register is a bit interesting since is a mask, if the value is &lt;code&gt;0x0&lt;/code&gt; means no decode so the data are just the segment to set on.&lt;br&gt;
But if you want a specific digit to use BCD, you can use as mask, so for example to enable BCD on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Digit 0 &lt;code&gt;0x1&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Digit 1 &lt;code&gt;0x2&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Digit 0 and 1 &lt;code&gt;0x3&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Register: Loading Data
&lt;/h2&gt;

&lt;p&gt;The loading data is very simple, when you rise the &lt;code&gt;CLK&lt;/code&gt; it will read the &lt;code&gt;DIN&lt;/code&gt; and add to serial buffer (&lt;code&gt;MSB&lt;/code&gt; to &lt;code&gt;LSB&lt;/code&gt; order).&lt;br&gt;
So sending a bit is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;digitalWrite(PIN_CLK, LOW);
// check if MSB bit is on
if (cmd &amp;amp; 0x8000) {
    digitalWrite(PIN_DIN, HIGH);
} else {
    digitalWrite(PIN_DIN, LOW);
}
digitalWrite(PIN_CLK, HIGH);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to send a 16 bit value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// enable test mode
// 0x0F is test mode register
// 0x01 is enable data
uint16_t cmd = 0x0F01;
for (int i = 0; i &amp;lt; 16; i++) {
    digitalWrite(PIN_CLK, LOW);
    // check if MSB bit is on
    if (cmd &amp;amp; 0x8000) {
        digitalWrite(PIN_DIN, HIGH);
    } else {
        digitalWrite(PIN_DIN, LOW);
    }
    digitalWrite(PIN_CLK, HIGH);
    // shift one bit
    cmd &amp;lt;&amp;lt;= 1;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of the MAX7219 when &lt;code&gt;LOAD&lt;/code&gt; rises, it will load the last 16 bits from the &lt;code&gt;DIN&lt;/code&gt; input into the decoder and run the command.&lt;br&gt;
So this is achieved after sending the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// latch the data
// rise the LOAD pin from low to high and go back into low after that
digitalWrite(PIN_LOAD, LOW);
digitalWrite(PIN_LOAD, HIGH);
digitalWrite(PIN_LOAD, LOW);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Commands
&lt;/h2&gt;

&lt;p&gt;Everything is a 16 bit data, so there is a helper function to build the data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;uint16_t buildCmd(uint8_t registerAddress, uint8_t data)
{
    return ((uint16_t)registerAddress &amp;lt;&amp;lt; 8) | data;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that this can be converted into a macro if is needed better performance.&lt;/p&gt;

&lt;p&gt;So the commands are very easy to build, for example to send a number 6 to digit 0 (using BCD):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 0x1 is the register for digit 0
uint16_t cmd = buildCmd(0x1, 6);
// this is the function using code previously 
// posted to send data to module
sendCmd(cmd);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or if not using BCD:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// 0x1 is the register for digit 0
// 6 uses A,C,D,E,F,G so is 
// 0101 1111 or 0x5F
uint16_t cmd = buildCmd(0x1, 0x5F);
// this is the function using code previously 
// posted to send data to module
sendCmd(cmd);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;The example uses the test mode, but later sets all the registers to "reset" most of them, note that this is not really needed if you only reset the module and never use the test mode.&lt;br&gt;
But I think is good to have it so you can configure everything before use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cmdSetScanLimit(7); // Enable all 8 digits
cmdSetIntensity(0); // lowest intensity
cmdSetDecodeMode(0xFF); // all digits will use BCD

// set all segments to blank
for (uint8_t i = 0; i &amp;lt; 8; i++) {
  uint16_t cmd = buildCmd(REGISTER_DIGIT0 + i, 0xF);
  sendCmd(cmd);
}

// send all the possible values on BCD, finishing with blank
for (uint8_t i = 0; i &amp;lt; 8; i++) {
  for (uint8_t j = 0; j &amp;lt; 16; j++) {
    uint16_t cmd = buildCmd(REGISTER_DIGIT0 + i, j); 
    sendCmd(cmd);
    delay(200);
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Example url
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/danguer/arduino-examples/tree/main/max7219" rel="noopener noreferrer"&gt;https://github.com/danguer/arduino-examples/tree/main/max7219&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Datasheet
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.analog.com/media/en/technical-documentation/data-sheets/max7219-max7221.pdf" rel="noopener noreferrer"&gt;https://www.analog.com/media/en/technical-documentation/data-sheets/max7219-max7221.pdf&lt;/a&gt;&lt;/p&gt;

</description>
      <category>arduino</category>
    </item>
    <item>
      <title>TM1637 Board Arduino Example</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Tue, 18 Nov 2025 07:10:10 +0000</pubDate>
      <link>https://forem.com/danielmx/tm1637-board-arduino-example-1po1</link>
      <guid>https://forem.com/danielmx/tm1637-board-arduino-example-1po1</guid>
      <description>&lt;p&gt;The TM1637 is a 8 segments led controller which can control up to 6 displays and key scan of 16 inputs.&lt;br&gt;
There are multiple boards but the most common is using 4 displays with two dots in the middle so can be used as a timer display.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy8e9upz01mn8q1zm1gb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foy8e9upz01mn8q1zm1gb.jpg" alt="TM1637 Board" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The protocol is similar to I2C but is simpler as there is no need of device address.&lt;br&gt;
So the protocol is the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Signal&lt;/li&gt;
&lt;li&gt;Command Data Byte&lt;/li&gt;
&lt;li&gt;Optional Data Byte(s)&lt;/li&gt;
&lt;li&gt;End Signal&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrl8lek7kpru49666k48.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftrl8lek7kpru49666k48.png" alt="Example of protocol" width="800" height="212"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Start Signal
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CLK&lt;/code&gt; must be &lt;code&gt;HIGH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DIO&lt;/code&gt; must transition from &lt;code&gt;HIGH&lt;/code&gt; to &lt;code&gt;LOW&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  End Signal
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;CLK&lt;/code&gt; must be &lt;code&gt;HIGH&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DIO&lt;/code&gt; must transition from &lt;code&gt;LOW&lt;/code&gt; to &lt;code&gt;HIGH&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Sending Data
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DIO&lt;/code&gt; must be set to value when &lt;code&gt;CLK&lt;/code&gt; is low&lt;/li&gt;
&lt;li&gt;Send 8 bits, each clock cycle can be at most &lt;code&gt;2us&lt;/code&gt; (maximum speed of &lt;code&gt;500Khz&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;After 8 bits the 9th clock cycle the chip will send an ACK setting DIO to &lt;code&gt;LOW&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are 3 types of commands:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data&lt;/strong&gt; command (write to displays or read key scan)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Address&lt;/strong&gt; command (which display to use, it can be up to 6 displays, but the board only contain 4)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display&lt;/strong&gt;, set displays &lt;code&gt;ON&lt;/code&gt;/&lt;code&gt;OFF&lt;/code&gt; and set brightness (8 possible levels)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Data&lt;/strong&gt; command allows to send a specific address or auto-increment (the most common scenario) so after setting the initial address it can be sent all the data to write in the displays without need to keep setting the address after each command.&lt;/p&gt;

&lt;p&gt;The examples in the datasheet shows that &lt;strong&gt;Display&lt;/strong&gt; commands are sent at the end; but there is no need for that, it can be sent before any &lt;strong&gt;Data&lt;/strong&gt; command to set the configuration; after set, there is no need to be changed (except for some reason the display is reset)&lt;/p&gt;

&lt;p&gt;The displays in the board are 8 Segments Displays&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepo5n21sm8nuse8dfzzl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fepo5n21sm8nuse8dfzzl.png" alt="8 Segments Display" width="378" height="507"&gt;&lt;/a&gt;&lt;br&gt;
Actually are 7 Segments Displays as there is no dot and the two dots in the middle are handled by the second display.&lt;br&gt;
The byte order is: &lt;code&gt;Xgfedcba&lt;/code&gt; where X is the dot or &lt;code&gt;DP&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Arduino Code
&lt;/h2&gt;

&lt;p&gt;To make work in Arduino, you need 2 pin inputs and three functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Start Transfer&lt;/li&gt;
&lt;li&gt;End Transfer&lt;/li&gt;
&lt;li&gt;Byte Write
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void dataTransferStart() {
  // according to doc, start must be
  // a transition of DIO from LOW to HIGH
  // when a CLK clock is HIGH
  digitalWrite(PIN_DIO, HIGH);
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_DIO, LOW);
  delayClock();
  digitalWrite(PIN_CLK, LOW);
  delayClock();
}

void dataTransferEnd() {
  // according to doc, end must be
  // a transition of DIO from HIGH to LOW
  // when a CLK clock is HIGH
  digitalWrite(PIN_DIO, LOW);
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_DIO, HIGH);
  digitalWrite(PIN_CLK, LOW);
  delayClock();
}

unsigned char writeByte(unsigned char data) {
  // clock is assumed to be low, but just in case
  digitalWrite(PIN_CLK, LOW);

  for (unsigned char i = 0; i &amp;lt; 8; i++) {
    digitalWrite(PIN_DIO, (data &amp;amp; 0x1) ? HIGH : LOW);
    data = data &amp;gt;&amp;gt; 1;

    // run a clock cycle
    delayClock();
    digitalWrite(PIN_CLK, HIGH);
    delayClock();
    digitalWrite(PIN_CLK, LOW);
  }

  // here the chip does an ACK for one cycle
  pinMode(PIN_DIO, INPUT);
  delayClock();
  unsigned char ack = digitalRead(PIN_DIO);

  // finish clock cycle
  digitalWrite(PIN_CLK, HIGH);
  delayClock();
  digitalWrite(PIN_CLK, LOW);
  pinMode(PIN_DIO, OUTPUT);

  return ack;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The commands are very simple, the two MSB bits define the type of command:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;01&lt;/code&gt; &lt;strong&gt;Data&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;10&lt;/code&gt; &lt;strong&gt;Display&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;11&lt;/code&gt; &lt;strong&gt;Address&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The most simple is the display:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;void setBrightness(unsigned char brightness) {
  // display settings
  dataTransferStart();
  // this will be 0b10_00_1_XXX
  writeByte(CMD_DISPLAY | CMD_DISPLAY_ON | (brightness &amp;amp; 0x7));
  dataTransferEnd();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the &lt;code&gt;0b10_00_1_XXX&lt;/code&gt; means: &lt;code&gt;10&lt;/code&gt; is the &lt;strong&gt;Display&lt;/strong&gt; command, the &lt;code&gt;00&lt;/code&gt; are "irrelevant" items in the datasheet, &lt;code&gt;1&lt;/code&gt; is to enable the display and &lt;code&gt;XXX&lt;/code&gt; is the level of the brightness.&lt;/p&gt;

&lt;p&gt;The full code and example is here: &lt;a href="https://github.com/danguer/arduino-examples/tree/main/tm1637" rel="noopener noreferrer"&gt;https://github.com/danguer/arduino-examples/tree/main/tm1637&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Links
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/avishorp/TM1637/blob/master/docs/TM1637_V2.4_EN.pdf" rel="noopener noreferrer"&gt;Datasheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/dmadison/LED-Segment-ASCII/tree/master/7-Segment" rel="noopener noreferrer"&gt;ASCII library&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>arduino</category>
    </item>
    <item>
      <title>HC05 / XBee First Steps</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Sun, 19 Oct 2025 03:17:16 +0000</pubDate>
      <link>https://forem.com/danielmx/hc05-xbee-first-steps-3h48</link>
      <guid>https://forem.com/danielmx/hc05-xbee-first-steps-3h48</guid>
      <description>&lt;p&gt;Long time ago, while researching ways to communicate through arduino, I found XBee modules, I was looking LoRa modules and this seems to fit so I got several of them&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhp9sohh174d492wl1g9.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjhp9sohh174d492wl1g9.jpg" alt="XBee Modules" width="458" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;since the pins are smaller than regular later I got something called an XBee Explorer to connect to computer&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fge3giyi8at49h96c2twb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fge3giyi8at49h96c2twb.jpg" alt="XBee Explorer" width="400" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn't know at the time much about communication modules so didn't do much research. &lt;br&gt;
Recently I wanted to test the modules again, so I started doing the research.&lt;/p&gt;

&lt;p&gt;The original XBee are devices from &lt;a href="https://www.digi.com/products/embedded-systems/digi-xbee/rf-modules" rel="noopener noreferrer"&gt;Zigbee&lt;/a&gt; that have a specific shape and specific pins, there are different options for modules, including LoRa, WiFi and Bluetooth&lt;/p&gt;

&lt;p&gt;The pinout for the Xbee is this:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauyyy8b7rdpklzudpqk0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fauyyy8b7rdpklzudpqk0.png" alt="XBee Pinout" width="800" height="509"&gt;&lt;/a&gt; &lt;br&gt;
&lt;a href="https://www.electronicwings.com/sensors-modules/xbee-module" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, the modules I got are labeled "HC05" it turns those are actually a breakout board for a module called HC05 which is soldered to the pin, the module is this:&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1ik0c1ump54nfes89dd.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa1ik0c1ump54nfes89dd.jpg" alt="HC05" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This module is also a breakout board to only use Serial capabilities&lt;/p&gt;

&lt;p&gt;The pinout for the module is this: &lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl58sonfpjx91fg69p9ex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl58sonfpjx91fg69p9ex.png" alt="HC05 Pinout" width="254" height="319"&gt;&lt;/a&gt; &lt;a href="https://components101.com/sites/default/files/component_datasheet/HC-05%20Datasheet.pdf" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So contain a lot of pins that are not used in any board&lt;/p&gt;

&lt;p&gt;The HC05 is a Bluetooth module that supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Master / Slave Mode&lt;/li&gt;
&lt;li&gt;AT Commands&lt;/li&gt;
&lt;li&gt;Serial data transmission&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So the module is a bit similar to the &lt;a href="https://dev.to/danielmx/example-code-for-ch9143-13e5"&gt;CH9143&lt;/a&gt; except:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CH9143 is a BLE device and HC05 only supports Bluetooth pairing&lt;/li&gt;
&lt;li&gt;Master mode can pair to any other device&lt;/li&gt;
&lt;li&gt;There is no USB support on HC05, only Serial&lt;/li&gt;
&lt;li&gt;You can set name of the device (among other things)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Connect to module
&lt;/h2&gt;

&lt;p&gt;There is a lot of examples using Arduino to send Serial data, but in this case will be directly connected to computer with python.&lt;/p&gt;

&lt;p&gt;So to connect to computer the XBee Explorer seems like a good solution, this contains an USB to Serial solution. The main issue is to enter into AT Commands you need to set AD0 / Key / BTN pin to VCC, otherwise the module will be in pairing and only sending / receiving data but can't configure.&lt;/p&gt;

&lt;p&gt;So a solution is to use a USB to Serial module and a breakout board (to convert 2mm pins from xbee to standard 2.5mm, an alternative could be to solder into the pin of the XBee Explorer), so the connection is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;3.3v -&amp;gt; VCC (PIN 1)&lt;/li&gt;
&lt;li&gt;RX -&amp;gt; Dout (PIN 2)&lt;/li&gt;
&lt;li&gt;TX -&amp;gt; Din (PIN 3)&lt;/li&gt;
&lt;li&gt;GND -&amp;gt; Dout (PIN 10)&lt;/li&gt;
&lt;li&gt;RTS -&amp;gt; AD0/Key/BTN (PIN 20)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72smq2glg38j23pbwbe6.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F72smq2glg38j23pbwbe6.jpg" alt="Xbee Breakout Board" width="500" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The RTS is needed to enter into AT Mode, the serial code will send this signal to enter and leave after paired with other device.&lt;/p&gt;

&lt;p&gt;To test you could use the app &lt;a href="https://play.google.com/store/apps/details?id=de.kai_morich.serial_bluetooth_terminal&amp;amp;gl=US" rel="noopener noreferrer"&gt;Serial Bluetooth Terminal&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 ch05.py /dev/ttyACM1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will show some info about the device and wait until you pair the device in the app&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Opening port:  /dev/ttyACM1
Entering into AT mode
Sending AT... (checking if AT is enabled)
Response:  ['ERROR:(0)']
AT+VERSION? ['+VERSION:2.0-20100601', 'OK']
device MAC XX:XX:XX:XX:XX:XX
AT+NAME?: [device name] H-C-2010-06-01
AT+ROLE?: [role, 0=Slave, 1=Master] ['+ROLE:0', 'OK']
AT+ADCN?:  ['+ADCN:7', 'OK']
AT+MRAD? [connected device mac]:  XX:XX:XX:XX:XX:XX
Pair to the device: H-C-2010-06-01 with password 1234
Waiting until is paired
Sending and receiving messages, press CTRL+C to stop
Creating background receiving thread
Sending ping 0
Sending ping 1
Sending ping 2
Sending ping 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To pair in device, in the app select the three dots, then &lt;code&gt;Devices&lt;/code&gt; and later the &lt;code&gt;H-C-2010-06-01&lt;/code&gt; (note that name can be different like &lt;code&gt;HC05&lt;/code&gt; or similar but that will show in the console)&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5ho2murqre7v7tu7ypp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi5ho2murqre7v7tu7ypp.jpg" alt="Devices Menu" width="800" height="1587"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3av6self64sla98mce73.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3av6self64sla98mce73.jpg" alt="List of Devices" width="800" height="1588"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And on device will show the ping&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2satdhjgzyvy8xxhpms.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq2satdhjgzyvy8xxhpms.jpg" alt="Android Bluetooth Serial Terminal" width="800" height="1587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;typing&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;

&lt;span class="n"&gt;keep_reading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_serial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;keep_reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_waiting&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;waiting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_waiting&lt;/span&gt;
            &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Serial Input: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
    &lt;span class="c1"&gt;# send command
&lt;/span&gt;    &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# read command back
&lt;/span&gt;    &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;clean_mac_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# first part is always from response
&lt;/span&gt;    &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:]&lt;/span&gt;
    &lt;span class="c1"&gt;# make a single string
&lt;/span&gt;    &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# split into groups of 2 values
&lt;/span&gt;    &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HC05 Uart Example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serial_port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Serial port like /dev/ttyACM0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serial_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baudrate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;38400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytesize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EIGHTBITS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARITY_NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stopbits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STOPBITS_ONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Opening port: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serial_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Entering into AT mode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# this will set RTS=3.3v 
&lt;/span&gt;    &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
    &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending AT... (checking if AT is enabled)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+VERSION?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+VERSION?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+ADDR?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;device MAC&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;clean_mac_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;device_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+NAME?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+NAME:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+NAME?: [device name]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+ROLE?: [role, 0=Slave, 1=Master]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+ROLE?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+ADCN?: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+ADCN?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+MRAD?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ERROR&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+MRAD? [connected device mac]: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;clean_mac_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="c1"&gt;# wait until is paired
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Pair to the device: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;device_name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt; with password 1234&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Waiting until is paired&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+STATE?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;OK&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+STATE:PAIRED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;+STATE:CONNECTED&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


    &lt;span class="c1"&gt;# disable AT mode
&lt;/span&gt;    &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;

    &lt;span class="c1"&gt;# send and receive data
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending and receiving messages, press CTRL+C to stop&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creating background receiving thread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;thread_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;read_serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;thread_read&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending ping &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UART PING &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Finishing reading thread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;keep_reading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;thread_read&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need &lt;a href="https://pyserial.readthedocs.io/en/latest/pyserial_api.html" rel="noopener noreferrer"&gt;&lt;code&gt;pyserial&lt;/code&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install pyserial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Notes
&lt;/h2&gt;

&lt;p&gt;There are more commands in AT mode, here is a simple list of all: &lt;a href="https://s3-sa-east-1.amazonaws.com/robocore-lojavirtual/709/HC-05_ATCommandSet.pdf" rel="noopener noreferrer"&gt;https://s3-sa-east-1.amazonaws.com/robocore-lojavirtual/709/HC-05_ATCommandSet.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The HC05 module is actually a MCU &lt;a href="https://cdn.sparkfun.com/datasheets/Wireless/Bluetooth/CSR-BC417-datasheet.pdf" rel="noopener noreferrer"&gt;BC417&lt;/a&gt; with a flash memory with the firmware.&lt;br&gt;
The MCU seems very capable of different things, including sending audio and controlling several GPIO and SPI, but there is no documentation about how to program it.&lt;/p&gt;

</description>
      <category>bluetooth</category>
    </item>
    <item>
      <title>Starting With Luckfox Lyra Zero W</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Sat, 04 Oct 2025 21:43:55 +0000</pubDate>
      <link>https://forem.com/danielmx/starting-with-lucfox-lyra-zero-w-9ko</link>
      <guid>https://forem.com/danielmx/starting-with-lucfox-lyra-zero-w-9ko</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.luckfox.com/Luckfox-Lyra-Zero-W" rel="noopener noreferrer"&gt;Luckfox Lyra Zero W&lt;/a&gt; is a Development Board with RK3506B Chip, Triple-core Arm Cortex-A7 and Arm Cortex-M0 Processors.&lt;/p&gt;

&lt;p&gt;The Ubuntu image is here:&lt;br&gt;
&lt;a href="https://github.com/platima/SBC-Images/tree/main/Luckfox/Lyra/Lyra%20Zero%20W" rel="noopener noreferrer"&gt;https://github.com/platima/SBC-Images/tree/main/Luckfox/Lyra/Lyra%20Zero%20W&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main issue with image is there no extra disk space so you can't do any resize operation in the same device.&lt;/p&gt;

&lt;p&gt;So the options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resize the &lt;code&gt;img&lt;/code&gt; file&lt;/li&gt;
&lt;li&gt;Resize the SD partition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For both operations you'll need a Linux machine to run the commands&lt;/p&gt;
&lt;h2&gt;
  
  
  Resize the &lt;code&gt;img&lt;/code&gt; file
&lt;/h2&gt;

&lt;p&gt;When you have the &lt;code&gt;img&lt;/code&gt; file after bunzip it, run the following commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# grow the image by 7GB so final will be 8GB, change to proper SD size
dd if=/dev/zero bs=1G count=7 \
  oflag=append conv=notrunc \
  of=Luckfox_Lyra_Zero_W-2503_Ubuntu.img

sudo losetup --find --partscan \
  Luckfox_Lyra_Zero_W-2503_Ubuntu.img

# check with lsblk which loop device 
# (there will be 3 partitions)
# in my case the device is /dev/loop2
lsblk

# data is partition 3 so check for failed sectors
sudo e2fsck -y /dev/loop2p3

# grow partition
sudo growpart -v /dev/loop2 3

# resize ext4 partition
sudo resize2fs /dev/loop2p3

# unmount loop file
sudo losetup --detach /dev/loop2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The new size of the &lt;code&gt;img&lt;/code&gt; file will be of 8GB after this so the root will have now 7GB of free space, this is simpler as you don't need to mount the SD card, but the problem is that you will get unused space in the card.&lt;/p&gt;

&lt;h2&gt;
  
  
  Resize the SD card
&lt;/h2&gt;

&lt;p&gt;Once you write the img to SD using a tool like Balena Etcher or Rufus, you need to do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# check the device used
lsblk

# in my case is /dev/sdd

# if is automatically mounted, unmount it
sudo umount /dev/sdd3

# data is partition 3 so check for failed sectors
sudo e2fsck -y -f /dev/sdd3

# grow partition
sudo growpart -v /dev/sdd 3

# resize ext4 partition
sudo resize2fs /dev/sdd3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Connect through USB
&lt;/h2&gt;

&lt;p&gt;To connect to device, &lt;a href="https://developer.android.com/tools/releases/platform-tools" rel="noopener noreferrer"&gt;ADB tools&lt;/a&gt; can be used&lt;/p&gt;

&lt;p&gt;Run adb to list devices&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb devices -l
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a device is present, then connect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;adb shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  WiFi setup
&lt;/h2&gt;

&lt;p&gt;You need to provide the details of your network, for this edit the &lt;code&gt;/etc/wpa_supplicant.conf&lt;/code&gt;&lt;br&gt;
The original contents will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ctrl_interface=/var/run/wpa_supplicant
ap_scan=1
update_config=1

network={
        ssid="SSID"
        psk="PASSWORD"
        key_mgmt=WPA-PSK
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Change the &lt;code&gt;SSID&lt;/code&gt; and &lt;code&gt;PASSWORD&lt;/code&gt; for the details of your WiFi network.&lt;br&gt;
After that create a file &lt;code&gt;/etc/network/interfaces.d/wlan0&lt;/code&gt;&lt;br&gt;
And there are two options: &lt;strong&gt;dhcp&lt;/strong&gt; (most common) or &lt;strong&gt;static ip&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  WiFi DHCP
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auto wlan0
iface wlan0 inet dhcp
    wpa-conf /etc/wpa_supplicant.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  WiFi Static IP
&lt;/h3&gt;

&lt;p&gt;Change address, gateway and other params to your proper settings&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;auto wlan0
iface wlan0 inet static
    wpa-conf /etc/wpa_supplicant.conf
    address 192.168.2.100
    netmask 255.255.255.0
    gateway 192.168.2.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is an issue with &lt;code&gt;resolv.conf&lt;/code&gt; that image set to a docker nameserver, so needs to be replaced:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo "nameserver 1.1.1.1 8.8.8.8" &amp;gt; /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the config with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;systemctl restart networking
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>tutorial</category>
      <category>cli</category>
      <category>linux</category>
      <category>iot</category>
    </item>
    <item>
      <title>Example using ST TOF VL53L4CD</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Sun, 21 Sep 2025 06:24:02 +0000</pubDate>
      <link>https://forem.com/danielmx/example-using-st-tof-vl53l4cd-160m</link>
      <guid>https://forem.com/danielmx/example-using-st-tof-vl53l4cd-160m</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.st.com/en/imaging-and-photonics-solutions/vl53l4cd.html" rel="noopener noreferrer"&gt;VL53L4CD&lt;/a&gt; is a TOF (Time of Flight) sensor capable of measure distances from 1mm to 1200mm.&lt;/p&gt;

&lt;p&gt;Unfortunately the datasheet doesn't provide any register information. But they &lt;a href="https://www.st.com/resource/en/user_manual/um2931-a-guide-to-using-the-vl53l4cd-ultra-lite-driver-uld-stmicroelectronics.pdf" rel="noopener noreferrer"&gt;provide an API&lt;/a&gt; but no good documentation about api functions.&lt;/p&gt;

&lt;p&gt;The STM32Cube have a package for this: &lt;a href="https://www.st.com/en/embedded-software/x-cube-tof1.html" rel="noopener noreferrer"&gt;X-CUBE-TOF1&lt;/a&gt; there are several applications but all uses a lot of abstractions to handle all the devices, so my goal was to have a very simple example for this specific board based on that.&lt;/p&gt;

&lt;p&gt;To setup the project, you need to do:&lt;br&gt;
&lt;strong&gt;Enable I2C1&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7e6yi5lfeuh1mfrjtr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7e6yi5lfeuh1mfrjtr3.png" alt="Enable I2C1" width="786" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable X-CUBE-TOF1 in the Middleware &amp;amp; Software section&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7hg5o1vw0mr7mug4im8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7hg5o1vw0mr7mug4im8.png" alt="Enable X-CUBE-TOF1" width="266" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Select Board Part Ranging, and select VL53L4CD&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aodw3xainuxa9wb5w6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aodw3xainuxa9wb5w6p.png" alt="Select Board Part Ranging" width="572" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configure to use the I2C1 and XShut pin&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhealu13p8g9b4rifcea9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhealu13p8g9b4rifcea9.png" alt="Configure Package" width="800" height="805"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create a project that will contain one file called &lt;code&gt;custom_tof_conf.h&lt;/code&gt; which contains some defines, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#define USE_CUSTOM_RANGING_VL53L4CD (1U)

#define CUSTOM_VL53L4CD_XSHUT_PORT    GPIOA
#define CUSTOM_VL53L4CD_XSHUT_PIN     GPIO_PIN_1

#define CUSTOM_VL53L4CD_I2C_INIT      BSP_I2C1_Init
#define CUSTOM_VL53L4CD_I2C_DEINIT    BSP_I2C1_DeInit
#define CUSTOM_VL53L4CD_I2C_WRITEREG  BSP_I2C1_Send
#define CUSTOM_VL53L4CD_I2C_READREG   BSP_I2C1_Recv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to create a file to use the API, I've created two files: &lt;code&gt;tof.c&lt;/code&gt; and &lt;code&gt;tof.h&lt;/code&gt;&lt;br&gt;
The code is very simple it will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Init the device (check device is reachable through I2C and get capabilities)&lt;/li&gt;
&lt;li&gt;Configure the device (set device settings and set the measure as continuous)&lt;/li&gt;
&lt;li&gt;Get the distance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Is important to note that the XShut pin in the TOF is an enable pin and the API is toggling automatically, so for this example the XShut is connected to VCC (3.3v) to be always enabled, if you have multiple I2C devices, you will need to enable / disable using the &lt;code&gt;CUSTOM_VL53L4CD_XSHUT_PORT&lt;/code&gt; and &lt;code&gt;CUSTOM_VL53L4CD_XSHUT_PIN&lt;/code&gt; before any API call (or add in the &lt;code&gt;tof.c&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;UM2931&lt;/strong&gt; contains more information about how to connect each pin in TOF board and dev board.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;tof.c&lt;/code&gt; code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"tof.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"custom_tof_conf.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_Object_t&lt;/span&gt;   &lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_Capabilities_t&lt;/span&gt; &lt;span class="n"&gt;tof_cap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_ProfileConfig_t&lt;/span&gt; &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;float_t&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;int_part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;int_part&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;NumberOfZones&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Targets = %lu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;NumberOfTargets&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;NumberOfTargets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt; |---&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Status = %ld, Distance = %5ld mm "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Distance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableAmbient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", Ambient = %ld.%02ld kcps/spad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Ambient&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Ambient&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableSignal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", Signal = %ld.%02ld kcps/spad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;VL53L4CD_IO_t&lt;/span&gt;              &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt;                   &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Configure the ranging sensor driver */&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_DEVICE_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_INIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeInit&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_DEINIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteReg&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_WRITEREG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadReg&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_READREG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetTick&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_GetTick&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_RegisterBusIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot register bus&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_ReadID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot read ID %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wrong ID %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_UNKNOWN_COMPONENT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Got device id: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;//init device&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot init tof&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_GetCapabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_cap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot get capabilities&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TOF Initialized&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_NONE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RangingProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_PROFILE_CONTINUOUS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimingBudget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Frequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Induces intermeasurement period, NOT USED for normal ranging */&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableAmbient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Enable: 1, Disable: 0 */&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Enable: 1, Disable: 0 */&lt;/span&gt;

    &lt;span class="cm"&gt;/* set the profile if different from default one */&lt;/span&gt;
    &lt;span class="n"&gt;VL53L4CD_ConfigProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_MODE_BLOCKING_CONTINUOUS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_NONE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;print_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to get measure: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tof.h&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;
&lt;span class="cp"&gt;#ifndef INC_TOF_H_
#define INC_TOF_H_
&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef __cplusplus
&lt;/span&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"vl53l4cd.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cp"&gt;#ifdef __cplusplus
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* INC_TOF_H_ */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"tof.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE BEGIN 2 */&lt;/span&gt;
  &lt;span class="c1"&gt;// init TOF device&lt;/span&gt;
  &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;tof_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to init TOF: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tof_status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE END 2 */&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="cm"&gt;/* USER CODE BEGIN WHILE */&lt;/span&gt;
  &lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/* USER CODE END WHILE */&lt;/span&gt;

      &lt;span class="cm"&gt;/* USER CODE BEGIN 3 */&lt;/span&gt;
      &lt;span class="n"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;HAL_Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE END 3 */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize the device and configure it.&lt;br&gt;
After that it will get the distance, the &lt;code&gt;tof.c&lt;/code&gt; will by default print the results like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Targets = 1
 |---&amp;gt; Status = 0, Distance =   110 mm , Ambient = 0.00 kcps/spad, Signal = 112.00 kcps/spad
Targets = 1
 |---&amp;gt; Status = 0, Distance =   112 mm , Ambient = 0.00 kcps/spad, Signal = 113.00 kcps/spad
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But can be changed to not print it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Example using ST TOF VL53L4CD</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Sun, 21 Sep 2025 06:24:02 +0000</pubDate>
      <link>https://forem.com/danielmx/example-using-st-tof-vl53l4cd-5ch3</link>
      <guid>https://forem.com/danielmx/example-using-st-tof-vl53l4cd-5ch3</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.st.com/en/imaging-and-photonics-solutions/vl53l4cd.html" rel="noopener noreferrer"&gt;VL53L4CD&lt;/a&gt; is a TOF (Time of Flight) sensor capable of measure distances from 1mm to 1200mm.&lt;/p&gt;

&lt;p&gt;Unfortunately the datasheet doesn't provide any register information. But they &lt;a href="https://www.st.com/resource/en/user_manual/um2931-a-guide-to-using-the-vl53l4cd-ultra-lite-driver-uld-stmicroelectronics.pdf" rel="noopener noreferrer"&gt;provide an API&lt;/a&gt; but no good documentation about api functions.&lt;/p&gt;

&lt;p&gt;The STM32Cube have a package for this: &lt;a href="https://www.st.com/en/embedded-software/x-cube-tof1.html" rel="noopener noreferrer"&gt;X-CUBE-TOF1&lt;/a&gt; there are several applications but all uses a lot of abstractions to handle all the devices, so my goal was to have a very simple example for this specific board based on that.&lt;/p&gt;

&lt;p&gt;To setup the project, you need to do:&lt;br&gt;
&lt;strong&gt;Enable I2C1&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7e6yi5lfeuh1mfrjtr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb7e6yi5lfeuh1mfrjtr3.png" alt="Enable I2C1" width="786" height="685"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enable X-CUBE-TOF1 in the Middleware &amp;amp; Software section&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7hg5o1vw0mr7mug4im8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fk7hg5o1vw0mr7mug4im8.png" alt="Enable X-CUBE-TOF1" width="266" height="682"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Select Board Part Ranging, and select VL53L4CD&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aodw3xainuxa9wb5w6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2aodw3xainuxa9wb5w6p.png" alt="Select Board Part Ranging" width="572" height="858"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Configure to use the I2C1 and XShut pin&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhealu13p8g9b4rifcea9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhealu13p8g9b4rifcea9.png" alt="Configure Package" width="800" height="805"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will create a project that will contain one file called &lt;code&gt;custom_tof_conf.h&lt;/code&gt; which contains some defines, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#define USE_CUSTOM_RANGING_VL53L4CD (1U)

#define CUSTOM_VL53L4CD_XSHUT_PORT    GPIOA
#define CUSTOM_VL53L4CD_XSHUT_PIN     GPIO_PIN_1

#define CUSTOM_VL53L4CD_I2C_INIT      BSP_I2C1_Init
#define CUSTOM_VL53L4CD_I2C_DEINIT    BSP_I2C1_DeInit
#define CUSTOM_VL53L4CD_I2C_WRITEREG  BSP_I2C1_Send
#define CUSTOM_VL53L4CD_I2C_READREG   BSP_I2C1_Recv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need to create a file to use the API, I've created two files: &lt;code&gt;tof.c&lt;/code&gt; and &lt;code&gt;tof.h&lt;/code&gt;&lt;br&gt;
The code is very simple it will:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Init the device (check device is reachable through I2C and get capabilities)&lt;/li&gt;
&lt;li&gt;Configure the device (set device settings and set the measure as continuous)&lt;/li&gt;
&lt;li&gt;Get the distance&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Is important to note that the XShut pin in the TOF is an enable pin and the API is toggling automatically, so for this example the XShut is connected to VCC (3.3v) to be always enabled, if you have multiple I2C devices, you will need to enable / disable using the &lt;code&gt;CUSTOM_VL53L4CD_XSHUT_PORT&lt;/code&gt; and &lt;code&gt;CUSTOM_VL53L4CD_XSHUT_PIN&lt;/code&gt; before any API call (or add in the &lt;code&gt;tof.c&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;UM2931&lt;/strong&gt; contains more information about how to connect each pin in TOF board and dev board.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;tof.c&lt;/code&gt; code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"tof.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;"custom_tof_conf.h"&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_Object_t&lt;/span&gt;   &lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_Capabilities_t&lt;/span&gt; &lt;span class="n"&gt;tof_cap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;VL53L4CD_ProfileConfig_t&lt;/span&gt; &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;float_t&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;int_part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int32_t&lt;/span&gt;&lt;span class="p"&gt;)((&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;int_part&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;print_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint8_t&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;NumberOfZones&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Targets = %lu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;NumberOfTargets&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;NumberOfTargets&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt; |---&amp;gt; "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Status = %ld, Distance = %5ld mm "&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Status&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Distance&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableAmbient&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", Ambient = %ld.%02ld kcps/spad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Ambient&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Ambient&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableSignal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", Signal = %ld.%02ld kcps/spad"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                  &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;decimal_part&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ZoneResult&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;Signal&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;VL53L4CD_IO_t&lt;/span&gt;              &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;uint32_t&lt;/span&gt;                   &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cm"&gt;/* Configure the ranging sensor driver */&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Address&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_DEVICE_ADDRESS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Init&lt;/span&gt;        &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_INIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DeInit&lt;/span&gt;      &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_DEINIT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteReg&lt;/span&gt;    &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_WRITEREG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadReg&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;CUSTOM_VL53L4CD_I2C_READREG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GetTick&lt;/span&gt;     &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_GetTick&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_RegisterBusIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;IOCtx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot register bus&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_ReadID&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot read ID %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Wrong ID %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_UNKNOWN_COMPONENT&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Got device id: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;//init device&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot init tof&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_GetCapabilities&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_cap&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Cannot get capabilities&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_COMPONENT_FAILURE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"TOF Initialized&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;ret&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_NONE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RangingProfile&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_PROFILE_CONTINUOUS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TimingBudget&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;30U&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Frequency&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Induces intermeasurement period, NOT USED for normal ranging */&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableAmbient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Enable: 1, Disable: 0 */&lt;/span&gt;
    &lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableSignal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Enable: 1, Disable: 0 */&lt;/span&gt;

    &lt;span class="cm"&gt;/* set the profile if different from default one */&lt;/span&gt;
    &lt;span class="n"&gt;VL53L4CD_ConfigProfile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_profile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_Start&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_MODE_BLOCKING_CONTINUOUS&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="nf"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VL53L4CD_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tof_obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;BSP_ERROR_NONE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;print_result&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to get measure: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;tof.h&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;
&lt;span class="cp"&gt;#ifndef INC_TOF_H_
#define INC_TOF_H_
&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef __cplusplus
&lt;/span&gt;&lt;span class="k"&gt;extern&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;
&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"vl53l4cd.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cp"&gt;#ifdef __cplusplus
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cp"&gt;#endif
#endif &lt;/span&gt;&lt;span class="cm"&gt;/* INC_TOF_H_ */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The use is very simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;"tof.h"&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE BEGIN 2 */&lt;/span&gt;
  &lt;span class="c1"&gt;// init TOF device&lt;/span&gt;
  &lt;span class="kt"&gt;int32_t&lt;/span&gt; &lt;span class="n"&gt;tof_status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TOF_Init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tof_status&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to init TOF: %ld&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tof_status&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;TOF_Configure&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE END 2 */&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="cm"&gt;/* USER CODE BEGIN WHILE */&lt;/span&gt;
  &lt;span class="n"&gt;VL53L4CD_Result_t&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="cm"&gt;/* USER CODE END WHILE */&lt;/span&gt;

      &lt;span class="cm"&gt;/* USER CODE BEGIN 3 */&lt;/span&gt;
      &lt;span class="n"&gt;TOF_GetDistance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="n"&gt;HAL_Delay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="cm"&gt;/* USER CODE END 3 */&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will initialize the device and configure it.&lt;br&gt;
After that it will get the distance, the &lt;code&gt;tof.c&lt;/code&gt; will by default print the results like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Targets = 1
 |---&amp;gt; Status = 0, Distance =   110 mm , Ambient = 0.00 kcps/spad, Signal = 112.00 kcps/spad
Targets = 1
 |---&amp;gt; Status = 0, Distance =   112 mm , Ambient = 0.00 kcps/spad, Signal = 113.00 kcps/spad
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But can be changed to not print it.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Example Code for CH9143</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Thu, 21 Aug 2025 06:40:57 +0000</pubDate>
      <link>https://forem.com/danielmx/example-code-for-ch9143-13e5</link>
      <guid>https://forem.com/danielmx/example-code-for-ch9143-13e5</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.wch-ic.com/downloads/CH9143DS1_PDF.html" rel="noopener noreferrer"&gt;CH9143&lt;/a&gt; is an UART to BLE transceiver.&lt;br&gt;
When connected will be a Peripheral/Slave BLE device advertising as &lt;code&gt;CH9143BLE2U&lt;/code&gt; name. When a Central/Master is connected  it will have two characteristic (channels) one for reading (Notifications) and other for writing.&lt;br&gt;
When you write from Central you can read from Serial and when you write to Serial you will get a notification in the Central.&lt;/p&gt;

&lt;p&gt;The board is from WeAct: &lt;a href="https://github.com/WeActStudio/WeActStudio.CH9143_BLE2USB2UART" rel="noopener noreferrer"&gt;https://github.com/WeActStudio/WeActStudio.CH9143_BLE2USB2UART&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The chip contains two modes that can be set through Low/High levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Master and Slave&lt;/strong&gt; modes (&lt;code&gt;BLE_MODE&lt;/code&gt; pin in IC). The master setting only works to pair with other CH9143 / CH9140 / CH9141 creating a point to point serial communication. If don't find any other device to pair in the first seconds after powered, it will just go into Slave mode.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AT Mode&lt;/strong&gt; (&lt;code&gt;AT&lt;/code&gt; pin in IC) this allows to set the chip in AT mode so from UART can be send AT commands to set some settings like device MAC, paired device MAC, TX Power or UART settings. If the AT mode is disabled then is in "transparent mode" which is sending and receiving data through serial console. Is important to note that when AT mode is enabled, you won't receive or send data to BLE Central device.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following image shows the switch in the board and what enables each position.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0uyugyzc771lm3zj6hdi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0uyugyzc771lm3zj6hdi.png" alt="Board Modes" width="165" height="91"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To test you will need to connect the CH9143 board either through USB or through a USB to TTL converter. &lt;em&gt;As a note&lt;/em&gt;, use either USB or RX/TX pins, if you use both you will get garbled data in the RX/TX  &lt;/p&gt;

&lt;p&gt;You need also a BLE device available, to check if you have it, you can try with &lt;code&gt;hcitool dev&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ hcitool dev
Devices:
    hci0    XX:XX:XX:XX:XX:XX
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The code can be found here: &lt;a href="https://github.com/danguer/embedded-boards101/tree/main/weact-ch9143" rel="noopener noreferrer"&gt;https://github.com/danguer/embedded-boards101/tree/main/weact-ch9143&lt;/a&gt; and there are two parts: &lt;code&gt;UART&lt;/code&gt; and &lt;code&gt;BLE&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  UART
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;requirements.txt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pyserial==3.5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;uart.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;

&lt;span class="n"&gt;keep_reading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;read_serial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="n"&gt;keep_reading&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_waiting&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;waiting&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;in_waiting&lt;/span&gt;
            &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;waiting&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Serial Input: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# send command
&lt;/span&gt;    &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;command&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="c1"&gt;# read command back
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;readline&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CH9143 Uart Example&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--use-at-commands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Use AT Commands&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BooleanOptionalAction&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;serial_port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Serial port like /dev/ttyACM0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;port&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serial_port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;baudrate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;115200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;bytesize&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EIGHTBITS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;parity&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PARITY_NONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stopbits&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;STOPBITS_ONE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;timeout&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Opening port: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serial_port&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;with&lt;/span&gt; &lt;span class="n"&gt;serial&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Serial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;use_at_commands&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending AT... (checking if AT is enabled)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending AT+MAC? (checking current MAC)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+MAC?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reverse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending AT+CCADD? (checking connected MAC)&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Response: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;send_at_command&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AT+CCADD?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;


    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Creating background receiving thread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;thread_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;threading&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;read_serial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;
    &lt;span class="n"&gt;thread_read&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending ping &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;ser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;UART PING &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
            &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;pass&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Finishing reading thread&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;keep_reading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
        &lt;span class="n"&gt;thread_read&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 uart/uart.py /dev/ttyACM0 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the output will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Opening port:  /dev/ttyACM0
Creating background receiving thread
Sending ping 0
Sending ping 1
Sending ping 2
Sending ping 3
Sending ping 4
Serial Input:  HOST PING 0
Sending ping 5
Serial Input:  HOST PING 1
Sending ping 6
Serial Input:  HOST PING 2
Sending ping 7
Sending ping 8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;HOST PING&lt;/code&gt; messages are when the BLE central is connected&lt;/p&gt;

&lt;h2&gt;
  
  
  BLE
&lt;/h2&gt;

&lt;p&gt;For the BLE Central side will be under &lt;code&gt;ble&lt;/code&gt; folder:&lt;br&gt;
&lt;code&gt;requirements.txt&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bleak==0.22.3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;ble-central.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;asyncio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;bleak&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;discover_mac&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;scanner&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BleakScanner&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find_device_by_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;CH9143BLE2U&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Failed to find CH9143BLE2U device&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found device:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;notify_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;BleakGATTCharacteristic&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;bytearray&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Got from device:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;connect_to_mac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Connecting to mac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;device_mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;BleakClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Listing services&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;uuid_write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="n"&gt;uuid_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[Service] {0}: {1}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0000&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fff0&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found transparent service&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;characteristics&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="c1"&gt;# print("Char", char, char.properties) # debug printing
&lt;/span&gt;                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fff1&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;uuid_read&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;
                &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fff2&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;uuid_write&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;char&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;uuid&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;uuid_read&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;uuid_write&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Found needed characteristics, read:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="n"&gt;uuid_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;, write:&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;uuid_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start_notify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uuid_read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;notify_callback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Sending ping &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;write_gatt_char&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;uuid_write&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;HOST PING &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;send_idx&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ascii&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;send_idx&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
                &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sleep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;pass&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Finishing app&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;argparse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ArgumentParser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prog&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BLE CH9143 Host&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;add_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--device-mac&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;help&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Device MAC to connect&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;parser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse_args&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device_mac&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;device_mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;discover_mac&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;device_mac&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;device_mac&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;connect_to_mac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device_mac&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;asyncio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can run like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 ble/ble-central.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will discover a device with &lt;code&gt;CH9143BLE2U&lt;/code&gt;, if you have multiple devices then you need to supply the mac as will connect to the first device it finds&lt;br&gt;
The output looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Found device: XX:XX:XX:XX:XX:XX: CH9143BLE2U
Connecting to mac XX:XX:XX:XX:XX:XX
Listing services
[Service] 0000fff0-0000-1000-8000-00805f9b34fb: Vendor specific
Found transparent service
[Service] 00001801-0000-1000-8000-00805f9b34fb: Generic Attribute Profile
Found needed characteristics, read: 0000fff1-0000-1000-8000-00805f9b34fb , write: 0000fff2-0000-1000-8000-00805f9b34fb
Sending ping 0
Sending ping 1
Got from device: UART PING 5
Sending ping 2
Got from device: UART PING 6
Got from device: UART PING 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;UART PING&lt;/code&gt; are messages received from the UART serial data&lt;/p&gt;

&lt;p&gt;This chip is a tool to easily create a BLE device and pass data to a MCU through UART; but lacking things like ability to set device name it will limit the number of applications. Also switching to AT mode can receive wrong data from previous packets received so data needs to be cleaned. In the case of the board, this setting is through a physical switch which make it impossible for real apps to use it as AT modes are things that needs to be switched through a MCU&lt;/p&gt;

</description>
      <category>ch9143</category>
      <category>wch</category>
      <category>bluetooth</category>
    </item>
    <item>
      <title>Compiling Docker in RISC-V</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Sat, 09 Aug 2025 18:45:41 +0000</pubDate>
      <link>https://forem.com/danielmx/compiling-docker-in-risc-v-5100</link>
      <guid>https://forem.com/danielmx/compiling-docker-in-risc-v-5100</guid>
      <description>&lt;p&gt;Docker CE is not supported in Ubuntu 24 for RISC-V, probably it will be soon for this support as is really easy to compile and use it.&lt;br&gt;
Here are the instructions for make it work.&lt;/p&gt;

&lt;p&gt;I've tested the following in OrangePi RV2 and qemu-riscv.&lt;/p&gt;

&lt;p&gt;Note that I'm using static releases but shared should also work.&lt;br&gt;
Also the configuration files through heredoc are directly from docker-ce packages so should work the same as official packages&lt;/p&gt;
&lt;h2&gt;
  
  
  dependencies
&lt;/h2&gt;

&lt;p&gt;You need a compiler and &lt;code&gt;make&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; \
sudo apt install -y build-essential make
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  go
&lt;/h2&gt;

&lt;p&gt;You need &lt;code&gt;go&lt;/code&gt; to compile docker, but the version in Ubuntu 24 is old to compile latest version, so can be setup directly from compiled  binaries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp &amp;amp;&amp;amp; \
wget https://go.dev/dl/go1.24.4.linux-riscv64.tar.gz &amp;amp;&amp;amp; \
sudo tar -C /usr/local -xzf go1.24.4.linux-riscv64.tar.gz &amp;amp;&amp;amp; \
rm -f go1.24.4.linux-riscv64.tar.gz

# set the path in bash or copy into /etc/profile or .bashrc
export PATH=$PATH:/usr/local/go/bin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  runc
&lt;/h2&gt;

&lt;p&gt;this is already compiled so just copy to your system&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp &amp;amp;&amp;amp; /
wget -O runc https://github.com/opencontainers/runc/releases/download/v1.3.0/runc.riscv64 &amp;amp;&amp;amp; \
chmod +x runc &amp;amp;&amp;amp; \
sudo mv runc /usr/bin/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  containerd
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp &amp;amp;&amp;amp; \
wget -O containerd-2.1.3.tar.gz https://github.com/containerd/containerd/archive/refs/tags/v2.1.3.tar.gz &amp;amp;&amp;amp; \
tar zxf containerd-2.1.3.tar.gz &amp;amp;&amp;amp; \
cd containerd-2.1.3 &amp;amp;&amp;amp; \
make VERSION=2 REVISION=1.3 static-release &amp;amp;&amp;amp; \
sudo cp ./bin/containerd /usr/local/bin &amp;amp;&amp;amp; \
sudo cp ./bin/containerd-shim-runc-v2 /usr/local/bin &amp;amp;&amp;amp; \
sudo cp ./bin/ctr /usr/local/bin &amp;amp;&amp;amp; \
sudo cp ./containerd.service /lib/systemd/system/ &amp;amp;&amp;amp; \
{ cat &amp;lt;&amp;lt;-EOF &amp;gt; /tmp/config.toml
#   Copyright 2018-2022 Docker Inc.

#   Licensed under the Apache License, Version 2.0 (the "License");
#   you may not use this file except in compliance with the License.
#   You may obtain a copy of the License at

#       http://www.apache.org/licenses/LICENSE-2.0

#   Unless required by applicable law or agreed to in writing, software
#   distributed under the License is distributed on an "AS IS" BASIS,
#   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#   See the License for the specific language governing permissions and
#   limitations under the License.

disabled_plugins = ["cri"]

#root = "/var/lib/containerd"
#state = "/run/containerd"
#subreaper = true
#oom_score = 0

#[grpc]
#  address = "/run/containerd/containerd.sock"
#  uid = 0
#  gid = 0

#[debug]
#  address = "/run/containerd/debug.sock"
#  uid = 0
#  gid = 0
#  level = "info"
EOF
} &amp;amp;&amp;amp; sudo mkdir -p /etc/containerd/ &amp;amp;&amp;amp; \
sudo mv /tmp/config.toml /etc/containerd/ &amp;amp;&amp;amp; \
sudo systemctl --system daemon-reload &amp;amp;&amp;amp; \
sudo systemctl enable containerd &amp;amp;&amp;amp; \
sudo systemctl start containerd &amp;amp;&amp;amp; \
cd /tmp &amp;amp;&amp;amp; \
rm -rf containerd-2.1.3 containerd-2.1.3.tar.gz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker daemon (moby)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp &amp;amp;&amp;amp; \
wget -O moby-28.3.1.tar.gz https://github.com/moby/moby/archive/refs/tags/v28.3.1.tar.gz &amp;amp;&amp;amp; \
tar -zxf moby-28.3.1.tar.gz &amp;amp;&amp;amp; \
cd moby-28.3.1 &amp;amp;&amp;amp; \
DOCKER_GITCOMMIT=5beb93de84f02bf7e167cbb87ce81355ddd8f560 ./hack/make.sh binary &amp;amp;&amp;amp; \
sudo cp bundles/binary-daemon/* /usr/bin/ &amp;amp;&amp;amp; \
sudo cp ./contrib/dockerd-rootless.sh /usr/bin/ &amp;amp;&amp;amp; \
sudo cp ./contrib/dockerd-rootless-setuptool.sh /usr/bin/ &amp;amp;&amp;amp; \
sudo mkdir -p /etc/docker &amp;amp;&amp;amp; \
{ cat &amp;lt;&amp;lt;-EOF &amp;gt; /tmp/docker
# Docker SysVinit configuration file

#
# THIS FILE DOES NOT APPLY TO SYSTEMD
#
#   Please see the documentation for "systemd drop-ins":
#   https://docs.docker.com/engine/admin/systemd/
#

# Customize location of Docker binary (especially for development testing).
#DOCKERD="/usr/local/bin/dockerd"

# Use DOCKER_OPTS to modify the daemon startup options.
#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"

# If you need Docker to use an HTTP proxy, it can also be specified here.
#export http_proxy="http://127.0.0.1:3128/"

# This is also a handy place to tweak where Docker's temporary files go.
#export DOCKER_TMPDIR="/mnt/bigdrive/docker-tmp"
EOF
} &amp;amp;&amp;amp; \
sudo mv /tmp/docker /etc/default/ &amp;amp;&amp;amp; \
{ cat &amp;lt;&amp;lt;-EOF &amp;gt; /tmp/docker.socket
[Unit]
Description=Docker Socket for the API

[Socket]
# If /var/run is not implemented as a symlink to /run, you may need to
# specify ListenStream=/var/run/docker.sock instead.
ListenStream=/run/docker.sock
SocketMode=0660
SocketUser=root
SocketGroup=docker

[Install]
WantedBy=sockets.target
EOF
} &amp;amp;&amp;amp; sudo mv /tmp/docker.socket /usr/lib/systemd/system/ &amp;amp;&amp;amp; \
{ cat &amp;lt;&amp;lt;-EOF &amp;gt; /tmp/docker.service
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target nss-lookup.target docker.socket firewalld.service containerd.service time-set.target
Wants=network-online.target containerd.service
Requires=docker.socket
StartLimitBurst=3
StartLimitIntervalSec=60

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always

# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity

# Comment TasksMax if your systemd version does not support it.
# Only systemd 226 and above support this option.
TasksMax=infinity

# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes

# kill only the docker process, not all processes in the cgroup
KillMode=process
OOMScoreAdjust=-500

[Install]
WantedBy=multi-user.target
EOF
} &amp;amp;&amp;amp; \
sudo mv /tmp/docker.service /usr/lib/systemd/system/ &amp;amp;&amp;amp; \
sudo systemctl --system daemon-reload &amp;amp;&amp;amp; \
sudo systemctl enable docker.socket docker.service &amp;amp;&amp;amp; \
sudo systemctl start docker.socket docker.service &amp;amp;&amp;amp; \
cd /tmp &amp;amp;&amp;amp; \
rm -rf moby-28.3.1.tar.gz moby-28.3.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker-cli
&lt;/h2&gt;

&lt;p&gt;With previous steps you will have docker daemon running in your system, but the easy way to interact is with docker-cli (or &lt;code&gt;docker&lt;/code&gt; command)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp &amp;amp;&amp;amp; \
wget -O cli-28.3.1.tar.gz https://github.com/docker/cli/archive/refs/tags/v28.3.1.tar.gz &amp;amp;&amp;amp; \
tar -zxf cli-28.3.1.tar.gz &amp;amp;&amp;amp; \
cd cli-28.3.1 &amp;amp;&amp;amp; \
mkdir -p .gopath/src/github.com/docker &amp;amp;&amp;amp; \
export GOPATH=/tmp/cli-28.3.1/.gopath &amp;amp;&amp;amp; \
ln -s `pwd` .gopath/src/github.com/docker/cli &amp;amp;&amp;amp; \
DISABLE_WARN_OUTSIDE_CONTAINER=1 make binary &amp;amp;&amp;amp; \
sudo cp build/docker-linux-riscv64 /usr/bin &amp;amp;&amp;amp; \
sudo cp build/docker /usr/bin &amp;amp;&amp;amp; \
cd /tmp &amp;amp;&amp;amp; \
rm -rf cli-28.3.1.tar.gz cli-28.3.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  docker-cli extensions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.docker.com/build/buildkit/" rel="noopener noreferrer"&gt;buildkit&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/" rel="noopener noreferrer"&gt;docker compose&lt;/a&gt; are fundamental for any setup, so must be setup, good thing is that are already compiled for riscv, so just need to be copied into proper dir.&lt;br&gt;
Note that documentation suggest a lot of possible local/global paths, &lt;code&gt;/usr/libexec/docker/cli-plugins&lt;/code&gt; worked for me, but feel free to setup other dirs if you need.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo mkdir -p /usr/libexec/docker/cli-plugins
# docker compose
cd /tmp &amp;amp;&amp;amp; \
wget -O docker-compose https://github.com/docker/compose/releases/download/v2.38.2/docker-compose-linux-riscv64 &amp;amp;&amp;amp; \
chmod +x docker-compose &amp;amp;&amp;amp; \
sudo mv docker-compose /usr/libexec/docker/cli-plugins &amp;amp;&amp;amp; \
wget -O docker-buildx https://github.com/docker/buildx/releases/download/v0.26.1/buildx-v0.26.1.linux-riscv64 &amp;amp;&amp;amp; \
chmod +x docker-buildx &amp;amp;&amp;amp; \
sudo mv docker-buildx /usr/libexec/docker/cli-plugins
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>riscv</category>
      <category>docker</category>
    </item>
    <item>
      <title>Nvidia NeMo Speech Recognition Starting Guide</title>
      <dc:creator>Daniel Guerrero</dc:creator>
      <pubDate>Fri, 08 Aug 2025 06:57:17 +0000</pubDate>
      <link>https://forem.com/danielmx/nvidia-nemo-speech-recognition-starting-guide-1529</link>
      <guid>https://forem.com/danielmx/nvidia-nemo-speech-recognition-starting-guide-1529</guid>
      <description>&lt;p&gt;After reading an article that nvidia had several models in top of &lt;a href="https://huggingface.co/spaces/hf-audio/open_asr_leaderboard" rel="noopener noreferrer"&gt;HF ASR Leaderboard&lt;/a&gt; I wanted to test in my local computer.&lt;br&gt;
Even the code seems pretty simple from HF it turns didn't work for &lt;code&gt;nvidia/canary-qwen-2.5b&lt;/code&gt; so I started to dig a bit more and test several features.&lt;/p&gt;
&lt;h2&gt;
  
  
  Base Setup
&lt;/h2&gt;

&lt;p&gt;To test you will need a base setup, I'm using docker so the options are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Using &lt;a href="https://catalog.ngc.nvidia.com/orgs/nvidia/containers/pytorch" rel="noopener noreferrer"&gt;Nvidia PyTorch container&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Using python with cuda enabled libraries&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  Nvidia PyTorch container
&lt;/h3&gt;

&lt;p&gt;This is the simplest, but of course could contain a lot of libraries not needed, the size of the container is 12.78GB&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run \
  --gpus all \
  -it \
  --rm \
  --shm-size=16g \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  nvcr.io/nvidia/pytorch:25.06-py3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Python image with cuda libraries
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run \
  --gpus all \
  -it \
  --rm \
  python:3.12-bookworm \
  /bin/bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setup cuda libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt update &amp;amp;&amp;amp; \
  apt install -y wget &amp;amp;&amp;amp; \
  wget https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/cuda-keyring_1.1-1_all.deb &amp;amp;&amp;amp; \
  dpkg -i cuda-keyring_1.1-1_all.deb &amp;amp;&amp;amp; \
  apt-get update &amp;amp;&amp;amp; \
  apt-get -y install --no-install-recommends cuda-toolkit-12-9
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Note: the image is around 11.5Gb so probably is not really much different from Nvidia container image.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup NeMo libraries
&lt;/h2&gt;

&lt;p&gt;This is pretty simple:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install nemo-toolkit[asr]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setup ffmpeg
&lt;/h2&gt;

&lt;p&gt;For the examples should not be needed but libraries will report missing and is good to have for creating proper input files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd /tmp
wget https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-linux64-gpl.tar.xz
tar xvf ffmpeg-master-latest-linux64-gpl.tar.xz 
cp ffmpeg-master-latest-linux64-gpl/bin/* /usr/bin/
rm -rf ffmpeg-master-latest-linux64-gpl ffmpeg-master-latest-linux64-gpl.tar.xz
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get audio samples
&lt;/h2&gt;

&lt;p&gt;You need audio samples that are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1 single channel&lt;/li&gt;
&lt;li&gt;16Khz Sample Rate&lt;/li&gt;
&lt;li&gt;less than 20 seconds&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An example used on several examples is this:&lt;br&gt;
&lt;a href="https://dldata-public.s3.us-east-2.amazonaws.com/2086-149220-0033.wav" rel="noopener noreferrer"&gt;https://dldata-public.s3.us-east-2.amazonaws.com/2086-149220-0033.wav&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;so you can download:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;wget https://dldata-public.s3.us-east-2.amazonaws.com/2086-149220-0033.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sample have the previous requirements, so is not needed to process; but if you want to have a proper sample from any file you can do with ffmpeg:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg -i INPUT_FILE -ac 1 -ar 16000 example.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A more complex can be to extract just a part of the audio, the following will get 10 seconds, starting at second 29 so will extract audio from 29s - 39s:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ffmpeg -i INPUT_FILE -s 29 -t 10 -ac 1 -ar 16000 example.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Code example
&lt;/h2&gt;

&lt;p&gt;The following file (&lt;code&gt;asr_example.py&lt;/code&gt;) will help you to test the different models:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import nemo.collections.asr as nemo_asr
import argparse

parser = argparse.ArgumentParser(prog="ASR NeMo Example")
parser.add_argument(
    "--enable-timestamps", 
    help="Enable timestamps", 
    action=argparse.BooleanOptionalAction,
)

parser.add_argument(
    "model_name", 
     help="Name of the model like 'nvidia/canary-1b-flash'",
)

parser.add_argument(
    "input_file", 
    help="Path of the wav file, must be 16000Hz and 1 channel",
)
args = parser.parse_args()

asr_model = nemo_asr.models.ASRModel.from_pretrained(args.model_name)

transcriptions = asr_model.transcribe(
    args.input_file, 
    timestamps=args.enable_timestamps,
)
for idx, transcript in enumerate(transcriptions):
    print(f"[{idx}] {transcript.text}")
    if args.enable_timestamps:
        for stamp in transcript.timestamp["word"]:
            word = stamp['word']
            output_line = f"{stamp['start']:0&amp;gt;5.2f}"
            output_line += f"-{stamp['end']:0&amp;gt;5.2f}"
            output_line += f": {word}"

            print(output_line)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is a list of models: &lt;a href="https://docs.nvidia.com/nemo-framework/user-guide/latest/nemotoolkit/asr/models.html" rel="noopener noreferrer"&gt;https://docs.nvidia.com/nemo-framework/user-guide/latest/nemotoolkit/asr/models.html&lt;/a&gt; &lt;br&gt;
Note that list is not fully updated as the most recent is &lt;a href="https://huggingface.co/nvidia/canary-qwen-2.5b" rel="noopener noreferrer"&gt;nvidia/canary-qwen-2.5b&lt;/a&gt; but this won't work with current code.&lt;/p&gt;
&lt;h2&gt;
  
  
  Testing the code
&lt;/h2&gt;

&lt;p&gt;You need to provide the model name and the input file, so you can call like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 asr_example.py \
  nvidia/canary-1b-flash \
  2086-149220-0033.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0] Well, I don't wish to see it any more, observed Phoebe, turning away her eyes. It is certainly very like the old portrait.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can enable the timestamps per word (not all the models support timestamps, but it will trigger an error if doesn't support it)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 asr_example.py \
  --enable-timestamps \
  nvidia/canary-1b-flash \
  2086-149220-0033.wav
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0] Well I don't wish to see it any more observed Phoebe turning away her eyes it is certainly very like the old portrait
00.32-00.40: Well
00.56-00.72: I
00.72-01.04: don't
01.04-01.28: wish
01.28-01.36: to
01.44-01.52: see
01.60-01.68: it
01.76-01.84: any
01.92-02.00: more
02.24-02.64: observed
02.64-03.12: Phoebe
03.36-03.68: turning
03.76-03.84: away
04.08-04.16: her
04.24-04.48: eyes
04.96-05.04: it
05.12-05.20: is
05.36-05.76: certainly
05.84-05.92: very
06.08-06.16: like
06.24-06.32: the
06.40-06.48: old
06.64-07.12: portrait
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Multilanguage
&lt;/h2&gt;

&lt;p&gt;One of the cool features of the Canary family is the support of multiple input languages (English, German, French, Spanish) and can even translate the output.&lt;br&gt;
I will use one file from this dataset: &lt;a href="https://www.kaggle.com/datasets/carlfm01/120h-spanish-speech" rel="noopener noreferrer"&gt;https://www.kaggle.com/datasets/carlfm01/120h-spanish-speech&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the case of the language instead of passing the wav file, it needs to be created an input manifest json.&lt;br&gt;
The format is like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "audio_filepath": "FILE.wav",
    "duration": 10, 
    "source_lang": "es",
    "target_lang": "en"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But the trick is the input file is actually a text file where each line is a json entry, so the &lt;code&gt;input-spanish.json&lt;/code&gt; must be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"audio_filepath": "0000df16-47ea-428f-8367-df2ce365d5c4.wav","duration": 9, "source_lang": "es","target_lang": "es"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And to run with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 asr_example.py \
  --enable-timestamps \
  nvidia/canary-1b-flash \
  input-spanish.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0] con efeto, su lenguaje y singulares maneras me divertían extraordinariamente, porque nuestro hombre era un verdadero andaluz,
00.00-00.08: con
00.48-01.04: efeto,
01.12-01.20: su
01.36-01.84: lenguaje
01.92-02.00: y
02.08-02.64: singulares
02.72-03.04: maneras
03.20-03.28: me
03.36-03.92: divertían
04.08-05.92: extraordinariamente,
05.92-06.00: porque
06.40-06.48: nuestro
06.88-06.96: hombre
07.28-07.36: era
07.52-07.60: un
07.68-08.16: verdadero
08.24-08.96: andaluz,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And if you want to translate into english, the &lt;code&gt;input-spanish.json&lt;/code&gt; must be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{"audio_filepath": "0000df16-47ea-428f-8367-df2ce365d5c4.wav","duration": 9, "source_lang": "es","target_lang": "en"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this case the output of the same command will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[0] with effect his language and singular manners amused me extraordinarily because our man was a true Andalusian
00.00-00.08: with
00.48-00.56: effect
01.12-01.20: his
01.36-01.76: language
01.84-01.92: and
02.00-02.56: singular
02.64-03.04: manners
03.20-03.84: amused
04.08-04.16: me
04.24-05.28: extraordinarily
05.92-06.00: because
06.40-06.48: our
06.80-06.88: man
07.20-07.28: was
07.44-07.52: a
07.60-07.68: true
08.16-08.80: Andalusian
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>asr</category>
      <category>nemo</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
