论坛上分享了很多F1C100s的裸机工程,但基本都是包含了这样那样RTOS系统的代码,对我这样的小白来说,感觉很复杂,缺少一个简单的裸机程序,帮助初学者入门。经过几天研究,成功的用最简单代码完成了裸机点灯,现在把笔记分享一下,高手请飘过。
## 开发环境搭建
在ubuntu下搭建开发环境很简单,只需要安装交叉编译工具链和sunxi-tools
### 1. 安装交叉编译工具链
$ sudo apt install gcc-arm-none-eabi
### 2. 安装sunxi-tools
克隆sunxi-tools仓库,签出f1c100s-spiflash分支
$ git clone https://github.com/Icenowy/sunxi-tools.git
$ git checkout f1c100s-spiflash
$ sudo make sunxi-fel && sudo make install
安装好以后,将nano的SPI Flash CS接地,进入FEL模式
$ sudo sunxi-fel ver
AWUSBFEX soc=00001663(F1C100s) 00000001 ver=0001 44 08 scratchpad=00007e00 00000000 00000000
烧录裸机程序
$ sudo sunxi-fel -p spiflash-write 0 blinkled.bin
编写裸机点亮LED程序
1. 启动代码 start.s
.text
.arm
.global _start
_start:
/* Boot head information for BROM */
.long 0xea000006
.byte 'e', 'G', 'O', 'N', '.', 'B', 'T', '0'
.long 0, __bootloader_size
.byte 'S', 'P', 'L', 2
.long 0, 0
_reset:
/* Initialize stacks. Interrupts disabled */
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xdb
msr cpsr, r0
ldr sp, _stack_und_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd7
msr cpsr, r0
ldr sp, _stack_abt_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd2
msr cpsr, r0
ldr sp, _stack_irq_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd1
msr cpsr, r0
ldr sp, _stack_fiq_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xdf
msr cpsr, r0
ldr sp, _stack_sys_end
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
ldr sp, _stack_srv_end
/* Set vector to the low address */
// mrc p15, 0, r0, c1, c0, 0
// bic r0, #0x20000
// mcr p15, 0, r0, c1, c0, 0
//
/* Call main */
ldr r1, =main
mov pc, r1
/*
* The location of section
*/
.align 4
_stack_und_end:
.long 0x00006C00
_stack_abt_end:
.long 0x00007000
_stack_irq_end:
.long 0x00007400
_stack_fiq_end:
.long 0x00007800
_stack_sys_end:
.long 0x00008000
_stack_srv_end:
.long 0x00007C00
这段程序包括这样几个方面的内容:
1. Boot head information for BROM
SPL代码必须按照BROM要求的格式,提供文件头信息,包含特定的信息,否则BROM会认为代码不是有效的SPL引导程序,将不加载。
__bootloader_size是由连接脚本计算出来的代码尺寸。
2. 堆栈初始化
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr, r0
ldr sp, _stack_srv_end
类似这样的代码,是设置arm处理器各种模式的堆栈指针。_stack_srv_end是定义在文件末尾的。
3. 跳转到main程序
### 2. main程序
由于仅仅是让LED闪烁,所以程序没有对时钟、存储器等进行初始化,只是操作了GPIOA的寄存器,实现设置引脚状态。代码如下
#define PORTA_CFG0_REG ((volatile unsigned int *)(0x01C20800))
#define PORTA_DATA_REG ((volatile unsigned int *)(0x01C20810))
void port_a_init(void)
{
//Setup all port A pint for output
*PORT_A_CFG_REG = (*PORT_A_CFG_REG & 0xFFFF0000) | 0x00001111;
}
void port_a_output(unsigned char data)
{
*PORTA_DATA_REG = (*PORTA_DATA_REG & 0xFFFFFFF0) | (data & 0x0000000F);
}
int main(void)
{
int i;
port_a_init();
for(i=0;i<10000;i++);
while(1)
{
port_a_output(0x00);
for(i=0;i<10000;i++);
port_a_output(0x0F);
for(i=0;i<10000;i++);
}
}
* PORTA_CFG0_REG寄存器设置引脚的工作模式
* PORTA_DATA_REG设置引脚的值
### 3. 链接脚本
MEMORY
{
ram : org = 0x000000000, len = 32K
}
SECTIONS
{
. = ORIGIN(ram);
.text :
{
start.o (.text)
*(.text);
} >ram
__bootloader_size = SIZEOF(.text);
}
由于程序非常简单,小巧,链接脚本仅仅是指出将代码定位到0x0000_0000的SRAM位置,将start.o放置到程序的开始的位置。
### 4. Makefile
# Object Files
OBJECTFILES= \
blinkled.o \
start.o
AS=arm-none-eabi-gcc
CC=arm-none-eabi-gcc
RM=rm
# C Compiler Flags
CFLAGS=-Wall -Wno-write-strings -Wno-char-subscripts -fno-stack-protector -DNO_STDLIB=1 -mcpu='arm926ej-s' -O0
# CC Compiler Flags
CCFLAGS=
CXXFLAGS=
# Assembler Flags
ASFLAGS=-x assembler-with-cpp -c -O0 -mcpu='arm926ej-s' -mthumb -Wall -fmessage-length=0
# Link Libraries and Options
LDLIBSOPTIONS=
all: blinkled.elf
arm-none-eabi-objcopy -O binary blinkled.elf blinkled.bin
./mksunxi blinkled.bin
blinkled.elf: ${OBJECTFILES}
$(CC) -o blinkled.elf ${OBJECTFILES} ${LDLIBSOPTIONS} -T./blinkled.ld -nostdlib
blinkled.o: blinkled.c
${RM} "$@.d"
$(CC) $(CFLAGS) -c -g -MMD -MP -MF "$@.d" -o blinkled.o blinkled.c
start.o: start.S
$(AS) $(ASFLAGS) -g -o start.o start.S
Makefile写的也是最笨的方法,需要注意的是在编译.c文件时,需要指定不连接标准库。
程序生成完以后,需要使用mksunxi这个工具处理得到的bin文件,使得它成为一个“合法”的启动代码。
剩下的就是下载到开发板,就可以观察到LED在欢快的闪烁了。
## 简要说明下程序的加载过程
1. 芯片上电,运行片内固化的BROM
2. BROM在SD卡、SPI Nor Flash搜索“合法”的SPL
3. BROM将SPL加载到片内0000_0000开始的SRAM中(32K)
4. 跳转到SPL开始执行
离线
直接写到寄存器里面
离线
请问mksunxi去哪下载呀?
离线
sfd@ubuntu:~/桌面$ sudo make sunxi-fel && sudo make install
make: *** 没有规则可制作目标“sunxi-fel”。 停止。
这个怎么弄啊,大佬
离线
sfd@ubuntu:~/桌面$
$号前的"桌面"是什么鬼?源码放到A目录,你去B目录make吗?
离线