完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
STM32H743ZIT6移植uboot
Stm32H743移植linux 1, 首先在Linux系统下安装交叉编译环境 下载Cortex-M系列的交叉编译环境 下载对应系统的文件 解压 tar –xjf gcc-arm-none-eabi-10.3-2021.07-x86_64-linux.tar.bz2 解压后的文件拷贝到/user/local Sudo cp gcc-arm-none-eabi-10.3-2021.07 /user/local 修改环境变量 sudo vim /etc/profile 文件最后增加export PATH=$PATH:/usr/local/ gcc-arm-none-eabi-10.3-2021.07/bin 运行source /etc/profile使环境变量生效 要想在其他位置生效,重启系统即可 安装完成 用hello world 验证 直接编译会报错 可能是默认的libc缺少某些标准函数,需要使用–specs选项。arm-none-eabi-gcc配套的readme文件中有关于libc库及–specs选项的解释,使用前建议阅读一下readme文件) 使用arm-none-eabi-gcc --specs=nosys.specs -o main main.c编译 查看文件信息:file main 表示交叉编译环境安装成功 2, 编译uboot 首先去uboot官网下载最新uboot源码 进入源码 选择FTP 选择自己想要下载的版本 解压:tar –xjf u-boot-2021.07.tar.bz2 查看configs目录 uboot支持stm32H743,先使用默认配置文件 Makefile 文件增加交叉编译器 执行make stm32h743-disco_defconfig得到.config文件 make –j4编译uboot 使用STLink烧录u-boot.bin文件到H7的芯片上,串口没有打印信息 首先怀疑串口引脚配置不同 初始化串口的函数没有对串口引脚的配置,查看uboot编译,发现是通过设备树进行引脚配置,所以找到对应的设备树arch/arm/dts/stm32h743i-disco.dts 查看配置发现与自己板子上的串口引脚不匹配,修改为自己板子上的引脚配置 重新烧录,串口还是没有打印,发现是.bin文件不匹配,因为使用了设备树,所以要使用u-boot-dtb.bin文件。 使用STLink烧录u-boot-dtb.bin文件到flash中 stm32h743属于ARMV7M架构 串口成功打印uboot信息。 打印信息只有少部分,没有完全打印,分析uboot启动流程 3, 分析启动流程 首先分析u-boot.lds链接脚本 Uboot代码当前的入口点:_start,真正的.text段是从.vectors开始的 _start 在文件 arch/arm/lib/vectors.S 中有定义。 _start后面的就是中断向量表 可以看出,直接跳转到了reset,reset位于arch/arm/cpu/armv7m/start.S文件中 跳转到第一个C程序,main函数,位于arch/arm/lib/crt0.S文件中 默认使用的外部DDR内存,需要修改为内部SDRAM 使用AXI-SRAM 起始地址0x2400 0000 大小 0x8 0000 CONFIG_SYS_INIT_SP_ADDR 修改SP指针初始化的地址为0x2401 0000 board_init_f_alloc_reserve 函数主要是留出早期的malloc内存区域和gd内存区域 SYS_MALLOC_F_LEN 0xF00 #define CONFIG_SYS_MALLOC_F_LEN 0xF00 (include/generated /autoconf.h) GD_SIZE 216 #define GD_SIZE 216 (include/generated/generic-asm-offsets.h) 返回最新的top值 0x2401 0000-0xF00-0xE0(16字节对齐) = 0x2400 F020 r9寄存器存放着全局变量gd的地址,设置gd所指向的位置 调用函数 board_init_f_init_reserve,此函数在文件common/init/board_init.c 中有定义 此函数用于初始化gd,其实就是清零处理 还设置了gd->malloc_base为基地址+gd大小,再做16字节对齐 = 0x2400 F100 最终gd->malloc_base= 0x2400 F100这个就是early malloc的起始地址。 进入board_init_f函数,进入uboot第一阶段的初始化。 board_init_f 函数主要的作用: 初始化一系列外设,比如串口、定时器,或者打印一些消息等,init_sequence_f 初始化列表里面包含了一系列的初始化函数。 去掉条件编译以后的 init_sequence_f 定义如下: setup_mon_len, __bss_end-_start 得到uboot总长度 _start为我们.text的首地址 0x 0803 2fe0-0x0800 0000=0x3 2fe0 fdtdec_setup, 加载设备树以及设备树地址 initf_malloc, 设置内存池的大小 为0xF00 initf_bootstage setup_spl_handoff, arch_cpu_init, mach_cpu_init, initf_dm, arch_cpu_init_dm, timer_init, env_init, init_baud_rate, 设置串口速率115200 serial_init, 初始化串口 serial_uclass 通过设备树方式初始化串口 console_init_f, 设置gd->have_console为1,打开控制台 display_options, 打印uboot版本以及编译信息 display_text_info checkcpu, show_board_info, 打印板子信息 INIT_FUNC_WATCHDOG_INIT INIT_FUNC_WATCHDOG_RESET announce_dram_init, 打印DRAM dram_init, ram_size=0x80000 ram_base=0x2400 0000 需要在设备树文件中修改对应的memory节点,根据选择的SRAM的地址和大小 INIT_FUNC_WATCHDOG_RESET INIT_FUNC_WATCHDOG_RESET INIT_FUNC_WATCHDOG_RESET setup_dest_addr, ram_top=0x2408 0000 relocaddr=0x2408 0000 reserve_round_4k, 4K向下对齐 arch_reserve_mmu, 页表64K对齐relocaddr=0x2407 0000 reserve_video, reserve_trace, reserve_uboot, start_addr_sp= relocaddr =relocaddr-uboot长度(0x32fe0)=0x2403 D000 reserve_malloc, 保留一段堆空间(也就是堆的大小100K)start_addr_sp=0x2402 2000 默认值为(11024 1024)1M的大小,由于单片机的SRAM大小不够,修改为100K(11001024) reserve_board, 保留bd的空间(大小0x50)start_addr_sp=0x24021fb0 reserve_global_data, 设置新的gd地址(大小0xE0)start_addr_sp=0x24021ed0 reserve_fdt, 设备树大小size 0x5760 start_addr_sp= 0x24010770 reserve_bootstage, reserve_bloblist, reserve_arch, reserve_stacks, 预留16字节start_addr_sp= 0x24010750 dram_init_banksize, 起始地址0x2400 0000 show_dram_config, 打印DRAM大小0x8 0000(512K) INIT_FUNC_WATCHDOG_RESET setup_bdinfo, display_new_sp, INIT_FUNC_WATCHDOG_RESET reloc_fdt, 重定位设备树,把设备树段拷贝到新的位置 reloc_bootstage, reloc_bloblist, setup_reloc, 重定位gd_t clear_bss, 最终内存分布: board_init_f中的内容就已经分析完了。 接下来就剩下uboot本身的搬移和bss段的初始化 调用函数 relocate_code 代码重定位函数,将uboot拷贝到SRAM中去 这三句代码重点分析一下: adr是个位置无关的加载指令,无论here的链接地址是多少,adr加载的都是当前pc +偏移,然后得到新的规划的uboot和旧的uboot之间的偏移量给r0 之后把偏移和旧的uboot的here加起来,最终得到新的uboot里面的here地址,然后 放进lr,等进入后面的relocate_code函数,返回来的时候就直接返回到新的uboot的 代码段运行了。 R0 = relocaddr R1 = 0x0800 0000 uboot存储在flash中的地址 R2 = 0x0803 0324 uboot存储在flash中的结束的地址 R4 = reloc_off 循环拷贝flash中的uboot到SRAM中uboot预留的空间中去 调用函数relocate_vectors 对中断向量表做重定位 函数代码位于 arch/arm/lib/relocate.S文件中 uboot第一部分的初始化工作到这里就完成了 总结:主要的工作就是把flash中的uboot搬移到SRAM中,同时初始化了一些底层的配置,把一些参数保存在了全局变量gd中,方便后面使用。 Flash 起始地址 0x0800 0000 大小 0x20 0000 1MB 终止地址 0x0820 0000 SRAM 起始地址 0x2400 0000 大小 0x08 0000 512KB 终止地址 0x2408 0000 Uboot第二阶段初始化: gd的地址和当前新的uboot的起始地址传参给board_init_r 进入board_init_r函数中 进入初始化列表init_sequence_r中 得到列表中定义的执行的重要函数 initr_trace initr_reloc 标记已经重定位成功,malloc初始化 initr_caches 使能cache initr_reloc_global_data 初始化全局变量monitor_flash_len = _end - __image_copy_start initr_malloc 初始化堆的大小 定义为100K initr_bootstage 把动态内存分配的bootargs处理一下 initr_dm 驱动模型初始化 uboot增加设备树以后特有的 board_init gd->bd->bi_boot_params = gd->bd->bi_dram[0].start + 0x100; stdio_init_tables 初始化一下设备链表 serial_initialize 再一次初始化串口,并标记串口初始化成功 initr_mmc 初始化MMC或者SD卡,默认的MMC控制器和自己板子的不同,修改对应 的设备树MMC控制器引脚,初始化SD卡完成 stdio_add_devices 增加标准输出 initr_net 网口模块初始化,目前没有解决问题,后续继续研究 run_main_loop 最后的大循环函数 bootstage_mark_name函数调用了show_boot_progress,利用它显示启动进程(progress), 这里为空函数 cli_init 用来初始化hush shell使用的一些变量 bootdelay_process 从环境变量中取出bootdelay和bootcmd的配置值 bootdelay为uboot的启动延时值,计数期间没有干预,将执行bootcmd配置的命令 cli_process_fdt 环境变量里有bootcmd,fdt如果有,fdt会覆盖env里面的 autoboot_commands 执行倒计时函数,没按键进入bootcmd cli_loop 进入uboot命令行中 到这里,uboot移植已完成,运行print命令打印环境变量 |
|
|
|
只有小组成员才能发言,加入小组>>
3280 浏览 9 评论
2958 浏览 16 评论
3460 浏览 1 评论
9004 浏览 16 评论
4052 浏览 18 评论
1115浏览 3评论
573浏览 2评论
const uint16_t Tab[10]={0}; const uint16_t *p; p = Tab;//报错是怎么回事?
571浏览 2评论
用NUC131单片机UART3作为打印口,但printf没有输出东西是什么原因?
2303浏览 2评论
NUC980DK61YC启动随机性出现Err-DDR是为什么?
1859浏览 2评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-25 12:20 , Processed in 1.232634 second(s), Total 81, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号