IMX6ULL學(xué)習(xí)筆記(13)——GPIO接口使用(匯編方式)

一把兔、GPIO簡(jiǎn)介

i.MX6ULL 芯片的 GPIO 被分成 5 組,并且每組 GPIO 的數(shù)量不盡相同,例如 GPIO1 擁有 32 個(gè)引腳声畏, GPIO2 擁有 22 個(gè)引腳喝检, 其他 GPIO 分組的數(shù)量以及每個(gè) GPIO 的功能請(qǐng)參考 《i.MX 6UltraLite Applications Processor Reference Manual》 第26章General Purpose Input/Output (GPIO)(P1133)俏蛮。


通過(guò) GPIO 硬件結(jié)構(gòu)框圖,就可以從整體上深入了解 GPIO 外設(shè)及它的各種應(yīng)用模式麦撵。

1.1 IO命名

打開(kāi) i.MX6ULL 參考手冊(cè)的第 32 章“Chapter 32: IOMUX Controller(IOMUXC)”


i.MX6ULL 的 IO 分為兩類:SNVS 域的和通用的刽肠,這兩類 IO 本質(zhì)上都是一樣的。

“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 等等。他是 根據(jù)某個(gè) IO 所擁有的功能來(lái)命名的扼雏。比如我們一看到 GPIO1_IO01 就知道這個(gè)肯定能做 GPIO坚嗜,看到 UART1_TX_DATA 肯定就知道這個(gè) IO 肯定能做為 UART1 的發(fā)送引腳夯膀。

IO 復(fù)用功能。 i.MX6ULL 除了 GPIO1_IO00~GPIO1_IO09 引腳外苍蔬,其它 IO 也是可以復(fù)用為 GPIO 功能诱建。同樣的,GPIO1_IO00~GPIO_IO09 也是可以復(fù)用為其它外設(shè)引腳碟绑。

1.2 IO復(fù)用

IOMUX 譯為 IO 復(fù)用選擇器俺猿。i.MX6ULL 的芯片每個(gè) GPIO 都通過(guò) IOMUX 支持多種功能, 例如一個(gè) IO 可用于網(wǎng)絡(luò)外設(shè) ENET 的數(shù)據(jù)接收引腳蜈敢,也可以被配置成 PWM 外設(shè)的輸出引腳辜荠, 這樣的設(shè)計(jì)大大增加了芯片的適用性,這樣可選的功能就是由 IOMUX 實(shí)現(xiàn)的抓狭。IOMUX 相當(dāng)于增加了多根內(nèi)部信號(hào)線與 IO 引腳相連伯病,最多有 8 根,也就是說(shuō)一個(gè) IO 最多可支持 8 種可選的功能否过。

以“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”這個(gè) IO 為例午笛,打開(kāi)參考手冊(cè)的 1568 頁(yè)。



可以看到有個(gè)名為:IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 的寄存器苗桂,寄存器地址為 0X020E005C药磺,這個(gè)寄存器是 32 位的,但是只用到了最低 5 位煤伟,其中 bit0~bit3(MUX_MODE) 就是設(shè)置 GPIO1_IO00 的復(fù)用功能的癌佩。GPIO1_IO00 一共可以復(fù)用為 9 種功能 IO,分別對(duì)應(yīng) ALT0~ALT8便锨,其中 ALT5 就是作為 GPIO1_IO00围辙。GPIO1_IO00 還可以作為 I2C2_SCL、GPT1_CAPTURE1放案、ANATOP_OTG1_ID 等姚建。

1.3 IO配置

IOMUX 由其左側(cè)的 IOMUXC 控制(C表示Controler),IOMUXC 提供寄存器給用戶進(jìn)行配置吱殉, 它又分成 MUX Mode(IO模式控制) 以及 Pad Settings(Pad配置) 兩個(gè)部分:

在 IOMUXC 外設(shè)中關(guān)于 MUX Mode 和 Pad Settings 寄存器命名格式如下:

IOMUXC控制類型 寄存器名稱
MUX Mode IOMUXC_SW_MUX_CTL_PAD_XXXX
Pad Settings IOMUXC_SW_PAD_CTL_PAD_XXXX

每個(gè)引腳都包含這兩個(gè)寄存器掸冤,表中的XXXX表示引腳的名字

1.3.1 MUX Mode配置

MUX Mode 就是用來(lái)配置引腳的復(fù)用功能,即選擇引腳具體是用于網(wǎng)絡(luò)外設(shè) ENET 的數(shù)據(jù)接收友雳, 還是用于 PWM 外設(shè)的輸出引腳稿湿,當(dāng)然,也可以配置成普通的 IO 口押赊,僅用于控制輸出高低電平饺藤。

以 GPIO1_IO04 引腳為例對(duì) MUX 寄存器進(jìn)行說(shuō)明,該引腳相應(yīng)的 MUX 寄存器在參考手冊(cè)中的描述如下:

該寄存器主要有兩個(gè)配置域,分別是 SIONMUX_MODE策精。

  • SION: 用于設(shè)置引腳在輸出模式下同時(shí)開(kāi)啟輸入通道舰始。
  • MUX_MODE: 使用 4 個(gè)寄存器位表示可選的 ALT0~ALT7 這 8 個(gè)模式。
    • 如 ALT2 模式就是用于 USB 外設(shè)的 USB_OTG1_PWR 信號(hào)咽袜;
    • 若配置為 ALT5 則引腳會(huì)用作普通的 GPIO 功能丸卷, 用于輸出高、低電平询刹。

1.3.2 Pad Settings配置

Pad Settings 用于配置引腳的屬性谜嫉,例如驅(qū)動(dòng)能力,是否使用上下拉電阻凹联, 是否使用保持器沐兰,是否使用開(kāi)漏模式以及使用施密特模式還是CMOS模式等。

以 GPIO1_IO04 引腳中 PAD 寄存器在參考手冊(cè)中的描述如下:

相對(duì)來(lái)說(shuō) PAD 寄存器的配置項(xiàng)就更豐富了蔽挠,而且圖中僅是該寄存器的部分說(shuō)明住闯,如 HYS 設(shè)置使用施密特模式的滯后功能,PUS 配置上下拉電阻的阻值澳淑, 其它的還包含PUE比原、PKE、ODE杠巡、SPEED量窘、DSE 及 SRE 的配置。

1.3.3 PAD(可跳過(guò)不看)

PAD 代表了一個(gè) i.MX6ULL 的 GPIO 引腳氢拥。在它的左側(cè)是一系列信號(hào)通道及控制線蚌铜,如 input_on 控制輸入開(kāi)關(guān),Dir 控制引腳的輸入輸出方向嫩海,Data_out 控制引腳輸出高低電平冬殃,Data_in 作為信號(hào)輸入,這些信號(hào)都經(jīng)過(guò)一個(gè) IOMUX 的器件連接到左側(cè)的寄存器出革。

①PAD引腳
代表一個(gè)i.MX6ULL的引腳造壮。
②輸出緩沖區(qū)
當(dāng)輸出緩沖區(qū)使能時(shí)渡讼,引腳被配置為輸出模式骂束。在輸出緩沖區(qū)中,又包含了如下的屬性配置:

  • DSE驅(qū)動(dòng)能力
    當(dāng)IO用作輸出的時(shí)候用來(lái)設(shè)置IO的驅(qū)動(dòng)能力成箫。DSE可以調(diào)整芯片內(nèi)部與引腳串聯(lián)電阻R0的大小展箱,從而改變引腳的驅(qū)動(dòng)能力。例如蹬昌,R0的初始值為260歐姆混驰,在3.3V電壓下其電流驅(qū)動(dòng)能力為12.69mA,通過(guò)DSE可以把R0的值配置為原值的1/2、1/3…1/7等栖榨。

    位設(shè)置 速度
    000 輸出驅(qū)動(dòng)關(guān)閉
    001 R0(3.3V 下 R0 是 260Ω昆汹,1.8V 下 R0 是 150Ω,接 DDR 的時(shí)候是 240Ω)
    010 R0/2
    011 R0/3
    100 R0/4
    101 R0/5
    110 R0/6
    111 R0/7
  • SRE壓擺率配置
    設(shè)置壓擺率婴栽。壓擺率是指電壓轉(zhuǎn)換速率满粗,可理解為電壓由波谷升到波峰的時(shí)間。增大壓擺率可減少輸出電壓的上升時(shí)間愚争。i.MX6ULL的引腳通過(guò)SRE支持低速和高速壓擺率這兩種配置映皆。當(dāng)此位為0的時(shí)候是低壓擺率,當(dāng)為1的時(shí)候是高壓擺率轰枝。壓擺率是大信號(hào)特性捅彻,下面的帶寬是小信號(hào)特性。

  • SPEED帶寬配置
    設(shè)置IO的帶寬鞍陨。分別可設(shè)置為50MHz步淹、100MHz以及200MHz。帶寬的意思是能通過(guò)這個(gè)IO口最高的信號(hào)頻率诚撵,通俗點(diǎn)講就是方波不失真贤旷,如果超過(guò)這個(gè)頻率方波就變正弦波。但是這個(gè)帶寬要區(qū)別于IO的翻轉(zhuǎn)速率砾脑,IO的翻轉(zhuǎn)速率的信號(hào)來(lái)自于GPIO這個(gè)外設(shè)幼驶,而IO的帶寬只是限制了IO口引腳的物理特性,IO口的信號(hào)可以來(lái)自于內(nèi)部定時(shí)器輸出的PWM信號(hào)韧衣,也可以來(lái)自于GPIO翻轉(zhuǎn)輸出的信號(hào)盅藻,兩者相比之下,PWM信號(hào)的頻率是遠(yuǎn)遠(yuǎn)高于GPIO翻轉(zhuǎn)輸出的信號(hào)頻率畅铭。

    位設(shè)置 速度
    00 低速 50M
    01 中速 100M
    10 中速 100M
    11 最大速度 200M
  • ODE開(kāi)漏輸出配置
    設(shè)置引腳是否工作在開(kāi)漏輸出模式氏淑。在該模式時(shí)引腳可以輸出高阻態(tài)和低電平,此位為0的時(shí)候禁止開(kāi)路輸出硕噩,當(dāng)此位為1的時(shí)候就使能開(kāi)路輸出功能假残。輸出高阻態(tài)時(shí)可由外部上拉電阻拉至高電平。開(kāi)漏輸出模式常用在一些通訊總線中炉擅,如I2C辉懒。

③輸入緩沖區(qū)
當(dāng)輸入緩沖區(qū)使能時(shí),引腳被配置為輸入模式谍失。在輸入緩沖區(qū)中眶俩,又包含了如下的屬性配置:

  • HYS滯后使能
    用來(lái)使能遲滯比較器。i.MX6ULL的輸入檢測(cè)可以使用普通的CMOS檢測(cè)或施密特觸發(fā)器模式(滯后模式)快鱼。施密特觸發(fā)器具有滯后效應(yīng)颠印,對(duì)正向和負(fù)向變化的輸入信有不同的閾值電壓纲岭。如果需要對(duì)輸入波形進(jìn)行整形的話可以使能此位。此位為0的時(shí)候禁止遲滯比較器线罕,為1的時(shí)候使能遲滯比較器止潮。常被用于電子開(kāi)關(guān)、波形變換等場(chǎng)合钞楼,其轉(zhuǎn)換特性和對(duì)比如下沽翔,如檢測(cè)按鍵時(shí),使用施密特模式即可起到消抖的功能窿凤。

④Pull/Keeper上下拉仅偎、保持器
引腳的控制邏輯中還包含了上下拉、保持器的功能雳殊。芯片內(nèi)部的上拉和下拉電阻可以將不確定的信號(hào)鉗位在高橘沥、低電平,或小幅提高的電流輸出能力夯秃,上拉提供輸出電流座咆,下拉提供輸入電流。注意這些上下拉配置只是弱拉仓洼,對(duì)于類似I2C之類的總線介陶,還是必須使用外部上拉電阻。i.MX6ULL芯片的電源模塊中包含轉(zhuǎn)換器色建,當(dāng)轉(zhuǎn)換器停止工作時(shí)哺呜,保持器會(huì)保持輸入輸出電壓。

上下拉箕戳、保持器可以通過(guò)如下屬性配置:

  • PUS上下拉配置
    設(shè)置上下拉電阻某残。PUS可配置項(xiàng)可選為100K歐下拉以及22K歐、47K歐及100K歐上拉陵吸。
    位設(shè)置 含義
    00 100K 下拉
    01 47K 上拉
    10 100K 上拉
    11 22K 上拉
  • PUE上下拉玻墅、保持器選擇
    上下拉功能和保持器功能是二選一的,可以通過(guò)PUE來(lái)選擇壮虫。當(dāng)IO作為輸入的時(shí)候澳厢,這個(gè)位用來(lái)設(shè)置 IO 使用上下拉還是狀態(tài)保持器。當(dāng)為0的時(shí)候使用狀態(tài)保持器囚似,當(dāng)為1的時(shí)候使用上下拉剩拢。狀態(tài)保持器在IO作為輸入的時(shí)候才有用,顧名思義谆构,就是當(dāng)外部電路斷電以后此IO口可以保持住以前的狀態(tài)裸扶。
  • PKE上下拉框都、保持器配置
    用來(lái)使能或者禁止上下拉/狀態(tài)保持器功能搬素。為0時(shí)禁止上下拉/狀態(tài)保持器呵晨,為1時(shí)使能上下拉和狀態(tài)保持器。

注意熬尺,當(dāng)引腳被配置為輸出模式時(shí)摸屠,不管上下拉、保持器是什么配置粱哼,它們都會(huì)被關(guān)閉季二。

1.4 GPIO配置

GPIO 模塊是每個(gè) IO 都具有的外設(shè),它具有 IO 控制最基本的功能揭措,如輸出高低電平胯舷、檢測(cè)電平輸入等。 它也占用 IOMUX 分配的復(fù)用信號(hào)绊含,也就是說(shuō)使用 GPIO 模塊功能時(shí)同樣需要使用 IOMUX 選中 GPIO 外設(shè)桑嘶,對(duì)其 GPIO 的功能進(jìn)行配置。


1.4.1 GDIR方向寄存器

設(shè)置某個(gè) IO 的工作方向躬充。控制一個(gè) GPIO 引腳時(shí)逃顶,要先用 GDIR 方向寄存器配置該引腳用于輸出電平信號(hào)還是用作輸入檢測(cè)。 典型的例子是使用輸出模式可以控制LED燈的亮滅充甚,輸入模式時(shí)可以用來(lái)檢測(cè)按鍵是否按下以政。

GDIR 寄存器的每一個(gè)數(shù)據(jù)位代表一個(gè)引腳的方向,對(duì)應(yīng)的位被設(shè)置為0時(shí)該引腳為輸入模式伴找,被設(shè)置為1時(shí)該引腳為輸出模式盈蛮。

例如,對(duì) GPIO1 的 GDIR 寄存器的 bit3 位被寫(xiě)入為 1技矮,那么 GPIO1.3 引腳的模式即為輸出眉反。

1.4.2 DR數(shù)據(jù)寄存器

DR 數(shù)據(jù)寄存器直接代表了引腳的電平狀態(tài),它也使用 1 個(gè)數(shù)據(jù)位表示 1 個(gè)引腳的電平穆役,每位用 1 表示高電平寸五,用 0 表示低電平。

當(dāng) GDIR 方向寄存器設(shè)置引腳為輸出模式時(shí)耿币,寫(xiě)入 DR 數(shù)據(jù)寄存器對(duì)應(yīng)的位即可控制該引腳輸出的電平狀態(tài)梳杏, 如這時(shí) GPIO1 的 DR 寄存器的 bit4 被寫(xiě)入為 1,則引腳為輸出高電平淹接。

當(dāng) GDIR 方向寄存器設(shè)置引腳為輸入模式時(shí)十性,讀取 DR 數(shù)據(jù)寄存器對(duì)應(yīng)的位即可獲取該引腳當(dāng)前的輸入電平狀態(tài),例如這里讀取 GPIO1 的DR寄存器的 bit4塑悼,得到該位的值為 0劲适,表示當(dāng)前引腳的輸入狀態(tài)為低電平。


1.4.3 PSR引腳狀態(tài)寄存器

讀取相應(yīng)的位即可獲取對(duì)應(yīng)的 GPIO 的狀態(tài)厢蒜,也就是 GPIO 的高低電平值霞势。PSR 引腳狀態(tài)寄存器相當(dāng)于 DR 寄存器的簡(jiǎn)化版烹植,它僅在 GDIR 方向寄存器設(shè)置為輸入模式時(shí)有效,它的每個(gè)位表示一個(gè)引腳當(dāng)前的輸入電平狀態(tài)愕贡。PSR 寄存器的權(quán)限是只讀的草雕,對(duì)它進(jìn)行寫(xiě)操作是無(wú)效的。

特別地固以,當(dāng)引腳被配置成輸出模式時(shí)墩虹,若 IOMUXC 中的 MUX 寄存器使能了 SION 功能(輸出通道回環(huán)至輸入), 可以通過(guò) PSR 寄存器讀取回引腳的狀態(tài)值憨琳。

二诫钓、引腳確定

我使用的是 野火_EBF6ULL S1 Pro 開(kāi)發(fā)板


從原理圖可看到 RGB 燈的三個(gè)陰極 R、G篙螟、B 連接分別連接至標(biāo)號(hào) GPIO_4尖坤、CSI_HSYNCCSI_VSYNC闲擦, 這些標(biāo)號(hào)實(shí)際上與配套核心板上 i.MX6ULL 芯片的引腳相連慢味。由于引腳功能眾多, 繪制原理圖時(shí)不可避免地?zé)o法完全表示引腳信息的所有信息墅冷。而無(wú)論是具體的引腳名還是復(fù)用功能纯路, 我們都無(wú)法直接得知這些具體是 i.MX6ULL 芯片的哪個(gè)引腳。我們需要知道這些引腳是對(duì)應(yīng)的具體 GPIO寞忿,這樣我們才能編寫(xiě)程序進(jìn)行控制驰唬。

由于還不清楚標(biāo)號(hào) GPIO_4CSI_HSYNC腔彰、CSI_VSYNC 的具體引腳名叫编,我們首先要在核心板原理圖中查看它與 i.MX6ULL 芯片的關(guān)系。打開(kāi) 《野火_EBF6ULL S1 郵票孔核心板V1.0原理圖》霹抛,在PDF閱讀器的搜索框輸入前面的 GPIO_4搓逾、CSI_HSYNCCSI_VSYNC 標(biāo)號(hào)杯拐。


查找到了 GPIO_4 信號(hào)的具體引腳名為 GPIO1_IO04霞篡。 但是當(dāng)我們使用同樣的方法查找時(shí)發(fā)現(xiàn)只能找到 CSI_HSYNCCSI_VSYNC端逼, 并沒(méi)有我們熟悉的 GPIOx_IOx 標(biāo)注的引腳名朗兵。這兩個(gè)引腳默認(rèn)情況下不用作 GPIO,而是用作攝像頭的某一功能引腳顶滩,但是它可以復(fù)用為 GPIO余掖,我們?cè)趺凑业綄?duì)應(yīng)的 GPIO 呢?

  • 方法一:
    《i.MX 6UltraLite Applications Processor Reference Manual》的第4章 External Signals and Pin Multiplexing 搜索引腳名

  • 方法二:
    在官方寫(xiě)好的文件 fsl_iomuxc.h(路徑:SDK文件夾/devices/MCIMX6Y2/drivers/fsl_iomuxc.h) 中搜索引腳名

經(jīng)查閱礁鲁,我們把以上連接 LED 燈的各個(gè) i.MX6ULL 芯片引腳總結(jié)出如表:

LED燈 原理圖的標(biāo)號(hào) 具體引腳名 GPIO端口及引腳編號(hào)
R燈 GPIO_4 GPIO1_IO04 GPIO1_IO04
G燈 CSI_HSYNC CSI_HSYNC GPIO4_IO20
B燈 CSI_VSYNC CSI_VSYNC GPIO4_IO19

三盐欺、編程流程

1. 開(kāi)啟GPIO時(shí)鐘
2. 設(shè)置引腳的復(fù)用功能以及引腳屬性
3. 設(shè)置引腳方向以及輸出電平

四赁豆、編程代碼

4.1 完整代碼

/*************************第一部分*************************/
.text            //代碼段
.align 2         //設(shè)置2字節(jié)對(duì)齊
.global _start   //定義一個(gè)全局標(biāo)號(hào)

/*************************第二部分*************************/
_start:          //程序的開(kāi)始
   b reset      //跳轉(zhuǎn)到reset標(biāo)號(hào)處

/*************************第三部分*************************/
reset:
   mrc     p15, 0, r0, c1, c0, 0     /*  將 CP15 協(xié)處理器中的寄存器數(shù)據(jù)讀到 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位)禁止嚴(yán)格對(duì)齊   */
   bic     r0,  r0, #(0x1 << 11)     /*  清除第11位(Z位)分支預(yù)測(cè)   */
   bic     r0,  r0, #0x1             /*  清除第 0位(M位)禁用 MMU   */
   mcr     p15, 0, r0, c1, c0, 0     /*  將 ARM 寄存器的數(shù)據(jù)寫(xiě)入到 CP15 協(xié)處理器寄存器中   */

/*************************第四部分*************************/
   /*跳轉(zhuǎn)到light_led函數(shù)*/
   bl light_led
   /*進(jìn)入死循環(huán)*/
 /*************************第五部分*************************/
loop:
   b loop


/*************************第六部分*************************/
/*CCM_CCGR1 時(shí)鐘使能寄存器地址,默認(rèn)時(shí)鐘全部開(kāi)啟*/
#define gpio1_clock_enible_ccm_ccgr1  0x20C406C


/*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04
寄存器地址找田,用于設(shè)置GPIO1_iIO04的復(fù)用功能*/
#define gpio1_io04_mux_ctl_register  0x20E006C
/*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04寄存器地址歌憨,用于設(shè)置GPIO的PAD屬性*/
#define gpio1_io04_pad_ctl_register  0x20E02F8


/*GPIO1_GDIR寄存器着憨,用于設(shè)置GPIO為輸入或者輸出*/
#define  gpio1_gdir_register  0x0209C004
/*GPIO1_DR寄存器墩衙,用于設(shè)置GPIO輸出的電平狀態(tài)*/
#define  gpio1_dr_register  0x0209C000



/*************************第七部分*************************/
light_led:
   /*開(kāi)啟GPIO1的時(shí)鐘*/
   ldr r0, =gpio1_clock_enible_ccm_ccgr1
   ldr r1, =0xFFFFFFFF
   str r1, [r0]

/*************************第八部分*************************/
   /*將PAD引腳復(fù)用為GPIO*/
   ldr r0, =gpio1_io04_mux_ctl_register
   ldr r1, =0x5
   str r1, [r0]

/*************************第九部分*************************/
   /*設(shè)置GPIO PAD屬性*/
   ldr r0, =gpio1_io04_pad_ctl_register
   ldr r1, =0x1F838
   str r1, [r0]
/*************************第十部分*************************/
   /*將GPIO_GDIR.[4] 設(shè)置為1, gpio1_io04設(shè)置為輸出模式*/
   ldr r0, =gpio1_gdir_register
   ldr r1, =0x10
   str r1, [r0]

/*************************第十一部分*************************/
   /*將GPIO_DR 設(shè)置為0甲抖, gpio1全部輸出為低電平*/
   ldr r0, =gpio1_dr_register
   ldr r1, =0x0
   str r1, [r0]

/*************************第十二部分*************************/
   /*跳出light_led函數(shù)漆改,返回跳轉(zhuǎn)位置*/
   mov pc, lr

4.2 分析代碼

在 Ubuntu 下創(chuàng)建 led.S 文件用于編寫(xiě) LED 匯編驅(qū)動(dòng)代碼。

  • 第一部分
    .text 定義代碼段准谚。
    .align 2 設(shè)置字節(jié)對(duì)齊挫剑。
    .global _start 生命全局標(biāo)號(hào)_start。
/*************************第一部分*************************/
.text            //代碼段
.align 2         //設(shè)置2字節(jié)對(duì)齊
.global _start   //定義一個(gè)全局標(biāo)號(hào)
  • 第二部分
    _start: 定義標(biāo)號(hào)_start: 柱衔,它位于匯編的最前面樊破,說(shuō)以會(huì)首先被執(zhí)行。
    b reset 使用b指令將程序跳轉(zhuǎn)到reset標(biāo)號(hào)處唆铐。
/*************************第二部分*************************/
_start:          //程序的開(kāi)始
   b reset      //跳轉(zhuǎn)到reset標(biāo)號(hào)處
  • 第三部分
    通過(guò)修改CP15寄存器(系統(tǒng)控制寄存器) 關(guān)閉 I Cache 哲戚、D Cache、MMU 等等艾岂。
    我們暫時(shí)用不到的功能顺少,如果開(kāi)啟可能會(huì)影響我們裸機(jī)運(yùn)行,為避免不必要的麻煩暫時(shí)關(guān)閉這些功能王浴。
/*************************第三部分*************************/
reset:
   mrc     p15, 0, r0, c1, c0, 0     /*  將 CP15 協(xié)處理器中的寄存器數(shù)據(jù)讀到 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位)禁止嚴(yán)格對(duì)齊   */
   bic     r0,  r0, #(0x1 << 11)     /*  清除第11位(Z位)分支預(yù)測(cè)   */
   bic     r0,  r0, #0x1             /*  清除第 0位(M位)禁用 MMU   */
   mcr     p15, 0, r0, c1, c0, 0     /*  將 ARM 寄存器的數(shù)據(jù)寫(xiě)入到 CP15 協(xié)處理器寄存器中   */
  • 第四部分
    bl light_led 執(zhí)行跳轉(zhuǎn)指令脆炎,代碼將跳轉(zhuǎn)到函數(shù)“l(fā)ight_led”執(zhí)行。
    “bl”指令是“可返回”跳轉(zhuǎn)氓辣,跳轉(zhuǎn)之前的執(zhí)行地址保存在lr(連接寄存器)中秒裕。
    “l(fā)ight_led” 函數(shù)實(shí)現(xiàn)位于第六到十二部分。
/*************************第四部分*************************/
   /*跳轉(zhuǎn)到light_led函數(shù)*/
   bl light_led
   /*進(jìn)入死循環(huán)*/
  • 第五部分
    light_led函數(shù)返回后就會(huì)執(zhí)行標(biāo)號(hào)loop處的代碼钞啸,而標(biāo)號(hào)loop處只有一條指令 b loop簇爆, 這個(gè)指令是代碼再次跳轉(zhuǎn)到loop標(biāo)號(hào)處,所以這是一個(gè)死循環(huán)爽撒。
/*************************第五部分*************************/
loop:
   b loop
  • 第六部分
    定義我們用到的寄存器地址入蛆。
    配置時(shí)鐘使能寄存器地址 設(shè)置時(shí)鐘控制寄存器CCM_CCGR1的地址如下:

    配置MUX Mode寄存器地址 MUX Mode用于設(shè)置GPIO1_IO04的復(fù)用功能。配置成普通的IO口硕勿,僅用于控制輸出高低電平哨毁。寄存器地址如下:

    配置Pad Settings寄存器地址 Pad Settings用于設(shè)置GPIO的PAD屬性。例如驅(qū)動(dòng)能力源武,是否使用上下拉電阻扼褪, 是否使用保持器想幻,是否使用開(kāi)漏模式以及使用施密特模式還是CMOS模式等。寄存器地址如下:
/*************************第六部分*************************/
/*CCM_CCGR1 時(shí)鐘使能寄存器地址话浇,默認(rèn)時(shí)鐘全部開(kāi)啟*/
#define gpio1_clock_enible_ccm_ccgr1  0x20C406C


/*IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04
寄存器地址脏毯,用于設(shè)置GPIO1_IO04的復(fù)用功能*/
#define gpio1_io04_mux_ctl_register  0x20E006C
/*IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04寄存器地址,用于設(shè)置GPIO的PAD屬性*/
#define gpio1_io04_pad_ctl_register  0x20E02F8


/*GPIO1_GDIR寄存器幔崖,用于設(shè)置GPIO為輸入或者輸出*/
#define  gpio1_gdir_register  0x0209C004
/*GPIO1_DR寄存器食店,用于設(shè)置GPIO輸出的電平狀態(tài)*/
#define  gpio1_dr_register  0x0209C000
  • 第七部分
    開(kāi)啟GPIO1的時(shí)鐘。
    設(shè)置的時(shí)鐘控制寄存器 CCM_CCGR1赏寇。

從上表中可以看出CCM_CCGR1[26:27]用于使能GPIO1的時(shí)鐘吉嫩,這里不僅僅設(shè)置時(shí)鐘的開(kāi)或者關(guān), 還可以設(shè)置在芯片在不同工作模式下的時(shí)鐘狀態(tài)如下表:

CCM_CCGR1[26:27]的值 時(shí)鐘狀態(tài)描述
00 時(shí)鐘在所有模式下都是關(guān)閉的
01 時(shí)鐘在運(yùn)行模式下為開(kāi)嗅定,但在等待和停止模式下為關(guān)
10 保留
11 除停止模式外自娩,時(shí)鐘一直開(kāi)啟

我們將CCM_CCGR1[26:27]設(shè)置為11(二進(jìn)制)即可。仔細(xì)觀察可以發(fā)現(xiàn)發(fā)現(xiàn)CCM_CCGR1寄存器默認(rèn)全為1渠退,即默認(rèn)開(kāi)啟了時(shí)鐘忙迁。 為了程序規(guī)范我們?cè)俅问褂么a開(kāi)啟時(shí)鐘。將CCM_CCGR1寄存器設(shè)置全為1碎乃。

ldr r0, =gpio1_clock_enible_ccm_ccgr1 從存儲(chǔ)器Rn+offset(即gpio1_clock_enible_ccm_ccgr1)的位置讀取數(shù)據(jù)存放到r0中姊扔。
str r1, [r0] 將r1中的數(shù)據(jù)寫(xiě)入到存儲(chǔ)器中的Rn+offset(即r0的指向)位置。

/*************************第七部分*************************/
light_led:
   /*開(kāi)啟GPIO1的時(shí)鐘*/
   ldr r0, =gpio1_clock_enible_ccm_ccgr1
   ldr r1, =0xFFFFFFFF
   str r1, [r0]
  • 第八部分
    設(shè)置引腳復(fù)用功能為GPIO荠锭。
    這里設(shè)置的是GPIO1_04的引腳復(fù)用寄存器旱眯,我們直接搜索 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04 可以找到如下所示的寄存器。

從上圖可知IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04[MUX_MODE]=0101(二進(jìn)制)時(shí)GPIO1_04復(fù)用功能是GPIO证九。所以在程序中我們將0x5寫(xiě)入該寄存即可删豺。

/*************************第八部分*************************/
   /*將PAD引腳復(fù)用為GPIO*/
   ldr r0, =gpio1_io04_mux_ctl_register
   ldr r1, =0x5
   str r1, [r0]
  • 第九部分
    設(shè)置引腳的PAD屬性。
    這里設(shè)置的是GPIO1_04的引腳PAD屬性寄存器“IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04”
/*************************第九部分*************************/
   /*設(shè)置GPIO PAD屬性*/
   ldr r0, =gpio1_io04_pad_ctl_register
   ldr r1, =0x1F838
   str r1, [r0]
  • 第十部分
    設(shè)置GPIO為輸出模式愧怜。
/*************************第十部分*************************/
   /*將GPIO_GDIR.[4] 設(shè)置為1呀页, gpio1_io04設(shè)置為輸出模式*/
   ldr r0, =gpio1_gdir_register
   ldr r1, =0x10
   str r1, [r0]
  • 第十一部分
    設(shè)置GPIO輸出電平為低電平。
/*************************第十一部分*************************/
   /*將GPIO_DR 設(shè)置為0拥坛, gpio1全部輸出為低電平*/
   ldr r0, =gpio1_dr_register
   ldr r1, =0x0
   str r1, [r0]
  • 第十二部分
    從light_led函數(shù)返回蓬蝶。在第四部分說(shuō)到,我們使用“bl”指令跳轉(zhuǎn)到light_led函數(shù)執(zhí)行猜惋, “bl”指令是“可返回”的跳轉(zhuǎn)指令丸氛,返回地址保存在“LR”(連接寄存器)里。
    mov pc, lr 將“l(fā)r”寄存器的值寫(xiě)入“pc”寄存器即可著摔。
/*************************第十二部分*************************/
   /*跳出light_led函數(shù)缓窜,返回跳轉(zhuǎn)位置*/
   mov pc, lr

五、編譯下載驗(yàn)證

5.1 編譯生成.bin文件

5.1.1 編譯文件

編譯出在ARM開(kāi)發(fā)板上運(yùn)行的可執(zhí)行文件,所以要使用我們安裝的交叉編譯器arm-linux-gnueabihf-gcc來(lái)編譯禾锤。 編譯出的led.o文件并不是我們可以下載到開(kāi)發(fā)板中運(yùn)行的文件私股,一個(gè)工程中所有的C文件和匯編文件都會(huì)編譯生成一個(gè)對(duì)應(yīng)的.o文件,我們需要將這.o文件鏈接起來(lái)組合成可執(zhí)行文件恩掷。

arm-none-eabi-gcc -g -c led.S -o led.o
  • -g :加入GDB能夠使用的調(diào)試信息,能夠使用GDB調(diào)試倡鲸。
  • -c :對(duì)源程序example.c進(jìn)行預(yù)處理、編譯黄娘、匯編操作峭状,生成example.o文件。
  • led.S :要編譯的源文件寸宏。
  • -o :指定輸出文件的文件名宁炫,不加“-o led.o”默認(rèn)會(huì)輸出led.o偿曙。 正常情況下執(zhí)行該命令后會(huì)在當(dāng)前文件夾下生成led.o文件氮凝。

5.1.2 鏈接文件

arm-linux-gnueabihf-ld用來(lái)將眾多的.o文件鏈接到一個(gè)指定的鏈接地址。這里我們要區(qū)分“存儲(chǔ)地址”和“運(yùn)行地址”這兩個(gè)概念望忆,“存儲(chǔ)地址”就是可執(zhí)行文件存儲(chǔ)在哪里罩阵,可執(zhí)行文件的存儲(chǔ)地址可以隨意選擇∑羯悖“運(yùn)行地址”就是代碼運(yùn)行的時(shí)候所處的地址惩猫,這個(gè)我們?cè)阪溄拥臅r(shí)候就已經(jīng)確定好了检号,代碼要運(yùn)行,那就必須處于運(yùn)行地址處,否則代碼肯定運(yùn)行出錯(cuò)纤壁。比如I.MX6ULL支持SD卡、EMMC空凸、NAND啟動(dòng)避矢,因此代碼可以存儲(chǔ)到SD卡、EMMC或者NAND中龟再,但是要運(yùn)行的話就必須將代碼從SD卡书闸、EMMC或者NAND中拷貝到其運(yùn)行地址(鏈接地址)處,“存儲(chǔ)地址”和“運(yùn)行地址”可以一樣利凑,比如STM32的存儲(chǔ)起始地址和運(yùn)行起始地址都是0X08000000浆劲。上電以后I.MX6ULL的內(nèi)部boot rom程序會(huì)將可執(zhí)行文件拷貝到鏈接地址處,這個(gè)鏈接地址可以在I.MX6UL的內(nèi)部128KB RAM中(0X900000~0X91FFFF)哀澈,也可以在外部的DDR中牌借。led.elf 文件也不是我們最終燒寫(xiě)到SD卡中的可執(zhí)行文件,我們要燒寫(xiě)的.bin文件割按,因此還需要將led.elf文件轉(zhuǎn)換為.bin文件膨报。

arm-none-eabi-ld -Ttext 0x80000000 led.o -o led.elf
  • -Ttext 0x80000000設(shè)置程序代碼段的起始地址為0x80000000。0x80000000是外部?jī)?nèi)存的起始地址。這個(gè)地址是由芯片本身決定的丙躏,我們打開(kāi) 《IMX6ULRM》手冊(cè)在Chapter 2 Memory Maps章節(jié)ARM平臺(tái)內(nèi)存映射表 介紹了這部分內(nèi)容择示,如下所示。
  • -o :指定輸出的文件名晒旅。

5.1.3 格式轉(zhuǎn)換

上一步鏈接生成的.elf文件是帶有地址信息的文件栅盲,不能放在存儲(chǔ)器中執(zhí)行,要使用格式轉(zhuǎn)換命令轉(zhuǎn)化為二進(jìn)制文件废恋。

arm-none-eabi-objcopy -O binary -S -g led.elf led.bin
  • -O binary :指定輸出文件格式為二進(jìn)制文件谈秫。
  • -S選項(xiàng) :不從源文件中復(fù)制重定位信息和符號(hào)信息。
  • -g選項(xiàng) :不從源文件中復(fù)制可調(diào)試信息鱼鼓。

5.1.4 反匯編(可跳過(guò))

大多數(shù)情況下我們都是用C語(yǔ)言寫(xiě)試驗(yàn)例程的拟烫,有時(shí)候需要查看其匯編代碼來(lái)調(diào)試代碼,因此就需要進(jìn)行反匯編迄本,一般可以將elf文件反匯編硕淑。

arm-linux-gnueabihf-objdump -D led.elf > led.dis
  • -D :表示反匯編所有的段,反匯編完成以后就會(huì)在當(dāng)前目錄下出現(xiàn)一個(gè)名為led.dis文件嘉赎。

5.2 代碼燒寫(xiě)

編譯成功后會(huì)在當(dāng)前文件夾下生成.bin文件置媳,這個(gè).bin文件也不能直接放到開(kāi)發(fā)板上運(yùn)行, 這次是因?yàn)樾枰?bin文件缺少啟動(dòng)相關(guān)信息公条。

為二進(jìn)制文件添加頭部信息并燒寫(xiě)到SD卡拇囊。查看 IMX6ULL學(xué)習(xí)筆記(12)——通過(guò)SD卡啟動(dòng)官方SDK程序

進(jìn)入燒寫(xiě)工具目錄,執(zhí)行 ./mkimage.sh <燒寫(xiě)文件路徑> 命令靶橱,例如要燒寫(xiě)的 led.bin 位于 home 目錄下寥袭,則燒寫(xiě)命令為 ./mkimage.sh /home/led.bin

執(zhí)行上一步后會(huì)列出linux下可燒寫(xiě)的磁盤(pán)关霸,選擇你插入的SD卡即可传黄。這一步 非常危險(xiǎn)!Z怂尝江!一定要確定選擇的是你插入的SD卡!英上!炭序,如果選錯(cuò)很可能破壞你電腦磁盤(pán)內(nèi)容,造成數(shù)據(jù)損壞2匀铡2涯簟! 確定磁盤(pán)后SD卡以“sd”開(kāi)頭相恃,選擇“sd”后面的字符即可辜纲。例如要燒寫(xiě)的sd卡是“sdb”則輸入“b”即可。

5.3 實(shí)驗(yàn)現(xiàn)象

將開(kāi)發(fā)板設(shè)置為SD卡啟動(dòng),接入SD卡耕腾,開(kāi)發(fā)板上電见剩,正常情況下可以看到開(kāi)發(fā)板RGB燈紅燈亮。


? 由 Leung 寫(xiě)于 2022 年 12 月 12 日

? 參考:4. 匯編點(diǎn)亮LED燈

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扫俺,一起剝皮案震驚了整個(gè)濱河市苍苞,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌狼纬,老刑警劉巖羹呵,帶你破解...
    沈念sama閱讀 223,126評(píng)論 6 520
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異疗琉,居然都是意外死亡冈欢,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,421評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門(mén)盈简,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凑耻,“玉大人,你說(shuō)我怎么就攤上這事送火∪埃” “怎么了先匪?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,941評(píng)論 0 366
  • 文/不壞的土叔 我叫張陵种吸,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我呀非,道長(zhǎng)坚俗,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,294評(píng)論 1 300
  • 正文 為了忘掉前任岸裙,我火速辦了婚禮猖败,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘降允。我一直安慰自己恩闻,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,295評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布剧董。 她就那樣靜靜地躺著幢尚,像睡著了一般。 火紅的嫁衣襯著肌膚如雪翅楼。 梳的紋絲不亂的頭發(fā)上尉剩,一...
    開(kāi)封第一講書(shū)人閱讀 52,874評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音毅臊,去河邊找鬼理茎。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的皂林。 我是一名探鬼主播朗鸠,決...
    沈念sama閱讀 41,285評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼础倍!你這毒婦竟也來(lái)了童社?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,249評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤著隆,失蹤者是張志新(化名)和其女友劉穎扰楼,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體美浦,經(jīng)...
    沈念sama閱讀 46,760評(píng)論 1 321
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡弦赖,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,840評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了浦辨。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蹬竖。...
    茶點(diǎn)故事閱讀 40,973評(píng)論 1 354
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖流酬,靈堂內(nèi)的尸體忽然破棺而出币厕,到底是詐尸還是另有隱情,我是刑警寧澤芽腾,帶...
    沈念sama閱讀 36,631評(píng)論 5 351
  • 正文 年R本政府宣布旦装,位于F島的核電站,受9級(jí)特大地震影響摊滔,放射性物質(zhì)發(fā)生泄漏阴绢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,315評(píng)論 3 336
  • 文/蒙蒙 一艰躺、第九天 我趴在偏房一處隱蔽的房頂上張望呻袭。 院中可真熱鬧,春花似錦腺兴、人聲如沸左电。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,797評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)篓足。三九已至,卻和暖如春拘泞,著一層夾襖步出監(jiān)牢的瞬間纷纫,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,926評(píng)論 1 275
  • 我被黑心中介騙來(lái)泰國(guó)打工陪腌, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辱魁,地道東北人烟瞧。 一個(gè)月前我還...
    沈念sama閱讀 49,431評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像染簇,于是被迫代替她去往敵國(guó)和親参滴。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,982評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容