刚入门F1C没多久,自己写了个BootLoader玩,一定程度上参考了达克罗德大神的minimal。
我把代码尽量优化了,最终Boot0总共不到3KB,这里面大部分都是设置DDR控制器的代码,但由于DDR控制器的资料太少了,我没有头绪怎么去编写和优化,就只好照搬了达神的代码。
这个BootLoader有一个比较大的特点就是Boot0部分链接到了SRAM里,而其他程序链接到DDR里,在加载程序到DDR时只加载用户代码,这样应该使用绝对地址码也不会出错。实现这一点的链接脚本下文会提到。
在时钟的初始化中,我把ARM内核频率和DDR频率都设置为了408MHz,受DDR1限制再高就说不准会出问题了。
仿照达神的信息头,我写了一个简化版的,只有加载长度和校验和两个变量,校验和由我写的一个工具在编译时生成,加载长度通过链接脚本可以得知,在编译时进行字节对齐即可。
与BootLoader有关的代码都在Boot0里,还有一个引用的头文件是我自己编写的寄存器结构体(写这个老费劲了XD)文件,如果一定要移到别的工程里只需要移植这几个文件即可,需要注意的是链接脚本的修改,可以参考下文。代码整体实现了较高的内聚度和较低的耦合度。在用户代码中可以完全当BootLoader不存在,值得注意的是跳转到DDR时直接跳转到链接首地址,此后BootLoader就永久留在了SRAM里。
目前Boot0部分关闭了中断,如果需要使用中断可以在用户程序里把中断向量表啥的设置好,然后CPSR里把bit[7:6]都置零以开启中断。
在编写过程中遇到过的几个比较大的坑:
SRAM的地址和BROM是重合的,都是0x0开始,这与手册不一致,但影响不大,即使不知道也可以用位置无关码避免
手动设置SP指针时尽量不要指向DDR以外的区域比如SRAM,因为某些玄学因素我设置SP指针在SRAM里后入栈出栈就会出问题,这时使用上电自动设置好的SP指针即可(上电后SP指针指向0x9FE4)
硬件SPI的FIFO如果设置成字节读写,那就必须使用BYTE大小的指针读写,这其实是个比较低级的错误,但我查了好久。。Orz
链接脚本中如果把两段代码链接到不同的内存区域,这两个内存区域之间没用的部分也会被写入生成的文件,导致编译完的文件有好几个G大。。解决办法也很简单,只需要指定SRAM段后第一个DDR段在生成文件中的相对地址即可,这需要用AT()关键字实现,下面是链接脚本的一部分:
MEMORY
{
sram : ORIGIN = 0x00000000, LENGTH = 24K
ddr : ORIGIN = 0x80000000, LENGTH = 32M
}
SECTIONS
{
.boot0 :
{
Obj/Boot0.o (.text)
Obj/ClockInit.o (.text)
Obj/DDRInit.o (.text)
Obj/SPIFlashInit.o (.text)
Obj/CodeLoader.o (.text)
} > sram
__boot0_size = SIZEOF(.boot0);
__image_file_start = .;
.text : AT(__image_file_start) //就是这里,表示代码链接到DDR内,但编译时存放在文件的__image_file_start处
{
PROVIDE(__image_start = .);
Obj/start.o (.text)
Obj/main.o (.text)
*(.text)
*(.note.gnu.build-id)
} > ddr
……………………
}
这个文件里我的用户程序初始化了串口,打印测试了Data段、RoData段和BSS段的读写,然后就一直闪灯,需要注意的是我用的是一个外接的LED接到了PA0上灌电流驱动,大家如果需要测试可以修改或是直接删掉。
编译只需要make就行。
伪目标recompile用来重新编译工程。
伪目标write用来写入SPI Flash,这会调用sunxi-fel,这个工具所需要的运行库似乎在Ubuntu18下apt-get不到,我重装了Ubuntu16才能使用
伪目标maketool用来编译那个加载信息头的程序,一般应该用不到
伪目标clean用来清理工程,不用多说
目前只支持SPI Flash启动,大家可以自己添加SDIO的驱动来从SD卡加载程序
我写这段代码使用的是VSCode,这里面有些关于VSCode的文件忽略掉就行。
代码中对寄存器的每一位操作都有非常详细的注释,觉得看手册晕的可以瞄一眼0v0
其实这段代码要说实用性多高估计也谈不上,发出来主要是跟大家共同学习一下,以后有新人入坑也能多一个参考,少踩点坑
工程下载:BootLoader.zip
离线
支持,鼓励一下!
离线
这个可以用来启动 Kernel 吗?
UBoot 太复杂了
离线
Q群看到有朋友用 u-boot的spl直接引导Linux, 但是不知道怎么玩.
离线
不错,很精简。
离线
这个可以用来启动 Kernel 吗?
UBoot 太复杂了
没试过,应该够呛,这个写来主要是引导裸机程序用的
离线
支持,鼓励一下!
惊现大佬(ΩДΩ)
离线
厉害了,顺便也弄一个V3s的裸机开发程序吧,楼主
离线
感谢楼主分享,正在纠结这个!!!!!
离线
厉害了,顺便也弄一个V3s的裸机开发程序吧,楼主
我手上目前只有个荔枝派Nano,等以后有机会再研究研究Zero吧,就启动程序来说应该区别不会很大,你可以仿照我这个思路试试弄一个V3s的
离线
有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel
离线
有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel
爆炸性好消息,坐等.gif
离线
有空我也开源我的BootLoader
IAR环境,SPI DMA读取kernel,然后直接启动kernel
听上去很不错,期待一下
离线
支持支持
离线
离线
离线
离线
我也出现设置sp后程序出问题的情况,我启用了MMU,设置sp使用虚拟地址,这个地址映射到DDR物理地址上。但跑这段设置sp的代码程序就飞了
离线
厉害,要是可以启动kernel就更好了,可以先试试直接启动未压缩的内核比较简单些,这块boot与kernel参数传递好直接跳转就可以了。
离线
自己做了一块板,用这个可以出打印信息。
这个程序对自己做板子的用户来说,初期用来调试板子的一些基本功能非常有用,感谢。
最近编辑记录 三木同子 (2021-12-23 12:04:43)
离线
离线
离线
学习学习,是不是就当裸机运行一样
离线