入坑即烧机
最近在朋友的建议下,实战玩一下摄像头单板,于是从咸鱼上淘了一块君正T31的开发板。刚开始的上机使用和大家不一样,卖家卖的时候没有重新烧一下系统,导致我使用有点异常,直接进入了卖家的程序,且按照卖家的方法也无法退出,无法执行测试程序验证功能。只能重新开始烧录刷机。
物理链路联通
烧机第一步就是要设备和主机联通,目前我是直接使用有线连接的,然后从网上下载了个tftp工具,准备好文件。
然后就是去设置设备端的地址信息,方便起见,我把全部内容都写了,然后save保存
setenv ipaddr 192.168.137.250;setenv serverip 192.168.137.1;save
烧机
首先我对烧机是不了解的,按照卖家给的文档,看到这个方式,目前我只需要烧写下rootfs,不过之前看到卖家提供了uImage,就给一起烧了。
然后去了解下这几个命令。
mw.b 0x80600000 0xff 0x1000000
/*
作用:将内存地址 0x80600000 开始的 0x1C0000 字节(约1.8MB)区域填充为 0xFF
语法:mw.b address value size
address:目标内存地址。
value:要填充的值(以字节为单位)。
size:填充的大小(以字节为单位)。
用途:通常用于初始化内存区域,以便后续写入操作。
*/
tftp 0x80600000 u-boot-with-spl.bin
/*
作用:通过TFTP协议从服务器下载名为 uImage 的文件到内存地址 0x80640000。
语法:tftpboot address filename
address:目标内存地址。
filename:要下载的文件名。
用途:将内核镜像(uImage)下载到指定的内存地址,以便后续写入到SPI Flash。
*/
tftp 0x80640000 uImage
tftp 0x808c0000 rootfs.squashfs
tftp 0x80ac0000 appfs.jffs2
/*
目前设备应该就只有一个,然后就给省略了
sf probe 0
作用:探测并初始化SPI Flash设备,选择第一个SPI Flash设备。
语法:sf probe [bus:]cs [hz] [mode]
bus:SPI总线编号。
cs:芯片选择(Chip Select)编号。
hz:SPI通信速率(单位为Hz)。
mode:SPI模式(如raw、mmc、spi等)。
用途:确保SPI Flash设备被正确识别和初始化。
*/
sf probe
/*
作用:擦除SPI Flash中从偏移地址 0x0 开始,长度为 0x800000 的区域。
语法:sf erase offset len
offset:擦除的起始偏移地址。
len:擦除的长度。
注意事项:擦除操作是以擦除块(erase block)为单位的,要求 offset 和 len 参数必须是擦除块对齐的。
*/
sf erase 0x0 0x800000
/*
作用:将内存地址 0x80600000 处的数据写入SPI Flash的偏移地址 0x0 处,写入的数据长度为0x800000。
语法:sf write mem-addr offset len
mem-addr:内存地址。
offset:SPI Flash的偏移地址。
len:写入的数据长度。
用途:将下载的内核镜像(uImage)写入SPI Flash的指定位置。
*/
sf write 0x80600000 0x0 0x800000
原以为只要按照上面的内存偏移去计算就没有问题了。
计算了下uImage在flash中的地址偏移和内存安排
结果烧完以后,设备重启,然后就烧坏起不来了。。。。
然后询问了下卖家,发现目前单板的内存布局,其实和文档里写的不太一样,地址和长度不能原样照搬。这个是由用户自己配置的,加载时会出问题。
isvp_t31# pr
baudrate=115200
bootargs=mem=40M@0x0 rmem=24M@0x2800000 console=ttyS1,115200n8 root=/dev/mtdblock2 rootfstype=jffs2 rw mtdparts=jz_sfc:256K(Uboot),1792K(kernel),14336K(rootfs)
bootcmd=sf probe;sf read 0x80600000 0x40000 0x1C0000; bootm 0x80600000
bootdelay=1
ethact=Jz4775-9161
ethaddr=00:d0:d0:00:95:27
fileaddr=80600000
filesize=6cc5d8
gatewayip=192.168.137.1
ipaddr=192.168.137.250
loads_echo=1
netmask=255.255.255.0
serverip=192.168.137.1
stderr=serial
stdin=serial
stdout=serial
Environment size: 517/12284 bytes
boot通过用户给定的参数从flash中加载数据,这个参数就是bootargs,启动参数(bootargs)用于配置Linux内核启动时的环境和硬件资源分配,我们来解读下这个字段里的全部参数
bootargs=mem=40M@0x0 rmem=24M@0x2800000 console=ttyS1,115200n8 root=/dev/mtdblock2 rootfstype=jffs2 rw mtdparts=jz_sfc:256K(Uboot),1792K(kernel),14336K(rootfs)
/*
作用:指定物理内存的大小和起始地址。
解释:
40M:表示分配40MB的物理内存。
0x0:表示内存的起始地址为0。
用途:告诉内核系统可用的物理内存大小和起始地址。
*/
mem=40M@0x0
/*
作用:指定保留内存(Reserved Memory)的大小和起始地址。
解释:
24M:表示保留24MB的内存。
0x2800000:表示保留内存的起始地址为0x2800000。
用途:保留内存通常用于特定硬件或设备的内存需求,例如图形内存或DMA缓冲区。
*/
rmem=24M@0x2800000
/*
作用:指定内核日志和控制台输出的串口配置。
解释:
ttyS1:表示使用第二个串口(通常对应硬件上的UART1)。
115200n8:表示串口的波特率为115200,数据位为8位,无校验位(n表示none)。
用途:配置内核日志和调试信息的输出端口。
*/
console=ttyS1,115200n8
/*
作用:指定根文件系统的位置。
解释:
/dev/mtdblock2:表示根文件系统位于MTD(Memory Technology Device)分区的第二个块设备。
用途:告诉内核从哪个设备挂载根文件系统。
*/
root=/dev/mtdblock2
/*
作用:指定根文件系统的类型。
解释:
jffs2:表示根文件系统使用JFFS2(Journaling Flash File System 2)文件系统。
用途:告诉内核根文件系统的格式。
*/
rootfstype=jffs2
/*
作用:指定根文件系统以读写模式挂载。
解释:
rw:表示根文件系统可以读写。
用途:允许对根文件系统进行读写操作。
*/
rw
/*
作用:定义MTD分区的布局。
解释:
jz_sfc:表示使用JZ_SFC(JZ SPI Flash Controller)作为MTD设备。
256K(Uboot):第一个分区大小为256KB,名称为Uboot,用于存储U-Boot。
1792K(kernel):第二个分区大小为1792KB(约1.75MB),名称为kernel,用于存储内核。
14336K(rootfs):第三个分区大小为14336KB(约14MB),名称为rootfs,用于存储根文件系统。
用途:定义SPI Flash设备的分区布局,确保U-Boot、内核和根文件系统在SPI Flash中的位置和大小。
*/
mtdparts=jz_sfc:256K(Uboot),1792K(kernel),14336K(rootfs)
看到最后,MTD分区布局,明白了当前设备的地址空间说明,然后调整参数重新烧写。
| 256K | 1792K | 14336K |
|-----------|-------------|------------------|
| boot | kernel | rootfs |
// 烧写uimage
mw.b 0x80600000 0xFF 0x1C0000;
tftpboot 0x80600000 uImage;
sf probe 0;
sf erase 0x40000 0x1C0000;
sf write 0x80600000 0x40000 0x1C0000
// 烧写rootfs
mw.b 0x80600000 0xFF 0xE00000;
tftpboot 0x80600000 rootfs.jffs2;
sf probe 0;
sf erase 0x200000 0xE00000;
sf write 0x80600000 0x200000 0xE00000
上面只是给定了一些参数,但是参数怎么用,还是得看等uboot真正启动的时候,启动时会去读取flash里的数据,怎么读取也是由用户给定的。
bootcmd:U-Boot的启动命令,系统在启动时会自动执行该命令
bootcmd=sf probe;sf read 0x80600000 0x40000 0x1C0000; bootm 0x80600000
/*
作用:从SPI Flash的偏移地址0x40000处读取0x1C0000字节的数据到内存地址0x80600000
语法:sf read <addr> <offset>|<partition> <len>
addr:内存地址,表示数据将被读取到内存的起始地址。
offset:SPI Flash中的偏移地址,表示从Flash的哪个位置开始读取数据。
也可以使用分区名称(如partition),但需要支持CONFIG_CMD_MTDPARTS。
len:要读取的数据长度,单位为字节。
*/
sf read 0x80600000 0x40000 0x1C0000;
/*
作用:从内存地址0x80600000处启动内核镜像
语法:bootm [addr] [addr] [addr]
addr:内存地址,表示内核镜像的起始地址。这是必须提供的参数。
addr:可选参数,表示 RAMDISK 的起始地址(如果使用了 RAMDISK)。
addr:可选参数,表示设备树(Device Tree Blob,DTB)的起始地址(如果使用了设备树)。
启动内核镜像(无 RAMDISK 和设备树):
bootm 0x80600000
作用:从内存地址 0x80600000 加载并启动内核镜像。
适用场景:适用于没有使用 RAMDISK 和设备树的简单启动场景。
启动内核镜像并指定 RAMDISK:
bootm 0x80600000 0x81000000
作用:从内存地址 0x80600000 加载内核镜像,并从内存地址 0x81000000 加载 RAMDISK。
适用场景:适用于需要在启动时加载 RAMDISK 的场景。
启动内核镜像并指定设备树:
bootm 0x80600000 - 0x82000000
作用:从内存地址 0x80600000 加载内核镜像,并从内存地址 0x82000000 加载设备树。
适用场景:适用于需要在启动时加载设备树的场景。
启动内核镜像并同时指定 RAMDISK 和设备树:
bootm 0x80600000 0x81000000 0x82000000
作用:从内存地址 0x80600000 加载内核镜像,从内存地址 0x81000000 加载 RAMDISK,并从内存地址 0x82000000 加载设备树。
适用场景:适用于需要同时加载 RAMDISK 和设备树的复杂启动场景。
*/
bootm 0x80600000
然后reset重新启动登陆后就正常了。