Skip to main content

XIAO SAMD21 With Zephyr(RTOS)

What is RTOS

One of the most important components of today's embedded systems is the RTOS also known as Real-Time Operating System, which is responsible for everything from task scheduling to performing applications.

RTOS is designed to provide a predictable execution mode. When the processing must meet the time limit of the system, RTOS is used. Therefore, compared with GPOS (General Purpose Operating System), RTOS is usually light in weight and small in size, and generally only provides functions required to run specific types of applications on specific hardware. In some cases, developers can modify the existing RTOS, narrow it down to only provide the functionality required by a specific application, and/or customize its functionality or performance characteristics.

What is Zephyr

The Zephyr OS is based on a small-footprint kernel designed for use on resource-constrained and embedded systems: from simple embedded environmental sensors and LED wearables to sophisticated embedded controllers, smart watches, and IoT wireless applications.

Feature

Zephyr offers a large and ever growing number of features including:

Extensive suite of Kernel services

Zephyr offers a number of familiar services for development:

  • Multi-threading Services for cooperative, priority-based, non-preemptive, and preemptive threads with optional round robin time-slicing. Includes POSIX pthreads compatible API support.
  • Interrupt Services for compile-time registration of interrupt handlers.
  • Memory Allocation Services for dynamic allocation and freeing of fixed-size or variable-size memory blocks.
  • Inter-thread Synchronization Services for binary semaphores, counting semaphores, and mutex semaphores.
  • Inter-thread Data Passing Services for basic message queues, enhanced message queues, and byte streams.
  • Power Management Services such as overarching, application or policy-defined, System Power Management and fine-grained, driver-defined, Device Power Management.

Multiple Scheduling Algorithms

Zephyr provides a comprehensive set of thread scheduling choices:

  • Cooperative and Preemptive Scheduling
  • Earliest Deadline First (EDF)
  • Meta IRQ scheduling implementing “interrupt bottom half” or “tasklet” behavior
  • Timeslicing: Enables time slicing between preemptible threads of equal priority
  • Multiple queuing strategies:
    • Simple linked-list ready queue
    • Red/black tree ready queue
    • Traditional multi-queue ready queue

Bluetooth Low Energy 5.0 support

Bluetooth 5.0 compliant (ESR10) and Bluetooth Low Energy Controller support (LE Link Layer). Includes Bluetooth mesh and a Bluetooth qualification-ready Bluetooth controller.

  • Generic Access Profile (GAP) with all possible LE roles
  • Generic Attribute Profile (GATT)
  • Pairing support, including the Secure Connections feature from Bluetooth 4.2
  • Clean HCI driver abstraction
  • Raw HCI interface to run Zephyr as a Controller instead of a full Host stack
  • Verified with multiple popular controllers
  • Highly configurable

Mesh Support:

  • Relay, Friend Node, Low-Power Node (LPN) and GATT Proxy features
  • Both Provisioning bearers supported (PB-ADV & PB-GATT)
  • Highly configurable, fitting in devices with at least 16k RAM

Reference: Zephyr Project

Getting Started

This wiki covers Zephyr support for the XIAO SAMD21 Zephyr(RTOS) Getting Started. With the assistance of this guide you will be able to utilize the feature set available to the board.

The first step to working with Zephyr is to get the SDK and toolchain setup for local development. The Zephyr getting started guide should be referenced for the associated setup procedure needed for your environment.

Once the Zephyr toolchain has been setup and an associated SDK has been downloaded you can begin application development.

To program the Xiao SAMD21 the following steps can be taken:

  1. Build an example or your application
  2. Plugin the Xiao SAMD21
  3. Short the RST pin to GND (using the visible test points) to boot the MCU into bootloader mode (or press the RESET button on an attached expansion board twice in a row quickly)
  4. Proceed to use west flash to flash your firmware to the board

The simplest example is to run the "Hello World" sample on the board. After changing to the directory of the Zephyr install run the following commands.

west build -p always -b seeeduino_xiao samples/subsys/usb/console

Double press RESET or short the RST pin to the GND:

west flash

Find the port for your device by typing ls /dev/tty* and confirming which device appears when your USB has been plugged in.

In my example I see /dev/ttyACM0 as the newly added device.

Using screen you can then connect and monitor the serial response:

screen /dev/ttyACM0 115200

You should see a response similar to the following:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
Hello World! arm
Hello World! arm
Hello World! arm
Hello World! arm

To assist with the process of using Zephyr with Xiao and its expansion board a repository has been constructed with several overlays and configurations used here. The commands included in this wiki article assume it is located ../applications/xiao-zephyr-examples relative to the zephyr root. An alternative path can be provided to the commands below by updating it.

git clone https://github.com/Cosmic-Bee/xiao-zephyr-examples

Hardware Preparation

Seeed Studio XIAO SAMD21Seeed Studio Expansion Board

Developer Knowledge

XIAO Expansion Board

In order to use Grove modules with Seeed Studio XIAO SAMD21, we will use a Seeed Studio Expansion Base for XIAO and connect XIAO SAMD21 on it.

After that, the Grove connectors on the board can be used to connect Grove modules

Pin Definitions

You need to follow the graphic below to use the appropriate internal pin numbers when connecting the Grove modules to the Grove connectors on Grove Shield for Seeed Studio XIAO.

Primary Functionality

  • Onboard LED
  • USB HID
  • LittleFS
  • TFLite

Onboard LED

For this example we'll use the blinky sample to blink the onboard LED.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/basic/blinky

Double press RESET or short the RST pin to the GND:

west flash

You will see the onboard yellow LED toggle on and off creating a blinking effect.

Let's dive into this example a bit to see why it works.

The associated example code reference led0:

#define LED0_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(LED0_NODE, gpios);

This is defined in the Xiao SAMD21 devicetree code via an alias:

    aliases {
led0 = &led;
};

leds {
compatible = "gpio-leds";
led: led_0 {
gpios = <&porta 17 GPIO_ACTIVE_LOW>;
label = "LED";
};
};

It corresponds with the PA17 pin on the board. This can be found via the Xiao SAMD21 schematic by looking over the MCU and seeing the labeling on the pins.

For the pins with the Xiao breakut you don't need to use the &porta and &portb pin mapping directly as the board files provide a Xiao connector which simplifies the interface.

For example if I were to reference D0 I'd reference it either as &porta 2 or &xiao_d 0.

/ {
xiao_d: connector {
compatible = "seeed,xiao-gpio";
#gpio-cells = <2>;
gpio-map-mask = <0xffffffff 0xffffffc0>;
gpio-map-pass-thru = <0 0x3f>;
gpio-map
= <0 0 &porta 2 0> /* D0 */
, <1 0 &porta 4 0> /* D1 */
, <2 0 &porta 10 0> /* D2 */
, <3 0 &porta 11 0> /* D3 */
, <4 0 &porta 8 0> /* D4 */
, <5 0 &porta 9 0> /* D5 */
, <6 0 &portb 8 0> /* D6 */
, <7 0 &portb 9 0> /* D7 */
, <8 0 &porta 7 0> /* D8 */
, <9 0 &porta 5 0> /* D9 */
, <10 0 &porta 6 0> /* D10 */
;
};
};

USB HID

For this sample application we'll use the USB HID Mouse sample to allow the Xiao SAMD21 to trigger mouse clicks for the host computer.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/subsys/usb/hid-mouse -- -DDTC_OVERLAY_FILE=/home/nineso/zephyrproject/zephyr/boards/shields/seeed_xiao_expansion_board/seeed_xiao_expansion_board.overlay

Double press RESET or short the RST pin to the GND:

west flash

After your Xiao resets you should now be able to control the left mouse button via the button on your expansion board. Try hovering over some text and double clicking the button quickly. You'll see the text get highlighted in a similar manner as if you were to use your normal mouse to left click. You'll also notice the onboard LED lights up when you click the button as the sample also relies on an LED being set in the devicetree.

Additional buttons can be configured for use with the sample as it allows for up to 4 buttons to be configured to trigger both buttons and direction for the mouse for sample purposes.

    buttons {
compatible = "gpio-keys";
xiao_button0: button_0 {
gpios = <&xiao_d 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "SW0";
zephyr,code = <INPUT_KEY_0>;
};
};

aliases {
sw0 = &xiao_button0;
};

You can see here from the example &xiao_d 1 is used here to indicate the D1 pin. This mapping is provided by the Xiao SAMD21 board files and makes it conveinent for connecting to a given pin as you do not need to know the underlying MCU mapping but can rely on the Xiao pinout.

For the HID Mouse sample the buttons are determined by if they are compatible = "gpio-keys"; and if they have have a mapping to associated keys (0-3 for the mouse). In this case we're using zephyr,code = <INPUT_KEY_0>; which corresponds to the left mouse button.

The led0 alias is set by the board's devicetree file as mentioned in the previous section.

LittleFS

For this example we'll use the littlefs zephyr sample to create a littlefs partition and save the file to the filesystem. Then we'll reconnect and confirm it's still there via the serial output.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/subsys/fs/littlefs -- -DDTC_OVERLAY_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/console.overlay" -DEXTRA_CONF_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/console.conf

Double press RESET or short the RST pin to the GND:

west flash

Wait a moment for the MCU to reset after flashing and connect to monitor:

screen /dev/ttyACM0 115200

With this loaded you should see something similar to:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
Sample program to r/w files on littlefs
Area 2 at 0x3c000 on nvmctrl@41004000 for 16384 bytes
I: LittleFS version 2.8, disk version 2.1
I: FS at nvmctrl@41004000:0x3c000 is 64 0x100-byte blocks with 512 cycle
I: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
E: WEST_TOPDIR/modules/fs/littlefs/lfs.c:1351: Corrupted dir pair at {0x0, 0x1}
W: can't mount (LFS -84); formatting
I: /lfs mounted
/lfs mount: 0
/lfs: bsize = 16 ; frsize = 256 ; blocks = 64 ; bfree = 62

Listing dir /lfs ...
/lfs/boot_count read count:0 (bytes: 0)
/lfs/boot_count write new boot count 1: [wr:1]
I: Test file: /lfs/pattern.bin not found, create one!
------ FILE: /lfs/pattern.bin ------
01 55 55 55 55 55 55 55 02 55 55 55 55 55 55 55
03 55 55 55 55 55 55 55 04 55 55 55 55 55 55 55
05 55 55 55 55 55 55 55 06 55 55 55 55 55 55 55
07 55 55 55 55 55 55 55 08 55 55 55 55 55 55 55
09 55 55 55 55 55 55 55 0a 55 55 55 55 55 55 55
0b 55 55 55 55 55 55 55 0c 55 55 55 55 55 55 55
screen /dev/ttyACM0 115200

Now connecting again to the serial monitor we do not see the formatting nor does it need to create a file:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
Sample program to r/w files on littlefs
Area 2 at 0x3c000 on nvmctrl@41004000 for 16384 bytes
I: LittleFS version 2.8, disk version 2.1
I: FS at nvmctrl@41004000:0x3c000 is 64 0x100-byte blocks with 512 cycle
I: sizes: rd 16 ; pr 16 ; ca 64 ; la 32
/lfs mount: 0
/lfs: bsize = 16 ; frsize = 256 ; blocks = 64 ; bfree = 59

Listing dir /lfs ...
[FILE] boot_count (size = 1)
[FILE] pattern.bin (size = 547)
/lfs/boot_count read count:1 (bytes: 1)
/lfs/boot_count write new boot count 2: [wr:1]
------ FILE: /lfs/pattern.bin ------
02 55 55 55 55 55 55 55 03 55 55 55 55 55 55 55
04 55 55 55 55 55 55 55 05 55 55 55 55 55 55 55
06 55 55 55 55 55 55 55 07 55 55 55 55 55 55 55
08 55 55 55 55 55 55 55 09 55 55 55 55 55 55 55
0a 55 55 55 55 55 55 55 0b 55 55 55 55 55 55 55
0c 55 55 55 55 55 55 55 0d 55 55 55 55 55 55 55
0e 55 55 55 55 55 55 55 0f 55 55 55 55 55 55 55
10 55 55 55 55 55 55 55 11 55 55 55 55 55 55 55
12 55 55 55 55 55 55 55 13 55

TFLite - Hello World

Enable TFLite with Zephyr and update:

west config manifest.project-filter -- +tflite-micro
west update

For this example we're going to use the sample tflite "Hello World" along with our console overlay and conf to read the response over USB serial.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/modules/tflite-micro/hello_world -- -DDTC_OVERLAY_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/console.overlay -DEXTRA_CONF_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/console.conf

Double press RESET or short the RST pin to the GND:

west flash

Wait a moment for the MCU to reset after flashing and connect to monitor:

screen /dev/ttyACM0 115200

You will see results returned from the console:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
x_value: 1.0*2^-127, y_value: 1.0*2^-127

x_value: 1.2566366*2^-2, y_value: 1.4910772*2^-2

x_value: 1.2566366*2^-1, y_value: 1.1183078*2^-1

x_value: 1.8849551*2^-1, y_value: 1.677462*2^-1

x_value: 1.2566366*2^0, y_value: 1.9316229*2^-1

x_value: 1.5707957*2^0, y_value: 1.0420598*2^0

x_value: 1.8849551*2^0, y_value: 1.9146791*2^-1

x_value: 1.0995567*2^1, y_value: 1.6435742*2^-1

x_value: 1.2566366*2^1, y_value: 1.0674761*2^-1

x_value: 1.4137159*2^1, y_value: 1.8977352*2^-3

Additional Components

Grove - Expansion Board - I2C Display

To test this setup we can use an existing sample with Zephyr:

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/drivers/display -- -DSHIELD=seeed_xiao_expansion_board

Double press RESET or short the RST pin to the GND:

west flash

You'll see a display showing multiple black boxes and a blinking box in the corner given this display only supports two colors.

Let's dive into this example a bit to see why it works:

/ {
chosen {
zephyr,display = &ssd1306;
};
};

&xiao_i2c {
status = "okay";

ssd1306: ssd1306@3c {
compatible = "solomon,ssd1306fb";
reg = <0x3c>;
width = <128>;
height = <64>;
segment-offset = <0>;
page-offset = <0>;
display-offset = <0>;
multiplex-ratio = <63>;
segment-remap;
com-invdir;
prechargep = <0x22>;
};

The shield's overlay file in this example sets up a SSD1306 OLED screen at the 0x3C register. It is selected as the zephyr display in the chosen section.

Grove - Expansion Board - Button

To test this setup we can use an existing sample with Zephyr which we will use along with the USB console overlay and conf.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/basic/button -- -DDTC_OVERLAY_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/console.overlay" -DEXTRA_CONF_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/console.conf -DSHIELD=seeed_xiao_expansion_board

Double press RESET or short the RST pin to the GND:

west flash

Wait a moment for the MCU to reset after flashing and connect to monitor:

screen /dev/ttyACM0 115200

Pressing the button with the sample will trigger the onboard LED to light up.

You will see results returned from the console:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
Set up button at gpio@41004400 pin 4
Set up LED at gpio@41004400 pin 17
Press the button
Button pressed at 420744116
Button pressed at 454208099
Button pressed at 484598863
Button pressed at 518217016
Button pressed at 550754013
Button pressed at 591496990

Let's dive into this example a bit to see why it works:

/ {
aliases {
sw0 = &xiao_button0;
};

buttons {
compatible = "gpio-keys";
xiao_button0: button_0 {
gpios = <&xiao_d 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>;
label = "SW0";
zephyr,code = <INPUT_KEY_0>;
};
};
};

The app overlay file is used to setup various board components. Using this file the button example can be utilized as the overlay allows the Zephyr to configure the button and make it available for the associated code.

In this case it is using the &xiao_d connector interface to associate D1 as a button. Alternatively we could have used the &porta interface here as &porta 4 which is the corresponding pin on the MCU associated with D1.

Grove - Expansion Board - Buzzer

We'll activate our buzzer using the blinky PWM example to control its activation via a PWM signal. For this we'll use a custom overlay which enables the PWM for the A3 pin.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/basic/blinky_pwm -- -DDTC_OVERLAY_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/xiao-samd21/xiao_expansion_buzzer.overlay"

After uploading the uf2 file you should begin hearing a series of buzzes which change in sound as the sample runs its course.

Let's look at why this works:

/delete-node/ &pwm_led0;

/ {
aliases {
pwm-led = &pwm_led0;
};

pwm_leds {
status = "okay";
compatible = "pwm-leds";

pwm_led0: pwm_led_0 {
pwms = <&tcc1 1 PWM_HZ(880) >;
};
};
};

&pinctrl {
pwm_default: pwm_default {
group1 {
pinmux = <PA11E_TCC1_WO1>;
};
};
};

&tcc1 {
status = "okay";
compatible = "atmel,sam0-tcc-pwm";
/* Gives a maximum period of 1.4 s */
prescaler = <1024>;
#pwm-cells = <2>;

pinctrl-0 = <&pwm_default>;
pinctrl-names = "default";
};

The overlay in use first removes the existing pwm_led0 node as this board is configured with this alias already. It then configures the A3 pin for use as a PWM.

We're using pin A3 which corresponds with the GPIO PA11 on the SAMD21. Given its associated PWM pinmux is PA11E_TCC1_WO1 we use the tcc1 timer for the PWM.

Grove - Expansion Board - SD Card

We'll use the filesystem sample here along with the Xiao Expansion Board shield to try interfacing with the SD card reader over SPI. The expansion board shield has the CS pin configured for the associated &xiao_d 2 pin so no work is needed on your part for associating this capability with the board aside from adding the shield. To further prepare it we are using a custom config that enables the SD card functionality.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/subsys/fs/fs_sample -- -DDTC_OVERLAY_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/console.overlay $(dirname $(pwd))/applications/xiao-zephyr-examples/xiao_expansion_sd.overlay" -DEXTRA_CONF_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/console.conf $(dirname $(pwd))/applications/xiao-zephyr-examples/xiao_expansion_sd.conf" -DSHIELD=seeed_xiao_expansion_board

After uploading the uf2 file connect to monitor:

screen /dev/ttyACM0 115200
*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
[00:00:00.197,000] <inf> sd: Maximum SD clock is under 25MHz, using clock of 10000000Hz
[00:00:00.198,000] <inf> main: Block count 15519744
Sector size 512
Memory Size(MB) 7578
Disk mounted.

Listing dir /SD: ...
[FILE] IMAGE1.JPG (size = 58422)
[FILE] IMAGE2.JPG (size = 97963)

In this case my SD card had two files. Their names and their sizes were outputted to my console.

Let's look over the relevant elements at play here:

CONFIG_SPI=y
CONFIG_DISK_DRIVER_SDMMC=y
CONFIG_GPIO=y

In the associated config we're enabling SPI, the SDMMC disk driver, and the GPIO. Without this config the overlay will lead to an error as the sample is unable to find the SD card.

The relevant part of the Xiao Expansion Board shield is actually overridden in this example via the xiao_expansion_sd.overlay used for the Xiao SAMD21 shown below:

&xiao_spi {
status = "okay";
cs-gpios = <&xiao_d 2 GPIO_ACTIVE_LOW>;

sdhc0: sdhc@0 {
compatible = "zephyr,sdhc-spi-slot";
reg = <0>;
status = "okay";
mmc {
compatible = "zephyr,sdmmc-disk";
status = "okay";
};
spi-max-frequency = <10000000>;
};
};

As mentioned previously the &xiao_d 2 pin mapping is used to allow the D2 pin to be selected for this regardless of the board used so long as it supports the &xiao_d pin setup.

The reason we're not using the shield's overlay here but overriding it is that the spi-max-frequency of 24000000 set by the shield is too high which causes the SAMD21 to fail.

Grove - Temperature and Humidity Sensor (SHT31)

First solder on pins and connect your Xiao SAMD21 to the expansion board. Then connect a grove connector cable between the Grove SHT31 and one of the I2C ports on the expansion board.

To test this setup we can use an existing sample with Zephyr which we will enable USB console support with our overlay and conf.

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/sensor/sht3xd -- -DDTC_OVERLAY_FILE="$(dirname $(pwd))/applications/xiao-zephyr-examples/sht31.overlay $(dirname $(pwd))/applications/xiao-zephyr-examples/console.overlay" -DEXTRA_CONF_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/console.conf

Double press RESET or short the RST pin to the GND:

west flash

Wait a moment for the MCU to reset after flashing and connect to monitor:

screen /dev/ttyACM0 115200

You will see results returned from the console:

*** Booting Zephyr OS build v3.6.0-2566-gc9b45bf4672a ***
SHT3XD: 26.13 Cel ; 47.34 %RH
SHT3XD: 26.11 Cel ; 46.93 %RH
SHT3XD: 26.14 Cel ; 46.78 %RH
SHT3XD: 26.17 Cel ; 46.60 %RH
SHT3XD: 26.19 Cel ; 46.25 %RH
SHT3XD: 26.21 Cel ; 46.01 %RH
SHT3XD: 26.21 Cel ; 45.82 %RH
SHT3XD: 26.23 Cel ; 46.28 %RH
SHT3XD: 26.27 Cel ; 47.11 %RH
SHT3XD: 26.27 Cel ; 47.72 %RH

Let's dive into this example a bit to see why it works:

&xiao_i2c {
status = "okay";

ssd1306: ssd1306@3c {
compatible = "solomon,ssd1306fb";
reg = <0x3c>;
width = <128>;
height = <64>;
segment-offset = <0>;
page-offset = <0>;
display-offset = <0>;
multiplex-ratio = <63>;
segment-remap;
com-invdir;
prechargep = <0x22>;
};
};

The app overlay file is used to setup various board components. Using this file the SHT31 example can be utilized as the overlay informs the sample logic how to configure the sensor for our board.

1.69inch LCD Display Module, 240×280 Resolution, SPI Interface

For this example we'll use SPI to connect to a 1.69 inch LCD with a 240x280 resolution.

First connect your board to the LCD screen using the following image as a guide (in this case we're using the Xiao SAMD21 but the same pin layout is used for connecting here).

1.69-inch LCD SPI DisplayXIAO SAMD21
VCC3V3
GNDGND
DIND10
CLKD8
CSD1
DCD3
RSTD0
BLD6

Next with the hardware prepared we can build and flash:

cd ~/zephyrproject/zephyr
west build -p always -b seeeduino_xiao samples/drivers/display -- -DDTC_OVERLAY_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/240x280_st7789v2.overlay -DEXTRA_CONF_FILE=$(dirname $(pwd))/applications/xiao-zephyr-examples/240x280_st7789v2.conf

Double press RESET or short the RST pin to the GND:

west flash

With the new firmware in place the device now shows the same demo screen we saw previously on the expansion board just now updated for the color LCD over SPI.

✨ Contributor Project

Tech Support & Product Discussion

Thank you for choosing our products! We are here to provide you with different support to ensure that your experience with our products is as smooth as possible. We offer several communication channels to cater to different preferences and needs.

Loading Comments...