文章目錄
- Linux驅動開發:匯編LED燈實驗(I.MX6UL芯片)
- 一、I.MX6UL的GPIO原理
- 1.1 I.MX6UL IO命名
- 1.2 I.MX6UL IO復用
- 1.3 I.MX6UL IO配置
- 1.4 I.MX6UL GPIO配置
- 1.5 I.MX6UL時鐘使能
- 二、開發板原理圖
- 三、程式撰寫
- 四、編譯下載
- 五、實驗現象
Linux驅動開發:匯編LED燈實驗(I.MX6UL芯片)
一、I.MX6UL的GPIO原理
研究IMX6UL GPIO 原理前先回憶一下STM32GPIO配置流程,其主要分為4個步驟:
- 使能指定 GPIO 的時鐘,
- 初始化 GPIO,如輸出功能、上拉、速度等
- 是否開啟 IO 復用將IO作為其它外設 引腳使用
- 設定初始輸出的電平高低
下面我們學習 IMX6UL 的 GPIO 原理也是按照這樣的流程來學習
1.1 I.MX6UL IO命名
學習前先了解一下 IMX 的命名方式,在以前學STM32時他的 IO 口是按照一組一組來命名的,如PA是一組,一組里面有16個 IO 口即 PA0-PA15;而在 IMX6UL里面命名方式則大不一樣,I.MX6UL 的 IO 主要分為兩類:SNVS 域IO和通用 IO
SNVC域 IO 命名: IOMUXC_SNVC_SW_MUX_CTL_PAD_XX_XX,后面的 XX_XX 就是 GPIO 命名, 比如:BOOT_MODE0 等等
通用 IO 命名: IOMUXC_SW_MUX_CTL_PAD_XX_XX,后面的 XX_XX 就是 GPIO 命名, 比如:GPIO1_IO01、UART1_TX_DATA、JTAG_MOD 等等
具體IO檔案可以參考 IMX6UL 官方檔案
1.2 I.MX6UL IO復用
IO 復用是通過一個暫存器來控制的,這里我以 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 為例子,翻閱手冊可以看到一個 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO01 的32位暫存器,暫存器如下:

可以看到暫存器的地址為 20E_005CH 低5位用于模式控制分為 SION 和 MUX_MODE,其他的則是保留位
MUX_MODE 的0到3位對應具體模式,具體有以下幾個:
| MUX_MODE | 復用模式 |
|---|---|
| 0000 | ALT0 復用為 IIC2_SCL |
| 0001 | ALT1 復用為 GPT1_CAPTURE1 |
| 0010 | ALT2 復用為 ANATOP_OTG1_ID |
| 0011 | ALT3 復用為 ENET1_REF_CLK1 |
| 0100 | ALT4 復用為 MQS_RIGHT |
| 0101 | ALT5 復用為 GPIO1_IO00 |
| 0110 | ALT6 復用為 ENET1_1588_EVENT0_IN |
| 0111 | ALT7 復用為 SRC_SYSTEM_RESET |
| 1000 | ALT8 復用為 WDOG3_WDOG_B |
SION 的控制功能如下:
| SION | 功能 |
|---|---|
| 0 | IO輸入路徑按照復用的模式來 |
| 1 | IO輸入路徑強制按照GPIO1——IO00來 |
以上就是 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 的復用暫存器一個簡單的介紹,不同的 IO 他的復用暫存器不完全相同,需要根據手冊具體去查詢
I.MX6U 的 GPIO 一共有 5 組:GPIO1、GPIO2、GPIO3、GPIO4 和 GPIO5, 其中 GPIO1 有 32 個 IO,GPIO2 有 22 個 IO,GPIO3 有 29 個 IO、GPIO4 有 29 個 IO,GPIO5 有 12 個 IO,一共有 124 個 GPIO
1.3 I.MX6UL IO配置
1.2 講述的是 IO 口的復用配置暫存器,但 IO 的具體作業配置還有另外一個暫存器進行控制,繼續以 GPIO1 組的 IO00 為例子;具體 IO 作業配置暫存器由 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO00 控制,該暫存器如下:

其不同位控制的 IO 配置功能不同,需要結合 IO 的作業原理圖來理解,上 IO 原理圖:

暫存器分析:
HYS(bit16): 對應圖中 HYS,用來使能遲滯比較器,在 IO 輸入時有效,可以用來對輸入波形進行處理,關于遲滯比較器可以看這篇文章 : 遲滯比較器;HYS 為 0 的時候禁止遲滯比較器,為 1 的時候使能遲滯比較器
PUS(bit15:14): 圖中的 PUS,用來設定上下拉電阻的:
| 位 | 功能 |
|---|---|
| 00 | 100k 下拉 |
| 01 | 47k 上拉 |
| 10 | 100k 上拉 |
| 11 | 22k 上拉 |
PUE(bit13): 上圖沒有顯示,當 IO 作為輸入的時候,這個位用來設定 IO 是使用上下拉還是使用狀態保持器,為 0 的時候使用狀態保持器,當為 1 的時候使用上下拉,
狀態保持器在 IO 作為輸入的時候才有用,當外部電路斷電以后此 IO 口可以保持住之前狀態,
PKE(bit12): 對應圖中的 PKE,此位用來使能或者禁止上下拉或者狀態保持器功能,為 0 時禁止上下拉/狀態保持器,為 1 時使能上下拉和狀態保持器,
ODE(bit11): 對應圖中的 ODE,當 IO 作為輸出的時候,此位用來禁止或者使能開路輸出,此位為 0 的時候禁止開路輸出,當此位為 1 的時候就使能開路輸出功能,
SPEED(bit7:6): 對應圖中的 SPEED,當 IO 用作輸出的時候,此位用來設定 IO 速度
| 位設定 | 速度 |
|---|---|
| 00 | 低速 50M |
| 01 | 中速 100M |
| 10 | 中速 100M |
| 11 | 最大速度 200M |
DSE(bit5:3): 對應圖中 DSE,當 IO 用作輸出的時候用來設定 IO 的驅動能力, 總共有 8 個可選選項,如表所示:
(3.3V 下 R0 是 260Ω,1.8V 下 R0 是 150Ω,接 DDR 的時候是 240Ω)
| 位設定 | 速度 |
|---|---|
| 000 | 輸出驅動關閉 |
| 001 | R0 **** |
| 010 | R0/2 |
| 011 | R0/3 |
| 100 | R0/4 |
| 101 | R0/5 |
| 110 | R0/6 |
| 111 | R0/7 |
SRE(bit0): 對應圖中的 SRE,設定壓擺率,當此位為 0 的時候是低壓擺率,當為 1 的時候是高壓擺率,
壓擺率就是 IO 電平跳變所需要的時間,比如從 0 到 1 需要多少時 間,時間越小波形就越陡,說明壓擺率越高;反之,時間越多波形就越緩,壓擺率就越低,高速信號壓擺率要高,速度快;而要考慮電磁兼容性的話壓擺率要低
壓擺率參考文章:運放壓擺率
1.4 I.MX6UL GPIO配置
1.2 和 1.3 講了IO 的復用與功能暫存器配置,1.4 小節分析 IO 眾多復用里面的一種 GPIO 的具體配置
首先看一下 GPIO 的結構圖:

結構中可以看到 IOMUXC 里面有 SW_MUX_CTL_PAD_* 和 SW_PAD_CTL_PAD__* 兩個暫存器用于配置 IO;而單獨的 GPIO 配置則是另外 8 個 GPIO 自己的暫存器進行配置;

這 8 個暫存器介紹如下:
首先看 GPIOx_DR 資料暫存器,由翻譯可以看到,DR 暫存器在 IO 的模式設定為 GPIO 且 GPIO 的輸入輸出方向確定好后,輸出狀態時 DR 暫存器里面的位可以控制 GPIO 的輸出值,輸入時則存盤輸入的狀態值,通過讀取可以獲取 GPIO 狀態,比如當 GPIO1_IO00 引腳接地,那么 GPIO1.DR 的 bit0 就是 0

GPIOx_IR 方向暫存器,結構如下:

GPIO_GDIR 作為方向控制,每個位指定了一位信號的方向,此暫存器用來設定某個 IO 的作業方向,是輸入還是輸出,同 樣的,每個 IO 對應一個位,如果要設定 GPIO 為輸入的話就設定相應的位為 0,如果要設定為輸出的話就設定為 1
PSR 暫存器: GPIO 的狀態暫存器


PSR 暫存器也是一個 GPIO 對應一個位,讀取相應的位即可獲取對應的 GPIO 的狀態,也就是 GPIO 的高低電平值,功能和輸入狀態下的 DR 暫存器一樣
ICR1和ICR2 是中斷控制暫存器, ICR1用于配置低16個GPIO, ICR2 用于配置高 16 個 GPIO,以 ICR1 為例子:暫存器結構如下:

兩位一組控制一個 GPIO 的中斷,和 STM32 的中斷類似,每一組可配置的選線如下:

| 位設定 | 速度 |
|---|---|
| 00 | 低電平觸發 |
| 01 | 高電平觸發 |
| 10 | 上升沿觸發 |
| 11 | 下降沿觸發 |
比如要設定 GPIO1_IO15 為上升沿觸發中斷,那么使用 GPIO1.ICR1=2<<30 就可以設定
IMR : 中斷屏蔽暫存器,一個 GPIO 對應一個位,IMR 暫存器用來控制 GPIO 的中斷禁止和使能,1 對應中斷使能,0 則是禁止

**ISR 是中斷狀態暫存器 ** :一個 GPIO 對應一個位,只要某個 GPIO 的中斷發生,那么 ISR 中相應的位就會被置 1,通過讀取值判斷中斷有沒有發生
注意:處理完中斷以后,必須清除中斷標志位,清除方法就是向 ISR 中相應的位寫 1 清零

EDGE_SEL 暫存器用來設定邊沿中斷,該暫存器會覆寫 ICR1 和 ICR2 的設定,同樣是一 個 GPIO 對應一個位,如果相應的位被置 1,那么就相當與設定了對應的 GPIO 是上升沿和下降 沿(雙邊沿)觸發,暫存器如下

1.5 I.MX6UL時鐘使能
I.MX6U 有復雜的時鐘系統,每個外設的時鐘都可以獨立的使能或禁止,這樣可以關閉掉不使用的外設時鐘,起到 省電的目的,時鐘系統后面學習到在分析,當前先研究 IO 時鐘如何使能
時鐘系統有關的模塊叫做 Clock Controller Module(CCM) ,其中控制時鐘使能的暫存器為CCM_CCGR0~CCM_CCGR6 這 7 個暫存器,這 7 個暫存器控制著 I.MX6U 的所有外設時鐘開關,CCM_CCGR0 結構體如圖:

每 2 位控制一個外設的時鐘,控制功能如下:
| 位設定 | 時鐘控制 |
|---|---|
| 00 | 所有模式下都關閉外設時鐘, |
| 01 | 只有在運行模式下打開外設時鐘,等待模式和停止模式下均關閉外設時鐘, |
| 10 | 未使用(保留位), |
| 11 | 除了停止模式以外,其他所有模式下時鐘都打開, |
要使能對應的時鐘只要置位對應的時鐘控制位就行!
二、開發板原理圖
正點原子阿爾法LED燈原理圖如下:

LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03
三、程式撰寫
程式撰寫按照下面的流程進行撰寫:
- 使能IO時鐘
- 設定IO復用功能
- 配置IO運行功能
- 配置具體GPIO暫存器
- 設定輸入輸出
- 使能IO時鐘
配置 CCM 的 CCGR0-6 暫存器,開啟所有時鐘
讀取立即數到 R0 、 R1,通過暫存器間接尋址將 R1 的值賦值給目標地址
ldr r0, =0X020C4068 # CCGR0
ldr r1, =0XFFFFFFFF
str r1, [r0]
ldr r0, =0X020C406C # CCGR1
str r1, [r0]
ldr r0, =0X020C4070 # CCGR2
str r1, [r0]
ldr r0, =0X020C4074 # CCGR3
str r1, [r0]
ldr r0, =0X020C4078 # CCGR4
str r1, [r0]
ldr r0, =0X020C407C # CCGR5
str r1, [r0]
ldr r0, =0X020C4080 # CCGR6
str r1, [r0]
- 設定IO復用功能
ldr r0, =0X020E0068 # 將暫存器 SW_MUX_GPIO1_IO03_BASE 地址加載到 r0 中
ldr r1, =0X5
str r1,[r0] # 設定暫存器 SW_MUX_GPIO1_IO03_BASE 的 MODE 為5
- 配置IO運行功能
# 模式配置
# bit 16:0 HYS關閉
# bit [15:14]: 00 默認下拉
# bit [13]: 0 kepper功能
# bit [12]: 1 pull/keeper使能
# bit [11]: 0 關閉開路輸出
# bit [7:6]: 10 速度100Mhz
# bit [5:3]: 110 R0/6驅動能力
# bit [0]: 0 低轉換率
# 暫存器 SW_PAD_GPIO1_IO03_BASE
ldr r0, =0X020E02F4
ldr r1, =0X10B0
str r1,[r0]
- 配置具體GPIO暫存器
# 暫存器GPIO1_GDIR
ldr r0, =0X0209C004
# 配置為輸出模式
ldr r1, =0X0000008
str r1,[r0]
- 設定GPIO輸入輸出值
# 暫存器GPIO1_DR
ldr r0, =0X0209C000
# 輸出低電平
ldr r1, =0
str r1,[r0]
在開頭添加一個全域入口宣告代碼
.global _start
_start
# 需要運行的代碼
結尾加一個死回圈,防止程式結束
loop:
b loop
四、編譯下載
編譯使用 makefile 進行編譯鏈接得到 .elf 檔案,之后轉化為 .bin 檔案,通過 imxdownload 到 sd 下插到開發板上進行 SD 啟動,具體步驟可以參考我之前的文章: Linux驅動開發:I.MX6UL 程式編譯下載(SD卡)
五、實驗現象
下載程式后,LED 燈點亮

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/297214.html
標籤:其他
