一.LED燈的點亮——從簡單的彙編開始瞭解
首先,我們一步步從彙編開始點亮板子上的LED燈!
為什麼要先從彙編開始呢?一般來說我們只用C寫程式就行了,但是系統上電以後要對SOC的外設、DDR進行初始化(我們用的是I.MX6U,不需要這一步),設定堆疊指標(一般指向DDR),設定好C語言的環境關閉看門狗等流程,但這些功能用C是無法實現的,必須通過彙編來做。好在只需要簡單幾個指令就可以了。
下面我們從開發板的LED硬體來分析下原理:
先看下硬體原理圖:
燈通過3.3V供電,經過510歐的限流電阻和控制口LED0相連,通過搜尋查詢,我們發現LED0節點和GPIO_3相連(應該是GPIO1_3)
以前搞過STM32的夥伴們應該知道,要對IO進行初始化,需要下面的流程:
- 使能GPIO時鐘
- 設定IO複用,將其設定為GPIO
- 配置GPIO的電氣屬性
- 使用GPIO,輸出高低電平
對於IMX6ULL來說,流程基本是一樣的,我們一步一步來設定
一.使能GPIO時鐘:
查詢IMX6ULL的晶片手冊,CCM_CCGR0-6一共7個暫存器控制了6UL上所有的外設時鐘的使能(第18.6.23章 CCM Clock Gating Register 0 (CCM_CCGR0)),而gpio1對應的時鐘管理是歸屬於CCM_CCGR1的26、27兩個bit管理,要想使能這個時鐘,將其按照要求設定就可以了
設定值得要求
簡單化,只要把兩個位元值都置一就行了。更簡單,吧CCGR0-6都設為0xFFFFFFFF,相當於使能所有外設時鐘。
二.IO複用設定
複用設定的管理屬於IOMUX Controller管理,查詢晶片手冊,我們要設定的是GPIO1的IO3,要設定的是IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03(SW_MUX_CTL_PAD_GPIO1_IO03 SW MUX ControlRegister )
下面有個表是對其進行說明的
複用模式(MUX_MODE)一共有7種模式,對應3-0bit,我們是要使用GPIO功能,也就是對應0101=5。
三.設定電氣屬性
下面要對GPIO1_IO03的電氣屬性進行設定。可以查下目錄,管理其屬性的暫存器是IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03(32.6.156
這個電氣屬性的內容比較多
Field | Description |
0 ODE_0_Open_Drain_Disabled — Open Drain Disabled 1 ODE_1_Open_Drain_Enabled — Open Drain Enabled |
|
31–17 |
This field is reserved. |
16 |
Hyst. Enable Field 0 HYS_0_Hysteresis_Disabled — Hysteresis Disabled |
15–14 |
Pull Up / Down Config. Field 00 PUS_0_100K_Ohm_Pull_Down — 100K Ohm Pull Down |
13 |
Pull / Keep Select Field Select one out of next values for pad: GPIO1_IO03 0 PUE_0_Keeper — Keeper |
12 |
Pull / Keep Enable Field 0 PKE_0_Pull_Keeper_Disabled — Pull/Keeper Disabled |
11 |
Open Drain Enable Field |
10–8 - |
This field is reserved. Reserved |
7–6 SPEED |
Speed Field Select one out of next values for pad: GPIO1_IO03 00 SPEED_0_low_50MHz_ — low(50MHz) 01 SPEED_1_medium_100MHz_ — medium(100MHz) 10 SPEED_2_medium_100MHz_ — medium(100MHz) 11 SPEED_3_max_200MHz_ — max(200MHz) |
5–3 DSE |
Drive Strength Field 000 DSE_0_output_driver_disabled_ — output driver disabled; |
2–1 - |
This field is reserved. Reserved |
0 |
Slew Rate Field 0 SRE_0_Slow_Slew_Rate — Slow Slew Rate |
也就是說暫存器IOMUSXC_SW_PAD_CTL_PAD_GPIO1_IO03是用來配置GPIO_IO03的,包括速度、驅動能力壓擺率等設定,下面挨個分析下這幾個引數
- SRE(bit0):壓擺率,指IO電平反轉所需要的時間,時間越小波形就越抖,即壓擺率高。0的時候為低壓擺率,1時為高。當我們的IO做高速IO時要設定為1
- DSE(bit5-3):當IO作為輸出時的驅動能力。共8個選項,0為關閉驅動,其餘對應表格查詢即可
- SPEED(bit7-6):IO用作輸出時的IO速度,按需求依據表格設定
- ODE(bit11):IO作為輸出時,是否使能開路輸出,0時禁止開路輸出,1時使能
- PKE(bit12):用來使能或禁止上下拉、狀態保持器的功能:0時禁止上下拉/狀態保持器,1時使能
- PUE(bit13):當IO為輸如的時候,用來設定IO使用上下拉還是狀態保持器:1時為上下拉,0時為狀態保持器,即外部電路斷電後此IO口可保持以前的狀態。
- PUS(bit15-14):設定上下拉電阻阻值,按需設定
- HYS(bit16):使能遲滯比較器,當IO作為輸入功能時有效,用於設定輸入接收器的施密特觸發器是否使能,如果需要對輸入波形進行整形的時候可以使能此位,0時禁止,1時使能
整個功能圖如圖所示
四.GPIO配置
這裡還有一個要配置是在STM32裡沒有的:配置GPIO,包含輸入/輸出,資料等等
手冊裡有一章是專門講GPIO的(Chapter28) ,查暫存器目錄發現有8個暫存器是我們需要設定的
GPIO data register(GPIOx_DR)
GPIO資料暫存器,一共32位,對應了IO的32個點,當GPIO配置為輸出到時候時,0為低電平,1為高電平。當GPIO為輸出到模式時,每個位對應一個GPIO,比方GPIO1_IO00引腳接地時,GPIO.DR的bit0值為0
GPIO direction register (GPIOx_GDIR)
方向暫存器(GPIO direction register (GPIOx_GDIR),28.5.2)
同樣也是32位,表明32個IO點工作的方向,0為輸入,1為輸出
我們需要的是將GPIO1_IO03設定為輸出模式,就要將GPIO1_GDIR的第3個bit置1
剩下的還有PSR,ICR1,ICR2,IMR,ISR,EDGE_SEL我們暫時用不到,這裡就先不講了,總之,GPIO的整體配置流程如下圖所示
程式碼編寫
這裡使用匯編來實現,組合語言的介紹我們放在另一章來講。反正這裡要用到就是讀取、寫入暫存器。
就按照前面的流程,先使能GPIO時鐘,這裡為了簡化操作,把所有Soc和GPIO1一個暫存器控制的所有外設都設為使能,也就是將CCM_CCGR1全都使能。
CCM_CCGR1的地址為20C_4000h base + 6Ch offset = 20C_406Ch(0x020c406c)
/*使能所有外設時鐘 */ ldr r0,=0x020c4068 @CCGR0 ldr r1,=0xffffffff @向CCGR0待寫入的資料 str r1,[r0] @將r1裡的資料寫入r0地址的暫存器
第二步就是設定複用,對應暫存器為IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03,地址為0x020e0068,應講MUX_MODE設定為ALT5
@設定複用IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5 ldr r0,=0x020e0068 ldr r1,=0x5 str r1,[r0]
第三步是設定電氣屬性,設定暫存器
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 地址0x020E02F4,對應前面的分解說明,按照下面的要求設定- bit 16:0 HYS關閉
- bit [15:14]: 00 預設下拉
- bit [13]: 0 kepper功能
- bit [12]: 1 pull/keeper使能
- bit [11]: 0 關閉開路輸出
- bit [10-8]: 000 空
- bit [7:6]: 10 速度100Mhz
- bit [5:3]: 110 R0/6驅動能力
- bit [2:1]: 00 空
- bit [0]: 0 低轉換率
ldr r0,=0x020e02f4 ldr r1,=0x10b0 str r1,[r0]
第四步是將GPIO設定為輸出模式,也就是將GPIO1_GDIR的第2個bit置1,換算值為0x8,GPIO1_GDIR的地址為0x209c004
ldr r0,=0x0209c004 ldr r1,=0x8 str r1,[r0]
下一步就是給GPIO的資料暫存器賦值,注意看前面的硬體原理圖,我們的LED要想點亮的話控制端需要為低電平,所以直接把GPIO1的值置0就好,GPIO1_DR的地址為0x209c000
ldr r0,=0x0209C000 ldr r1,=0 str r1,[r0]
最後放個死迴圈,讓程式跑起來就行了
loop: b loop
最後放上所有的程式碼
.global _start @全域性標號 _start: @ 開啟所有時鐘CCM_CCGR0-6 /*使能所有外設時鐘 */ ldr r0,=0x020c4068 @CCGR0 ldr r1,=0xffffffff @向CCGR0待寫入的資料 str r1,[r0] @將r1裡的資料寫入r0地址的暫存器內 @設定複用IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 = 5 ldr r0,=0x020e0068 ldr r1,=0x5 str r1,[r0] @設定電氣屬性IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 地址0x020E02F4 /* @ *bit 16:0 HYS關閉 @ *bit [15:14]: 00 預設下拉 @ *bit [13]: 0 kepper功能 @ *bit [12]: 1 pull/keeper使能 @ *bit [11]: 0 關閉開路輸出 @ *bit [10-8]: 000 空 @ *bit [7:6]: 10 速度100Mhz @ *bit [5:3]: 110 R0/6驅動能力 @ *bit [2:1]: 00 空 @ *bit [0]: 0 低轉換率 @ 00001 0000 1011 0000>0x10B0 */ ldr r0,=0x020e02f4 ldr r1,=0x10b0 str r1,[r0] /*設定GPIO1_IO03為輸出, GPIO1_GDIR地址為 0x209_C004 IO03對應第2bit,值為0x8 */ ldr r0,=0x0209C004 ldr r1,=0x8 str r1,[r0] /*設定GPIO輸出高電平 GPIO1_DR,地址為0x209_C000 IO03對應第3bit,低電平時燈點亮,值為0 */ ldr r0,=0x0209C000 ldr r1,=0 str r1,[r0] loop: b loopcode
整個程式碼的流程就完了,因為程式碼已經跑過,我這裡就不講除錯的過程了,下一章再仔細講一下如何編譯程式碼