当前文档版本为 v0.9.1,您可以访问当前页面的 开发中 版本以获取最近可能的更新。

SoC App 开发指南

本文介绍 PAN1080 SDK APP 开发的基础知识,如何新建一个简单的 App 工程,并举例说明如何在 App 工程中操作 PAN1080 EVB 开发板的外设模块。

1 概述

PAN1080 SDK 基于 Zephyr OS 开发,其构建系统(Build System)使用 CMake

01_SDK/zephyr目录下存放有 Zephyr OS 的核心代码、内核配置信息、SoC 定义、开发板定义以及 Panchip 提供的例程等。

Zephyr 目录结构如下所示:

  • Zephyr 的核心代码位于01_SDK/zephyr目录下,其中包含一些重要的文件:

    • CMakeLists.txt:CMake 构建系统的顶层文件,包含构建 Zephyr 核心代码所需的 CMake 信息。

    • Kconfig:Kconfig 顶层文件,其直接引用另一个顶层文件Kconfig.zephyr

    • west.yml:west manifest 文件,其中列出了 west 工具能够识别和管理的外部模块目录。

  • Zephyr 的核心代码还包括如下这些顶层目录(每个顶层目录下还包括一个或多个子目录):

    • arch:存放芯片 CPU 架构级信息,由于 PAN1080 是 ARM 架构,因此其中只保留了 ARM 架构信息。

    • soc:存放芯片 SoC 级信息及一些默认配置。

    • boards:存放板级信息,比如 PAN1080 各种 EVB 开发板。

    • doc:Zephyr 官方文档,其内容与 Zephyr文档官网一致。

    • drivers:存放设备驱动代码。

    • dts:存放 DeviceTree(芯片硬件初始化配置) 信息。

    • include:存放 Zephyr 公开的 API 头文件。

    • kernel:存放 Zephyr OS 内核代码。

    • lib:存放库文件,包含一个简单的标准C语言库等。

    • misc:其他一些不便分类的文件。

    • samples_panchip:存放 Panchip 提供的 PAN1080 官方例程。

    • scripts:存放编译测试相关的脚本文件。

    • cmake:存放 CMake 构建 Zephyr App 所需的相关配置和脚本文件。

    • subsys:Zephyr 子系统,包括:USB Device Stack(USB 设备栈)、File System(文件系统)、Bluetooth Host and Controller(低功耗蓝牙Host端与Controller端)等实现代码。

    • share:存放一些额外的架构无关的数据,目前包含 Zephyr CMake Package。

一个最简单的 APP 工程文件结构如下所示:

   <work_dir>/my_app
   ├── CMakeLists.txt
   ├── prj.conf
   └── src
       └── main.c

其中:

  • CMakeLists.txt: 构建系统从此文件中查找待编译 APP 源码,并将 APP 目录与 Zephyr 链接起来,使得 APP 可以编译、配置、使用 Zephyr 提供的各种功能。

  • 配置文件: APP 需要提供一个 Kconfig 配置文件(通常称为prj.conf),其中包含一个或多个 Zephyr 内核配置信息,这些配置与特定的芯片(SoC)配置、特定的开发板(Board)配置等配置信息合并,生成最终的配置文件(.config文件与autoconf.h文件)。

  • APP 源码文件: APP 需要包含一个或多个C语言或汇编源码文件,这些文件通常位于名为src的目录下。

  • <work_dir>:App 工程所在的目录,一般放在 samples_panchip 目录内。

    :从文件结构上来说,构建系统允许我们将自己的 APP 工程创建在任意目录下;只要配置正确,命令行方式的构建系统可以在编译 APP 工程的时候,自动识别到 SDK 中 Zephyr 的路径;但目前 ZAL 工具只支持从 samples_panchiptests_panchip 两个目录中搜索 App 工程。

APP 工程创建后,我们即可以使用 ZAL 工具(或直接使用west build CLI 命令)触发编译操作(其内部是调用 CMake),编译过程中会自动生成单独的 Build(构建)目录,其中存放编译输出的所有文件。

下面介绍如何创建、构建和运行一个自定义的 APP。

2 确认开发环境

参考 SDK 快速入门 文档,确认软硬件开发环境,可以正常编译、下载和调试程序。

3 参考相关例程

SDK 中提供了一些例程(位于01_SDK/zephyr/samples_panchip目录),可以直接编译下载到 EVB 开发板上执行,包括多线程打印消息、LED 闪灯、以及蓝牙相关例程等等。

在进行开发之前,建议先看一下相关的例程和文档,熟悉 Zephyr OS 的基本框架;然后实际将这些例程编译烧录至 EVB 开发板中查看运行效果,同时进一步熟悉开发环境的使用。

image

SDK 例程目录

另外,SDK 中也提供了一些 Zephyr 的测试用例(位于01_SDK/zephyr/tests_panchip目录),用于测试外设 Driver、OS Kernel 等功能是否正常。阅读这些测试用例代码,也有助于熟悉 Zephyr OS 提供的各种 API 的使用方法。

image

SDK 测试用例目录

4 新建一个 App 工程

创建一个 APP 最简单的方式,是从 01_SDK/zephyr/samples_panchip 目录下,Copy 一个例程,并将其中的非必要文件(如README.rstsample.yaml)删除即可。

假设我们希望创建一个名为my_led_blink的 App 工程,使用 PWM 的方式将 EVB 开发板上的 LED 灯点亮并令其闪烁,要求:

  1. 首先,LED 灯在每 100ms 的时间内,亮 20ms、灭 80ms,持续 3s

  2. 然后,LED 灯在每 100ms 的时间内,亮 80ms、灭 20ms,持续 3s

  3. 重复上述闪烁规则

  4. 每次闪烁频率切换的时候,均向 UART 串口打印闪烁频率信息

下面我们详细讲解如何新建一个工程来实现上述需求。

4.1 从例程中拷贝一份相似的工程

例程blinky(位置:01_SDK/zephyr/samples_panchip/basic/blinky目录)演示了如何使用 GPIO 的方式点亮 LED 并令其每隔 1s 闪烁一次。

我们以此例程为基础进行修改:

  1. 拷贝一份 blinky 并将其重命名为 my_led_blink

    image

    拷贝一个现有的例程

    打开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 单元测试的信息描述文件

  2. 确认 EVB 硬件接线:

    1. 使用 USB 线,将 PC USB 与 EVB Type-C USB(USB->UART)相连,用于供电及串口 Log 打印

    2. 将 JLink SWD 正确连接至 EVB 板(P46ICEKP47ICED

    3. 使用跳线帽将 P16 引脚与 RGB 灯的蓝色通道(RGB-B)引脚相连

  3. 打开 ZAL 工具,在 Project List 中找到新建的工程:

    image

    ZAL 选择新建的工程配置

    如果在新增 App 工程目录之前,已经打开了 ZAL 工具,则在选择新的 App 工程之前,应先点击一下 ZAL 工具 Config 列表右面的 U 按钮,更新 Project 列表。

  4. 点击build按钮,编译成功后会显示生成名为zephyr.elf的输出文件,同时显示当前工程的 FLASH 和 SRAM 占用信息:

    image

    ZAL Build 新建的工程

  5. 点击Flash按钮,将程序烧录至芯片Flash中:

    image

    ZAL 烧录 新建的工程

  6. 烧录成功后,即可观察到 EVB 板上的蓝色 LED 灯以 1Hz 的频率不断闪烁:

  7. 最后,点击Open IDE按钮,启动VS Code,后续代码修改与编译烧录调试均可在 VS Code 环境下进行:

    image

    启动 VS Code

4.2 硬件资源规划

4.2.1 时钟与电源配置

在实际项目中我们需要确定 SoC 时钟源、内部各模块的时钟配置、电源选择等事项。但这里我们直接使用 EVB 板开发,因此暂不关注这些内容,使用默认配置参数即可。

EVB 板的电源选择相关,请参考 PAN108x EVB 硬件资源介绍 文档。

低功耗的时钟选择(RCL32K,XTL32768,ACT32K),请参考 低功耗蓝牙 Peripheral HR 例程 文档。

4.2.2 PWM 模块配置

我们使用 PAN1080 SoC 的 PWM 模块控制 EVB 板上的 LED 灯,为此我们需要规划:

  • 使用哪个 PWM 模块的哪个输出通道(PAN1080 SoC 中内置了 3 个硬件 PWM 模块,分别为PWM0PWM1PWM2,每个模块均有 8 个通道)

  • 将 PWM 波形输出到 SoC 的哪个引脚

需要注意的是,由于 PAN1080 SoC 的每个引脚最多只能配置成预设的 8 个功能之一,因此我们在规划引脚资源的时候,要查阅各个引脚的 PINMUX 定义,从中找到合适的引脚使用。

  1. 我们可以从 PAN1080 Development Kit 中的如下几个文件的任意一个中找到 PAN1080 SoC 的 PINMUX 引脚定义:

    • 01_SDK/zephyr/dts/arm/panchip/pan1080/pan1080xx1_pinctrl.dtsi (32-Pin 封装引脚定义)

    • 01_SDK/zephyr/dts/arm/panchip/pan1080/pan1080xx5_pinctrl.dtsi (64-Pin 封装引脚定义)

    • 01_SDK/zephyr/include/drivers/pinmux/pinmux_pan1080.h

    • 04_DOC/07_others/PAN108x-Datasheet.pdf04_DOC/07_others/PAN1080x-产品说明书.pdf

  2. 这里,我们直接从 VS Code 中打开pan1080xx5_pinctrl.dtsi文件(按快捷键 Ctrl+P,输入文件名即可)

  3. 由于 EVB 板上的蓝色 LED 灯已经与P16引脚相连,我们先查找P16引脚的 PINMUX 定义,看是否有 PWM 功能;查阅后发现其正好有一个pwm0_ch6 (PWM0 Channel 6)的定义,可以供我们使用:

    image

    打开 pan1080xx5_pinctrl.dtsi 文件

  4. 为使规划的硬件资源生效,我们需要修改 SDK 中的板级 DeviceTree 文件。

    从 VS Code 中打开名为pan108xxb5_evb.dts的文件(按快捷键 Ctrl+P,输入文件名即可):

    image

    打开 pan108xxb5_evb.dts 文件

    此文件中描述了关于 PAN108X-XB5 EVB 的所有板级硬件配置信息,这些配置保证了我们可以使用 EVB 开发板成功运行 SDK 中的所有例程(samples_panchip)和测试用例(tests_panchip)。

    关于Zephyr DeviceTree(.dts/.dtsi)的更多细节,请参考:

  5. 我们暂不关心除PWM以外的模块配置,可以看到,pan108xxb5_evb.dts文件第 172~175 行描述了一个PWM0模块的配置:

    ...
    
    &pwm0 {
    	pinctrl-0 = <&p1_0_pwm0_ch4 &p1_1_pwm0_ch5 &p1_6_pwm0_ch6>;
    	status = "okay";
    };
    
    ...
    

    其含义如下:

    • 第一行&pwm0表示,当前配置文件中对pwm0中属性值的修改会更新默认的(名为pan1080.dtsi)配置文件中的值,亦即,若本次更新的属性不在默认配置文件中,则为此属性赋予一个值;若本次更新的属性已经在默认配置文件中已经有一个值,则覆盖此属性的默认值;

    • 第二行pinctrl-0表示,修改当前pwm0模块的 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模块的各项参数配置;

  6. 由于我们的规划是使用PWM0 Channel 6从芯片P16引脚输出方波,而此处已经配置好,因此 DTS 文件中我们无需做任何改动。

4.2.3 UART 模块配置

我们希望使用 PAN1080 SoC 的UART模块输出 Log 日志到 PC,为此我们需要明确:

  • 使用哪个 UART 模块(PAN1080 SoC 中内置了 2 个 UART 模块,分别为UART0UART1

  • UART Tx/Rx 分别映射到 SoC 的哪个引脚

  • 如何与 PC 通信

PAN1080 EVB 底板中提供了一个 USB 转 UART 的模块电路,其可以很方便地通过跳线帽与 PAN1080 SoC 的P00UART0 TX)、P01UART0 RX)相连,这里我们就使用这种方式与 PC 通信。

  1. 使用跳线帽将 EVB 底板(左侧)的 USB 转 UART 模块的 2 个通信排针连接至 PAN1080 SoC:

    • 将 TX0 引脚连接至 P00

    • 将 RX0 引脚连接至 P01

  2. 再次在 VS Code 中打开板级 DeviceTree 文件pan108xxb5_evb.dts,我们可以看到其中已经有了一些与UART 有关的配置:

    ...
    
    	chosen {
    		zephyr,console = &uart0;
    		zephyr,shell-uart = &uart0;
    		zephyr,bt-mon-uart = &uart0;
    		zephyr,bt-c2h-uart = &uart0;
            ...
    	};
    
    	soc {
    		pin-controller@40030000 {
    			/* port, pin, pinmux_name, pinmux_sel [, flag1, ... ] */
    			DT_PAN_PINS(p0, 1, uart0_rx, PAN1080_PIN_FUNC_P01_UART0_RX, input-enable);
    		};
    	};
    
    ...
    
    &uart0 {
    	current-speed = <921600>;
    	pinctrl-0 = <&p0_0_uart0_tx &p0_1_uart0_rx>;
    	status = "okay";
    };
    
    ...
    

    其含义如下:

    • chosen节点描述了 Zephyr OS 用到的硬件模块与实际硬件的映射关系:

      • zephyr,console = &uart0表示将 Zephyr Console 模块配置为使用UART0通信,我们此次向 UART 打印 LED 状态消息即使用此方式;

      • zephyr,shell-uart = &uart0zephyr,bt-mon-uart = &uart0zephyr,bt-c2h-uart = &uart0均与本文内容无关,这里不做详细介绍,只需了解我们将 Zephyr 所有用到的串口均默认映射到了PAN1080 SoC 的UART0模块即可;

    • soc节点描述了芯片级的硬件配置信息:

      • pin-controller@40030000是一个子节点,代表 PAN1080 SoC 的 PINMUX(MFP)模块;

      • DT_PAN_PINS(p0, 1, uart0_rx, PAN1080_PIN_FUNC_P00_UART0_RX, input-enable)用来辅助配置UART0的 PINMUX 参数;其中,此配置的前 4 个参数表示我们将芯片P01引脚的 PINMUX 切换为 UART0 RX 功能,最后一个参数表示辅助配置参数,这里input-enable表示打开此引脚的数字信号输入功能;

        注1:除input-enable参数外,此处还可以配置bias-pull-up以使用当前引脚的内部上拉电阻,或配置bias-pull-down以使用当前引脚的内部下拉电阻;

        注2:此处的 PINMUX 配置不是必须的,只有在需要打开某个引脚数字信号输入功能或内部上拉/下拉电阻功能的时候,才应该在此处进行配置,并且配置的引脚功能应当与对应外设模块中的pinctrl-0中的配置一致,例如:

        • 我们在 DeviceTree 的uart0节点中将Tx功能配置到了P00引脚,将Rx功能配置到了P01引脚,因此我们需要在soc/pin-controller节点中将P01引脚的数字信号输入功能打开,而P00为数字信号输出引脚,这里无需将其数字输入功能打开;

        • 如果我们使用I2C模块,则由于 I2C 协议要求有上拉电阻,因此我们可以配置bias-pull-up参数以使用 SoC 内部上拉电阻;如果我们将I2C模块配置为 Slave,则由于SCLSDA两根线均为输入信号,因此还需要配置input-enable参数以打开这两个引脚的数字信号输入功能;

    • &uart0表示,修改uart0节点中的属性,且其中的修改会更新默认配置文件(名为pan1080.dtsi)中的值:

      • current-speed = <921600>表示,波特率配置为921600;

      • pinctrl-0 = <&p0_0_uart0_tx &p0_1_uart0_rx>表示:

        • 将芯片P00引脚的 PINMUX 切换为 UART1 TX 功能;

        • 将芯片P01引脚的 PINMUX 切换为 UART1 RX 功能(与soc/pin-controller节点中的配置一致);

      • status = "okay"表示,在系统初始化过程中,使能 DeviceTree 中对当前UART模块的各项参数配置;

  3. 从 dts 文件中可知,SDK 中对于 UART 的配置已经与我们在 EVB 板中的接线一致,因此无需再做修改。

4.3 修改代码

下面我们演示如何在 VS Code 环境下写 App 代码,实现预期功能。

4.3.1 使用PWM

  1. Zephyr 提供了标准的 PWM API 接口(头文件位置:01_SDK/zephyr/include/drivers/pwm.h),为了使用这些接口,我们需要先使能 Zephyr PWM Driver,方法是在 App 目录的prj.conf,增加一个 Config 项:

    CONFIG_PWM=y
    

    增加后文件内容如图所示:

    image

    在prj.conf文件中使能PWM Driver

  2. 接着,我们在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 *pwm_dev;
    	bool flag = true;
    
    	pwm_dev = DEVICE_DT_GET(DT_NODELABEL(pwm0));
    	if (pwm_dev == NULL) {
    		return;
    	}
    
    	while (1) {
    		if (flag == true) {
    			flag = !flag;
    			/* LED Blink, turn on 20ms and turn off 80ms in every 100ms */
    			pwm_pin_set_usec(pwm_dev, 6, 100000, 20000, PWM_POLARITY_NORMAL);
    		} else {
    			flag = !flag;
    			/* LED Blink, turn on 80ms and turn off 20ms in every 100ms */
    			pwm_pin_set_usec(pwm_dev, 6, 100000, 80000, PWM_POLARITY_NORMAL);
    		}
    		k_msleep(3000);
    	}
    }
    
  3. 点击 VS Code 的Terminal菜单,选择Run Build Task...(或直接快捷键Ctrl + Shift + B),依次执行 Build 和 Flash 命令,将程序烧录至芯片中,即可观察到 LED 灯闪烁,且每 3s 切换一次闪烁频率。

4.3.2 使用 UART

我们可以直接使用 zephyr 提供的 printk 函数,将 Log 信息输出至串口,修改while(1)循环内的代码如下:

	while (1) {
		if (flag == true) {
			flag = !flag;
			/* LED Blink, turn on 20ms and turn off 80ms in every 100ms */
			if (pwm_pin_set_usec(pwm_dev, 6, 100000, 20000, PWM_POLARITY_NORMAL) == 0) {
				printk("LED Blink, turn-on 20ms and turn-off 80ms in every 100ms..");
			} else {
				printk("error occurs\n");
			}
		} else {
			flag = !flag;
			/* LED Blink, turn on 80ms and turn off 20ms in every 100ms */
			if (pwm_pin_set_usec(pwm_dev, 6, 100000, 80000, PWM_POLARITY_NORMAL) == 0) {
				printk("LED Blink, turn-on 80ms and turn-off 20ms in every 100ms..");
			} else {
				printk("error occurs\n");
			}
		}
		k_msleep(3000);
	}

重新编译烧录后,在 PC 中使用串口工具(如 SecureCRT)即可看到每 3s 打印一次消息:

image

修改后的 App Log 打印

5 芯片硬件校准参数

每颗量产的 PAN108x SoC 芯片,Panchip 均会在 CP/FT 阶段对其进行硬件参数校准(如各内部 LDO 的电压值、内部 RC 时钟频率、ADC 校准参数等等)。校准后的各项参数,会根据情况存储在 eFuse 或 Flash INFO 区域。

我们需要开启如下的 Config 配置以使能硬件校准功能:

CONFIG_SOC_HW_CALIBRATION=y
  • 在 SDK v0.8.0 及之后的版本中,此 Config 配置默认是打开的

  • 在 SDK v0.7.0 及之前的版本中,此 Config 配置默认是关闭的,我们需要在 App 层手动打开此配置

上述配置开启后,系统会在初始化阶段,自动将当前芯片的硬件校准参数,导入到各自的校准寄存器中以使它们生效。

另外,在校准参数的导入过程中,还会将芯片的一些其他信息读取出来,存入一个名为 otp 的全局结构体变量中,供 App 使用,例如:

  • 从名为 otp.m.uid[8] 的结构体成员中,可以获取当前芯片的唯一 ID (UID),共 8 字节

  • 从名为 otp.m.mac_addr[6] 的结构体成员中,可以获取当前芯片的出厂 MAC Address,共 6 字节

  • 注1:目前阶段,某些芯片中的 UID 区域可能没有数据,暂时可以用 MAC Address 代替作为芯片的唯一标识。

  • 注2:以上校准参数是在常温下测试给出的,而实际使用中,过高或过低的温度均可能影响芯片的性能:例如,对于 DeepSleep 低功耗唤醒功能,当温度低于 0℃ 后,默认的 LDO 校准参数可能不足以使芯片正常唤醒,这时候我们可以另外开启自动校准 LDO 的功能:CONFIG_SOC_LDO_CALIBRATION=y,此特性开启后,系统会每隔 10s 测量一次当前的芯片温度,若发现温度已降至 0℃ 附近,则重新配置 LDO 的校准参数,已确保低功耗唤醒功能正常(代价是低功耗状态下的功耗可能会变大)。

6 RF PHY 配置选择

我们在开发 BLE 或 2.4G 应用的时候,需要根据实际需求选择不同的 RF PHY 配置。目前 SDK 中提供了几种不同场景下可用的 RF PHY 配置,我们可以在 App 的prj.conf文件中使用名为CONFIG_BT_CTLR_AGC_MODE的 CONFIG 进行选择。

目前 SDK 支持 5 种不同的 RF PHY 配置:

CONFIG_BT_CTLR_AGC_MODE

Description

0

BLE应用,运动健康应用,RX灵敏度较高

1

BLE应用,RSSI精度不高

2

2.4G应用,发送/接收端均为PAN1080,如2.4G游戏键鼠

3

BLE应用,RSSI精度和抗干扰性高

4

2.4G应用,发送/接收端有一端为NRF芯片,对距离、收包率、抗干扰等性能有一定要求

7 系统启动与睡眠唤醒时间

系统启动时间:

启动阶段

所需时间

程序从 Bootloader 执行至 App

6.3 ms

程序从 App 初始化执行至 main() 函数

9.5 ms

芯片睡眠唤醒时间:

低功耗模式

睡眠唤醒所需时间

Sleep Mode

小于 1 us

DeepSleep Mode

300 us 左右

Standby Mode 0/1

1 ~ 2 ms(不包括软件重新初始化时间)

:以上时间基于 Zephyr Bluetooth Peripheral HR Clock XTL Sample 实测得出,不同 App 工程和配置下,系统启动时间与睡眠唤醒时间均可能会有所差异。

8 更多相关文档

  1. Zephyr Devicetree 与 Kconfig 配置指南:介绍 Zephyr Kconfig 配置的相关技巧

  2. Zephyr DeviceTree APIs:Zephyr官方对于DeviceTree接口的详细介绍

  3. Zephyr Peripheral APIs:Zephyr官方提供的外设Driver API接口详细介绍