一篇帶給你GPIO 軟件框架
GPIO 八種工作模式詳解
接著上一篇的講,我們上一篇研究了 GPIO 的硬件結構,其來源于 STM32 官方手冊,研究了 GPIO 的八種工作模式和推挽輸出及開漏輸出原理,接下來我們研究 GPIO 的軟件部分,分別從單片機平臺和 Linux 平臺來研究。
1、單片機平臺
單片機平臺編寫 GPIO 口程序,以 STM32F103 為例,有三種模式:庫函數、HAL庫、寄存器。
使用庫函數的方式操控 GPIO 方式如下:
- void LED_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能 PB 端口時鐘
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
- //PB5 端口配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO 口速度
- GPIO_Init(GPIOB, &GPIO_InitStructure); //根據設定參數初始化 GPIOB.5
- GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 輸出高
- }
上述代碼就是使用庫函數來初始化 STM32 的一個 IO 為輸出功能,可以看出上述初始化代碼中重點要做的事情有一下幾個:
①、使能指定 GPIO 的時鐘。
②、初始化 GPIO,比如輸出功能、上拉、速度等等。
③、STM32 有的 IO 可以作為其它外設引腳,也就是 IO 復用,如果要將 IO 作為其它外設引腳使用的話就需要設置 IO 的復用功能。
④、最后設置 GPIO 輸出高電平或者低電平。
STM32 的 GPIO 初始化就是以上四步,使用庫函數操作 GPIO 還是很簡單的。但是我們知道 STM32F1 系列是有庫函數的,但是 STM32F7 系列就沒有庫函數了,ST 公司沒有出,STM32F7 只有 HAL 庫和寄存器兩種操作方式。
2、嵌入式 Linux 平臺
先總結一句:不管是單片機還是高端 ARM 平臺,最底層都是寄存器,硬件之上就是寄存器,任何封裝形式到最底層就是操作寄存器。
對于上了 Linux 系統的平臺,我們有其他方法,讓它可以像單片機一樣簡單的操作 IO 口,這得益于各路 Linux 大神對系統底層的封裝。
在 Linux 中有 pinctrl 和 gpio 子系統,它們提供了 API 接口給你使用,讓你方便的操控 GPIO 口。
Linux 內核針對 PIN 的配置推出了 pinctrl 子系統,對 GPIO 的配置推出了 gpio 子系統。
上面這句話很重要,我詳細解釋一下:這里是將 pin 腳和控制 IO 口輸入輸出分離。
pinctrl 子系統管理 200 個 IO 口的上拉下拉電阻,電流驅動能力,是硬件底層的存在。如果 pinctrl 將某個 pin 腳初始化成了普通 GPIO 而不是 IIC 或者 SPI,那么接下來我們就可以使用 gpio 子系統的 API 去操作 IO 口輸出高低電平。
傳統的配置 pin 的方式就是直接操作相應的寄存器,但是這種配置 方式比較繁瑣、而且容易出問題(比如 pin 功能沖突)。pinctrl 子系統就是為了解決這個問題而引入的,pinctrl 子系統主要工作內容如下:
①、獲取設備樹中 pin 信息。
②、根據獲取到的 pin 信息來設置 pin 的復用功能
③、根據獲取到的 pin 信息來設置 pin 的電氣特性,比如上/下拉、速度、驅動能力等。
對于我們使用者來講,只需要在設備樹里面設置好某個 pin 的相關屬性即可,其他的初始化工作均由 pinctrl 子系統來完成,pinctrl 子系統源碼目錄為 drivers/pinctrl。
注意,pinctrl 子系統也是一個標準的 platform 驅動,當設備和驅動匹配的時候,probe 函數會執行,只是 pinctrl 子系統采用的 arch_initcall 去聲明,而不是 module_init(device_initcall),所以在系統起來的時候它會先加載。(具體原因看下面這篇文章)
pinctrl 和 gpio 子系統軟件框架如下:
pinctrl
gpio
可以看出其實兩者軟件框架一樣的,主要是 HW Abstract layer 具體實現不一樣。
你以為兩者是分離的,實際上不是的,gpio 子系統是基于 pinctrl 子系統的,gpio 的 API 接口的實現很多都是基于 pinctrl 子系統的函數。