Zephyr 之创建 Custom SoC - 1

本文详细描述了如何在Zephyr中为自定义SoC进行适配,包括设置环境、修改DTS文件、创建Kconfig和CMakeLists.txt等内容,以实现在非官方支持的MCU上运行Zephyr应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Zephyr 之创建 Custom SoC - 1

Intro

最开始看到 Zephyr 能够在 app 层添加 Custom SoC,于是兴奋地搞了两天,无果,网上找资料也找不到,只好向 Zephyr 源代码下手,这才发现在 app 层搞 Custom SoC 是不现实的,像什么 DeviceTree 文件,外设驱动层代码,头文件等等,根本不是一个在 app 层开一个 soc 文件夹那么简单,于是吭哧吭哧搞了快两周,终于在 20230901 周五晚上在基于 Custom SoC 的 Custom Board 上跑通了 hello_world 和 blinky 两个 Zephyr 的 Samples。
Zephyr 本身是支持很多家的 SoC 的,不管是 stm32,nxp_s32,gd32,esp32 等等,但总会出现你的项目所需要的 SoC 不在支持的列表中的情况,况且 Zephyr 支持的 “国产 MCU” 并不多,因此适配 Custom SoC 的需求还是很大的。

Preparation

适配 Custom SoC 是一个比较复杂的活,为了方便管理代码,建议在 github 或 gitee 上 fork 或者导入一下 Zephyr 的代码,在 github 或 gitee 上切换分支到 main 上,然后用下面的方式初始化 zephyr 的工作空间 (假设 Zephyr SDK 已经准备好了):

west init ./zephyrproject -m <git-url>

记得将 <git-url> 换成你的 git 链接。

然后 cd 到 zephyr 目录下,创建一个属于自己的 git 分支:

cd zephyr/
git checkout -b dev-custom-soc

在执行 west update 指令之前,先看下 west.yml 文件,里面记录了要 git clone 的 非 Zephyr 的代码,如果嫌 update 的时间过长,可以在这个文件中,将不需要的 hal_xxx 内容注释掉,这样可以减少 git clone 的时间,毕竟都是从 github 上下载文件,国内的网络环境笔者都花费了两个小时,经过多次 update 才搞定。

退回到 zephyrproject 文件夹内,执行 west update 指令:

cd ../
west update

如果 update 失败,多执行几次 west update 指令试试。

试试在 qemu_x86 上跑个 hello_world 试试,证明环境搭建完成:

cd zephyr/
west build samples/hello_world -b qemu_x86
west build -t run

如果能跑通,就说明环境 ok 了。
接下来说一个跑不通的情况,如果你是在虚拟机上跑 ubuntu,然后将一个实体的文件夹通过共享的挂载到 ubuntu 上,在这个共享文件夹下创建的 zephyrproject,则会出现权限问题,无法成功编译,因此,还是老老实实在虚拟机的虚拟硬盘上搞事情吧,当然有其他解法,暂时懒得去找。

接下来看下要改动的代码吧,看下 Zephyr 的文件结构,这里面要分别在下面的文件夹内添加个改动代码:

  • boards/
  • drivers/
  • dts/
  • include/zephyr/
  • soc/

boards 是为了给 Custom SoC 适配板子,drivers 适配驱动,第一步可以先不搞定这个,dts 是要放 soc 需要的 DeviceTree 文件,这个文件中定义了 flash 和 sram 的起始地址和大小,是的,这个信息不是在 linker 中定义的,include要添加相关的头文件,第一步也可以先不搞定这个,soc 要存放 soc 的定义文件。前期,我们要先搞定板子,设备树,还有 SoC 才行。

在开始搞定这三个文件夹之前,得先说明下我手上的 SoC,是一颗 Arm Cortex-M3 内核的微控制器,512KB Flash,128KB SRAM。

soc

按照 Zephyr 的目录结构,我需要将 SoC 相关的东西放在 soc/arm 文件夹下,因此,在 soc/arm 下创建 SoC 厂商名称,我这里称为 xx32,可根据

cd soc/arm
mkdir xx32
cd xx32

按照其他厂商芯片的样子,创建一个 common 文件夹,在common 文件夹下创建一个 CMakeLists.txt 文件,这个 CMakeLists.txt 中可以什么都不用写

mkdir common
cd common
touch CMakeLists.txt

在 custom32 文件夹下创建 Kconfig 文件,注意所有 Kconfig 名称的 K 一定要大写,Linux 下文件和文件夹是区分大小写的,一不注意这个 K 会让你找 bug 找好久的。

cd ../
vim Kconfig

填入下面的内容:

config SOC_FAMILY_XX32
    bool
    select HAS_SEGGER_RTT if ZEPHYR_SEGGER_MODULE
    select BUILD_OUTPUT_HEX

if SOC_FAMILY_XX32

config SOC_FAMILY
    string
    default "xx32"

source "soc/arm/xx32/*/Kconfig.soc"

endif # SOC_FAMILY_XX32

为什么写这些内容,别问,问就是别的 SoC 都这样写,其实仔细读也是能读懂的。

创建 Kconfig.defconfig,并填入下面的内容:

source "soc/arm/xx32/*/Kconfig.defconfig.series"

创建 Kconfig.soc,并填入下面的内容:

source "soc/arm/xx32/*/Kconfig.series"

上面这三个 Kconfig 文件,如果没有意外,到最后都不用改动,如果需要的话,可以在文件前面写上版权信息。

这样只是把厂商的内容创建好了,接下来该创建芯片系列了:
创建 xx32f0 文件夹,代表某一个系列的芯片,并进入:

mkdir xx32f0
cd xx32f0

在 xx32f0 文件夹下创建 CMakeLists.txt 文件,并填入以下内容:

zephyr_include_directories(${ZEPHYR_BASE}/drivers)
zephyr_sources(soc.c)

创建 Kconfig.sreies 文件,并填入以下内容:

config SOC_SERIES_XX32F0
	bool "Custom32 Series SoC"
	select ARM
	select CPU_CORTEX_M3
	select SOC_FAMILY_XX32
	help
	  Enable support.

创建 Kconfig.defconfig.series文件,并填入下面内容:

if SOC_SERIES_XX32F0

source "soc/arm/xx32/xx32f0/Kconfig.defconfig.xx32f0*"

config SOC_SERIES
	default "xx32f0"

config SYS_CLOCK_HW_CYCLES_PER_SEC
	default $(dt_node_int_prop_int,/clocks/clk_sys,clock-frequency)

endif # SOC_SERIES_XX32F0

创建 linker.ld 文件,填入以下内容:

#include <zephyr/arch/arm/cortex_m/scripts/linker.ld>

创建 soc.h 文件,里面填入以下内容:

#ifndef _XX32F0_H_
#define _XX32F0_H_

#ifndef _ASMLANGUAGE

#endif /* !_ASMLANGUAGE */

#endif /* _XX32F0_H_*/

创建 soc.c 文件,里面填入以下内容:

#include <zephyr/device.h>
#include <zephyr/init.h>
#include <soc.h>

static int xx32_init(void)
{
	return 0;
}

SYS_INIT(xx32_init, PRE_KERNEL_1, 0);

创建 Kconfig.defconfig.xx32f0x,代表具体的一颗 soc 型号,并填入以下内容:

if SOC_XX32F0X

config SOC
    default "SOC_XX32F0X"

config NUM_IRQS
    default 128

endif # SOC_XX32F0X

最后创建 Kconfig.soc 文件,前面定义了这个系列的 SoC 中有一个型号,因此在这个文件中填入下面内容:

choice
	prompt "xx32f0 MCU Selection"
	depends on SOC_SERIES_XX32F0

config SOC_XX32F0X
	bool "SOC_XX32F0X"

endchoice

到此为止,soc 下面的内容就写好了,当然,后面还会逐步添加东西,现在,回到 zephyr 目录下

cd ../../../../

dts

接下来填写 dts 中的内容,到 dts/arm 文件夹下,创建 xx32 文件夹,在 xx32 文件夹下创建 xx32f0 文件夹

cd dts/arm
mkdir xx32
cd xx32
mkdir xx32f0

在 xx32f0 下创建 xx32f0.dtsi 文件,并填入以下内容:

#include <mem.h>
#include <freq.h>
#include <arm/armv7-m.dtsi>

/ {
    cpus {
        #address-cells = <1>;
        #size-cells = <0>;

        cpu0: cpu@0 {
            device_type = "cpu";
            compatible = "arm,cortex-m3";
            reg = <0>;
        };
    };

    clocks {
        clk_sys: clk_sys {
            #clock-cells = <0>;
            compatible = "fixed-clock";
            clock-frequency = <DT_FREQ_M(96)>;
        };
    };

    soc {
        sram0: memory@20000000 {
            compatible = "mmio-sram";
            reg = <0x20000000 0x0001C000>;
        };

        flash0: flash@8000000 {
            compatible = "soc-nv-flash";
        };
    };
};

&nvic {
    arm,num-irq-priority-bits = <3>;
};

Flash 的起始地址是 0x08000000,大小会在下一个文件中定义,SRAM 的起始地址在 0x20000000,大小128KB。

创建 xx32f0x.dtsi 文件,填入以下内容:

#include <xx32/xx32f0/xx32f0.dtsi>

&flash0 {
    reg = <0x08000000 DT_SIZE_K(512)>;
};

定义 Flash 的大小为 256KB。

dts 的内容创建完毕,后面会在这两个文件中填入大量的内容。回到 zephyr 目录下:

cd ../../../..

boards

按照之前提到的创建 Custom Board 的方法,在 zephyr/boards/arm 下创建 Custom Board,并 cd 到 Custom Board 中,这里我定义 Custom Board 的名字为 xx32f0board
在 xx32f0board.dts 中填入以下内容:

/dts-v1/;
#include <xx32/xx32f0/xx32f0x.dtsi>

/ {
    model = "xx32f0board";
    compatible = "xx32f0";

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

xx32f0board_defconfig 中填入以下内容:

CONFIG_SOC_SERIES_XX32F0=y
CONFIG_SOC_XX32F0X=y

其它的文件照着别的板子一个个添加就行。

test

按照前文中提到的创建应用的方法,编写一个简单的main()函数:

int main(void)
{
    while(1)
    {}
}

然后测试下编译:

cd app
west build -b custom_board

如果能够成功编译通过,就差不多可以说明前面做的工作已经完成,接下来可以试着在芯片上跑下,由于还没有适配 west flash 指令,因此需要使用第三方工具来实现下载和调试的功能,我这里使用的是 SEGGER 的 OZONE 工具,只能使用 J-Link 下载调试程序,具体用法网上很多资料,这里不再展开讲述。
至于下载调试所需的 elf 文件,则是在 build/zephyr 文件夹下,找到这个 elf 文件,然后下载,运行,在 OZONE 上可以看到,程序能够成功执行,能够打断点,甚至有时候暂停能够看到切换上下文的操作,由此证明内核的移植已经成功。

至于板子,后续开发完成之后,可以将这个板子的文件放到 zephyr 的 boards 文件夹中。

Summary

本文讲述了如何在 Zephyr 中创建一个 Custom SoC,但仅仅讲述了内核的适配,驱动等代买还没有添加,将在后面的文章中继续讲解。

本文在 zephyr 中添加的代码以及 app 代码可见本文绑定的资源。

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值