1. 程式人生 > >《4.ARM裸機第四部分-GPIO和LED》

《4.ARM裸機第四部分-GPIO和LED》

《4.ARM裸機第四部分-GPIO和LED》

第一部分、章節目錄
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
1.4.2.裸機實驗體驗之SD卡下載
1.4.3.自己動手安裝交叉編譯工具鏈1
1.4.4.自己動手安裝交叉編譯工具鏈2
1.4.5.Makefile大俠隆重登場
1.4.6.mkv210_image.c檔案詳解1
1.4.7.mkv210_image.c檔案詳解2
1.4.8.一步步點亮LED1_硬體工作原理及原理圖查閱
1.4.9.一步步點亮LED2_資料手冊查閱及相關暫存器瀏覽
1.4.10.一步步點亮LED3_從零開始手寫彙編點亮LED
1.4.11.一步步點亮LED4_使用位運算實現複雜點亮要求
1.4.12.一步步點亮LED5_彙編編寫延時函式並實現LED閃爍效果
1.4.13.一步步點亮LED6_再難一點的流水燈效果
1.4.14.反彙編工具objdump的使用簡介

第二部分、章節介紹
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
本節的主要目的是學會從usb啟動,然後使用dnw工具下載裸機程式bin檔案到開發板內部SRAM執行。學完本節要求大家能夠使用usb啟動方式進行裸機程式除錯,以方便後面測試自己寫的程式碼(本節會提供我編譯好的led.bin)。
1.4.2.裸機實驗體驗之SD卡下載
本節的主要目的是學會設定開發板從SD2啟動(需要事先將板載SD0通道的iNand上的bootloader破壞掉),並且學會在Windows中使用燒錄軟體、linux中使用dd命令2種方式來製作啟動SD卡。學完本節要求大家能夠使用SD卡啟動方式進行裸機程式的除錯,以方便後面測試自己寫的程式碼(本節會提供我編譯好的led.bin)。
1.4.3.自己動手安裝交叉編譯工具鏈1
本節首先介紹linux中裝軟體和windows中的不同,然後手把手教大家從零開始自己動手安裝交叉編譯工具鏈並作測試。
1.4.4.自己動手安裝交叉編譯工具鏈2
本節接上節講解如何將安裝的交叉編譯工具鏈匯出到環境變數,並且為工具鏈製作arm-linux-符號連結。
1.4.5.Makefile大俠隆重登場
本節給大家引入Makefile,並且ubuntu環境下簡單介紹Makefile的書寫,目標、依賴等基本概念,最後分析了我們在裸機程式中使用到的Makefile。本節學完要求大家理解Makefile的基本用法,會自己根據需要修改Makefile。
1.4.6.mkv210_image.c檔案詳解1
本節回顧第三部分中講到的S5PV210啟動知識,並且分析SD卡啟動時頭資訊的技術要求,然後引入mkv210_image.c檔案並作簡單分析。
1.4.7.mkv210_image.c檔案詳解2
本節接上節繼續詳細分析mkv210_image.c檔案的技術細節,目的是使大家深入理解本檔案中C程式的工作原理和實現技巧。
1.4.8.一步步點亮LED1_硬體工作原理及原理圖查閱
本節從LED工作原理講起,通過查閱原理圖分析點亮LED的原理和方法。
1.4.9.一步步點亮LED2_資料手冊查閱及相關暫存器瀏覽
本節接上節內容,查閱SoC資料手冊中GPIO暫存器部分,找到板子上LED對應的GPIO並分析操作方法。
1.4.10.一步步點亮LED3_從零開始手寫彙編點亮LED
本節開始寫我們第一個彙編程式,從零開始用最少的程式碼點亮LED,並且使用之前講過的Makefile編譯,然後使用之前實踐過的下載方法下載執行測試。至此,本章點亮LED的目標已經實現。
1.4.11.一步步點亮LED4_使用位運算實現複雜點亮要求
本節以上節的彙編程式碼為基礎,進行必要修改,使用位運算的技巧來實現一些複雜的電燈要求(譬如隔一個亮一個)。學完本節要求大家對位運算有一定掌握,並基本掌握使用位運算來操作SoC暫存器
1.4.12.一步步點亮LED5_彙編編寫延時函式並實現LED閃爍效果
本節接上節並繼續複雜化。引入彙編編寫的延時函式,並通過延時達到LED閃爍顯示的效果。本節學習的目的是加深大家對彙編程式設計的理解,學會用匯編來寫函式並呼叫之,為以後編寫複雜彙編程式打基礎。
1.4.13.一步步點亮LED6_再難一點的流水燈效果
本節是點亮LED的最後一節了,實現的效果是流水燈(跑馬燈)。有了以上章節的學習,本節任務應該不難實現。
1.4.14.反彙編工具objdump的使用簡介
本節介紹交叉編譯工具鏈中的反彙編工具objdump。該工具是我們後面理解和分析連結地址、連結指令碼的利器,在這裡給大家先認識下,方便以後引入使用。

第三部分、隨堂記錄
1.4.1.裸機實驗體驗之usb啟動配合dnw工具下載
1.4.1.1、背景知識介紹
回顧S5PV210的啟動方式,必須將OM5打到VCC,才能從USB啟動。
S5PV210的啟動過程:開機時先執行內部的iROM中的BL0,然後BL0做了一系列的初始化後,再讀取外部OMpin的設定來確定使用者選擇了從哪裡啟動。當檢測到我們設定的是USB啟動時,S5PV210就會從USB OTG介面試圖連線主機進行下載啟動。
1.4.1.2、dnw工具介紹
dnw是一個軟體,是三星公司編寫的,這個軟體的功能是通過USB線連線開發板和電腦主機,然後從主機下載檔案映象到開發板中去燒錄系統。
dnw軟體使用注意1:dnw是需要裝usb驅動的,驅動在“X210光碟資料\A盤\tools\USB驅動”目錄中
dnw軟體使用注意2:dnw使用時通過usb線下載,所以一定要插USB線。
dnw軟體使用注意3:dnw下載時需要設定dnw下載記憶體地址。在dnw軟體的選單“Configuration”中設定
Download Address為0xd0020010,確認即可。
1.4.1.3、dnw驅動安裝
X210開發板使用了軟開關,但是我們這裡還沒到作業系統沒去處理開關,所以在整個裸機實驗中必須手工按下POWER鍵才能保持開機,只要手一擡起來就關機了····
dnw驅動裝好的標誌是:開發板開機從usb啟動後,裝置管理器中顯示已經安裝的裝置,並且關鍵是dnw工具中USB:OK
1.4.1.4、裸機程式下載地址設定
從usb啟動做裸機實驗時,因為不需要16位元組的校驗頭,所以直接下載到0xd0020010
1.4.1.5、usb啟動裸機實驗總結
usb啟動方式主要是用來除錯程式的,其實分析S5PV210即可知道,我們這裡是把裸機程式當作BL1來使用了。

擴充知識:Win7 X64版本驅動安裝非常麻煩,因為微軟啟用了USB裝置驅動簽名政策。

1.4.2.裸機實驗體驗之SD卡下載
1.4.2.1、背景知識
一般情況下,用USB下載來除錯裸機程式比較方便;但是有時候電腦使用dnw會頻繁藍屏,這時候用SD卡下載除錯是不錯選擇。
把OM5開啟GND,以從SD通道啟動。
從SD啟動時會先從iNand(SD0)啟動執行,當iNand啟動做校驗和時失敗才會轉為啟動SD2。而我們做裸機實驗時是通過SD2來提供裸機程式映象的,因此需要先破壞內部iNand的uboot才可以強迫開發板從SD2啟動去執行我們的裸機程式。
1.4.2.2、擦除開發板iNand中的uboot的方法
在linux和android系統下,擦除uboot的方法:
busybox dd if=/dev/zero of=/dev/block/mmcblk0 bs=512 seek=1 count=1 conv=sync
sync
在uboot底下如何擦除uboot:movi write u-boot 0x30000000
1.4.2.2、Windows下製作啟動SD卡
方法等同於我們第三部分講過的SD卡刷機時的操作
1.4.2.3、linux下製作啟動SD卡
後面章節再演示。

總結:SD卡啟動和usb啟動優劣勢對比:如果你的電腦本身支援usb啟動下載而且不藍屏,建議以後做實驗用usb下載除錯;

1.4.3.自己動手安裝交叉編譯工具鏈1
1.4.3.1、Windows中裝軟體的特點
Windows中裝軟體使用安裝包,安裝包解壓後有2種情況:一種是一個安裝檔案(.exe .msi),雙擊進行安裝,下一步直到安裝完畢。安裝完畢後會在桌面上生成快捷方式,我們平時使用快捷方式來啟動這些程式;另一種是所謂的綠色軟體、免安裝軟體。這種不用安裝,直接解壓開裡面就有exe可以直接雙擊執行。
1.4.3.2、linux中裝軟體的特點
linux中安裝軟體比windows中複雜。linux中安裝軟體一般有以下幾種方法:
第一種:線上安裝。譬如ubuntu中使用apt-get install vim來安裝vim軟體。
第二種:自己下載安裝包來安裝。這種方式的缺陷就是你不知道你下載的安裝包和你的系統是否匹配。
第三種:最裝逼的一種方式,就是原始碼安裝。
總結:我們安裝交叉編譯工具鏈(arm-linux-gcc)實際採用第二種安裝方式。
1.4.3.3、交叉編譯工具鏈的選擇
我們選擇交叉編譯工具鏈的原則:和我們所使用的目標平臺(給哪款SoC程式設計)儘量去匹配。譬如我們開發S5PV210的程式就是用arm-2009q3這個版本,因為三星官方在開發S5pv210時就使用這個版本的交叉編譯工具鏈,這樣可以最大限度的避免稀奇古怪的問題出現。
1.4.3.4、交叉編譯工具鏈的安裝
步驟1:開啟虛擬機器,在/usr/local/下建立/usr/local/arm資料夾
步驟2:先將安裝包從Windows中弄到linux中去。可以用共享資料夾,也可以用Samba,也可以cuteftp。
步驟3:解壓。tar -jxvf arm-2009q3.tar.bz2
到此相當於程式已經安裝完畢,真正的應用程式安裝在/usr/local/arm/arm-2009q3/bin目錄下

注:linux中的目錄管理方法。技術角度來講,linux中所有目錄性質都是一樣的,所以技術角度來講我們把軟體安裝到哪裡都行。但是因為如果胡亂放置,將來程式可能不好找。所以久而久之大家就總結了一個檔案放置的一般定義,譬如說/bin目錄放置一些系統自帶的使用者使用的應用程式,/sbin目錄下存放的是系統自帶的系統管理方面的應用程式。
那我們裝軟體放在哪裡?一般都在/usr目錄下。我們安裝arm-linux-gcc,就在/usr/local/底下建立一個arm資料夾,然後裝到裡面。
1.4.3.5、安裝後的測試
到真正的應用程式的安裝目錄下(也就是/usr/local/arm/arm-2009q3/bin),去執行arm-linux-gcc -v
執行方法是:./arm-none-linux-gnueabi-gcc -v
執行後可以得到一長串輸出,其中有“gcc version 4.4.1 ”字樣,即表示安裝成功。

1.4.4.自己動手安裝交叉編譯工具鏈2
1.4.3.1、環境變數的意義
環境變數就是作業系統的全域性變數。每一個環境變數對作業系統來說都是唯一的,名字和所代表的意義都是唯一的。linux系統可以有很多個環境變數。其中有一部分是linux系統自帶的,還有一些是我們自己來擴充的。我們這裡涉及到的一個環境變數是
PATH。PATH這個環境變數是系統自帶的,它的含義就是系統在查詢可執行程式時會搜尋的路徑範圍。
1.4.3.2、將工具鏈匯出到環境變數
export PATH=/usr/local/arm/arm-2009q3/bin: P A T H 使 a r m l i n u x g c c   / . b a s h r c e x p o r t P A T H = / u s r / l o c a l / a r m / a r m 2009 q 3 / b i n : PATH 在一個終端中執行以上命令後,該終端中就可以直接使用arm-linux-gcc了,但是隻要關掉這個終端再另外開啟一個立馬就不行了。原因是我們本次終端中執行時的操作只是針對本終端,以後再開啟的終端並未被執行過這個命令所以沒匯出。 解決方案是在~/.bashrc中,新增export PATH=/usr/local/arm/arm-2009q3/bin: PATH 即可。
注意:我們匯出這個環境變數是在當前使用者,如果你登入時在其他使用者下是沒用的。

1.4.3.3、為工具鏈建立arm-linux-xxx符號連結
ln arm-none-linux-gnueabi-addr2line -s arm-linux-addr2line

1.4.5.Makefile大俠隆重登場
1.4.5.1、為什麼需要Makefile
Makefile是用來管理工程的。
在一個正式的軟體專案中,由很多個.c和.h檔案構成,此時如果直接在命令列編譯,就會像這樣:gcc a.c b.c c.c d.c e.c f.c g.c -o exe 每次編譯都要輸入一堆東西很麻煩,這個問題嚴重影響工作效率,怎麼辦?Makefile來解決
1.4.5.2、一個簡單的Makefile示例
見光碟下載資料夾下面的 隨堂程式碼/1.4.5/Makefile1和Makefile2
1.4.5.3、Makefile中的一些基本概念
目標:目標定格寫,後面是冒號(冒號後面是依賴)
依賴:依賴是用來產生目標的原材料。
命令:命令前面一定是Tab,不能是定格,也不能說多個空格。命令就是要生成那個目標需要做的動作。
1.4.5.4、Makefile的基本工作原理
其一,當我們執行 make xx 的時候,Makefile會自動執行xx這個目標下面的命令語句。
其二,當我們make xx的時候,是否執行命令是取決於依賴的。依賴如果成立就會執行命令,否則不執行。
其三,我們直接執行make 和make 第一個目標 效果是一樣的。(第一個目標其實就是預設目標)
1.4.5.5、ARM裸機中用到的Makefile介紹

1.4.5.6、進一步學習Makefile的資料
我們學習Makefile的思路就是:先學會基本的概念和應用,先理解Makefile的概念和使用方法、工作原理。先自己會寫簡單的Makefile來管理工程。一般先學到這裡就可以了,更深入的內容可以隨同稍後的課程一起來學習,我們講到課程的時候會再次提及並且逐步深入。
對於我們有一定基礎的同學,同時還有時間,可以深入學習Makefile,看《跟我一起學Makefile》(作者:陳皓)

1.4.6.mkv210_image.c檔案詳解1
2.4.6.1、mkv210_image.c的使用演示
裸機程式中的Makefile(實際上真正的專案的Makefile都是這樣的)是把程式的編譯和連結過程分開的。(平時我們用gcc a.c -o exe這種方式來編譯時,實際上把編譯和連結過程一步完成了。在內部實際上編譯和連結永遠是分開獨立進行的,編譯要使用編譯器gcc,連結要使用連結器ld)
連結器得到led.elf其實就是我們的可執行程式,(如果是在作業系統下,這個led.elf就可以執行了)但是在嵌入式裸機中我們需要的是可以燒寫的檔案(可燒寫的檔案就叫映象image),因此我們需要用這個led.elf為原材料來製作映象,製作工具是交叉編譯工具鏈中的arm-linux-objcopy
我們使用arm-linux-objdump工具進行反編譯(反彙編),反彙編其實就是把編譯後的elf格式的可執行程式給反過來的到對應的彙編程式,的到它的彙編原始碼。我們使用反彙編主要是用來學習,見本部分最後一節。
mkv210_image.c這個程式其實最終不是在開發板上執行的,而是在主機linux(就是用來執行make對整個專案進行編譯的那個機器)中執行的,因此編譯這個程式用gcc而不是用arm-linux-gcc。這個.c檔案編譯後得到一個可執行程式mkmini210,目的是通過執行這個mkmini210程式而由led.bin得到210.bin。(210.bin是通過SD卡啟動時的裸機映象,這個映象需要由led.bin來加工的到,加工的具體方法和原理要看mkv210_image.c)

1.4.6.2、背景知識:S5PV210的啟動過程回顧
分析啟動過程可知;210啟動後先執行內部iROM中的BL0,BL0執行完後會根據OMpin的配置選擇一個外部裝置來啟動(有很多,我們實際使用的有2個:usb啟動和SD卡啟動)。在usb啟動時內部BL0讀取到BL1後不做校驗,直接從BL1的實質內部0xd0020010開始執行,因此usb啟動的景象led.bin不需要頭資訊,因此我們從usb啟動時直接將映象下載到0xd0020010去執行即可,不管頭資訊了;從SD啟動時,BL0會首先讀取sd卡得到完整的映象(完整指的是led.bin和16位元組的頭),然後BL0會自己根據你的實際映象(指led.bin)來計算一個校驗和checksum,然後和你完整映象的頭部中的checksum來比對。如果對應則執行BL1,如果不對應則啟動失敗(會轉入執行2st啟動,即SD2啟動。如果這裡已經是2st啟動了,這裡校驗通不過就死定了)。
1.4.6.3、mkv210_image.c的作用:為BL1新增校驗頭
我們編譯連結時只得到了led.bin,這個210.bin的得到和交叉編譯工具鏈是完全無關的。由led.bin得到210.bin的過程是三星的S5PV210所特有的,因此需要我們自己去完成,為此我們寫了mkv210_image.c來完成。
1.4.6.4、整個程式工作流分析
整個程式中首先申請一個16KB大小的buffer,然後把所有內容按照各自的位置填充進去,最終把填充好的buffer寫入到一個檔案(名叫210.bin)就形成了我們想要的映象。

1.4.7.mkv210_image.c檔案詳解2
1.4.7.1、程式碼詳解
第1步:檢驗使用者傳參是不是3個。
第2步:分配16K Bbuffer並且填充為0.
第3步:·········

1.4.7.2、main函式兩個形參的作用
main函式接收2個形參:argc和argv。
argc是使用者(通過命令列來)執行這個程式時,實際傳遞的引數個數。注意這個個數是包含程式執行本身的
argv是一個字串陣列,這個陣列中儲存的字串就是一個個的傳參。
譬如我們執行程式時使用./mkx210 led.bin 210.bin
則argc = 3
則argv[0] = “./mkx210” argv[1] = led.bin argv[2] = 210.bin
1.4.7.3、glibc讀寫檔案介面
linux中要讀取一個檔案,可以使用fopen開啟檔案,fread讀取檔案,讀完之後fclose關閉檔案。
要寫檔案用fwrite來寫。這些函式是glibc的庫函式,在linux中用man 3 可以查詢。
如果你本身就知道這些函式的用法,只是記不起來可以man查詢;如果你本身根本就不會用這些介面,建議先去baidu。
1.4.7.4、校驗和的計算方法
演算法:校驗和其實就是需要校驗的記憶體區域中,所有記憶體中的內容按照位元組為單位來進行相加,最終相加的和極為校驗和。
實現時大家要注意指標的型別為char *

1.4.8.一步步點亮LED1_硬體工作原理及原理圖查閱
1.4.8.1、LED物理特性介紹
LED本身有2個接線點,一個是LED的正極,一個是LED的負極。LED這個硬體的功能就是點亮或者不亮,物理上想要點亮一顆LED只需要給他的正負極上加正電壓即可,要熄滅一顆LED只需要去掉電壓即可。
1.4.8.2、查閱原理圖瞭解板載LED硬體接法
查閱原理圖,發現開發板上一共有5顆LED。其中一顆D26的接法是:正極接5V,負極接地。因此這顆LED只要上電就會常亮。因此我們分析這顆LED是電源指示燈。
剩下4顆LED的接法是:正極接3.3V,負極接了SoC上的一個引腳(GPIO),具體詳細接法是:
D22:GPJ0_3
D23:GPJ0_4
D24:GPJ0_5
D25:PWMTOUT1(GPD0_1)
1.4.8.3、分析如何點亮及熄滅LED(GPIO)
分析:LED點亮的要求是:正極和負極之間有正向電壓差。
思考:在開發板上如何為LED製造這個電壓差讓它點亮呢?
解答:因為正極已經定了(3.3V),而負極接在了SoC的引腳上,可以通過SoC中程式設計來控制負極的電壓值,因此我們可以通過程式控制負極輸出低電平(0V),這樣在正負極上就有了壓差,LED即可點亮。

1.4.9.一步步點亮LED2_資料手冊查閱及相關暫存器瀏覽
1.4.9.1、GPIO概念的引入
GPIO:general purpose input output 通用輸入輸出
GPIO就是晶片的引腳(晶片上的引腳有些不是GPIO,只有一部分是),作為GPIO的這類引腳,他的功能和特點是可以被程式設計控制它的工作模式,也可以程式設計控制他的電壓高低等。
通過之前的分析我們知道,我們設計電路時就把LED接在了一個GPIO上,這樣我們就可以通過程式設計控制GPIO的模式和輸入輸出值來操控LED亮還是滅;如果你當時設計電路時把LED接在非GPIO上那就不可能了。
1.4.9.2、閱讀資料手冊中有關部分
當我們想要通過程式設計操控GPIO來操作LED時,我們首先需要通讀一下S5PV210的資料手冊中有關於GPIO的部分,這部分在資料手冊的Section2.2中。

1.4.9.3、GPIO相關的暫存器介紹
回憶下之前說過的,軟體操作硬體的介面是:暫存器。
我們當前要操作的硬體是LED,但是LED實際是通過GPIO來間接控制的,所以當前我們實際要操作的裝置其實是SoC的GPIO。要操作這些GPIO,必須通過設定他們的暫存器。

查閱資料手冊可知,GPJ0相關的暫存器有以下:
GPJ0CON, (GPJ0 control)GPJ0控制暫存器,用來配置各引腳的工作模式	
GPJ0DAT, (GPJ0 data)當引腳配置為input/output模式時,暫存器的相應位和引腳的電平高低相對應。
GPJ0PUD, (pull up down)控制引腳內部弱上拉、下拉
GPJ0DRV, (driver)配置GPIO引腳的驅動能力
GPJ0CONPDN,(記得是低功耗模式下的控制暫存器)
GPJ0PUDPDN  (記得是低功耗模式下的上下拉暫存器)
注:在驅動LED點亮時,應該將GPIO配置為output模式。

實際上真正操控LED的硬體,主要的有:GPJ0CON, GPJ0DAT 這麼2個。
如何點亮LED,程式設計的步驟是:
1、操控GPJ0CON暫存器中,選中output模式
2、操控GPJ0DAT暫存器,相應的位設定為0

1.4.10.一步步點亮LED3_從零開始手寫彙編點亮LED
1.4.10.1、GPxCON、GPxDAT暫存器分析
GPJ0埠一共有8個引腳,分別記住:GPJ0_0 ~ GPJ0_7,相關重要暫存器就是GPJ0CON和GPJ0DAT
GPJ0CON暫存器中設定8個引腳的工作模式(32/8=4,每個引腳可以分到4位,譬如GPJ0_0對應的bit位為bit0bit3,GPJ0_3對應的位為bit12bit15。工作方法是:給相應的暫存器位寫入相應的值,該引腳硬體就會按照相應的模式去工作。譬如給bit12~bit15寫入0b0001,GPJ0_3引腳就成為輸出模式了)
1.4.10.2、從零開始寫程式碼操作暫存器
需要哪些先決條件才能寫呢?
1. 硬體接法和引腳:GPJ0_3 GPJ0_4 GPJ0_5 低電平亮/高電平滅
2. GPJ0CON(0xE0200240)暫存器和GPJ0DAT(0xE0200244)暫存器
3. 工程管理:Makefile等
根據以上分析,我們就知道程式碼的寫法了,程式碼所要完成的動作就是:
把相應的配置資料寫入相應的暫存器即可。
1.4.10.3、編譯、下載、執行看結果
編譯時用我們的工程管理,直接make編譯得到led.bin和210.bin
下載執行可以用usb啟動dnw下載;也可以用sd卡燒錄下載,根據自己的情況用
一般都用usb下載,因為方便。如果電腦主機板插上dnw會宕機沒法解決,那只有sd卡下載啟動了。
注意:開發板上按下電源鍵之後4顆LED預設都是半亮的,當我們下載程式後其中3顆變的很亮,這說明我們的程式已經運行了。
1.4.10.4、總結和回顧(軟體控制硬體思想、暫存器意義、原理圖資料手冊的作用)
軟體到底是怎麼控制硬體的?為什麼程式一執行硬體就能跟著動?
軟體程式設計控制硬體的介面就是:暫存器

1.4.11.一步步點亮LED4_使用位運算實現複雜點亮要求
上節回顧:程式碼寫的更漂亮一些
1. 用巨集定義來定義暫存器名字,再來操作。
2. 用 b . 來實現死迴圈
3. 用.global把_start連結屬性改為外部,消除連結時的警告
1.4.11.1、問題提出:如何只點亮中間1顆(兩邊是熄滅的)LED
分析:程式其實就是寫了GPJ0CON和GPJ0DAT這2個暫存器而已,功能更改也要從這裡下手。
GPJ0CON暫存器不需要修改,GPJ0DAT中設定相應的輸出值即可。
1.4.11.2、直接解法(不使用位運算)和它的弊端
GPJ0DAT = 0x28
程式碼見<3.led_s>
總結:1. 這樣寫可以完成任務。
2. 這樣寫有缺陷。缺陷就是需要人為的去計算這個特定的設定值,而且看程式碼的也不容易看懂。
解決方案:在寫程式碼時用位運算去讓編譯器幫我們計算這個特定值。
1.4.11.3、常用位運算:與、或、非、移位
位與(&) 位或(|) 位非(取反 ~) 移位(左移<< 右移>>)
1.4.11.4、使用位運算實現功能
1<<3 等於 0b1000
1<<5 等於 0b100000
(1<<3)|(1<<5) 等於 0b101000
1.4.11.5、擴充套件一下:如何只熄滅中間1顆而點亮旁邊2顆
ldr r0, =((0<<3) | (1<<4) | (0<<5))

1.4.12.一步步點亮LED5_彙編編寫延時函式並實現LED閃爍效果
1.4.12.1、閃爍效果原理分析
閃爍 = 亮 + 延時 + 滅 + 延時 + 亮 + 延時 ······
1.4.12.2、延時函式原理
在彙編中實現延時的方法:用一些沒有目的的程式碼來執行消耗時間,達到延時的效果。
1.4.12.3、彙編編寫延時函式
彙編編寫延時函式的原理,用一個暫存器存放一個數字,然後在迴圈中每個迴圈裡給數字減1,然後再判斷這個數字的值是否為0.如果為0則停止迴圈,如果不為0則繼續迴圈。
1.4.12.4、彙編編寫及呼叫函式的方式
彙編中整個彙編的主程式是一個死迴圈,這個死迴圈是我們彙編程式的主體,類似於C中的main函式。其他函式必須寫在這個主死迴圈程式的後面(死迴圈外),不然會出錯。
彙編編寫delay延時函式時,要注意函式的初始化和函式體的位置,不能把初始化寫在了迴圈體內。
彙編中呼叫函式用bl指令,子函式中最後用mov pc, lr來返回。

1.4.13.一步步點亮LED6_再難一點的流水燈效果
1.4.13.1、流水燈原理分析
流水燈又叫跑馬燈,實現的效果就是:挨著的LED一次點亮熄滅(同時只有1顆LED亮的)
1.4.13.2、流水燈編寫(使用迴圈)
LED1亮延時 + LED2亮延時 + LED3亮延時 + 迴圈
1.4.13.3、複雜點的實現
用位取反操作符來輕鬆愉快的實現單顆LED點亮流水效果
1.4.13.4、總結:一步步寫,根本不難
從一步一步點亮LED1開始到6,寫了8個示例程式碼,一步步的實現了更復雜的效果,其間夾雜使用了位運算來給LED賦值,以實現想要的點亮效果。如果按部就班實際上非常簡單。
程式設計操控一個硬體的步驟:1 分析硬體工作原理 2 分析原理圖 3 分析資料手冊 4 找到相關的SFR 5 寫程式碼設定暫存器得到想要的效果
1.4.13.5
作業:1、板子上有4顆LED的(還有個在GPD0_1),大家程式設計把LED4也點亮、熄滅
2、用4顆LED實現流水燈

1.4.14.反彙編工具objdump的使用簡介
1.4.14.1、反彙編的原理&為什麼要反彙編
arm-linux-objdump -D led.elf > led_elf.dis
objdump是gcc工具鏈中的反彙編工具,作用是由編譯連結好的elf格式的可執行程式反過來得到彙編原始碼
-D表示反彙編 > 左邊的是elf的可執行程式(反彙編時的原材料),>右邊的是反彙編生成的反彙編程式

反彙編的原因有以下:
	1.逆向破解。
	2.除錯程式時,反彙編程式碼可以幫助我們理解程式(我們學習時使用objdump主要目的是這個),尤其是在理解連結指令碼、連結地址等概念時。
	3. 把C語言原始碼編譯連結生成的可執行程式反彙編後得到對應的彙編程式碼,可以幫助我們理解C語言和組合語言之間的對應關係。非常有助於深入理解C語言。

1.4.14.2、反彙編檔案的格式和看法
(彙編 assembly 反彙編 dissembly)
標號地址、標號名字、指令地址、指令機器碼、指令機器碼反彙編到的指令
擴充套件:ARM彙編中用地址池方式來實現非法立即數

1.4.14.3、初識指令地址
下載燒錄執行的bin檔案,內部其實是一條一條的指令機器碼。這些指令每一條都有一個指令地址,這個地址是連線的時候ld給指定的(ld根據我們寫的連結指令碼來指定)
1.4.14.4、展望:反彙編工具幫助我們分析連結指令碼
反彙編的時候得到的指令地址是連結器考慮了連結指令碼之後得到的地址,而我們寫程式碼時通過指定連線指令碼來讓連結器給我們連結合適的地址。
但是有時候我們寫的連結指令碼有誤(或者我們不知道這個連結指令碼會怎麼樣),這時候可以通過看反彙編檔案來分析這個連結指令碼的效果,看是不是我們想要的,如果不是可以改了再看。

外鏈內容:C語言位操作