SD卡烧写脚本解释
2025-08-04
10
0
这个脚本是用于制作 I.MX6 处理器的 SD 卡启动系统的 Shell 脚本。
1. 脚本头
#! /bin/sh
#I.MX6 SD卡启动系统烧写脚本
#version v1.1
#Author QQ1252699831
#company 广州星翼电子科技有限公司
#!/bin/sh
:指定使用sh
(Bourne Shell)解释器执行脚本。- 注释说明脚本用途、版本、作者和公司信息。
2. 版本变更记录
#version v1.0 2019.10.26
#version v1.1 2020.11.7 1.添加判断文件系统是否存在/lib/modules目录的功能,再解压模块
VERSION="1.1"
- 记录脚本的版本变更历史。
VERSION="1.1"
:定义脚本版本变量。
3. usage()
函数(打印帮助信息)
usage ()
{
echo "
用法: `basename $1` [选项] <(必选)-device> <(可选)-flash> <(可选)-ddrsize>
用法示例:
sudo ./imx6mksdboot.sh -device /dev/sdd
sudo ./imx6mksdboot.sh -device /dev/sdd -flash emmc -ddrsize 512
命令选项:
-device SD卡块设备节点 (例如/dev/sdx)
-flash 请选择开发板Flash类型(emmc | nand)
-ddrsize 请选择DDR大小 (512 | 256)
可选选项:
--version 打印版本信息.
--help 打印帮助信息.
"
exit 1
}
- 定义
usage()
函数,用于打印脚本的使用方法。 basename $1
:提取脚本名称(去掉路径)。exit 1
:退出脚本,返回错误码1
。
4. 默认 U-Boot 镜像
Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx'
- 默认使用
DDR512
版本的 U-Boot 镜像。
5. execute()
函数(执行命令并检查错误)
execute ()
{
$* >/dev/null # 执行命令并丢弃输出
if [ $? -ne 0 ]; then # 检查上一条命令的返回值
echo
echo "错误: 执行 $*"
echo
exit 1 # 如果命令执行失败,退出脚本
fi
}
$*
:执行传入的所有参数(即命令)。$?
:获取上一条命令的返回值,0
表示成功,非0
表示失败。- 如果命令执行失败,打印错误信息并退出脚本。
6. version()
函数(打印版本信息)
version ()
{
echo
echo "`basename $1` version $VERSION"
echo "I.MX6 SD卡制卡脚本"
echo
exit 0
}
- 打印脚本版本信息并退出。
7. 参数解析
arg=$#
if [ $arg -ne 6 ];then
number=1
while [ $# -gt 0 ]; do
case $1 in
--help | -h) usage $0 ;;
-device) shift; device=$1; shift; ;;
--version) version $0;;
*) copy="$copy $1"; shift; ;;
esac
done
test -z $device && usage $0 # 如果未提供 -device 参数,打印帮助信息
echo ""
echo "根据下面的提示,补全缺省的参数-flash -ddrsize"
read -p "请选择开发板参数,输入数字1~4,按Enter键确认
1.-flash emmc,-ddrsize 512
2.-flash emmc,-ddrsize 256
3.-flash nand,-ddrsize 512
4.-flash nand,-ddrsize 256
输入数字1~4(default 1): " number
if [ -z $number ];then
echo "使用默认参数:EMMC版本,DDR大小为512MB"
else
case $number in
1) echo '您已经选择开发板参数为:EMMC版本,DDR大小为512MB'
Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx' ;;
2) echo '您已经选择开发板参数为:EMMC版本,DDR大小为256MB'
Uboot='u-boot-imx6ull-14x14-ddr256-emmc.imx' ;;
3) echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为512MB'
Uboot='u-boot-imx6ull-14x14-ddr512-nand-sd.imx' ;;
4) echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为256MB'
Uboot='u-boot-imx6ull-14x14-ddr256-nand-sd.imx' ;;
*) echo '输入的参数有误,退出制卡'; exit ;;
esac
fi
else
while [ $# -gt 0 ]; do
case $1 in
--help | -h) usage $0 ;;
-device) shift; device=$1; shift; ;;
-flash) shift; flash=$1; shift; ;;
-ddrsize) shift; ddrsize=$1; shift; ;;
--version) version $0;;
*) copy="$copy $1"; shift; ;;
esac
done
if [ $flash = "emmc" -a $ddrsize = "512" ];then
Uboot='u-boot-imx6ull-14x14-ddr512-emmc.imx'
echo '您已经选择开发板参数为:EMMC版本,DDR大小为512MB'
elif [ $flash = "emmc" -a $ddrsize = "256" ];then
Uboot='u-boot-imx6ull-14x14-ddr256-emmc.imx'
echo '您已经选择开发板参数为:EMMC版本,DDR大小为256MB'
elif [ $flash = "nand" -a $ddrsize = "512" ];then
Uboot='u-boot-imx6ull-14x14-ddr512-nand-sd.imx'
echo '您已经选择开发板参数为:NAND FLASH版本,DDR大小为512MB'
elif [ $flash = "nand" -a $ddrsize = "256" ];then
Uboot='u-boot-imx6ull-14x14-ddr256-nand-sd.imx'
echo '您的开发板参数为:NAND FLASH版本,DDR大小为256MB'
else
echo '参数有误!'
usage $0
fi
fi
- 检查参数数量:
- 如果参数不足 6 个,提示用户选择
Flash
类型和DDR
大小。 - 如果参数完整,直接解析
-device
、-flash
和-ddrsize
参数。
- 如果参数不足 6 个,提示用户选择
case
语句用于匹配不同的选项。
8. 检查必要文件
sdkdir=$PWD
if [ ! -d $sdkdir ]; then
echo "错误: $sdkdir目录不存在"
exit 1
fi
if [ ! -f $sdkdir/filesystem/*.tar.* ]; then
echo "错误: $sdkdir/filesystem/下找不到文件系统压缩包"
exit 1
fi
if [ ! -f $sdkdir/boot/zImage ]; then
echo "错误: $sdkdir/boot/下找不到zImage"
exit 1
fi
if [ ! -b $device ]; then
echo "错误: $device 不是一个块设备文件"
exit 1
fi
if [ $device = '/dev/sda' ];then
echo "请不要选择sda设备,/dev/sda通常是您的Ubuntu硬盘!
继续操作你的系统将会受到影响!脚本已自动退出"
exit 1
fi
$PWD
:当前工作目录。- 检查:
- 当前目录是否存在。
filesystem/
下是否有文件系统压缩包。boot/
下是否有zImage
(内核镜像)。$device
是否是块设备(-b
检查)。- 防止误操作
/dev/sda
(系统硬盘)。
9. 警告信息
echo "即将进行制作SD系统启动卡,大约花费几分钟时间,请耐心等待!"
echo "************************************************************"
echo "* 注意:这将会清除$device所有的数据 *"
echo "* 在脚本执行时请不要将$device拔出 *"
echo "* 请按<Enter>确认继续 *"
echo "************************************************************"
read enter
- 提示用户确认操作,防止误操作。
10. 卸载已有分区
for i in `ls -1 $device?`; do
echo "卸载 device '$i'"
umount $i 2>/dev/null
done
$device?
:匹配sdd1
、sdd2
等分区。umount
:卸载已挂载的分区,防止后续操作冲突。
11. 清空 SD 卡
execute "dd if=/dev/zero of=$device bs=1024 count=1024"
dd if=/dev/zero
:用0
填充设备的前1024KB
,清空分区表。
12. 使用 fdisk
分区
cat << END | fdisk -H 255 -S 63 $device
n # 新建分区
p # 主分区
1 # 分区号 1
# 起始扇区(默认)
+64M # 分区大小 64MB
n # 新建第二个分区
p # 主分区
2 # 分区号 2
# 起始扇区(默认)
# 结束扇区(默认,使用剩余空间)
t # 修改分区类型
1 # 选择分区 1
c # FAT32 (LBA)
a # 设置可启动标志
1 # 选择分区 1
w # 写入分区表
END
fdisk -H 255 -S 63
:指定磁头数255
和扇区数63
(传统磁盘参数)。- 创建:
- 第一个分区:
64MB
,FAT32
,用于存放zImage
和.dtb
。 - 第二个分区:剩余空间,
ext3
,用于存放根文件系统。
- 第一个分区:
13. 格式化分区
PARTITION1=${device}1
if [ ! -b ${PARTITION1} ]; then
PARTITION1=${device}1
fi
PARTITION2=${device}2
if [ ! -b ${PARTITION2} ]; then
PARTITION2=${device}2
fi
echo "格式化 ${device}1 ..."
if [ -b ${PARTITION1} ]; then
mkfs.vfat -F 32 -n "boot" ${PARTITION1}
else
echo "错误: /dev下找不到 SD卡 boot分区"
fi
echo "格式化${device}2 ..."
if [ -b ${PARITION2} ]; then
mkfs.ext3 -F -L "rootfs" ${PARTITION2}
else
echo "错误: /dev下找不到 SD卡 rootfs分区"
fi
mkfs.vfat -F 32
:格式化p1
为FAT32
,卷标boot
。mkfs.ext3 -F
:格式化p2
为ext3
,卷标rootfs
。
14. 烧写 U-Boot
echo "正在烧写${Uboot}到${device}"
execute "dd if=$sdkdir/boot/$Uboot of=$device bs=1024 seek=1 conv=fsync"
sync
dd if=... of=$device
:将U-Boot
烧写到SD
卡。seek=1
:跳过1KB
,确保正确写入启动位置。
15. 挂载 p1
并复制内核和设备树
execute "mkdir -p /tmp/sdk/$$"
while [ ! -e ${device}1 ]
do
sleep 1
echo "wait for ${device}1 appear"
done
execute "mount ${device}1 /tmp/sdk/$$"
execute "cp -r $sdkdir/boot/*${flash}*.dtb /tmp/sdk/$$/"
execute "cp -r $sdkdir/boot/zImage /tmp/sdk/$$/"
sync
/tmp/sdk/$$
:临时挂载点($$
是当前进程 ID,防止冲突)。mount
:挂载p1
到临时目录。cp
:复制zImage
和.dtb
文件。
16. 挂载 p2
并解压文件系统
execute "mkdir -p /tmp/sdk/$$"
execute "mount ${device}2 /tmp/sdk/$$"
echo "正在解压文件系统到${device}2 ,请稍候..."
rootfs=`ls -1 filesystem/*.tar.*`
execute "tar jxfm $rootfs -C /tmp/sdk/$$"
sync
tar jxfm
:解压bz2
格式的文件系统到p2
。
17. 检查并解压内核模块
if [ ! -e "/tmp/sdk//lib/modules/" ];then
mkdir -p /tmp/sdk/lib/modules/
fi
echo "正在解压模块到${device}2/lib/modules/ ,请稍候..."
modules=`ls -1 modules/*.tar.*`
execute "tar jxfm $modules -C /tmp/sdk/$$/lib/modules/"
sync
- 如果
/lib/modules
不存在,则创建。 - 解压内核模块到该目录。
18. 卸载分区并清理
echo "卸载${device}2"
execute "umount /tmp/sdk/$$"
execute "rm -rf /tmp/sdk/$$"
sync
echo "SD卡启动系统烧写完成!"
umount
:卸载分区。rm -rf
:删除临时目录。sync
:确保数据写入完成。
挂载点原理
/dev/sdx
:SD 卡设备节点。/dev/sdx1
:FAT32
分区,存放zImage
和.dtb
(内核启动所需)。/dev/sdx2
:ext3
分区,存放根文件系统。/tmp/sdk/$$
:临时挂载点,用于操作分区内容。
挂载的作用:
- 挂载后,可以通过文件系统访问设备内容(如
cp
、tar
)。 - 卸载后,确保数据写入完成,避免损坏。
总结
该脚本完成了:
- 分区(
FAT32
+ext3
)。 - 烧写 U-Boot(到
SD
卡)。 - 复制内核和设备树(到
p1
)。 - 解压文件系统和模块(到
p2
)。
适用于 I.MX6 平台的 SD 卡系统烧写。