Table of Contents

Zephyr

Länkar

Real world examples
Shawn Hymel / Digikey
Dokumentation

Vanliga kommandon

Bygg Zephyr-projekt med overlay

west build -p always -b esp32c6_devkitc -- -DDTC_OVERLAY_FILE=boards/esp32s3_devkitc.overlay

Öppna menuconfig

west build -p always -b esp32c6_devkitc -t menuconfig

Bygg med extra conf file

west build -p always -b esp32c6_devkitc -- -DEXTRA_CONF_FILE=boards/esp32s3_devkitc.conf 

Ladda kod

python -m esptool --port COM19 --chip auto --baud 921600 --before default_reset --after hard_reset write_flash -u --flash_size detect 0x0 .\build\zephyr\zephyr.bin

Platser

zephyr/dts/<arch>/<mfr>/<soc>/ .dtsi filer för olika chip
zephyr/dts/bindings/<feature>/<compatible>.yaml .yaml binding-filer för olika chips drivrutiner
zephyr/boards/<mfr>/<board>/ .dts, Kconfig och default configs för boards
zephyr/soc/<mfr>/<soc>/soc.h Startup-kod, HAL-includes etc för specifikt chip
zephyr/arch/<arch>/core/ Assembler-startup etc för specifik arkitektur

CMake

CMakeList.txt in project

cmake_minimum_required(VERSION 3.20.0)
 
# Optional for your own extra KConfig modules
set(ZEPHYR_EXTRA_MODULES "${CMAKE_SOURCE_DIR}/../../modules/say_hello")
 
# Mandatory thing
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
 
# Name your project
project(random)
 
# Adds your main entry point to the Zephyr-created "app" lib
target_sources(app PRIVATE src/main.c)

CMakeLists.txt

CMakeLists file for your own modules

# Check if SAY_HELLO is set in Kconfig
if(CONFIG_SAY_HELLO)
 
    # Add your include directory
    zephyr_include_directories(.)
 
    # Add the source file you want to compile
    zephyr_library_sources(say_hello.c)
 
endif()

KConfig

Öppna menuconfig

west build -p always -b esp32c6_devkitc -t menuconfig

Sparas till ./build/zephyr/.config som kommer tas bort vid nästa bygge.

Generates an include file in build/zephyr/include/generated/zephyr/autoconf.h

För att göra persistent, kolla diff mellan ./build/zephyr/.config.old

# diff build/zephyr/.config.old build/zephyr/.config
574a575,576
> # CONFIG_STACK_CANARIES is not set
> CONFIG_STACK_POINTER_RANDOM=0
1136c1138
< # CONFIG_TEST_RANDOM_GENERATOR is not set
---
> CONFIG_TEST_RANDOM_GENERATOR=y
1137a1140,1141
> CONFIG_TIMER_RANDOM_GENERATOR=y
> CONFIG_TEST_CSPRNG_GENERATOR=y

Lägg sedan detta i antingen appens prj.conf eller ännu bättre i en board-specifik config

# File: boards/esp32s3_devkitc.conf
# CONFIG_STACK_CANARIES is not set
CONFIG_STACK_POINTER_RANDOM=0
CONFIG_TEST_RANDOM_GENERATOR=y
CONFIG_TIMER_RANDOM_GENERATOR=y
CONFIG_TEST_CSPRNG_GENERATOR=y
# CONFIG_SAY_HELLO=y

Och lägg med denna till bygget med -DEXTRA_CONF_FILE=boards/esp32s3_devkitc.conf

west build -p always -b esp32c6_devkitc -- -DEXTRA_CONF_FILE=boards/esp32s3_devkitc.conf 

Egna moduler

För att lägga till egna moduler som går att aktivera i menuconfig, lägg in en fil som heter exempelvis KConfig i modulens mapp.

# Create a new option in menuconfig
config SAY_HELLO
    bool "Basic print test to console"
    default n   # Set the library to be disabled by default
    depends on PRINTK   # Make it dependent on PRINTK
    help
        Adds say_hello() function to print a basic message to the console.

Lägg även till en mapp som heter exakt zephyr i modulens mapp. Lägg in en fil som heter exakt module.yaml med likande innehåll. kconfig: pekar ut KConfig-filen ovan.

name: say_hello
build:
  cmake: .
  kconfig: Kconfig

Devicetree

The final devicetree will end up under build/zephyr/zephyr.dts.

There is an include file generated from this in build/zephyr/include/generated/zephyr/devicetree_generated.h

Words

Property types

string status = "disabled";
int current-speed = <115200>;
boolean hw-flow-control;
array 32bit offsets = <0x100 0x200 0x300>;
uint8-array local-mac-address = [de ad be ef 12 34];
string-array dma-names = "tx", "rx";
phandle interrupt-parent = <&gic>;
phandles pinctrl-0 = <&usart2_tx_pd5 &usart2_rx_pd6>;
phandle-array dmas = <&dma0 2>, <&dma0 3>;
path zephyr,bt-c2h-uart = &uart0; or foo = "/path/to/some/node";

Structure

Zephyr DTS Syntax Structure

In the boards folder for esp32s3_devkitc there is a DTS file for the appcpu, /opt/toolchains/zephyr/boards/espressif/esp32s3_devkitc/esp32s3_devkitc_appcpu.dts.

/*
 * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */
/dts-v1/;

#include <espressif/esp32s3/esp32s3_appcpu.dtsi>
#include <espressif/partitions_0x0_amp.dtsi>

/ {
	model = "Espressif ESP32S3-DevkitC APPCPU";
	compatible = "espressif,esp32s3";

	chosen {
		zephyr,sram = &sram0;
		zephyr,ipc_shm = &shm0;
		zephyr,ipc = &ipm0;
	};
};

&trng0 {
	status = "okay";
};

&ipm0 {
	status = "okay";
};

This #include <espressif/esp32s3/esp32s3_appcpu.dtsi> includes a devicetree source include-file which in turn includes #include "esp32s3_common.dtsi".

Int the file /opt/toolchains/zephyr/dts/xtensa/espressif/esp32s3/esp32s3_common.dtsi there is a part defining the alias gpio0 for the path /soc/gpio/gpio@60004000.

			gpio0: gpio@60004000 {
				compatible = "espressif,esp32-gpio";
				gpio-controller;
				#gpio-cells = <2>;
				reg = <0x60004000 0x800>;
				interrupts = <GPIO_INTR_SOURCE IRQ_DEFAULT_PRIORITY 0>;
				interrupt-parent = <&intc>;
				/* Maximum available pins (per port)
				 * Actual occupied pins are specified
				 * on part number dtsi level, using
				 * the `gpio-reserved-ranges` property.
				 */
				ngpios = <32>;  /* 0..31 */
			};

The compatible = "espressif,esp32-gpio"; tells Zephyr to look for a bindings file containing the similar line (file name doesn't really matter, but is by convention the same).

Binding file can be found in /opt/toolchains/zephyr/dts/bindings/gpio/espressif,esp32-gpio.yaml

# Copyright (c) 2019, Yannis Damigos
# SPDX-License-Identifier: Apache-2.0

description: ESP32 GPIO controller

compatible: "espressif,esp32-gpio"

include: [gpio-controller.yaml, base.yaml]

properties:
  reg:
    required: true

  "#gpio-cells":
    const: 2

gpio-cells:
  - pin
  - flags

Also at the location for the board files is the /opt/toolchains/zephyr/boards/espressif/esp32s3_devkitc/esp32s3_devkitc-pinctrl.dtsi device tree source include file. The start of the file looks like this:

/*
 * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/dt-bindings/pinctrl/esp-pinctrl-common.h>
#include <dt-bindings/pinctrl/esp32s3-pinctrl.h>
#include <zephyr/dt-bindings/pinctrl/esp32s3-gpio-sigmap.h>

&pinctrl {
	uart0_default: uart0_default {
		group1 {
			pinmux = <UART0_TX_GPIO43>;
			output-high;
		};
		group2 {
			pinmux = <UART0_RX_GPIO44>;
			bias-pull-up;
		};
	};

	i2c0_default: i2c0_default {
		group1 {
			pinmux = <I2C0_SDA_GPIO1>,
				 <I2C0_SCL_GPIO2>;
			bias-pull-up;
			drive-open-drain;
			output-high;
		};
	};

The line #include <dt-bindings/pinctrl/esp32s3-pinctrl.h> refers to the file /opt/toolchains/zephyr/include/zephyr/dt-bindings/pinctrl/esp32s3-pinctrl.h which has a lot of defines used in the device tree include file.

#define UART0_TX_GPIO43 ESP32_PINMUX(43, ESP_NOSIG, ESP_U0TXD_OUT)

All of the files in /opt/toolchains/zephyr directories are default files and the device tree thingies can be overridden in you project with a overlay-file.

Lables, names, property names

Kernel DTS Coding Style

/chosen och /aliases

Dessa är två speciella noder i device-trädet som DTC behandlar speciellt. Dessa går att fylla på för att ställa in vissa saker eller introducera alias.

/ {
     chosen {
             zephyr,console = &uart0;
     };

     aliases {
             my-uart = &uart0;
     };

     soc {
             uart0: serial@12340000 {
                     ...
             };
     };
};

Overlay files

Example

boards/esp32s3_devkitc.overlay

/ {
    aliases {
        my-led = &led0;
    };

    leds {
        compatible = "gpio-leds";
        led0: d5 {
            gpios = <&gpio0 5 GPIO_ACTIVE_HIGH>;
        };
    };
};

C-kod

#include <stdio.h>
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
 
// Settings
static const int32_t sleep_time_ms = 1000;
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(my_led), gpios);
 
int main(void)
{
	int ret;
	int state = 0;
 
	// Make sure that the GPIO was initialized
	if (!gpio_is_ready_dt(&led))
	{
		return 0;
	}
 
	// Set the GPIO as output
	ret = gpio_pin_configure_dt(&led, GPIO_OUTPUT);
	if (ret < 0)
	{
		return 0;
	}
 
	// Do forever
	while (1)
	{
 
		// Change the state of the pin and print
		state = !state;
		printk("LED state: %d\r\n", state);
 
		// Set pin state
		ret = gpio_pin_set_dt(&led, state);
		if (ret < 0)
		{
			return 0;
		}
 
		// Sleep
		k_msleep(sleep_time_ms);
	}
 
	return 0;
}