摘要: 树莓派是英国的慈悲组织“Raspberry Pi 基金会”开发的一款基于 arm 的微型电脑主板。本文介绍基于 LiteOS 的树莓派移植过程。
本文分享自华为云社区《2021 LiteOS 树莓派移植指南 (一)》,作者:Lionlace。
树莓派是英国的慈悲组织“Raspberry Pi 基金会”开发的一款基于 arm 的微型电脑主板。本文介绍基于 LiteOS 的树莓派移植过程。
硬件信息
开发板:Raspberry Pi 2 Model B(树莓派 2B)
CPU:Broadcom BCM2836
主频:900MHz
内存:1GB
GPU:VideoCore IV GPU
移植筹备
硬件环境
本试验应用了 Raspberry Pi 2 Model B 开发板、USB 转 TTL 模块、SDcard 和读卡器。
软件环境
- 本试验须要先依照码云上的 LiteOS 教程搭建好 linux 环境(make、arm-none-eabi 编译工具链)。环境搭建教程:https://gitee.com/LiteOS/Lite…
- 本试验须要下载官网的镜像制作工具(Raspberry Pi Imager),下载地址:https://www.raspberrypi.org/s…
移植步骤
创立目录构造
在 targets 目录下新增 Raspberry_Pi2B 目录,参考与 cortex-A7 架构差别较小的 realview-pbx-a9 的启动流程进行移植。
将 realview-pbx-a9 目录下的 reset_vector.S 和 main.c 拷贝到 Raspberry_Pi2B 目录下并将 reset_vector.S 重命名为 los_startup_gcc.S。
将 realview-pbx-a9 目录下的 board.ld 和 liteos.ld 中内容合并到 Raspberry_Pi2B 目录下 liteos.ld 文件中。
拷贝 realview-pbx-a9 目录下 include、os_adapt 文件夹到 Raspberry_Pi2B 目录下,并删除不须要的 dma 相干头文件 include/asm/dma.h。
敞开 SMP 和 MMU
在 los_startup_gcc.S 文件中减少敞开 SMP 和 MMU 的代码。
- 敞开 SMP 性能
mrc p15, 0, r0, c1, c0, 1
bic r0, r0, #0x40
mcr p15, 0, r0, c1, c0, 1
上表是 ACTLR(Auxiliary Control Register)寄存器 bit6 性能形容信息,理解更多寄存器相干信息能够参考 Cortex-A7 MPCore Technical Reference Manual。
- 敞开 MMU 的性能
mrc p15, #0, r0, c1, c0, #0
bic r0, r0, #1
mcr p15, #0, r0, c1, c0, #0 @ clear mmu bit
上表是 SCTLR(System Control Register)寄存器 bit0 性能形容信息,理解更多寄存器相干信息能够参考 Cortex-A7MPCore Technical Reference Manual。
- 删除调用 SMP 相干函数
删除 los_startup_gcc.S 中的 enable_scu 和 secondary_cpu_start。
使能 FPU/ENON
配置 FPU/NEON:
/* enable fpu+neon */
LDR r0, =(0xF << 20)
MCR p15, 0, r0, c1, c0, 2
MOV r3, #0x40000000
VMSR FPEXC, r3
以上前两行代码用于设置 CP10 和 CP11 的拜访权限,后两行用于设置寄存器 FPEXC 的 EN 位来使能 FPU。
注: 在 arm 的协处理器设计中,最多能够反对 16 个协处理器,通常被命名为 cp0~cp15。
上表为寄存器 CPACR bit20-23 性能形容信息,理解更多寄存器相干信息能够参考 Cortex-A7 MPCore Technical Reference Manual。
批改链接脚本
树莓派启动时首先加载 SD 卡中的 start.elf 文件,该程序会读取 SD 卡中的 config.txt 文件内容,该文件记录了一些配置信息。如果没有设置启动地址和启动文件,则默认会加载 kernel8.img 文件,该文件是 aarch64 编译的程序,启动地址为 0x80000。如果 SD 卡中无 kernel8.img 镜像文件,则会加载 kernel7.img 镜像文件,该文件是 32 位编译器编译的程序,启动地址为 0x8000。树莓派 2B 的 cpu 是 32 位架构,因而设置 liteos.ld 文件中启动地址为 0x8000。
栈初始化
树莓派 2B 启动文件 los_startup_gcc.S 中只设置了 SVC 模式的 sp 寄存器,新增 cpuInit 函数来初始化其余模式的 sp 指针。如下所示:
VOID cpuInit(VOID)
{
__asm__ (
"msr cpsr_c, %1\n\t"
"mov sp, %0\n\t"
"msr cpsr_c, %3\n\t"
"mov sp, %2\n\t"
"msr cpsr_c, %5\n\t"
"mov sp, %4\n\t"
"msr cpsr_c, %7\n\t"
"mov sp, %6\n\t"
"msr cpsr_c, %8\n\t"
:
: "r" (__irq_stack_top),
"I" (PSR_F_BIT | PSR_I_BIT | CPSR_IRQ_MODE),
"r" (__abt_stack_top),
"I" (PSR_F_BIT | PSR_I_BIT | CPSR_ABT_MODE),
"r" (__undef_stack_top),
"I" (PSR_F_BIT | PSR_I_BIT | CPSR_UNDEF_MODE),
"r" (__fiq_stack_top),
"I" (PSR_F_BIT | PSR_I_BIT | CPSR_FIQ_MODE),
"I" (PSR_F_BIT | PSR_I_BIT | CPSR_SVC_MODE)
: "r14");
}
配置动态内存地址
#define OS_SYS_MEM_ADDR ((void *)(&__bss_end))
#define LOS_HEAP_ADDR_END (void*)(0x0 + 4 * 1024 * 1024)
#define OS_SYS_MEM_SIZE (UINT32)(((UINT32)LOS_HEAP_ADDR_END - (UINT32)OS_SYS_MEM_ADDR + (64 - 1)) & ~(64 - 1))
以上代码定义 OS_SYS_MEM_ADDR 为动态内存起始地址,LOS_HEAP_ADDR_END 为动态内存完结地址,OS_SYS_MEM_SIZE 为动态内存大小。
串口实现
树莓派 2B 原理图引出了 mini_uart 串口 TXD0、RXD0,对应的引脚为 GPIO14、GPIO15,如下图所示:
创立 usart.c 和 usart.h 文件,在 usart.c 中编写串口初始化函数 UartInit,并实现 uart_debug.c 文件中 uart_getc、uart_hwiCreate、uart_write 接口,实现 printf 函数从串口输入。
适配中断
树莓派 2B 的中断属于 bcm 特定的中断控制器。在 drivers/interrupt 目录下新增 arm_control.c 文件,并在该文件中实现 HwiControllerOps 构造体内的回调函数。
STATIC const HwiControllerOps g_armControlOps = {
.enableIrq = HalIrqUnmask,
.disableIrq = HalIrqMask,
.getCurIrqNum = HalCurIrqGet,
.getIrqVersion = HalIrqVersion,
.getHandleForm = HalIrqGetHandleForm,
.handleIrq = IrqEntryArmControl,
.clearIrq = HalIrqClear,
.triggerIrq = HalIrqPending,
};
以上表格是 interrupt 寄存器偏移地址,读者想理解具体寄存器相干信息请参考官网芯片手册。
适配 zhongduan
树莓派 2B 通过 Timer(arm side) 来触发 systick 中断。具体操作细节请参考文件:drivers\timer\rasp_systick.c。
/* systime=250000000 */
timer->preDivider = (OS_SYS_CLOCK / OS_SYS_US_PER_SECOND - 1);
timer->reload = 0;
timer->load = 0;
timer->IRQClear = 0;
timer->control = 0;
timer->reload = LOSCFG_BASE_CORE_TICK_PER_SECOND;
timer->load = LOSCFG_BASE_CORE_TICK_PER_SECOND;
/* 23-bit counter, enable interrupt, enable timer */ timer->control = (1 << 1) | (1 << 5) | (1 << 7);
UINT32 ret = LOS_HwiEnable(ARM_TIMER_INI);
以上代码配置定时器 Timer 为每 1ms 触发一次 systick 中断。
以上是 Timer 寄存器偏移地址,读者想理解具体寄存器相干信息请参考官网芯片手册。
配置编译
在 targets 目录下新增 kconfig.raspberry 文件:
ConfigLOSCFG_PLATFORM
config LOSCFG_PLATFORM
string
default "Raspberry_Pi2B" if LOSCFG_PLATFORM_Raspberry_Pi2B
choice
prompt "Board"
depends on LOSCFG_FAMILY_RASPBERRY
default LOSCFG_PLATFORM_Raspberry_Pi2B
help
Raspberry_Pi2B
config LOSCFG_PLATFORM_Raspberry_Pi2B
bool "Raspberry_Pi2B"
select LOSCFG_ARCH_CORTEX_A7
select LOSCFG_USING_BOARD_LD
select LOSCFG_PLATFORM_ARM_CONTROL
select LOSCFG_Raspberry_Pi2B_SYSTICK
endchoice
批改 Makefile 文件
别离批改以下门路 Makefile(详情请参考 gitee 仓库对应文件):driver/timer/Makefiledriver/interrupt/Makefiletargets/Raspberry_Pi2B/Makefile
增加.img 生成指令
在根目录下 Makefile 中增加指令 $(OBJCOPY) -O binary $(OUT)/$@.elf $(OUT)/kernel7.img,用来将生成的 elf 文件转换生成 kernel7.img 文件。
制作启动 SDcard
- 应用 Raspberry Pi Imager 工具制作 Raspberry Pi 零碎。
Raspberry Pi Imager 下载链接:https://www.raspberrypi.org/s…
- 将编译生成的 kernel7.img 文件替换掉 SDcard 中 kernel7.img 文件。
-
将写入镜像文件的 SDcard 插入树莓派 2B 中并上电,树莓派 2B 即可运行 LiteOS 零碎。运行后果如下:
********Hello Huawei LiteOS******** LiteOS Kernel Version : 5.1.0 build data : Jul 13 2021 16:40:42 ********************************** OsAppInit cpu 0 entering scheduler app init! Hello, welcome to liteos demo! Huawei LiteOS #
至此,LiteOS 零碎胜利启动和运行。该移植工程曾经在 Gitee LiteOS 社区上线,相干代码链接地址为:https://gitee.com/LiteOS/Lite…
参考文献链接
[1] Raspberry Pihardware – Raspberry Pi Documentation:https://www.raspberrypi.org/d…
[2] 树莓派官网芯片手册:
https://datasheets.raspberryp…
[3] Cortex-A7 MPCore Technical Reference Manual:
https://developer.arm.com/doc…
点击关注,第一工夫理解华为云陈腐技术~