为 Zephyr 适配自己的开发板

Zephyr Dec 28, 2022

为了入门 Zephyr,首先就需要有一块官方适配的开发板,但是大多数人没有,或者与列表上的有所不同。

手上的开发板有挺多,就用RTThread的Art-Pi来做演示吧,这是一块基于STM32H750XBH6的开发板,板上有一些比较常见的外设组件,如SDRAM、QSPI和SPI FLASH、WIFI等,足够入门了。

在这摆上 Art-Pi 的原理图

在开始之前先细说一下咱们的文件夹结构,首先是可以按照官方推荐,把咱们适配的board直接扔到 zephyr/boards/* 目录下,但我觉得这样太丑了,还有些污染目录,我们这次创建一个新项目,并单独创建 boards 文件夹。

# ~/zephyrproject/applications/artpi
.
├── boards
│   └── arm
│       └── artpi
│           ├── artpi_defconfig
│           ├── artpi.dts
│           ├── board.cmake
│           ├── Kconfig.board
│           ├── Kconfig.defconfig
│           └── support
│               └── openocd.cfg
├── CMakeLists.txt
└── src
    └── main.c

Devicetree

Devicetree 是一种描述硬件的结构语言,Zephyr使用 Devicetree 来适配硬件驱动与进行硬件初始化设置。在这就不细说Devicetree的语法了。

// artpi.dts

/dts-v1/;

#include <st/h7/stm32h750Xb.dtsi>
#include <st/h7/stm32h750xbhx-pinctrl.dtsi>

/ {
    model = "RTThread Art-Pi";
    compatible = "rtt,art-pi";

    chosen {
        zephyr,console = &uart4;
        zephyr,sram = &sram0;
        zephyr,flash = &flash0;
    };
};

&clk_hse {
    clock-frequency = <DT_FREQ_M(25)>;
    status = "okay";
};

&clk_lse {
    lse-bypass;
    status = "okay";
}

&pll {
    clocks = <&clk_hse>;

    div-m = <5>;
    mul-n = <192>;
    div-p = <2>;
    div-q = <2>;
    div-r = <2>;

    status = "okay";
};

&rcc {
    clocks = <&pll>;

    clock-frequency = <DT_FREQ_M(480)>;

    d1cpre = <1>;
    hpre = <2>;
    d1ppre = <2>;
    d2ppre1 = <2>;
    d2ppre2 = <2>;
    d3ppre = <2>;
    
    status = "okay";
};

&uart4 {
    pinctrl-0 = <&uart4_tx_pa0 &uart4_rx_pi9>;
    pinctrl-names = "default";
    current-speed = <115200>;
    status = "okay";
}

这是一个最简单的配置,首先配置时钟树 clk_hse clk_lse pll rcc ,参考了一下CubeMX的相关配置, SysTick 为 480M。接下来配置 uart4 的引脚和速率。

先写一个简陋的版本来测试能否正常工作。

Kconfig

在上面的文件结构中的Kconfig有 Kconfig.board Kconfig.defconfig artpi_defconfig

# Kconfig.board

config BOARD_ARTPI
    bool "ArtPi board"
    depends on SOC_STM32H750XX
# Kconfig.defconfig

if BOARD_ARTPI

config BOARD
    default "ArtPi"

endif
# artpi_defconfig

CONFIG_SOC_SERIES_STM32H7X=y
CONFIG_SOC_STM32H750XX=y

# Enable MPU
CONFIG_ARM_MPU=y

# Enable HW stack protection
CONFIG_HW_STACK_PROTECTION=y

CONFIG_SERIAL=y

# console
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

# Enable GPIO
CONFIG_GPIO=y

# Enable Clocks
CONFIG_CLOCK_CONTROL=y

# Enable pin controller
CONFIG_PINCTRL=y

Test

到此为止,我们完成了一个简单的移植(指只移植了时钟树和串口),可以用来进行简单的测试。

# CMakeLists.txt

cmake_minimum_required(VERSION 3.20)

set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
set(BOARD artpi)

find_package(Zephyr REQUIRED)
project(artpi)

target_sources(app PRIVATE src/main.c)
// src/main.c

#include <zephyr/kernel.h>

void main()
{
    printk("Hello Zephyr! %s\n", CONFIG_BOARD);
}

LED & Button

在完成以上内容后,我们来适配一些其他的简单外设,LED和Button。

GPIO_LED_B <-> PI8
GPIO_LED_R <-> PC15
GPIO_USER_KEY1 <-> PH4

artpi.dts 中添加LED与Button的定义。

/ {
    model = "RTThread Art-Pi";
    compatible = "rtt,art-pi";

    chosen {
        zephyr,console = &uart4;
        zephyr,sram = &sram0;
        zephyr,flash = &flash0;
    };

    leds {
        compatible = "gpio-leds";

        blue_led: led_1 {
            gpios = <&gpioi 8 GPIO_ACTIVE_LOW>;
            label = "User LD1";
        };

        red_led: led_2 {
            gpios = <&gpioc 15 GPIO_ACTIVE_LOW>;
            label = "User LD2";
        };
    };

    keys {
        compatible = "gpio-keys";

        user_button: key_1 {
            gpios = <&gpioh 4 GPIO_ACTIVE_LOW>;
            label = "User Btn";
        };
    };
};

标签