2021-09-10

STM32H743ZIT6移植uboot

Stm32H743移植linux
1, 首先在Linux系统下安装交叉编译环境
下载Cortex-M系列的交叉编译环境:https://launchpad.net/gcc-arm-embedded
在这里插入图片描述

下载对应系统的文件
解压 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选项的解释,如https://launchpadlibrarian.net/287100883/readme.txt。使用前建议阅读一下readme文件)
使用arm-none-eabi-gcc --specs=nosys.specs -o main main.c编译
查看文件信息:file main
在这里插入图片描述

表示交叉编译环境安装成功
2, 编译uboot
首先去uboot官网下载最新uboot源码
http://www.denx.de/wiki/U-Boot/
在这里插入图片描述

进入源码
在这里插入图片描述

选择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命令打印环境变量

在这里插入图片描述

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用python中的pymsql完成如下:表结构与数据创建 1. 建立 `users` 表和 `orders` 表。 `users` 表有用户ID、用户名、年龄字段,(id,name,age) `orders` 表有订单ID、订单日期、订单金额,用户id字段。(id,order_date,amount,user_id) 2 两表的id作为主键,`orders` 表用户id为users的外键 3 插入数据 `users` (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28); `orders` (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4); 查询语句 1. 查询订单总金额 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 3. 查询订单总数最多的用户的姓名和订单总数。 4. 查询所有不重复的年龄。 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 8. 查询订单总金额最大的用户的姓名和订单总金额。 9. 查询订单总金额最小的用户的姓名和订单总金额。 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。
最新发布
06-03
这里是使用 Python 的 PyMySQL 完成上述任务的代码: ```python import pymysql # 连接数据库 conn = pymysql.connect(host='localhost', port=3306, user='root', password='123456', database='test') # 创建游标 cur = conn.cursor() # 创建 users 表 cur.execute(''' CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(20), age INT ) ''') # 创建 orders 表 cur.execute(''' CREATE TABLE orders ( id INT PRIMARY KEY, order_date DATE, amount INT, user_id INT, FOREIGN KEY (user_id) REFERENCES users(id) ) ''') # 插入数据 users_data = [ (1, '张三', 18), (2, '李四', 20), (3, '王五', 22), (4, '赵六', 25), (5, '钱七', 28) ] orders_data = [ (1, '2021-09-01', 500, 1), (2, '2021-09-02', 1000, 2), (3, '2021-09-03', 600, 3), (4, '2021-09-04', 800, 4), (5, '2021-09-05', 1500, 5), (6, '2021-09-06', 1200, 3), (7, '2021-09-07', 2000, 1), (8, '2021-09-08', 300, 2), (9, '2021-09-09', 700, 5), (10, '2021-09-10', 900, 4) ] for user in users_data: cur.execute('INSERT INTO users VALUES (%s, %s, %s)', user) for order in orders_data: cur.execute('INSERT INTO orders VALUES (%s, %s, %s, %s)', order) # 提交事务 conn.commit() # 查询语句 # 1. 查询订单总金额 cur.execute('SELECT SUM(amount) FROM orders') print(cur.fetchone()[0]) # 2. 查询所有用户的平均年龄,并将结果四舍五入保留两位小数。 cur.execute('SELECT ROUND(AVG(age), 2) FROM users') print(cur.fetchone()[0]) # 3. 查询订单总数最多的用户的姓名和订单总数。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_orders DESC LIMIT 1 ''') print(cur.fetchone()) # 4. 查询所有不重复的年龄。 cur.execute('SELECT DISTINCT age FROM users') print([row[0] for row in cur.fetchall()]) # 5. 查询订单日期在2021年9月1日至9月4日之间的订单总金额。 cur.execute('SELECT SUM(amount) FROM orders WHERE order_date BETWEEN "2021-09-01" AND "2021-09-04"') print(cur.fetchone()[0]) # 6. 查询年龄不大于25岁的用户的订单数量,并按照降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders FROM users JOIN orders ON users.id = orders.user_id WHERE age <= 25 GROUP BY users.id ORDER BY total_orders DESC ''') print(cur.fetchall()) # 7. 查询订单总金额排名前3的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 3 ''') print(cur.fetchall()) # 8. 查询订单总金额最大的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC LIMIT 1 ''') print(cur.fetchone()) # 9. 查询订单总金额最小的用户的姓名和订单总金额。 cur.execute(''' SELECT users.name, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount ASC LIMIT 1 ''') print(cur.fetchone()) # 10. 查询所有名字中含有“李”的用户,按照名字升序排序。 cur.execute('SELECT * FROM users WHERE name LIKE "%李%" ORDER BY name ASC') print(cur.fetchall()) # 11. 查询所有年龄大于20岁的用户,按照年龄降序排序,并只显示前5条记录。 cur.execute('SELECT * FROM users WHERE age > 20 ORDER BY age DESC LIMIT 5') print(cur.fetchall()) # 12. 查询每个用户的订单数量和订单总金额,并按照总金额降序排序。 cur.execute(''' SELECT users.name, COUNT(*) AS total_orders, SUM(amount) AS total_amount FROM users JOIN orders ON users.id = orders.user_id GROUP BY users.id ORDER BY total_amount DESC ''') print(cur.fetchall()) # 关闭游标和连接 cur.close() conn.close() ``` 注意:在运行代码之前,需要先安装 PyMySQL 模块,可以使用以下命令进行安装: ``` pip install pymysql ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值