树莓派高级开发之树莓派博通BCM2835芯片手册导读与及“相关IO口驱动代码的编写”
首先我們要知道,驅動的兩大利器:電路圖(通過電路圖去尋找寄存器)和芯片手冊
一、寄存器的介紹
芯片手冊第六章的89頁,GPIO有41個寄存器,所有訪問都是32位的。Description是寄存器的功能描述。GPFSEL0(寄存器名) GPIO Function Select 0(功能選擇:輸入或輸出);GPSET0 (寄存器名) GPIO Pin Output Set 0(將IO口置0);GPSET1(寄存器名) GPIO Pin Output Set 1(將IO口置1);GPCLR0(寄存器名) GPIO Pin Output Clear 0 (清0)下圖的地址是:總線地址(并不是真正的物理地址)
GPFSEL0是pin0 ~ pin9的配置寄存器,GPFSEL1是pin10 ~ pin19的配置寄存器,以此類推,GPFSEL5就是pin50~pin53的配置寄存器。
| GPFSEL0 | GPIO Function select 0,功能選擇輸出/輸入 | 以引腳9舉例:000 = GPIO Pin 9 is an input,001 = GPIO Pin 9 is an output |
| GPSET0 | GPIO Pin output Set 0,輸出0 | 0 = No effect ,1 = Set GPIO pin n |
| GPSET1 | GPIO Pin output set 1,輸出1 | 0 = No effect ,1 = Set GPIO pin n |
| GPCLR0 | GPIO Pin output clear 0,清0 | 0 = No effect ,1 = Clear GPIO pin n |
在上面的文檔里已經說的很清楚了,000是引腳輸入,而001則是引腳輸出,在這里要注意每個寄存器都是32位的
- FSELn表示GPIOn,下圖給出第九個引腳的功能選擇示例,對寄存器的29-27進行配置,進而設置相應的功能。根據圖片下方的register
0表示0~9使用的是register 0(即GPFSEL0)這個寄存器。
- 輸出集寄存器用于設置GPIO管腳。SET{n}字段定義,分別對GPIO引腳進行設置,將“0”寫入字段沒有作用。如果GPIO管腳為在輸入(默認情況下)中使用,那么SET{n}字段中的值將被忽略。然而,如果引腳隨后被定義為輸出,那么位將被設置根據上次的設置/清除操作。分離集和明確功能取消對讀-修改-寫操作的需要。GPSETn寄存器為了使IO口設置為1,set4位設置第四個引腳,也就是寄存器的第四位。
- 輸出清除寄存器用于清除GPIO管腳。CLR{n}字段定義要清除各自的GPIO引腳,向字段寫入“0”沒有作用。如果在輸入(默認),然后在CLR{n}字段的值是忽略了。然而,如果引腳隨后被定義為輸出,那么位將被定義為輸出根據上次的設置/清除操作進行設置。分隔集與清函數消除了讀-修改-寫操作的需要。GPCLRn是清零功能寄存器。
把pin4引腳配置為輸出引腳:
FSEL4 14-12 001 我們把4引腳的14-12配置成001 GPIO Pin 4 is an output
詳細操作:
只需要將GPFSL0這個寄存器的14~12位設置為001就可以了。只需要將0x6(對應的2進制是110)左移12位·然后取反再與上GPFSL0就可以將13、14這兩位配置為0,然后再將0x6(對應2進制110)左移12位,然后或上GPFSL0即可將12位置1。
特別提示:進行取反后再進行按位與操作是為了不影響其他引腳
配置pin4引腳為輸出引腳 bit 12-14 配置成001
31 30 ······14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 0 ······0 0 1 0 0 0 0 0 0 0 0 0 0 0 //配置pin4引腳為輸出引腳 bit 12-14 配置成001 *GPFSEL0 &= ~(0x6 <<12); // 把bit13 、bit14置為0 //0x6是110 <<12左移12位 ~取反 &按位與*GPFSEL0 |= (0x1 <<12); //把12置為1 |按位或忘了按位與和按位或的點這里
代碼實現:
*GPFSEL0 &=~(0x6 <<12); // 把13 、14置為0*GPFSEL0 |= (0x1 <<12); //把12置為1- 注意:我們配置的底層引腳對應得是BCM 寄存器第0組位FESL0–9, 這個就是在寄存器GPFSEL0里,寄存器已經分好組了
寄存器第1組位FSEL10–19,這個在寄存器GPFSEL1里
更多的引腳對應的寄存器可以去樹莓派官網進行查看
樹莓派引腳查看官網
在上圖中我們可以點擊對應的引腳編號,就可以查看到對應的引腳的相關的信息
二、寄存器的地址問題
我們在編寫驅動程序的時候,IO口空間的起始地址是0x3f00 0000,加上GPIO的偏移量0x200 0000,所以GPIO的物理地址應該是0x3f20 0000開始的,然后在這個基礎上進行Linux系統的MMU內存虛擬化管理,映射到虛擬地址上。
上圖的尾部偏移是對的,根據GPIO的物理地址0x3f20 0000可以知道:
- 在原來框架的基礎上,添加寄存器的定義
完成以上代碼需要搞清楚的幾點
弄清楚寄存器的分組
GPFSEL0是pin0 ~ pin9的配置寄存器,GPFSEL1是pin10 ~ pin19的配置寄存器,以此類推,GPFSEL5就是pin50~pin53的配置寄存器。這個由查閱芯片手冊可以得知
volatile關鍵字的使用(筆試可能會考)
-
在此處的作用:防止編譯器優化(可能是省略,也可能是更改)這些寄存器地址變量,常見于在內核中對IO口進行操作
-
作用:確保指令不會因編譯器的優化而省略,且要求每次直接讀值,在這里的意思就是確保地址不會被編譯器更換
首先是在1.的基礎上,在pin4_drv_init這個函數里面添加寄存器地址的配置
寫出以上的代碼,要搞清楚以下幾點
分別找到幾個IO寄存器的物理地址(非常易錯),弄清楚GPIO的物理地址(真實地址)
記住并不是用下面這張圖的地址來對應GPIO功能選擇寄存器0的地址,否則編譯后運行會有段錯誤。
IO口的起始地址是0x3f000000,加上GPIO的偏移量0x2000000,所以GPIO的實際物理地址應該是從0x3f200000開始的,然后在這個基礎上進行Linux系統的MMU內存虛擬化管理,映射到虛擬地址上,編程都是操作虛擬地址。
然后我們可以根據這個偏移值來確定寄存器的物理地址(真實的地址)
可以看到寄存器GPSET0相對于GPIO物理地址的偏移值為1C。即0x3f20001C
同樣的方法,寄存器GPCLR0的偏移值為28,即0x3f200028
寄存器GPFSEL0的偏移值為0,即0x3f200000
代碼實現:
引腳輸出高電平:
*GPSET0 |= (0x1 << 4);
左移4位, 這里無論什么寄存器都是寫1,寫1并不是為某個io口去寫1,而是1是驅動(SET)設置寄存器工作將bit4的電平拉高即變為高電平,為什么要進行或操作,是因為為了不影響其他引腳的狀態
引腳輸出低電平:
*GPCLR0 |= (0x1 << 4);
同樣道理,左移4位,這里的1也并不是為了某個io口去寫1,而是1是驅動(CLR)清零寄存器將電平拉低,即變為低電平,進行或操作也一樣是為了不影響其他引腳的電平狀態
copy_from_user和copy_to_user這兩個函數相信做內核開發的人都非常熟悉,分別是將用戶空間的數據拷貝到內核空間以及將內核空間中的數據拷貝到用戶空間
詳細了解copy_from_user和copy_to_user
三、驅動代碼與應用測試代碼
3.1 相關代碼
底層驅動代碼:
上層應用測試代碼:
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h>int main() {int fd;int userCmd;fd = open("/dev/pin4",O_RDWR);if(fd < 0){printf("fail to open the pin4\n");perror("the reason:");}else{printf("success to open the pin4\n");}printf("please Input 1-HIGH,0-LOW \n");scanf("%d",&userCmd);write(fd,&userCmd,4); //這里userCmd是一個整型數,所以寫的是4個字節return 0; }至于怎么在虛擬機中編譯驅動文件以及如何將編譯好的文件發送至樹莓派,敬請關注以下博文
如何將編譯好的文件發送至樹莓派底下
3.2 在樹莓派底下進行代碼的測試與驗證
相關的驅動的裝載與卸載也查看驅動裝載與卸載
- 先來查看一下樹莓派4號引腳的初始狀態是什么
輸入1,將引腳電平變為高電平
輸入0,將引腳電平變為低電平
到目前為止,我們經過那么多節的對驅動的學習的博文,現在終于自己終于實現了類似于wiringPi這樣的一個驅動文件,我們在這里做的是引腳4的驅動,那么我們就可以按著模樣來寫引腳5,引腳6,甚至其他引腳的驅動,在這里想說一句,驅動代碼的編寫,都是基于linux內核源碼來進行編寫的,linux內核源碼這個文件在前面的博文有,如有需要自行去下載。
學習筆記,僅供參考
樹莓派高級開發之IO口驅動代碼編寫 優秀博文參考一
樹莓派高級開發之IO口驅動代碼編寫 優秀博文參考二
總結
以上是生活随笔為你收集整理的树莓派高级开发之树莓派博通BCM2835芯片手册导读与及“相关IO口驱动代码的编写”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 什么是业财一体化?
- 下一篇: UTL_FILE包的使用解析