Skip to content

LV055-裸机程序烧写

一、概述

我们之前学习STM32的时候知道编译完代码以后可以直接通过 MDK 或者 IAR下载到内部的 flash 中,也就是内部的ROM。I.MX6ULL有内部ROM嘛?我们翻开芯片手册看一眼:i.MX 6ULL Applications Processors for Consumer Products (nxp.com.cn)

image-20260114152729729

我们看到内部有96KB的ROM和128KB的RAM,但是 I.MX6U 虽然内部有 96K 的 ROM,但是这 96K 的 ROM 是 NXP 自己用的,不向用户开放。所以相当于说 I.MX6ULL 是没有内部 flash 的,但是我们的代码得有地方存放啊,为此, I.MX6ULL 支持从外置的 NOR Flash、 NAND Flash、 SD/EMMC、 SPI NOR Flash和 QSPI Flash 这些存储介质中启动,所以我们可以将代码烧写到这些存储介质中。

在这些存储介质中,除了 SD 卡以外,其他的一般都是焊接到了板子上的,我们没法直接烧写。但是 SD卡是活动的,是可以从板子上插拔的,我们可以将 SD 卡插到电脑上,在电脑上使用软件将 .bin 文件烧写到 SD 卡中,然后再插到板子上就可以了。其他的几种存储介质是我们量产的时候用到的,量产的时候代码就不可能放到 SD 卡里面了,毕竟 SD 是活动的,不牢固,而其他的都是焊接到板子上的,很牢固。

因此,我们在调试裸机和 Uboot 的时候是将代码下载到 SD 中,因为方便嘛,当调试完成以后量产的时候要将裸机或者 u-boot 烧写到 SPI NOR Flash、 EMMC、 NAND 等这些存储介质中的。那么,如何将我们前面编译出来的 led.bin 烧写到 SD 卡中呢?

编译出来的可执行文件是怎么存放到 SD 中的,存放的位置是什么?这个 NXP 是有详细规定的!我们必须按照 NXP 的规定来将代码烧写到 SD 卡中,否则代码是绝对运行不起来的。《i.MX 6ULL Applications Processor Reference Manual》的第 8 章“Chapter 8 System Boot”就是专门讲解 I.MX6U 启动的,在前边我们已经学习过了。

接下来就来学习一下裸机程序烧写。

二、imxdownload工具

我们先来学习一下正点原子提供的这个imxdownload工具。

1. 工具源码

正点原子有提供源码的,路径在《阿尔法Linux开发板(A盘)-基础资料/05、开发工具/02、Ubuntu下裸机烧写软件》:

image-20241108071442966

1.1 imxdownload.c

c
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
#include "imxdownload.h"

#define SHELLCMD_LEN	(200)
#define BIN_OFFSET		(3072)

/* 此宏指明是否打印u-boot.imx的IVT DCD表信息,不同的开发板其IVT和DCD
 * 表的数据是不同的,因此需要获取所使用的开发板的IVT和DCD表信息,最
 * 简单的方法就是读取开发板配套资料里面的u-boot.imx的前1KB数据,理论上
 * 应该读取3KB的数据,但是表信息远远没有3K这么多,因此读1KB即可 
 */
#define PRINT_TAB		0	
/*
 * 介绍: 此软件是针对NXP的IMX6U系列芯片的,软件用来烧写bin文件到SD卡里面,
 *        本软件会自动添加IVT、DCD等信息到原始的bin文件里面,主要用于裸机和uboot的烧写。
 * 使用方法: 1、编译好原始的二进制bin文件,如,u-boot.bin等,并将编译好的.bin文件和本
 *             软件放置到同一个目录下!!!!
 *        	2、执行命令sudo ./imxdownload <soucre_bin> <sd_device>
 *             如烧写u-boot.bin到/dev/sdd中即可使用如下所示命令:
 *             sudo ./imxdownload u-boot.bin /dev/sdd
 */

/*
 * 输出一些信息
 */
void message_print(void)
{	
	printf("I.MX6ULL bin download software\r\n");
	printf("Edit by:zuozhongkai\r\n");
	printf("Date:2019/6/10\r\n");
	printf("Version:V1.1\r\n");
	printf("log:V1.0 initial version,just support 512MB DDR3\r\n");
	printf("    V1.1 and support 256MB DDR3\r\n");
}

int main(int argc, char *argv[])
{
	FILE *fp;
	unsigned char *buf;
	unsigned char *cmdbuf;
	int nbytes, filelen;
	int i = 0, j = 0;
	int ddrsize = 0; /* 0为512MB,1为256MB,2为128MB...... */

	message_print();

	if((argc != 3) && (argc != 4)){
		printf("Error Usage! Reference Below:\r\n");
		printf("sudo ./%s <-512m or -256m> <source_bin> <sd_device>\r\n", argv[0]);
		return -1;
	}

	/* 查找参数,获取DDR容量 */
	for(i = 0; i < argc; i++)
	{
		char *param = argv[i];
		if(param[0] != '-')
			continue;
		if(strcmp(param, "-256m") == 0) 		/* 256MB */
			ddrsize = 1;
		else if(strcmp(param, "-512m") == 0)	/* 512MB */
			ddrsize = 0;
	}
	if(argc == 3)	/* 三个参数,也就是不输入DDR容量的话默认为512MB */
		ddrsize = 0;

	/* 打开bin文件 */
	fp = fopen(argv[1], "rb"); /* 以二进制只读方式打开bin文件 */
	if(fp == NULL){
		printf("Can't Open file %s\r\n", argv[1]);
		return -1;
	}
	
	/* 获取bin文件长度 */
	fseek(fp, 0L, SEEK_END);
	filelen = ftell(fp);
	fseek(fp, 0L, SEEK_SET);
	printf("file %s size = %dBytes\r\n", argv[1], filelen);
	
	/* 读取bin文件到缓冲区buf中 */
	buf = malloc(filelen + BIN_OFFSET);
	if(buf == NULL){
		printf("Mem Malloc Failed!\r\n");
		fclose(fp);
		return -1;
	}
	memset(buf, 0, filelen + BIN_OFFSET); /* 清零 */
	/* 读取bin源码文件 */
	fread(buf + BIN_OFFSET, 1, filelen, fp);

	/* 关闭文件 */
	fclose(fp);

#if PRINT_TAB
	printf("IVT DCD Table:\r\n");
	for(i = 0; i < 1024/32; i++){
		for(j = 0; j < 8; j++)
		{
			printf("0X%08X,",*(int *)(buf + BIN_OFFSET + (((i * 8) + j) * 4)));
		}
		printf("\r\n");
	}	
	free(buf);
	return 0;
#endif
	
	/* 添加IVT DCD等表信息到bin文件里面 */
	if(ddrsize == 0) {		/* 512MB */
		printf("Board DDR SIZE: 512MB\r\n");
		memcpy(buf, imx6_512mb_ivtdcd_table, sizeof(imx6_512mb_ivtdcd_table));
	}
	else if (ddrsize == 1) {	/* 256MB */
		printf("Board DDR SIZE: 256MB\r\n");
		memcpy(buf, imx6_256mb_ivtdcd_table, sizeof(imx6_256mb_ivtdcd_table));
	}

	/* 现在我们已经在buf中构建好了可以用于下载的bin文件,将buf中的数据保存到
	 * 到一个文件中,文件命名为load.imx
	 */
	printf("Delete Old load.imx\r\n");
	system("rm -rf load.imx");		/* 先删除旧的load.imx文件	*/
	
	printf("Create New load.imx\r\n");
	system("touch load.imx");		/* 创建新的load.imx文件		*/
	fp = fopen("load.imx", "wb");	/* 打开laod.imx				*/
	if(fp == NULL){
		printf("Cant't Open load.imx!!!\r\n");
		free(buf);
		return -1;
	}
	nbytes = fwrite(buf, 1, filelen + BIN_OFFSET, fp);
	if(nbytes != (filelen + BIN_OFFSET)){
		printf("File Write Error!\r\n");
		free(buf);
		fclose(fp);
		return -1;
	}
	free(buf);
	fclose(fp);	
	
	/* 构建烧写的shell命令 */
	cmdbuf = malloc(SHELLCMD_LEN);
	sprintf(cmdbuf, "sudo dd iflag=dsync oflag=dsync if=load.imx of=%s bs=512 seek=2",argv[2]);	
	printf("Download load.imx to %s  ......\r\n", argv[2]);
	
	/* 执行上面的shell命令 */
	system(cmdbuf);
	free(cmdbuf);
	return 0;	
}

1.2 imxdownload.h

这个文件里边的就是DCD信息,不同的芯片可能都是不一样的,需要注意。这个DCD信息我们其实可以去uboot源码中找,这后面学习另一个工具的时候会学习。

c
#ifndef _IMXDOWNLOAD_H
#define _IMXDOWNLOAD_H
/* IMX6U IVT DCD表信息  暂时定义为1K Bytes,此表是读取的u-boot.imx前1K Bytes
 * imx6_ivedcd_table[9]是指明代码长度的,本应该根据实际的代码长度来修改
 * 这里为了方便,就直接定义为2M Bytes,即
 */

const int imx6_512mb_ivtdcd_table[256] = {
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00200000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X0B000300,0X3C081B02,
0X44014801,0X48081B02,0X302C4040,0X50081B02,0X343E4040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF3526B67,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23106B00,0X40001B02,0X4F000000,0X00001B02,0X00001884,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000
};

const int imx6_256mb_ivtdcd_table[256] = {
0X402000D1,0X87800000,0X00000000,0X877FF42C,0X877FF420,0X877FF400,0X00000000,0X00000000,
0X877FF000,0X00076000,0X00000000,0X40E801D2,0X04E401CC,0X68400C02,0XFFFFFFFF,0X6C400C02,
0XFFFFFFFF,0X70400C02,0XFFFFFFFF,0X74400C02,0XFFFFFFFF,0X78400C02,0XFFFFFFFF,0X7C400C02,
0XFFFFFFFF,0X80400C02,0XFFFFFFFF,0XB4040E02,0X00000C00,0XAC040E02,0X00000000,0X7C020E02,
0X30000000,0X50020E02,0X30000000,0X4C020E02,0X30000000,0X90040E02,0X30000000,0X88020E02,
0X30000C00,0X70020E02,0X00000000,0X60020E02,0X30000000,0X64020E02,0X30000000,0XA0040E02,
0X30000000,0X94040E02,0X00000200,0X80020E02,0X30000000,0X84020E02,0X30000000,0XB0040E02,
0X00000200,0X98040E02,0X30000000,0XA4040E02,0X30000000,0X44020E02,0X30000000,0X48020E02,
0X30000000,0X1C001B02,0X00800000,0X00081B02,0X030039A1,0X0C081B02,0X04000000,0X3C081B02,
0X3C013C01,0X48081B02,0X38324040,0X50081B02,0X28304040,0X1C081B02,0X33333333,0X20081B02,
0X33333333,0X2C081B02,0X333333F3,0X30081B02,0X333333F3,0XC0081B02,0X09409400,0XB8081B02,
0X00080000,0X04001B02,0X2D000200,0X08001B02,0X3030331B,0X0C001B02,0XF352433F,0X10001B02,
0X630B6DB6,0X14001B02,0XDB00FF01,0X18001B02,0X40172000,0X1C001B02,0X00800000,0X2C001B02,
0XD2260000,0X30001B02,0X23104300,0X40001B02,0X47000000,0X00001B02,0X00001883,0X90081B02,
0X00004000,0X1C001B02,0X32800002,0X1C001B02,0X33800000,0X1C001B02,0X31800400,0X1C001B02,
0X30802015,0X1C001B02,0X40800004,0X20001B02,0X00080000,0X18081B02,0X27020000,0X04001B02,
0X2D550200,0X04041B02,0X06100100,0X1C001B02,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,0X00000000,
};

#endif

2. 编译工具

上边只是源码,我们想要使用的话,还需要进行编译,我们由于是在ubuntu中使用此工具,所以直接在ubuntu中使用gcc编译即可。

shell
gcc imxdownload.c -o imxdownload -Wall

然后我们就会得到一个 imxdownload 可执行文件,我们运行这个文件就可以将相应的uboot烧写到sd卡中。我们也可以写一个makefile文件来编译:

makefile
TARGET      := imxdownload
CC          := gcc

$(TARGET):imxdownload.c
	gcc imxdownload.c -o $(TARGET)

.PHONY: clean
clean: 
	rm -vf *.o $(TARGET)

3. 使用方式

我们之前已经生成好了led.bin文件,然后就是在ubuntu下降此文件烧写到sd卡中。我们可以执行以下命令查看一下SD卡在ubuntu中的节点:

shell
sudo fdisk -l

然后可以看到自己的SD卡的节点:

image-20230716203141888

或者直接用这个命令看:

shell
ls /dev/sd*
image-20241108072116161

注意使用的是这个/dev/sdc节点,sdc1是SD卡的1分区,不要用这个。然后我们可以执行以下命令完成烧写:

shell
./imxdownload <.bin file> <SD Card>

在这里的话就是:

shell
../../tool/imxdownload/imxdownload led.bin /dev/sdc

烧写的过程中可能会让输入密码,输入 ubuntu 密码即可完成烧写,烧写过程如下:

image-20241108072347405

烧写的最后一行会显示烧写大小、用时和速度,比如 led.bin 烧写到 SD 卡中的大小是 3.2KB,用时 0.15951s,烧写速度是 20.3 KB/s。注意这个烧写速度,如果这个烧写速度在几百 KB/s 以下那么就是正常烧写。如果这个烧写速度大于几十 MB/s、甚至几百 MB/s 那么肯定是烧写失败了! 这个时候我们会发现目录中多了一个imx文件:

image-20241108072517469

其实前面学习启动方式的时候学习过,imx文件会比bin文件多一些IVT等数据,我们可以看一下:

image-20241108072705491

我们看一下开头就会发现链接地址:

image-20241108072800819

解决方法就是重新插拔 SD 卡,一般出现这种情况,重新插拔 SD 卡基本没啥用,只有重启 ubuntu,至于原因嘛,不详。

三、mkimage工具

1. uboot生成的imx文件

我们知道,生成了bin文件后,还需要将这个bin文件变为.imx文件,上边我们知道imxdownload这个工具可以直接将bin文件生成imx文件,然后烧写到sd卡中去,那不使用这个工具呢?其实也是有办法的。办法需要从u-boot中找,后边学习u-boot就会知道,编译u-boot的话,会生成bin文件,也会生成imx文件。我这里编译的是这个Release rel_imx_4.19.35_1.1.0: MLK-22866 imx8: Remove the optee shared memory from DDR banks · nxp-imx/uboot-imx (github.com),编译完毕后如下图:

image-20241108074122472

会发现上面会生成imx文件。这个文件我们就可以用于烧写到SD卡中。

2. DCD数据去哪里找?

前边学习映像文件的时候,有提到过这个DCD数据。那么这个DCD数据去哪找?我们去找一下怎么生成的imx文件:

image-20241108074514030

这个文件要编译完才有,先不管这个文件怎么来的以及原理,这里只看这个命令:

shell
cmd_u-boot-dtb.imx := ./tools/mkimage -n u-boot-dtb.cfgout -T imximage -e 0x87800000 -d u-boot-dtb.bin u-boot-dtb.imx >u-boot-dtb.imx.log

大概分析一些可以知道是用了这个u-boot-dtb.cfgout,我们打开看一眼:

image-20260114153109424

其实这个文件就来源于imximage.cfg文件。这个文件在哪? i.mx6ull的imximage.cfg 文件位于u-boot 源码的 board/freescale/mx6ullevk/ 目录下:

image-20260114153231655

这个imximage.cfg文件中就是厂家提供的DCD数据啦。会发现上面的u-boot-dtb.cfgout会比imximage.cfg多一些东西,但是这个DATA的行都是一样的:

image-20241108075212283

2. mkimage

这个工具的是u-boot编译完成后,会在tools目录下生成的,它的源码及可执行文件如下:

image-20241108075318604

这个工具与具体的开发板无关,是u-boot的工具,所以这里可以直接拿来用。该工具的使用命令如下:

shell
./mkimage -n ./imximage.cfg -T imximage -e <链接地> -d <.bin文> <.imx文>

【注意】这里的链接地址要与生成bin文件的时候使用的链接地址一样。

3. 生成.imx文件

我们拷贝上边的 imximage 工具和 board/freescale/mx6ullevk/imximage.cfg 文件到我们的下载工具目录下:

shell
cp ~/7Linux/imx6ull-uboot/tools/mkimage* tool/mkimage/
cp ~/7Linux/imx6ull-uboot/u-boot-dtb.cfgout tool/mkimage/
cp ~/7Linux/imx6ull-uboot/board/freescale/mx6ullevk/imximage.cfg tool/mkimage/

拷贝完后tool/mkimage/目录如下所示:

image-20241108075852152

我们现在用u-boot中的工具imximage 试一下生成一个imx文件,命令格式是这样的:

shell
./mkimage -n ./imximage.cfg -T imximage -e 0X87800000 -d led.bin led.imx

按照我的目录结构,在这里应该是:

shell
../../tool/mkimage/mkimage -n ../../tool/mkimage/imximage.cfg -T imximage -e 0X87800000 -d led.bin led.imx

额,然后就直接报错了:

image-20241108080128642

怀疑是文件不对?其实刚才已经多拷贝了一个文件u-boot-dtb.cfgout,这个是编译uboot的时候,调用mkimage工具生成的imx文件的时候用的,里面会多一些东西,可能就是这些多的东西的原因,那我们呢直接用这个文件试一下:

shell
../../tool/mkimage/mkimage -n ../../tool/mkimage/u-boot-dtb.cfgout -T imximage -e 0X87800000 -d led.bin led.imx

然后就可以了:

image-20241108080335996

其实数据还是那些,不过还有一些带#号的行出现,没有深究,就直接用就是了。

4. 对比区别

我们通过两种途径生成了imx文件,它们的IVT和DCD一样吗?我们用对比工具对比一下看看:

image-20241108080627488

发现还是有一些不一样,可能是因为我用的新的uboot的原因吧,之前用的Release rel_imx_4.1.15_2.1.0_ga: MLK-14707 fsl_esdhc: Fix eMMC 1.8v setting issue · nxp-imx/uboot-imx (github.com)这个版本,最后用这个工具生成的和正点原子的工具生成的是一样的:

image-20230716212636453

不过问题不大,可以直接烧写一下看 看能不能跑就知道了。烧写后会发现其实是一样的。

那有啥区别?区别就在于,正点原子提供给我们的imxdownload软件把链接地址写死为0x87800000,这意味着什么?这就意味着我们在后面编写链接脚本的时候只能用这个地址作为链接地址,我们的程序都将从这个地址开始存放,想修改怎么办?抱歉,没办法,除非修改imxdownload的源码,但是mkimage这个软件不一样,是在使用软件的时候指定了链接地址,这样我们就可以自定义啦。所以推荐还是用这个软件比较好。

5. 烧写到SD卡

上面我们只是生成了imx文件,这里我们还要烧写到SD卡中,我们可以使用以下命令烧写:

shell
sudo dd if=led.imx of=/dev/sdc bs=1k seek=1 conv=fsync

注意一定要加sudo,否则会提示权限不够。为什么要留1KB?前面学习映像文件的时候其实了解过了,从SD卡启动的时候,内部的boot ROM代码会从1KB的位置开始读,好像是因为我们常用的SD卡一个扇区的大小是512字节。前面两个扇区是不可以写入用户数据的,一般存的是SD卡相关的信息。而且imx6ull数据手册也写到SD/EMMC启动是从地址偏移0x400字节的地方开始,所以这里不能直接覆盖。

我们会看到如下提示信息:

image-20241108191248565

这样就烧写完毕了。

6. 编译mkimage

我们这里是有源码的,我们自己编译一下呢?Makefile如下:

makefile
TARGET      := mkimage
CC          := gcc

$(TARGET):mkimage.c
	gcc mkimage.c -o $(TARGET)

.PHONY: clean
clean: 
	rm -vf *.o $(TARGET)
image-20241108191446707

但是吧,报错了,看一眼,里面包含了不少的uboot内部的头文件,这里感觉没啥必要深究,就直接拿来用吧,以后有空再说。

四、mkImage.sh工具

这个其实是个脚本,这是NXP官方的SDK提供的,需要我们后面编译官方的SDK,所以后面学习到SDK的时候再来了解一下这种方式。可以看这里:《01嵌入式开发/02IMX6ULL平台/LV04-裸机开发/LV04-03-BSP工程管理-01-NXP官方SDK.md》

五、烧写img文件到SD卡

上边我们通过正点原子的imxdownload工具直接在ubuntu下完成imx文件的生成和烧写,那我们现在有一个imx文件,怎么办?回到bin文件?肯定不是啦,在ubuntu和windows下都有烧写的办法,这一节就来了解一下如何将imx文件烧写到sd卡中吧。

1. img文件

1.1 1K字节的空文件

为什么要有一个1K字节的空文件?原因就在于这个IVT,如下图:

image-20260114124406544

IVT的偏移的话,在sd卡中,mmc都需要偏移1KB,而我们生成的imx文件,IVT直接从0开始,所以需要制作一个IVT偏移了1K的文件。我们在ubuntu编译好了imx文件后,可以先做一个1K字节的空文件:

shell
dd if=/dev/zero of=1k.bin bs=1024 count=1

dd命令 可从标准输入或文件中读取数据,根据指定的格式来转换数据,再输出到文件、设备或标准输出。上边的命令含义就是以/dev/zero作为输入文件,1k.bin作为输出文件,同时设置读入/输出的块大小为1024个字节(1KB),仅拷贝1个块。这样我们就会生成一个1KB的1k.bin文件啦:

image-20230716214922380

1.2 生成img文件

接下来将imx文件和1k.bin文件合并起来,注意1k.bin文件要在前,这样才能保证生成的img文件的IVT在1K的偏移处:

shell
cat 1k.bin led.imx > led.img

2. windows下烧写img文件

2.1 Win32DiskImager软件

我们需要借助Win32DiskImager这个软件来吧img文件写入到sd卡中去,我们可以在这里下载这个软件:Win32 Disk Imager download | SourceForge.net,这个软件安装一路默认就好了,打开如下图所示:

image-20230716215247142

2.2 烧写img文件

imgimg

如上图所示:【选择img文件】→【选中要烧写的sd卡盘符】→【写入】,写入完成则会有提示,然后点击OK,再退出即可。

3. ubuntu下烧写img文件

ubuntu下的话,可以使用dd命令,使用该命令我们甚至可以不需要1k的哪个空文件,直接通过这个命令将imx文件烧写到sd卡挂载节点的1k处:

shell
sudo dd if=led.imx of=/dev/sdc bs=1k seek=1 conv=fsync

烧写完成会有如下提示:

image-20230716215956077

除了上面的命令,我们还可以使用正点原子提供的哪个烧写工具,那个其实也一样的,只是它是通过c语言的system函数来执行了dd这个shell命令。如果想要烧img文件,直接dd命令不偏移就可以了,不过还是直接烧到1KB处方便,毕竟少生成一个文件。

六、启动测试

代码已经烧写到了 SD 卡中了,接下来就是将 SD 卡插到开发板的 SD 卡槽中,然后设置拨码开关为 SD 卡启动,拨码开关设置如图 :

image-20260114153826699

设置好以后按一下开发板的复位键,如果代码运行正常的话 LED0 就会被点亮 :

image-20260114153836421