94 .4 GPIO 時鐘 時鐘 如果使用 GPIO,我們必須要使能 GPIO 的時鐘。i.MX6 ULL 的每個外設的時鐘可以獨立的使能,我們可以關閉不使用的外設時鐘,可以達到節能的目的。如果使用某個外設,我們必須要打開對應的時鐘。《I.MX6ULL 參考手冊》的第 18 章“Clock Controller Module (CCM)”是關于 i.MX6ULL 時鐘的講解,我們可以看下該章節里面外設時鐘的使能寄存器。跟外設時鐘使能相關的寄存器有: CCM_CCGR0 CCM_CCGR1 CCM_CCGR2 CCM_CCGR3 CCM_CCGR4 CCM_CCGR5 CCM_CCGR6 一共 7 個。我們來看下 CCM_CCGR0 寄存器如何使能一個外設時鐘,改寄存器的描述如下圖所示:
1.jpg (32.02 KB, 下載次數: 65)
下載附件
2020-6-22 14:56 上傳
我們從上圖可以看到 CCM_CCGR0 寄存器是 32 位的,每 2 位控制一個外設時鐘,比如 bit1:bit0 控制aips_tz1 的時鐘,兩位的操作方式如下: 00 //所有模式下都關閉外設時鐘 01 //只有在運行模式下打開外設時鐘 10 //保留 11 //除了停止模式以外,其他所有模式下時鐘都打開 如果我們要打開 aips_tz1 的外設時鐘,需要設置 CCM_CCGR0 的 bit1 和 bit0 都為 1,也就是 CCM_CCGR0=3,如果關閉 aips_tz1 的外設時鐘,CCM_CCGR0 的 bit1 和 bit0 都設置為 0。CCM_CCGR0-CCM_CCGR6 這 7 個寄存器的功能都是類似的,也是每兩位控制一種外設的時鐘,為了便于開發,我們在后面的例程里把所有的外設時鐘都使能了。至此關于 GPIO 的操作我們可以總結成下面的步驟: 1.使能 GPIO 對應的時鐘 2.設置 IOMUXC_SW_MUX_CTL_PAD_XX_XX 寄存器,把對應的 IO 設置成 GPIO 功能 3.設置 IOMUXC_SW_PAD_CTL_PAD_XX_XX 寄存器,設置 GPIO 的上拉下拉,以及驅動能力 4.設置輸入還是輸出,是否使用中斷,以及默認的輸出電平 9 95 .5 LED 原理分析 原理分析 i.MX6ULL 終結者開發板板載了一個 LED 燈,打開底板的原理圖(光盤資料的“i.MX6UL 終結者光盤資料\03_開發板硬件資料\01_開發板原理圖\pdf\ itopmx6ul_terminator_v1_0.pdf”), 原理圖如下圖所示:
2.jpg (4.73 KB, 下載次數: 57)
下載附件
2020-6-22 14:56 上傳
從上圖可以看到 LED2 一段接到了 3.3V 電源,另一端接到了 GPIO_3(CPU 的 GPIO1_IO03)引腳上,當GPIO1_IO03 引腳輸出低電平(0)的時候,LED2 會被點亮,當 GPIO1_IO03 引腳輸出高電平(1)的時候,LED2 會滅掉。 9 96 .6 LED 匯編程序 匯編程序 按照前面的介紹,我們需要對 GPIO1_IO03 做如下的設置: 1.使能 GPIO1 的時鐘 GPIO1 的時鐘由 CCM_CCGR1 寄存器的 bit27 和 26 控制,我們把這兩位設置成 1,就會使能 GPIO1 的時鐘了。 2.配置 GPIO1_IO03 的復用功能 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 寄存器是 GPIO1_IO03 的復用寄存器,地址是 0x20e0068,把這個寄存器設置成 GPIO 功能。 3.配置 GPIO1_IO03 上下拉 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 寄存器是 GPIO1_IO03 的配置寄存器,通過該寄存器配置 GPIO1_IO03為 GPIO 的上下拉。 4.設置 GPIO1_IO03 輸出 在第二步驟我們已經把 GPIO1_IO03 復用成 GPIO 了,然后我們需要配置 GPIO 為輸出,以及輸出時候的高低電平,在《IMX6ULL 參考手冊》的 1357 頁我們可以看到 GPIO1_IO03 對應的 GPIO 寄存器組,如下圖所示:
3.jpg (14.66 KB, 下載次數: 71)
下載附件
2020-6-22 14:56 上傳
通過設置寄存器 GPIO1_GDIR 的 bit3 為 1,可以設置 GPIO1_IO03 為輸出。然后通過設置 GPIO1_DR 寄存器的bit3為0,可以控制GPIO1_IO03輸出低電平,LED會亮。GPIO1_DR的bit3設置為1,可以控制GPIO1_IO03輸出高電平,LED 會滅。 本實驗的源碼在開發板光盤資料的"i.MX6UL 終結者光盤資料\04_裸機例程源碼\1_leds\1_leds"目錄下,我們可以把這個文件夾拷貝到 UBuntu 下,使用交叉編譯器編譯。 下面我們開始一步步的實現 LED 這個實驗。首先登錄 Ubuntu 系統,在用戶的根目錄下的 work 文件夾創建led 文件夾然后在 led 目錄下新建“led.s”的匯編文件,如下圖所示:
4.jpg (15.65 KB, 下載次數: 77)
下載附件
2020-6-22 14:56 上傳
然后使用“vi led.s”命令打開 led.s 文件,在 led.s 文件輸入如下代碼: 1 .global _start /* 全局標號 */ 2 /* 3 * _start 函數,程序從此函數開始執行此函數完成時鐘使能、 4 * GPIO 初始化、最終控制 GPIO 輸出低電平來點亮 LED 燈。 5 */ 6 _start: 7 /* 1、使能所有時鐘 */ 8 ldr r0, =0X020C4068 /* CCGR0 */ 9 ldr r1, =0XFFFFFFFF 10 str r1, [r0] 11 ldr r0, =0X020C406C /* CCGR1 */ 12 str r1, [r0] 13 ldr r0, =0X020C4070 /* CCGR2 */ 14 str r1, [r0] 15 ldr r0, =0X020C4074 /* CCGR3 */ 16 str r1, [r0] 17 ldr r0, =0X020C4078 /* CCGR4 */ 18 str r1, [r0] 19 ldr r0, =0X020C407C /* CCGR5 */ 20 str r1, [r0] 21 ldr r0, =0X020C4080 /* CCGR6 */ 22 str r1, [r0] 23 /* 設置 GPIO1_IO03 為 GPIO 模式 */ 24 ldr r0, =0X020E0068 /* 把寄存器 SW_MUX_GPIO1_IO03_BASE 加載到 r0 中 */ 25 ldr r1, =0X5 /* 設置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MUX_MODE 為 5 */ 26 str r1,[r0] 27 /* 配置 GPIO1_IO03 的 IO 屬性 28 *bit 16:0 HYS 關閉 29 *bit [15:14]: 00 默認下拉 30 *bit [13]: 0 kepper 功能 31 *bit [12]: 1 pull/keeper 使能 32 *bit [11]: 0 關閉開路輸出 33 *bit [7:6]: 10 速度 100Mhz 34 *bit [5:3]: 110 R0/6 驅動能力 35 *bit [0]: 0 低轉換率 36 */ 37 ldr r0, =0X020E02F4 /*寄存器 SW_PAD_GPIO1_IO03_BASE */ 38 ldr r1, =0X10B0 39 str r1,[r0] 40 /* 設置 GPIO1_IO03 為輸出 */ 41 ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */ 42 ldr r1, =0X0000008 43 str r1,[r0] 44 /* 點亮 LED0 45 * 設置 GPIO1_IO03 輸出低電平 46 */ 47 ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */ 48 ldr r1, =0 49 str r1,[r0] 50 /* 51 * 描述: loop 死循環 52 */ 53 loop: 54 b loop 第 2 行我們定義了全局標號_start,程序就是從_start 標號處開始順序往下執行的。 第 8 行使用 ldr 向寄存器 r0 寫入 0x20c4068,這是 CCM_CCGR0 的寄存器地址。 第 9 行使用 ldr 向寄存器 r1 寫入 0xffffffff,開啟所有外設的時鐘。 第 10 行使用 str 命令把 r1 中的值寫到 r0 所保存的地址中,相當于給 0x20c4068 這個地址寫入 0xffffffff, 也就是 CCM_CCGR0 寄存器設置成 0xffffffff,使能 CCM_CCGR0 寄存器控制的所有外設時鐘。 第 11 行到第 22 行是向 CCM_CCGR1-CCM_CCGR6 寄存器寫入 0xffffffff,使能所有的外設時鐘。 第 24 行到第 26 行是設置 GPIO1_IO03 這個 IO 為 GPIO 模式,GPIO1_IO03 的復用寄存器是 0x20e0068,把改 寄存器的 MUX_MODE 設置為 5(GPIO 模式) 第 37 行到第 39 行設置 GPIO1_IO03 的 IOMUX_SW_PAD_CTL_PAD_GPIO1_IO03 配置寄存器 第 40 行到第 43 行是設置 GPIO 為輸出功能。 第 47 到第 49 是設置 GPIO 輸出 0(低電平) 第 53 到第 54 行是死循環,使用 b 跳轉指令,程序不斷的跳轉到 loop 執行。 9.7 編譯 LED 匯編程序 匯編程序 我們在 Ubuntu 下通過 vim 編輯好 LED 的匯編程序(6.6 章節),然后保存并退出。然后我們使用 arm交叉編譯器來編譯該程序,我們在終端輸入“arm-linux-gnueabihf-gcc -g -c led.s -o led.o”命令,把 led.s 編譯成 led.o,其中的“-g”參數是產生調試信息,可以使用 GDB 來調試代碼。“-c”參數是編譯源文件,不鏈接。“-o”參數是指定產生的文件名稱,我們指定生成 led.o,運行效果如下圖所示所示:
5.jpg (6.27 KB, 下載次數: 67)
下載附件
2020-6-22 14:56 上傳
我們可以看到通過 arm 交叉編譯生成了 led.o 文件,這個文件相當于中間文件,我們還需要把編譯生成的.o文件鏈接起來生成可執行文件(我們這里只有一個 led.o,對于有的工程可能會生成多個.o 文件)。 接下來我們使用交叉編譯器的“arm-linux-gnueabihf-ld”命令來把“.o”文件鏈接起來。鏈接的目的就是把我們的程序固定到某個地址,這樣 cpu 在運行的時候就可以通過鏈接地址找到我們的程序,并運行它。在鏈接之前我們需要先了解下 i.MX6ULL 的啟動,i.MX6ULL 支持 SD 卡,EMMC,NAND 等方式啟動,i.MX6ULL啟動的時候首先將代碼從 SD 卡,EMMC,NAND 中拷貝到運行地址,然后開始從運行地址處開始運行,i.MX6ULL 芯片內部有 128K 的 RAM(0X900000~0X91FFFF),另外外部擴展了 DDR,所以 i.MX6ULL 的鏈接地址可以是內部的 RAM,也可以是外部的 DDR。我們所有的例程都是鏈接到 DDR 中,其地址為 0X87800000。i.MX6ULL終結者開發板的 DDR 有兩種:256MB 和 512MB,其實地址都是 0X80000000。256MB 的終止地址是 0X8FFFFFFF,512M 的終止地址是 0X9FFFFFFF,之所以選擇地址 0X87800000,是因為后面我們要學的 Uboot 鏈接地址也是0X87800000。所以為了學習方便,我們統一使用 0X87800000 地址。 下面我們開始使用 arm-linux-gnueabihf_ld 命令將前面我們生成的“led.o”文件鏈接到 0X87800000 地址處,我們在終端輸入“arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf”,其中的“-Ttext” 指定鏈接地址(0X87800000),“-o”生成鏈接文件名,運行效果如下圖所示:
6.jpg (5.61 KB, 下載次數: 72)
下載附件
2020-6-22 14:56 上傳
我們需要把鏈接文件轉換成“.bin”文件,然后燒寫到 EMMC,才能運行。 接下來我們使用“arm-linux-gnueabihf-objcopy”命令將鏈接文件 led.elf 轉換成“led.bin”文件。我們在終端輸入“arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin”命令,其中“-O”指定以什么格式輸出(binary 表示二進制輸出),“-S”表示不要賦值源文件中的重定位信息和符號信息,“-g”表示不復制源文件中的調試信息,運行效果如下圖所示:
7.jpg (5.96 KB, 下載次數: 60)
下載附件
2020-6-22 14:56 上傳
至此我們生成了最終的可執行程序“led.bin”文件。 我們可以總結下,為了生成 led.bin 文件,我們分別使用了命令: arm-linux-gnueabihf-gcc -g -c led.s -o led.o arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin 為了編譯方便,我們可以使用 Makefile 來編譯我們的 led 匯編程序,首先我們在 led 工程目錄下使用“touch Makefile”命令創建 Makefile 文件,如下圖所示:
8.jpg (6.78 KB, 下載次數: 67)
下載附件
2020-6-22 14:56 上傳
然后使用 vim 編輯器打開 Makefile 文件,輸入下面的命令: led.bin:led.s arm-linux-gnueabihf-gcc -g -c led.s -o led.o arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin clean: rm -rf *.o led.bin led.elf 添加完上面的命令,保存并退出,然后在 led 工程目錄下執行“make”命令編譯 led.S,過程如下圖所示:
9.jpg (11.17 KB, 下載次數: 68)
下載附件
2020-6-22 14:56 上傳
如果要清除工程,我們在終端執行“make clean”即可。 至此關于 arm 交叉編譯器的使用,我們就先介紹到這里。編譯生成了 led.bin 執行文件,下一步我們還需要給 led.bim 文件添加一些數據頭才能執行。我們為用戶提供了添加數據頭的工具“create_imx”(光盤資料的“i.MX6UL 終結者光盤資料\01_開發及燒寫工具\2.裸機鏡像制作工具”目錄下),我們通過 ssh工具拷貝改文件到 led 工程目錄下,然后在終端輸入命令“./create_imx led.bin”,生成 bare.imx 文件,如下圖所示:
10.jpg (10.63 KB, 下載次數: 60)
下載附件
2020-6-22 14:56 上傳
現在我們開始使用 MFG 燒寫工具來燒寫(光盤資料的“i.MX6UL 終結者光盤資料\01_開發及燒寫工具\3.mfgtools_for_6ULL”文件夾),首先我們進到該文件夾,我們修改“cfg.ini”文件,如果您的板子是EMMC 版本(8G flash 容量),按照下圖的方式修改:
11.jpg (11.05 KB, 下載次數: 67)
下載附件
2020-6-22 14:56 上傳
如果您的板子是 NAND 版本(512MB flash 容量)(NAND 版本的裸機驗證我們需要使用一張 TF 卡),按照下圖所示修改:
12.jpg (9.94 KB, 下載次數: 58)
下載附件
2020-6-22 14:56 上傳
修改完“cfg.ini”配置文件,然后我們在 Ubuntu 系統生成的“bare.imx”文件通過 ssh 工具拷貝到 MFG燒寫工具的“Profiles\Linux\OS Firmware\files\linux\”目錄下,如下圖所示:
13.jpg (13.53 KB, 下載次數: 59)
下載附件
2020-6-22 14:56 上傳
然后我們鼠標雙擊打開 MFG 燒寫工具,如下圖所示:
14.jpg (9.29 KB, 下載次數: 67)
下載附件
2020-6-22 14:56 上傳
MFG 燒寫工具打開以后,我們使用開發板配帶的 USB 數據線,連接開發板的 OTG 接口和 PC 的 USB 接口,使用開發板配帶的電源連接到開發板的電源接口,然后開發板的撥碼開關設置成 USB 啟動,如下圖所示:
15.jpg (8.49 KB, 下載次數: 67)
下載附件
2020-6-22 14:56 上傳
( 如果我們使用的是 D NAND 版本的開發板,我們需要先拔掉 F TF 卡)然后按下開發板的電源開關,使開發板上電,此時我們會看到 MFG 燒寫工具識別到開發板,如下圖所示:
16.jpg (10.12 KB, 下載次數: 71)
下載附件
2020-6-22 14:56 上傳
( 如果我們使用的是 D NAND 版本的開發板, , 我們需要插入 F TF 卡),然后我們點擊 MFG 燒寫工具的“Start”按鈕,開始燒寫鏡像,如下圖所示:
17.jpg (10.91 KB, 下載次數: 63)
下載附件
2020-6-22 14:56 上傳
等到進度條顯示綠色,燒寫完成,如下圖所示:
18.jpg (10.62 KB, 下載次數: 71)
下載附件
2020-6-22 14:56 上傳
然后我們在按下開發板的電源按鍵給開發板斷電,然后修改撥碼開關設置正常啟動。 如果您的板子是 EMMC 版本(8GB Flash 存儲),撥碼開關如下圖所示:
19.jpg (6.54 KB, 下載次數: 66)
下載附件
2020-6-22 14:56 上傳
如果您的開發板是 NAND 版本(512M Flash 存儲),撥碼開關如下圖所示(設置成 TF 卡啟動模式):
20.jpg (6.23 KB, 下載次數: 75)
下載附件
2020-6-22 14:56 上傳
最后我們在按下開發板的電源開關,給開發板上電,此時我們會看到開發板的 LED2 被點亮了,如下圖 所示:
21.jpg (8.67 KB, 下載次數: 59)
下載附件
2020-6-22 14:56 上傳
本節我們詳細的介紹了如何編譯代碼,并且如何使用 MFG 燒寫生成
|