快速上手 SoC App 开发¶
本文演示如何新建一个简单的App工程,并举例说明如何在App工程中操作PAN1080 EVB开发板的外设模块。
2 参考相关例程¶
SDK中提供了一些例程(位于01_SDK/zephyr/samples_panchip
目录),可以直接编译下载到EVB开发板上执行,包括多线程打印消息、LED闪灯、以及蓝牙相关例程等等。
在进行开发之前,建议先看一下相关的例程和文档,熟悉Zephyr OS的基本框架;然后实际将这些例程编译烧录至EVB开发板中查看运行效果,同时进一步熟悉开发环境的使用。
另外,SDK中也提供了一些外设模块的测试用例(位于01_SDK/zephyr/tests_panchip
目录),用于测试外设Driver功能是否正常。阅读这些测试用例代码,也有助于熟悉Zephyr外设 Driver的使用方法。
3 新建一个App工程¶
假设我们希望创建一个名为my_led_blink
的App工程,使用PWM的方式将EVB开发板上的红色LED灯点亮并令其闪烁,要求:
首先,LED灯以5Hz的频率闪烁,持续5s
重复上述闪烁规则
每次闪烁频率切换的时候,均向UART串口打印闪烁频率信息
下面我们详细讲解如何新建一个工程来实现上述需求。
3.1 从例程中拷贝一份相似的工程¶
例程blinky
(位置:01_SDK/zephyr/samples_panchip/basic/blinky
目录)演示了如何使用GPIO的方式点亮LED并令其每隔1s闪烁一次。
我们以此例程为基础进行修改:
首先,拷贝一份
blinky
并将其重命名为my_led_blink
:打开
CMakeList.txt
,将第5行project参数修改为新的项目名称my_led_blink
:# SPDX-License-Identifier: Apache-2.0 cmake_minimum_required(VERSION 3.20.0) find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE}) project(my_led_blink) target_sources(app PRIVATE src/main.c)
注:本App工程目录中,必要的文件为:
src\main.c
: 主程序代码CMakeList.txt
: cmake 文件prj.conf
: 项目配置文件
其它两个文件不是必须的(在本示例中我们可以直接将其删除):
README.rst
: 例程说明文件sample.yaml
: 用于Zephyr单元测试的信息描述文件
然后,拷贝一份名为
blinky.bat
的 Quick Build 脚本(位于01_SDK/quick_build_samples/basic
目录),用于执行编译烧录;我们同样将其重命名为与App工程相同,即my_led_blink.bat
:注:脚本内容无需修改,其会根据脚本文件名自动关联同名的App工程。
最后,确认新增的
my_led_blink.bat
可以正常编译、烧录、运行新增的my_led_blink
工程:将EVB开发板通过USB2(
USB to UART
)接口供电,并确认:JLink SWD正确连接至EVB板(
P46
:ICEK
,P47
:ICED
)使用跳线帽将EVB底板(左上侧)的LED/红外发射共用电路的排针连接至PAN1080 SoC(
P21
:FRTX
)
双击
my_led_blink.bat
脚本,执行第一次编译,成功后,会显示成功生成名为zephyr.elf
的输出文件,同时显示当前工程的FLASH和SRAM占用信息:输入指令
f
并回车,将程序烧录至芯片Flash中:烧录成功后,即可观察到EVB底板左上角的红色LED灯以1Hz的频率不断闪烁:
最后,我们输入指令
o
,启动VS Code
,后续代码修改与编译烧录调试均可在VS Code环境下进行:
3.2 硬件资源规划¶
3.2.1 时钟与电源配置¶
在实际项目中我们需要确定SoC时钟源、内部各模块的时钟配置、电源选择等事项。但这里我们直接使用EVB板开发,因此暂不关注这些内容,使用EVB板的默认配置参数即可。
我们通过PC使用MicroUSB数据线连接至EVB开发板的USB to UART
接口(如图蓝色圆框所示),为开发板提供5V电源;同时确认开发板相关电源跳线(如图红色方框所示)连接正确:
3.2.2 PWM模块配置¶
我们使用PAN1080 SoC的PWM模块控制EVB底板上的LED灯,为此我们需要规划:
使用哪个PWM模块的哪个输出通道(PAN1080 SoC中内置了3个硬件PWM模块,分别为
PWM0
、PWM1
、PWM2
,每个模块均有8个通道)将PWM波形输出到SoC的哪个引脚
需要注意的是,由于PAN1080 SoC的每个引脚最多只能配置成预设的8个功能之一,因此我们在规划引脚资源的时候,要查阅各个引脚的PINMUX定义,从中找到合适的引脚使用。
我们可以从PAN1080 Development Kit中的如下几个文件的任意一个中找到PAN1080 SoC的PINMUX引脚定义:
01_SDK/zephyr/dts/arm/panchip/pan1080/pan1080a_afld_pinctrl.dtsi
01_SDK/zephyr/include/drivers/pinmux/pinmux_pan1080.h
04_DOC/05_soc_manual/PAN1080 Datasheet.pdf
或04_DOC/05_soc_manual/PAN1080 产品说明书.pdf
这里,我们直接从VS Code中打开
pan1080a_afld_pinctrl.dtsi
文件(按快捷键Ctrl
+P
,输入文件名即可):由于当前EVB底板上的LED灯已经与
P21
引脚相连,我们先查找P21
引脚的PINMUX定义,看是否有PWM功能;查阅后发现其并没有PWM功能,但相邻的P22
引脚,有一个pwm1_ch4 (PWM1 Channel 4)
的定义,可以供我们使用:在EVB底板上,将
P21
排针与FRTX
排针连接的跳线帽拔出,另使用一根杜邦线将P22
排针与FRTX
排针相连:为使我们规划的硬件资源生效,我们需要修改SDK中的板级DeviceTree文件。
从VS Code中打开名为
pan1080a_afld_evb.dts
的文件(按快捷键Ctrl
+P
,输入文件名即可):此文件中描述了关于PAN1080A-AFLD EVB的所有板级硬件配置信息,这些配置保证了我们可以使用EVB开发板成功运行SDK中的所有例程(
samples_panchip
)和测试用例(tests_panchip
)。关于Zephyr DeviceTree(
.dts
/.dtsi
)的更多细节,请参考Zephyr官方文档:Introduction to devicetree我们暂不关心除PWM以外的模块配置,可以看到,
pan1080a_afld_evb.dts
文件第123~126行描述了一个PWM0
模块的配置:... &pwm0 { pinctrl-0 = <&p1_0_pwm0_ch4 &p1_1_pwm0_ch5 &p1_6_pwm0_ch6>; status = "okay"; }; ...
其含义如下:
第一行
&pwm0
表示,当前配置文件中对pwm0
中属性值的修改会更新默认配置文件(名为pan1080.dtsi
)中的值,亦即,若本次更新的属性不在默认配置文件中,则为此属性赋予一个值;若本次更新的属性已经在默认配置文件中已经有一个值,则覆盖此属性的默认值;第二行
pinctrl-0
表示,修改当前pwm
模块的PINMUX配置,其中尖括号中:&p1_0_pwm0_ch4
表示将芯片P10
引脚的PINMUX切换为PWM0 Channel 4功能;&p1_1_pwm0_ch5
表示将芯片P11
引脚的PINMUX切换为PWM0 Channel 5功能;&p1_6_pwm0_ch6
表示将芯片P16
引脚的PINMUX切换为PWM0 Channel 6功能;
第三行
status = "okay"
表示,在系统初始化过程中,使能DeviceTree中对当前PWM
模块的各项参数配置;
由于我们的规划是使用
PWM1 Channel 4
从芯片P22
引脚输出方波,因此我们仿照上述对PWM0
模块的描述,添加一个PWM1
模块配置:... &pwm0 { pinctrl-0 = <&p1_0_pwm0_ch4 &p1_1_pwm0_ch5 &p1_6_pwm0_ch6>; status = "okay"; }; &pwm1 { pinctrl-0 = <&p2_2_pwm1_ch4>; status = "okay"; }; ...
3.2.3 UART模块配置¶
我们希望使用PAN1080 SoC的UART
模块输出Log日志到PC,为此我们需要明确:
使用哪个UART模块(PAN1080 SoC中内置了2个UART模块,分别为
UART0
、UART1
)UART Tx/Rx分别映射到SoC的哪个引脚
如何与PC通信
PAN1080 EVB底板中提供了一个USB转UART的模块电路,其可以很方便地通过跳线帽与PAN1080 SoC的P06
(UART1 TX
)、P07
(UART1 RX
)相连,这里就采用这种方式与PC通信。
使用跳线帽将EVB底板(左上侧)的USB转UART模块的2个通信排针连接至PAN1080 SoC:
再次在VS Code中打开板级DeviceTree文件
pan1080a_afld_evb.dts
,我们可以看到其中已经有了一些与UART有关的配置:... chosen { zephyr,console = &uart1; zephyr,shell-uart = &uart1; zephyr,bt-mon-uart = &uart1; zephyr,bt-c2h-uart = &uart1; ... }; soc { pin-controller@40030000 { /* port, pin, pinmux_name, pinmux_sel [, flag1, ... ] */ DT_PAN_PINS(p0, 7, uart1_rx, PAN1080_PIN_FUNC_P07_UART1_RX, input-enable); }; }; ... &uart1 { current-speed = <921600>; pinctrl-0 = <&p0_6_uart1_tx &p0_7_uart1_rx>; status = "okay"; }; ...
其含义如下:
chosen
节点描述了Zephyr OS用到的硬件模块与实际硬件的映射关系:zephyr,console = &uart1
表示将Zephyr Console模块配置为使用UART1
通信,我们此次向UART打印LED状态消息即使用此方式;zephyr,shell-uart = &uart1
、zephyr,bt-mon-uart = &uart1
、zephyr,bt-c2h-uart = &uart1
均与本文内容无关,这里不做详细介绍,只需了解我们将Zephyr所有用到的串口均默认映射到了PAN1080 SoC的UART1
模块即可;
soc
节点描述了SoC级的硬件配置信息:pin-controller@40030000
是一个子节点,代表PAN1080 SoC的PINMUX(MFP)模块;DT_PAN_PINS(p0, 7, uart1_rx, PAN1080_PIN_FUNC_P07_UART1_RX, input-enable)
用来辅助配置UART1
的PINMUX参数;其中,此配置的前4个参数表示我们将芯片P07
引脚的PINMUX切换为UART1 RX功能,最后一个参数表示辅助配置参数,这里input-enable
表示打开此引脚的数字信号输入功能;注1:除
input-enable
参数外,此处还可以配置bias-pull-up
以使用当前引脚的内部上拉电阻,或配置bias-pull-down
以使用当前引脚的内部下拉电阻;注2:此处的PINMUX配置不是必须的,只有在需要打开某个引脚数字信号输入功能或内部上拉/下拉电阻功能的时候,才应该在此处进行配置,并且配置的引脚功能应当与对应外设模块中的
pinxtrl-0
中的配置一致,例如:我们在DeviceTree的
uart1
节点中将Tx功能配置到了P06
引脚,将Rx功能配置到了P07
引脚,因此我们需要在soc/pin-controller
节点中将P07
引脚的数字信号输入功能打开,但无需配置数字信号输出引脚P06
;如果我们使用
I2C
模块,则由于I2C协议要求有上拉电阻,因此我们可以配置bias-pull-up
参数以使用SoC内部上拉电阻;如果我们将I2C
模块配置为Slave,则由于SCL
和SDA
两根线均为输入信号,因此还需要配置input-enable
参数以打开这两个引脚的数字信号输入功能;
&uart1
表示,修改uart1
节点中的属性,且其中的修改会更新默认配置文件(名为pan1080.dtsi
)中的值:current-speed = <921600>
表示,波特率配置为921600;pinctrl-0 = <&p0_6_uart1_tx &p0_7_uart1_rx>
表示:将芯片
P06
引脚的PINMUX切换为UART1 TX功能;将芯片
P07
引脚的PINMUX切换为UART1 RX功能(与soc/pin-controller
节点中的配置一致);
status = "okay"
表示,在系统初始化过程中,使能DeviceTree中对当前UART
模块的各项参数配置;
从dts文件中可知,SDK中对于UART的配置已经与我们在EVB板中的接线一致,因此无需再做修改。
3.3 修改代码¶
下面我们演示如何在VS Code环境下写App代码,实现预期功能。
3.3.1 使用PWM¶
Zephyr提供了标准的PWM API接口(头文件位置:
01_SDK/zephyr/include/drivers/pwm.h
),为了使用这些接口,我们需要先使能Zephyr PWM Driver,方法是在App目录的prj.conf
,增加一个Config项:CONFIG_PWM=y
增加后文件内容如图所示:
接着,我们在
main.c
中,删除一些无关的代码,并增加PWM相关操作代码:/* * Copyright (c) 2021-2022 Shanghai Panchip Microelectronics Co.,Ltd. * * SPDX-License-Identifier: Apache-2.0 */ #include <zephyr.h> #include <device.h> #include <devicetree.h> #include <drivers/gpio.h> #include <drivers/pwm.h> void main(void) { const struct device *dev; dev = DEVICE_DT_GET(DT_NODELABEL(pwm1)); if (dev == NULL) { return; } while (1) { /* LED Blink 5Hz */ pwm_pin_set_usec(dev, 4, 200000, 100000, PWM_POLARITY_NORMAL); k_msleep(5000); } }
点击VS Code的
Terminal
菜单,选择Run Build Task...
(或直接快捷键Ctrl + Shift + B
),依次执行Build和Flash命令,将程序烧录至芯片中,即可观察到LED灯以5Hz的频率闪烁。
3.3.2 使用UART¶
我们可以直接使用zephyr提供的printk函数,将Log信息输出至串口,修改while(1)
循环内的代码如下:
while (1) {
printk("LED to Blink 5 times per second\n");
pwm_pin_set_usec(dev, 4, 200000, 100000, PWM_POLARITY_NORMAL);
k_msleep(5000);
}
重新编译烧录后,在PC中使用串口工具(如SecureCRT)即可看到每5s打印一次消息:
4 更多相关文档¶
Zephyr Kconfig配置指南:介绍Zephyr Kconfig配置的相关技巧
Zephyr DeviceTree APIs:Zephyr官方对于DeviceTree接口的详细介绍
Zephyr Peripheral APIs:Zephyr官方提供的外设Driver API接口详细介绍