最小系统实现
概述
本章节介绍如何在芯片上运行起最小系统。
最小系统开发
最小系统开发关键点如下: 1、搭建yoc开发环境
2、建立自己的芯片组件
3、CPU类型选择
4、链接脚本中的地址空间定义
5、printf功能移植
第一步、建立yoc开发环境
YoC 开发平台提供芯片SDK的模板工程,以RISCV CPU e907fp芯片为例,通过模板工程快速建立 SDK工程环境。
mkdir sdk_xxxchip
cd sdk_xxxchip
yoc init
yoc search dummy_demo
显示如下:
arm_dummy_demo - YoC dummy demo for arm.
csky_dummy_demo - YoC dummy demo for csky.
riscv_dummy_demo - YoC dummy demo for riscv.
YoC 开发平台提供了3种不同类型的芯片模板工程:
arm_dummy_demo/csky_dummy_demo/riscv_dummy_demo:
最小系统的芯片SDK模板工程,包括 aos、console、kv、csi等组件,及demo示例。
开发者根据芯片特性,选择适当的SDK模板工程,创建芯片SDK。以RISCV CPU为例,选择riscv_sdk_dummy模板工程。
下载dummy模板工程
示例:
yoc install riscv_dummy_demo
编译 riscv_dummy_demo
编译完成之后,正确显示结果如下:
AR yoc_sdk/lib/libchip_riscv_dummy.a
CC out/riscv_dummy_demo/app/src/main.o
ranlib yoc_sdk/lib/libchip_riscv_dummy.a
AR yoc_sdk/lib/libriscv_dummy_demo.a
ranlib yoc_sdk/lib/libriscv_dummy_demo.a
LINK out/riscv_dummy_demo/yoc.elf
Generating yoc.bin
riscv64-unknown-elf-objdump -d out/riscv_dummy_demo/yoc.elf > yoc.asm
INSTALL yoc.elf
scons: done building targets.
YoC SDK Done
第二步、建立自己的芯片组件
套件中自带 board_riscv_dummy
开发板组件与 chip_riscv_dummy
组件,需要根据自己芯片型号(名称)更名,例如:
yoc rename board_riscv_dummy board_cb8888
yoc rename chip_riscv_dummy chip_ch8888
make clean && make
根据以上几步,完成了开发工程的搭建,接下进入到芯片的 bring up 阶段。
第三步、CPU类型选择
修改components/chip_ch8888/package.yaml文件中的arch_name和cpu_name字段,如下:
hw_info:
arch_name: riscv # <可选项> cpu架构:csky、arm、riscv
cpu_name: e907fp # <可选项> cpu型号:e902、e906、e90fd...
第四步、链接脚本
程序的内存划分主要由链接脚本完成。
用户可以根据chip_ch8888
下的链接脚本(gcc_xip.ld
)进行修改。(如果是64BIT的CPU请参考gcc_xip_rv64.ld
进行修改。)
链接脚本修改
指定链接脚本
链接脚本存放在 chip_ch8888
目录下。
链接时使用哪个链接脚本描述在chip_ch8888/package.yaml
文件中,如下例:
hw_info:
arch_name: riscv
cpu_name: e907fp
ld_script: gcc_xip.ld # 链接脚本指定
指定内存空间
如下定义ISRAM起始地址为0x00000000,长度为0x20000
MEMORY
{
ISRAM : ORIGIN = 0x00000000 , LENGTH = 0x40000 /* ISRAM 256KB*/
DSRAM : ORIGIN = 0x20000000 , LENGTH = 0x20000 /* DSRAM 128KB*/
}
指定 HEAP 的分配
动态方式指定
如下例,定义 __heap_start
和 __heap_end
,即可指定堆区的起始和结束地址,用户只需要修改这两个符号即可。
下例中:__heap_start
从 .bss 段结束开始;__heap_end
指定为 ram 的结束地址
...
PROVIDE (__heap_end = __ram_end); # 指定 heap 结束
._user_heap : {
. = ALIGN(0x4) ;
__heap_start = .; # 指定 heap 开始,从.bss结束起划为heap
. += __min_heap_size;
. = ALIGN(0x4) ;
} > REGION_BSS AT > REGION_BSS
...
静态方式指定
用户也可以使用绝对地址定义 __heap_start
和 __heap_end
,该方法需要特别小心避免和其它内存段冲突,如下:
PROVIDE (__heap_start = 0x10000000);
PROVIDE (__heap_end = 0x10010000);
第五步、printf 功能实现
使用UART口打印,需要满足以下条件:
1、依赖UART驱动中的csi_uart_putc
接口(在chip_riscv_dummy/drivers/uart.c
文件中)
2、需要在boards/<board_name>/include/board.h
中定义如下宏定义
#define CONSOLE_UART_IDX (0) //控制器编号
#define CONFIG_CLI_USART_BAUD (115200) //串口波特率
#define CONFIG_CONSOLE_UART_BUFSIZE (128) //控制台缓存大小
#define CONSOLE_TXD PA10 //TX引脚名字
#define CONSOLE_RXD PA11 //RX引脚名字
#define CONSOLE_TXD_FUNC PA10_UART0_TX //TX引脚复用值
#define CONSOLE_RXD_FUNC PA11_UART0_RX //RX引脚复用值
3、UART驱动编写,请参考CSI驱动编写例程中的UART驱动编写章节。
第六步、最小系统运行
参考riscv_dummy_demo/README.md
文件进行编译以及运行。
运行最小系统,出现如下打印说明运行成功。
###Welcom to YoC###
[Sep 20 2022,09:25:18]
[ 0.000]<I>[INIT]<app_task>Build:Sep 20 2022,09:25:18
[ 0.010]<D>[app]<app_task>Hello world! YoC
(cli-uart)# [ 3.010]<D>[app]<app_task>Hello world! YoC
[ 6.010]<D>[app]<app_task>Hello world! YoC
[ 9.010]<D>[app]<app_task>Hello world! YoC
[ 12.010]<D>[app]<app_task>Hello world! YoC
[ 15.010]<D>[app]<app_task>Hello world! YoC