一很钓、GPIO簡介
i.MX6ULL 芯片的 GPIO 被分成 5 組,并且每組 GPIO 的數量不盡相同攀芯,例如 GPIO1 擁有 32 個引腳好渠, GPIO2 擁有 22 個引腳, 其他 GPIO 分組的數量以及每個 GPIO 的功能請參考 《i.MX 6UltraLite Applications Processor Reference Manual》 第26章General Purpose Input/Output (GPIO)(P1133)步咪。
通過 GPIO 硬件結構框圖,就可以從整體上深入了解 GPIO 外設及它的各種應用模式益楼。
1.1 IO命名
打開 i.MX6ULL 參考手冊的第 32 章“Chapter 32: IOMUX Controller(IOMUXC)”
i.MX6ULL 的 IO 分為兩類:SNVS 域的和通用的猾漫,這兩類 IO 本質上都是一樣的。
“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”的就是 GPIO 命名感凤,命名形式就是“IOMUXC_SW_MUC_CTL_PAD_XX_XX
”悯周,后面的“XX_XX
”就是 GPIO 命名,比如:GPIO1_IO01陪竿、UART1_TX_DATA禽翼、JTAG_MOD 等等。他是 根據某個 IO 所擁有的功能來命名的族跛。比如我們一看到 GPIO1_IO01 就知道這個肯定能做 GPIO闰挡,看到 UART1_TX_DATA 肯定就知道這個 IO 肯定能做為 UART1 的發(fā)送引腳。
IO 復用功能礁哄。 i.MX6ULL 除了 GPIO1_IO00~GPIO1_IO09 引腳外长酗,其它 IO 也是可以復用為 GPIO 功能。同樣的桐绒,GPIO1_IO00~GPIO_IO09 也是可以復用為其它外設引腳夺脾。
1.2 IO復用
IOMUX 譯為 IO 復用選擇器。i.MX6ULL 的芯片每個 GPIO 都通過 IOMUX 支持多種功能茉继, 例如一個 IO 可用于網絡外設 ENET 的數據接收引腳咧叭,也可以被配置成 PWM 外設的輸出引腳, 這樣的設計大大增加了芯片的適用性烁竭,這樣可選的功能就是由 IOMUX 實現(xiàn)的菲茬。IOMUX 相當于增加了多根內部信號線與 IO 引腳相連,
最多有 8 根,也就是說一個 IO 最多可支持 8 種可選的功能
生均。
以“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”這個 IO 為例听想,打開參考手冊的 1568 頁。
可以看到有個名為:IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 的寄存器马胧,寄存器地址為 0X020E005C汉买,這個寄存器是 32 位的,但是只用到了最低 5 位佩脊,其中 bit0~bit3(MUX_MODE) 就是設置 GPIO1_IO00 的復用功能的蛙粘。GPIO1_IO00 一共可以復用為 9 種功能 IO,分別對應 ALT0~ALT8威彰,其中 ALT5 就是作為 GPIO1_IO00出牧。GPIO1_IO00 還可以作為 I2C2_SCL、GPT1_CAPTURE1歇盼、ANATOP_OTG1_ID 等舔痕。
1.3 IO配置
IOMUX 由其左側的 IOMUXC 控制(C表示Controler),IOMUXC 提供寄存器給用戶進行配置豹缀, 它又分成 MUX Mode(IO模式控制) 以及 Pad Settings(Pad配置) 兩個部分:
在 IOMUXC 外設中關于 MUX Mode 和 Pad Settings 寄存器命名格式如下:
IOMUXC控制類型 | 寄存器名稱 |
---|---|
MUX Mode | IOMUXC_SW_MUX_CTL_PAD_XXXX |
Pad Settings | IOMUXC_SW_PAD_CTL_PAD_XXXX |
每個引腳都包含這兩個寄存器伯复,表中的XXXX表示引腳的名字
1.3.1 MUX Mode配置
MUX Mode 就是用來
配置引腳的復用功能
,即選擇引腳具體是用于網絡外設 ENET 的數據接收邢笙, 還是用于 PWM 外設的輸出引腳啸如,當然,也可以配置成普通的 IO 口氮惯,僅用于控制輸出高低電平叮雳。
以 GPIO1_IO04 引腳為例對 MUX 寄存器進行說明,該引腳相應的 MUX 寄存器在參考手冊中的描述如下:
該寄存器主要有兩個配置域妇汗,分別是 SION 和 MUX_MODE帘不。
- SION: 用于設置引腳在輸出模式下同時開啟輸入通道。
-
MUX_MODE: 使用 4 個寄存器位表示可選的 ALT0~ALT7 這 8 個模式杨箭。
- 如 ALT2 模式就是用于 USB 外設的 USB_OTG1_PWR 信號厌均;
- 若配置為 ALT5 則引腳會用作普通的 GPIO 功能, 用于輸出高告唆、低電平棺弊。
1.3.2 Pad Settings配置
Pad Settings 用于
配置引腳的屬性
,例如驅動能力擒悬,是否使用上下拉電阻模她, 是否使用保持器,是否使用開漏模式以及使用施密特模式還是CMOS模式等懂牧。
以 GPIO1_IO04 引腳中 PAD 寄存器在參考手冊中的描述如下:
相對來說 PAD 寄存器的配置項就更豐富了侈净,而且圖中僅是該寄存器的部分說明尊勿,如 HYS 設置使用施密特模式的滯后功能,PUS 配置上下拉電阻的阻值畜侦, 其它的還包含PUE元扔、PKE、ODE旋膳、SPEED澎语、DSE 及 SRE 的配置。
1.3.3 PAD(可跳過不看)
PAD 代表了一個 i.MX6ULL 的 GPIO 引腳验懊。在它的左側是一系列信號通道及控制線擅羞,如 input_on 控制輸入開關,Dir 控制引腳的輸入輸出方向义图,Data_out 控制引腳輸出高低電平减俏,Data_in 作為信號輸入秦效,這些信號都經過一個 IOMUX 的器件連接到左側的寄存器案站。
①PAD引腳
代表一個i.MX6ULL的引腳。
②輸出緩沖區(qū)
當輸出緩沖區(qū)使能時桩匪,引腳被配置為輸出模式怕篷。在輸出緩沖區(qū)中草慧,又包含了如下的屬性配置:
-
DSE驅動能力
當IO用作輸出的時候用來設置IO的驅動能力。
DSE可以調整芯片內部與引腳串聯(lián)電阻R0的大小匙头,從而改變引腳的驅動能力。例如仔雷,R0的初始值為260歐姆蹂析,在3.3V電壓下其電流驅動能力為12.69mA,通過DSE可以把R0的值配置為原值的1/2碟婆、1/3…1/7等电抚。位設置 速度 000 輸出驅動關閉 001 R0(3.3V 下 R0 是 260Ω,1.8V 下 R0 是 150Ω竖共,接 DDR 的時候是 240Ω) 010 R0/2 011 R0/3 100 R0/4 101 R0/5 110 R0/6 111 R0/7 SRE壓擺率配置
設置壓擺率蝙叛。
壓擺率是指電壓轉換速率,可理解為電壓由波谷升到波峰的時間公给。增大壓擺率可減少輸出電壓的上升時間借帘。i.MX6ULL的引腳通過SRE支持低速和高速壓擺率這兩種配置。當此位為0的時候是低壓擺率淌铐,當為1的時候是高壓擺率肺然。壓擺率是大信號特性,下面的帶寬是小信號特性腿准。-
SPEED帶寬配置
設置IO的帶寬际起。
分別可設置為50MHz、100MHz以及200MHz。帶寬的意思是能通過這個IO口最高的信號頻率街望,通俗點講就是方波不失真校翔,如果超過這個頻率方波就變正弦波。但是這個帶寬要區(qū)別于IO的翻轉速率灾前,IO的翻轉速率的信號來自于GPIO這個外設防症,而IO的帶寬只是限制了IO口引腳的物理特性,IO口的信號可以來自于內部定時器輸出的PWM信號豫柬,也可以來自于GPIO翻轉輸出的信號告希,兩者相比之下,PWM信號的頻率是遠遠高于GPIO翻轉輸出的信號頻率烧给。位設置 速度 00 低速 50M 01 中速 100M 10 中速 100M 11 最大速度 200M ODE開漏輸出配置
設置引腳是否工作在開漏輸出模式燕偶。
在該模式時引腳可以輸出高阻態(tài)和低電平,此位為0的時候禁止開路輸出础嫡,當此位為1的時候就使能開路輸出功能指么。輸出高阻態(tài)時可由外部上拉電阻拉至高電平。開漏輸出模式常用在一些通訊總線中榴鼎,如I2C伯诬。
③輸入緩沖區(qū)
當輸入緩沖區(qū)使能時,引腳被配置為輸入模式巫财。在輸入緩沖區(qū)中盗似,又包含了如下的屬性配置:
- HYS滯后使能
用來使能遲滯比較器。
i.MX6ULL的輸入檢測可以使用普通的CMOS檢測或施密特觸發(fā)器模式(滯后模式)平项。施密特觸發(fā)器具有滯后效應赫舒,對正向和負向變化的輸入信有不同的閾值電壓。如果需要對輸入波形進行整形的話可以使能此位闽瓢。此位為0的時候禁止遲滯比較器接癌,為1的時候使能遲滯比較器。常被用于電子開關扣讼、波形變換等場合缺猛,其轉換特性和對比如下,如檢測按鍵時椭符,使用施密特模式即可起到消抖的功能荔燎。
④Pull/Keeper上下拉、保持器
引腳的控制邏輯中還包含了上下拉销钝、保持器的功能湖雹。芯片內部的上拉和下拉電阻可以將不確定的信號鉗位在高、低電平曙搬,或小幅提高的電流輸出能力摔吏,上拉提供輸出電流鸽嫂,下拉提供輸入電流。注意這些上下拉配置只是弱拉征讲,對于類似I2C之類的總線据某,還是必須使用外部上拉電阻。i.MX6ULL芯片的電源模塊中包含轉換器诗箍,當轉換器停止工作時癣籽,保持器會保持輸入輸出電壓。
上下拉滤祖、保持器可以通過如下屬性配置:
- PUS上下拉配置
設置上下拉電阻筷狼。
PUS可配置項可選為100K歐下拉以及22K歐、47K歐及100K歐上拉匠童。位設置 含義 00 100K 下拉 01 47K 上拉 10 100K 上拉 11 22K 上拉 - PUE上下拉埂材、保持器選擇
上下拉功能和保持器功能是二選一的,可以通過PUE來選擇汤求。
當IO作為輸入的時候俏险,這個位用來設置 IO 使用上下拉還是狀態(tài)保持器。當為0的時候使用狀態(tài)保持器扬绪,當為1的時候使用上下拉竖独。狀態(tài)保持器在IO作為輸入的時候才有用,顧名思義挤牛,就是當外部電路斷電以后此IO口可以保持住以前的狀態(tài)莹痢。 - PKE上下拉、保持器配置
用來使能或者禁止上下拉/狀態(tài)保持器功能墓赴。
為0時禁止上下拉/狀態(tài)保持器竞膳,為1時使能上下拉和狀態(tài)保持器。
注意竣蹦,當引腳被配置為輸出模式時,不管上下拉沧奴、保持器是什么配置痘括,它們都會被關閉。
1.4 GPIO配置
GPIO 模塊是每個 IO 都具有的外設滔吠,它具有 IO 控制最基本的功能纲菌,如輸出高低電平、檢測電平輸入等疮绷。 它也占用 IOMUX 分配的復用信號翰舌,也就是說使用 GPIO 模塊功能時同樣需要使用 IOMUX 選中 GPIO 外設,對其 GPIO 的功能進行配置冬骚。
1.4.1 GDIR方向寄存器
設置某個 IO 的工作方向椅贱。
控制一個 GPIO 引腳時懂算,要先用 GDIR 方向寄存器配置該引腳用于輸出電平信號還是用作輸入檢測。 典型的例子是使用輸出模式可以控制LED燈的亮滅庇麦,輸入模式時可以用來檢測按鍵是否按下计技。
GDIR 寄存器的每一個數據位代表一個引腳的方向,對應的位被設置為0時該引腳為輸入模式山橄,被設置為1時該引腳為輸出模式垮媒。
例如,對 GPIO1 的 GDIR 寄存器的 bit3 位被寫入為 1航棱,那么 GPIO1.3 引腳的模式即為輸出睡雇。
1.4.2 DR數據寄存器
DR 數據寄存器直接代表了引腳的電平狀態(tài)
,它也使用 1 個數據位表示 1 個引腳的電平饮醇,每位用 1 表示高電平它抱,用 0 表示低電平。
當 GDIR 方向寄存器設置引腳為輸出模式時驳阎,寫入 DR 數據寄存器對應的位即可控制該引腳輸出的電平狀態(tài)抗愁, 如這時 GPIO1 的 DR 寄存器的 bit4 被寫入為 1,則引腳為輸出高電平呵晚。
當 GDIR 方向寄存器設置引腳為輸入模式時蜘腌,讀取 DR 數據寄存器對應的位即可獲取該引腳當前的輸入電平狀態(tài),例如這里讀取 GPIO1 的DR寄存器的 bit4饵隙,得到該位的值為 0撮珠,表示當前引腳的輸入狀態(tài)為低電平。
1.4.3 PSR引腳狀態(tài)寄存器
讀取相應的位即可獲取對應的 GPIO 的狀態(tài)
金矛,也就是 GPIO 的高低電平值芯急。PSR 引腳狀態(tài)寄存器相當于 DR 寄存器的簡化版,它僅在 GDIR 方向寄存器設置為輸入模式時有效驶俊,它的每個位表示一個引腳當前的輸入電平狀態(tài)娶耍。PSR 寄存器的權限是只讀的,對它進行寫操作是無效的饼酿。
特別地榕酒,當引腳被配置成輸出模式時,若 IOMUXC 中的 MUX 寄存器使能了 SION 功能(輸出通道回環(huán)至輸入)故俐, 可以通過 PSR 寄存器讀取回引腳的狀態(tài)值想鹰。
二、引腳確定
我使用的是 野火_EBF6ULL S1 Pro
開發(fā)板
從原理圖可看到 RGB 燈的三個陰極 R药版、G辑舷、B 連接分別連接至標號
GPIO_4
、CSI_HSYNC
槽片、CSI_VSYNC
何缓, 這些標號實際上與配套核心板上 i.MX6ULL 芯片的引腳相連肢础。由于引腳功能眾多, 繪制原理圖時不可避免地無法完全表示引腳信息的所有信息歌殃。而無論是具體的引腳名還是復用功能乔妈, 我們都無法直接得知這些具體是 i.MX6ULL 芯片的哪個引腳。我們需要知道這些引腳是對應的具體 GPIO氓皱,這樣我們才能編寫程序進行控制路召。
由于還不清楚標號 GPIO_4
、CSI_HSYNC
波材、CSI_VSYNC
的具體引腳名股淡,我們首先要在核心板原理圖中查看它與 i.MX6ULL 芯片的關系。打開 《野火_EBF6ULL S1 郵票孔核心板V1.0原理圖》廷区,在PDF閱讀器的搜索框輸入前面的 GPIO_4
唯灵、CSI_HSYNC
、CSI_VSYNC
標號隙轻。
查找到了
GPIO_4
信號的具體引腳名為GPIO1_IO04
埠帕。 但是當我們使用同樣的方法查找時發(fā)現(xiàn)只能找到CSI_HSYNC
、CSI_VSYNC
玖绿, 并沒有我們熟悉的 GPIOx_IOx 標注的引腳名敛瓷。這兩個引腳默認情況下不用作 GPIO,而是用作攝像頭的某一功能引腳斑匪,但是它可以復用為 GPIO呐籽,我們怎么找到對應的 GPIO 呢?
-
方法一:
在《i.MX 6UltraLite Applications Processor Reference Manual》的第4章 External Signals and Pin Multiplexing 搜索引腳名
-
方法二:
在官方寫好的文件 fsl_iomuxc.h(路徑:SDK文件夾/devices/MCIMX6Y2/drivers/fsl_iomuxc.h) 中搜索引腳名
經查閱蚀瘸,我們把以上連接 LED 燈的各個 i.MX6ULL 芯片引腳總結出如表:
LED燈 | 原理圖的標號 | 具體引腳名 | GPIO端口及引腳編號 |
---|---|---|---|
R燈 | GPIO_4 | GPIO1_IO04 | GPIO1_IO04 |
G燈 | CSI_HSYNC | CSI_HSYNC | GPIO4_IO20 |
B燈 | CSI_VSYNC | CSI_VSYNC | GPIO4_IO19 |
三狡蝶、編寫啟動文件
在 Ubuntu 下創(chuàng)建 start.S
文件用于編寫啟動文件。
在匯編文件中設置“棧地址”
并執(zhí)行跳轉命令跳轉到main函數
執(zhí)行C代碼贮勃。
3.1 完整代碼
/***********************第一部分*********************/
.text //代碼段
.align 2 //設置2字節(jié)對齊
.global _start //定義一個全局標號
/*************************第二部分*************************/
_start: //程序的開始
b reset //跳轉到reset標號處
/*************************第三部分*************************/
reset:
mrc p15, 0, r0, c1, c0, 0 /* 將 CP15 協(xié)處理器中的寄存器數據讀到 ARM 寄存器中 */
bic r0, r0, #(0x1 << 12) /* 清除第12位(I位)禁用 I Cache */
bic r0, r0, #(0x1 << 2) /* 清除第 2位(C位)禁用 D Cache */
bic r0, r0, #0x2 /* 清除第 1位(A位)禁止嚴格對齊 */
bic r0, r0, #(0x1 << 11) /* 清除第11位(Z位)分支預測 */
bic r0, r0, #0x1 /* 清除第 0位(M位)禁用 MMU */
mcr p15, 0, r0, c1, c0, 0 /* 將 ARM 寄存器的數據寫入到 CP15 協(xié)處理器寄存器中 */
/***********************第四部分*********************/
ldr sp, =0x84000000 //設置棧地址64M
b main //跳轉到main函數
/***********************第五部分*******************/
/*進入死循環(huán)*/
loop:
b loop
3.2 分析代碼
-
第一部分
.text
定義代碼段贪惹。
.align 2
設置字節(jié)對齊。
.global _start
生命全局標號_start寂嘉。
/*************************第一部分*************************/
.text //代碼段
.align 2 //設置2字節(jié)對齊
.global _start //定義一個全局標號
-
第二部分
_start:
定義標號_start: 奏瞬,它位于匯編的最前面,說以會首先被執(zhí)行垫释。
b reset
使用b指令將程序跳轉到reset標號處丝格。
/*************************第二部分*************************/
_start: //程序的開始
b reset //跳轉到reset標號處
-
第三部分
通過修改CP15寄存器(系統(tǒng)控制寄存器)
關閉 I Cache 撑瞧、D Cache棵譬、MMU 等等。
我們暫時用不到的功能预伺,如果開啟可能會影響我們裸機運行订咸,為避免不必要的麻煩暫時關閉這些功能曼尊。
/*************************第三部分*************************/
reset:
mrc p15, 0, r0, c1, c0, 0 /* 將 CP15 協(xié)處理器中的寄存器數據讀到 ARM 寄存器中 */
bic r0, r0, #(0x1 << 12) /* 清除第12位(I位)禁用 I Cache */
bic r0, r0, #(0x1 << 2) /* 清除第 2位(C位)禁用 D Cache */
bic r0, r0, #0x2 /* 清除第 1位(A位)禁止嚴格對齊 */
bic r0, r0, #(0x1 << 11) /* 清除第11位(Z位)分支預測 */
bic r0, r0, #0x1 /* 清除第 0位(M位)禁用 MMU */
mcr p15, 0, r0, c1, c0, 0 /* 將 ARM 寄存器的數據寫入到 CP15 協(xié)處理器寄存器中 */
-
第四部分
ldr sp, =0x84000000
用于設置棧指針。野火i.MX6ULL開發(fā)板標配512M的DDR內存脏嚷,裸機開發(fā)用不了這么多骆撇。程序中我們將棧地址設置到DDR的64M地址處。 這個值也可以根據需要自行定義父叙。
b main
只用跳轉指令跳轉到main函數中執(zhí)行神郊。
/***********************第四部分*********************/
ldr sp, =0x84000000 //設置棧地址64M
b main //跳轉到main函數
-
第五部分
b loop
是“無返回”的跳轉指令。正常情況下趾唱,不會執(zhí)行第五部分代碼涌乳。
/***********************第五部分*******************/
/*進入死循環(huán)*/
loop:
b loop
四、編程流程
1. 開啟GPIO時鐘
2. 設置引腳的復用功能以及引腳屬性
3. 設置引腳方向以及輸出電平
五甜癞、編寫C語言代碼
在 Ubuntu 下創(chuàng)建 led.c
文件用于驅動 LED 閃爍夕晓。
5.1 完整代碼
//時鐘控制寄存器
#define CCM_CCGR1 (volatile unsigned long*)0x20C406C
//GPIO1_04復用功能選擇寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E006C
//PAD屬性設置寄存器
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E02F8
//GPIO方向設置寄存器
#define GPIO1_GDIR (volatile unsigned long*)0x0209C004
//GPIO輸出狀態(tài)寄存器
#define GPIO1_DR (volatile unsigned long*)0x0209C000
#define uint32_t unsigned int
/*簡單延時函數*/
void delay(uint32_t count)
{
volatile uint32_t i = 0;
for (i = 0; i < count; ++i)
{
__asm("NOP"); /* 調用nop空指令 */
}
}
int main()
{
*(CCM_CCGR1) = 0xFFFFFFFF; //開啟GPIO1的時鐘
*(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04) = 0x5; //設置PAD復用功能為GPIO
*(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04) = 0x1F838; //設置PAD屬性
*(GPIO1_GDIR) = 0x10; //設置GPIO為輸出模式
*(GPIO1_DR) = 0x0; //設置輸出電平為低電平
while(1)
{
*(GPIO1_DR) = 0x0;
delay(0xFFFFF);
*(GPIO1_DR) = 1<<4;
delay(0xFFFFF);
}
return 0;
}
5.2 分析代碼
-
定義GPIO相關寄存器
這部分內容與“匯編點亮LED燈”中定義的寄存器相同, 只不過這里使用(volatile unsigned long*
)將地址強制轉化為指針悠咱。
配置時鐘使能寄存器地址
設置時鐘控制寄存器CCM_CCGR1的地址如下:
配置MUX Mode寄存器地址
MUX Mode用于設置GPIO1_IO04的復用功能蒸辆。配置成普通的IO口,僅用于控制輸出高低電平析既。寄存器地址如下:
配置Pad Settings寄存器地址
Pad Settings用于設置GPIO的PAD屬性躬贡。例如驅動能力,是否使用上下拉電阻渡贾, 是否使用保持器逗宜,是否使用開漏模式以及使用施密特模式還是CMOS模式等。寄存器地址如下:
//時鐘控制寄存器
#define CCM_CCGR1 (volatile unsigned long*)0x20C406C
//GPIO1_04復用功能選擇寄存器
#define IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E006C
//PAD屬性設置寄存器
#define IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04 (volatile unsigned long*)0x20E02F8
//GPIO方向設置寄存器
#define GPIO1_GDIR (volatile unsigned long*)0x0209C004
//GPIO輸出狀態(tài)寄存器
#define GPIO1_DR (volatile unsigned long*)0x0209C000
-
實現(xiàn)簡單的軟件延時函數
在函數體中調用__asm(“NOP”)
嵌入匯編指令空骚, 這條語句表示CPU什么都不做纺讲。
/*簡單延時函數*/
void delay(uint32_t count)
{
volatile uint32_t i = 0;
for (i = 0; i < count; ++i)
{
__asm("NOP"); /* 調用nop空指令 */
}
}
-
向寄存器中寫入值
在第一部分代碼中我們將寄存器地址強制轉換為指針,這里使用使用“*”
號再次“尋址”囤屹。 -
開啟GPIO1的時鐘
“*(CCM_CCGR1) = 0xFFFFFFFF;
” 代碼表示將0xFFFFFFFF寫入指針CCM_CCGR1所指定的地址中熬甚。
設置的時鐘控制寄存器CCM_CCGR1
。
從上表中可以看出CCM_CCGR1[26:27]用于使能GPIO1的時鐘肋坚,這里不僅僅設置時鐘的開或者關乡括, 還可以設置在芯片在不同工作模式下的時鐘狀態(tài)如下表:
CCM_CCGR1[26:27]的值 | 時鐘狀態(tài)描述 |
---|---|
00 | 時鐘在所有模式下都是關閉的 |
01 | 時鐘在運行模式下為開,但在等待和停止模式下為關 |
10 | 保留 |
11 | 除停止模式外智厌,時鐘一直開啟 |
我們將CCM_CCGR1[26:27]設置為11
(二進制)即可诲泌。仔細觀察可以發(fā)現(xiàn)發(fā)現(xiàn)CCM_CCGR1寄存器默認全為1,即默認開啟了時鐘铣鹏。 為了程序規(guī)范我們再次使用代碼開啟時鐘敷扫。將CCM_CCGR1寄存器設置全為1
。
-
設置引腳復用功能為GPIO
這里設置的是GPIO1_04的引腳復用寄存器诚卸,我們直接搜索IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04
可以找到如下所示的寄存器葵第。
從上圖可知IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04[MUX_MODE]=0101(二進制)時GPIO1_04復用功能是GPIO绘迁。所以在程序中我們將0x5
寫入該寄存即可。
*(CCM_CCGR1) = 0xFFFFFFFF; //開啟GPIO1的時鐘
*(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04) = 0x5; //設置PAD復用功能為GPIO
*(IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04) = 0x1F838; //設置PAD屬性
*(GPIO1_GDIR) = 0x10; //設置GPIO為輸出模式
*(GPIO1_DR) = 0x0; //設置輸出電平為低電平
- 不斷改變RGB紅燈所在引腳的高低電平
while(1)
{
*(GPIO1_DR) = 0x0;
delay(0xFFFFF);
*(GPIO1_DR) = 1<<4;
delay(0xFFFFF);
}
六卒密、編寫鏈接腳本
寫好的代碼(無論是匯編還是C語言)都要經過編譯缀台、匯編、鏈接等步驟生成二進制文件或者可供下載的文件哮奇。在編譯階編譯器會對每個源文件進行語法檢查并生成對應的匯編語言膛腐,匯編是將匯編文件轉化為機器碼。
使用
arm-none-eabi-gcc -g -c led.S -o led.o
命令完成源碼的編譯鼎俘、匯編工作依疼,生成了.o
文件。編譯和匯編是針對單個源文件而芥,也就編譯完成后一個源文件(.c
律罢,.S
或.s
)對應一個.o
文件。程序鏈接階段就會將這些.o
鏈接成一個文件棍丐。鏈接腳本的作用就是告訴編譯器怎么鏈接這些文件误辑,比如那個文件放在最前面,程序的代碼段歌逢、數據段巾钉、bss段分別放在什么位置等等。
在 Ubuntu 下創(chuàng)建 led.lds
鏈接腳本秘案。
6.1 完整代碼
ENTRY(_start)
SECTIONS {
. = 0x80000000;
. = ALIGN(4);
.text :
{
start.o (.text)
*(.text)
}
. = ALIGN(4);
.data :
{
*(.data)
}
. = ALIGN(4);
.bss :
{
*(.bss)
}
}
6.2 分析代碼
-
指定程序的入口
ENTRY(_start)
用于指定程序的入口砰苍,ENTRY()
是設置入口地址的命令,“_start”
是程序的入口阱高,led程序的入口地址位于start.S
的“_start”
標號處赚导。
ENTRY(_start)
-
定義SECTIONS
SECTIONS
可以理解為是一塊區(qū)域,我們在這塊區(qū)域排布我們的代碼赤惊,鏈接時鏈接器就會按照這里的指示鏈接我們的代碼吼旧。
SECTIONS {
···
···
}
-
定義鏈接起始地址
“.”
運算符代表當前位置。 我們在SECTION的最開始使用“.= 0x80000000”
就是將鏈接起始地址設置為0x80000000未舟。
. = 0x80000000;
設置字節(jié)對齊
“. = ALIGN(4);”
它表示從當前位置開始執(zhí)行四字節(jié)對齊圈暗。假設當前位置為0x80000001,執(zhí)行該命令后當前地址將會空出三個字節(jié)轉到0x80000004地址處裕膀。設置代碼段
“.text :”
用于定義代碼段员串,固定的語法要求,我們按照要求寫即可昼扛。在“{}”中指定那些內容放在代碼段寸齐。
將start.o
中的代碼放到代碼段的最前面。start.S
是啟動代碼應當首先被執(zhí)行,所以通常情況下要把它放到代碼段的最前面访忿,其他源文件的代碼按照系統(tǒng)默認的排放順序即可,通配符“*”
在這里表示其他剩余所有的.o
文件斯稳。
. = ALIGN(4);
.text :
{
start.o (.text)
*(.text)
}
-
設置數據段
同設置代碼段類似海铆,首先設置字節(jié)對齊,然后定義代碼段挣惰。在數據段里使用“*”
通配符卧斟, 將所有源文件中的代碼添加到這個數據段中。
. = ALIGN(4);
.data :
{
*(.data)
}
-
設置BSS段
設置方法與設置數據段完全相同憎茂。
. = ALIGN(4);
.bss :
{
*(.bss)
}
七珍语、編寫makefile文件
程序編寫完成后需要依次輸入編譯、鏈接竖幔、格式轉換命令才能最終生成二進制文件板乙。這種編譯方式效率低、容易出錯拳氢。
使用
makefile
只需要在所在文件夾下執(zhí)行make
命令募逞,makefile工具便會自動完成程序的編譯、鏈接馋评、格式轉換等工作放接。正常情況下我們可以在當前目錄看到生成的一些中間文件以及我們期待的.bin
文件。
在 Ubuntu 下創(chuàng)建 makefile
文件留特。
7.1 完整代碼
all: start.o led.o
arm-none-eabi-ld -Tled.lds $^ -o led.elf
arm-none-eabi-objcopy -O binary -S -g led.elf led.bin
%.o : %.S
arm-none-eabi-gcc -g -c $^ -o start.o
%.o : %.c
arm-none-eabi-gcc -g -c $^ -o led.o
.PHONY: clean
clean:
rm *.o *.elf *.bin
7.2 分析代碼
- 添加最終目標以及依賴文件
all: start.o led.o
-
添加鏈接命令
“-Tled.lds”
表示使用led.lds鏈接腳本鏈接程序纠脾。
“$^”
代表所有的依賴文件。
“-o”
指定輸出文件名蜕青。
arm-none-eabi-ld -Tled.lds $^ -o led.elf
-
添加格式轉換命令
“-O binary”
指定輸出二進制文件苟蹈。
“-S”
不從源文件中復制重定位信息和符號信息。
“-g”
不從源文件中復制可調試信息右核。
arm-none-eabi-objcopy -O binary -S -g led.elf led.bin
-
添加匯編文件編譯命令
“$^”
替代要編譯的源文件汉操。
%.o : %.S
arm-none-eabi-gcc -g -c $^ -o start.o
-
添加編譯C文件的命令
“$^”
替代要編譯的源文件。
%.o : %.c
arm-none-eabi-gcc -g -c $^ -o led.o
-
添加清理命令
“.PHONY”
定義了偽目標“clean”蒙兰。偽目標一般沒有依賴磷瘤,并且“clean”
偽目標一般放在Makefile文件的末尾。
“clean”
為目標用于刪除make生成的文件搜变。
.PHONY: clean
clean:
rm *.o *.elf *.bin
八采缚、編譯下載驗證
8.1 編譯代碼
make
執(zhí)行make命令,生成led.bin文件挠他。
8.2 代碼燒寫
編譯成功后會在當前文件夾下生成.bin文件扳抽,這個.bin文件也不能直接放到開發(fā)板上運行, 這次是因為需要在.bin文件缺少啟動相關信息。
為二進制文件添加頭部信息并燒寫到SD卡贸呢。查看 IMX6ULL學習筆記(12)——通過SD卡啟動官方SDK程序
進入燒寫工具目錄镰烧,執(zhí)行 ./mkimage.sh <燒寫文件路徑>
命令,例如要燒寫的 led.bin 位于 home 目錄下楞陷,則燒寫命令為 ./mkimage.sh /home/led.bin
怔鳖。
執(zhí)行上一步后會列出linux下可燒寫的磁盤,選擇你插入的SD卡即可固蛾。這一步 非常危險=嶂础!艾凯!一定要確定選擇的是你插入的SD卡O揍!!趾诗,如果選錯很可能破壞你電腦磁盤內容蜡感,造成數據損壞!J牙帷铸敏! 確定磁盤后SD卡以“sd”開頭,選擇“sd”后面的字符即可悟泵。例如要燒寫的sd卡是“sdb”則輸入“b”即可杈笔。
8.3 實驗現(xiàn)象
將開發(fā)板設置為SD卡啟動,接入SD卡糕非,開發(fā)板上電蒙具,可以看到開發(fā)板RGB紅燈閃爍。
? 由 Leung 寫于 2022 年 12 月 25 日