Linux之ARM(MX6ULL)裸機彙編LED驅動實驗--燒寫bin檔案到sd卡並執行

2020-08-14 21:08:14

Linux之ARM(MX6ULL)裸機彙編LED驅動實驗–燒寫bin檔案到sd卡並執行

一、程式碼燒寫

編譯完程式碼以後可以直接通過 MDK 或者 IAR 下載到內部的 flash 中。但是 I.MX6U 雖然內部有 96K 的 ROM,但是這 96K 的 ROM 是 NXP 自己用的,不向使用者開放。所以相當於說 I.MX6U 是沒有內部 flash 的,但是我們的程式碼得有地 方存放啊,爲此,I.MX6U 支援從外接的 NOR Flash、NAND Flash、SD/EMMC、SPI NOR Flash 和 QSPI Flash 這些儲存媒介中啓動,所以我們可以將程式碼燒寫到這些儲存媒介中中。在這些存 儲媒介中,除了 SD 卡以外,其他的一般都是焊接到了板子上的,我們沒法直接燒寫。但是 SD 卡是活動的,是可以從板子上插拔的,我們可以將 SD 卡插到電腦上,在電腦上使用軟體將.bin 檔案燒寫到 SD 卡中,然後再插到板子上就可以了。
因此,我們在偵錯裸機和 Uboot 的時候是將程式碼下載到 SD 中,因爲方便嘛,當偵錯完成 以後量產的時候要將裸機或者 Uboot 燒寫到 SPI NOR Flash、EMMC、NAND 等這些儲存媒介 中的。那麼,如何將我們前面編譯出來的 led.bin 燒寫到 SD 卡中呢?肯定有人會認爲直接複製 led.bin 到 SD 卡中不就行了,錯!編譯出來的可執行檔案是怎麼存放到 SD 中的,存放的位置是 什麼?這個 NXP 是有詳細規定的!我們必須按照 NXP 的規定來將程式碼燒寫到 SD 卡中,否則 程式碼是絕對執行不起來的。

二、燒寫工具

將 imxdownload 生成可執行檔案 , imxdownload 拷貝到工程根目錄下,也就是和 led.bin 處於同一個資料夾下

chmod 777  imxdownload 

在这里插入图片描述
imxdownload.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;	

}

imxdownload.h

#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

三、確定要燒寫的 SD 卡。

準備一張新的 SD(TF)卡,確保 SD 卡裏面沒有數據,因爲我們在燒寫程式碼的時候可能會格 式化 SD 卡!!!
Ubuntu 下所有的裝置檔案都在目錄「/dev」裏面,所以插上 SD 卡以後也會出現在「/dev」 裏面,其中儲存裝置都是以「/dev/sd」開頭的。我們要先看一下不插 SD 卡的時候電腦都有哪些 儲存裝置,以防插入 SD 卡以後分不清誰是誰。輸入如下所示命令:

 ls /dev/sd* 

在这里插入图片描述
從圖中可以看到當前電腦有/dev/sda、/dev/sda1 /dev/sda2 /dev/sda5

使用讀卡器將 SD 卡插到電腦,一定要確保 SD 卡是掛載到了 Ubuntu 系統中,而不是 Windows下。SD 卡掛載到電腦以後,VMware 桌面會出現boot圖示(Ubuntu16.04)

在这里插入图片描述
再次使用
ls /dev/sd*

在这里插入图片描述
圖中出現了 /dev/sdb /dev/sdb1
其中 /dev/sdb1 是 SD 卡 的第一個分割區,我們把bin檔案燒寫到/dev/sdb裏面
確定好SD 卡以後我們就可以使用軟體 imxdownload 向 SD 卡燒寫 led.bin 檔案了。

四、向 SD 卡燒寫 bin 檔案

使用 imxdownload 向 SD 卡燒寫 led.bin 檔案,命令格式如下:

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

其中.bin 就是要燒寫的.bin 檔案,SD Card 就是你要燒寫的 SD 卡,比如我的電腦使用如下 命令燒寫 led.bin 到/dev/sdb 中:

./imxdownload led.bin /dev/sdb  	

燒寫的過程中可能會讓你輸入密碼,輸入你的 Ubuntu 密碼即可完成燒寫,燒寫過程如圖:
在这里插入图片描述
燒寫的最後一行會顯示燒寫大小、用時和速度,比如 led.bin 燒寫到 SD 卡 中的大小是 3.2KB,用時 0.032755s,燒寫速度是 98.7KB/s。注意這個燒寫速度,如果這個燒寫 速度在幾百 KB/s 以下那麼就是正常燒寫。 如果這個燒寫速度大於幾十 MB/s、甚至幾百 MB/s 那麼肯定是燒寫失敗了!

燒寫完成以後會在當前工程目錄下生成一個 load.imx 的檔案
在这里插入图片描述

load.imx 這個檔案就是軟體 imxdownload 根據 NXP 官方啓動方式介紹的內容,在 leds.bin 檔案前面新增了一些數據頭以後生成的。最終燒寫到 SD 卡裏面的就是這個 load.imx 檔案,而非leds.bin。

五、程式碼驗證

程式碼已經燒寫到了 SD 卡中了,接下來就是將 SD 卡插到開發板的 SD 卡槽中,然後設定撥 碼開關爲 SD 卡啓動,撥碼開關設定如圖
在这里插入图片描述

設定好以後按一下開發板的復位鍵,如果程式碼執行正常的話 LED0 就會被點亮,如圖
在这里插入图片描述
LED0 被正常點亮,可能 LED0 之前會有一點微亮,那是因爲 I.MX6U 的 IO 預設電平可能讓 LED0 導通了,但是 IO 的預設設定內部可能有很大的電阻,所以電流就 很小,導致 LED0 微亮。但是我們自己編寫程式碼、設定好 IO 以後就不會有這個問題,LED0 就很亮了。