本文介紹海思平臺 Hi3516 的 GPIO 使用,包括手冊介紹及用戶空間控制。
一、GPIO概覽
Hi3516 芯片支持 12 組GPIO(General Purpose Input/Output),即GPIO0~GPIO11。每組 GPIO 提供 8 個可編程的輸入輸出管腳(GPIO11 只有 4個) 。
每個管腳可以配置爲輸入或者輸出。這些管腳用於生成特定應用的輸出信號或採集特定應用的輸入信號。作爲輸入管腳時,GPIO 可作爲中斷源;作爲輸出管腳時,每個 GPIO 都可以獨立地清 0 或置 1。
對於引腳複用的說明,海思在 SDK 包中提供了一個 excel 表說明,該表十分重要,包括了引腳複用地址及對應比特的說明。由於內容較多,可進行搜索定位。
GPIO 寄存器對應基地址如下:
GPIO控制器 | 基地址 |
---|---|
GPIO11 | 0x120D_B000 |
GPIO10 | 0x120D_A000 |
GPIO9 | 0x120D_9000 |
GPIO8 | 0x120D_8000 |
GPIO7 | 0x120D_7000 |
GPIO6 | 0x120D_6000 |
GPIO5 | 0x120D_5000 |
GPIO4 | 0x120D_4000 |
GPIO3 | 0x120D_3000 |
GPIO2 | 0x120D_2000 |
GPIO1 | 0x120D_1000 |
GPIO0 | 0x120D_0000 |
從表格中看出,寄存器的基地址分佈是十分有規律的。不同的寄存器,其操作的偏移量均相同。如 GPIO_DIR 偏移量爲 0x400,不同 GPIO 寄存基地址加上該偏移量即爲對應的 GPIO_DIR。
二、GPIO 控制
控制 GPIO 步驟分三步:先複用引腳爲 GPIO 功能,再設置方向(輸出或輸入),寄存器爲 GPIO_DIR,最後設置高低電平或讀取引腳值,寄存器爲 GPIO_DATA。
注意,不同平臺實現的機制不同,但大體上都有這三個步驟,。
注意:
當GPIO_DIR相應的比特配置爲輸入時,有效讀取的結果將返回管腳的值;當配置爲輸出的時候,有效讀取的結果將返回寫入的值。
GPIO_DATA 寄存器利用PADDR[9:2]實現了讀寫寄存器比特的屏蔽操作。該寄存器對應256個地址空間。PADDR[9:2]分別對應 GPIO_DATA[7:0],當相應的bit爲高時,則可以對相應的位進行讀寫操作;反之,若對應bit爲低則不能進行操作。例如:
若地址爲 0x3FC(0b11_1111_1100),則對GPIO_DATA[7:0]這8bit操作全部有效。
若地址爲 0x200(0b10_0000_0000),則僅對GPIO_DATA[7]的操作有效。
GPIO_DIR 偏移值爲 0x400,可單獨設置某一引腳,也可同時設置多個 GPIO 引腳。GPIO_DATA 範圍爲 0~0x3fc。
根據手冊和經驗,得到下表:
GPIO控制器 | 偏移量 | 值 |
---|---|---|
GPIOX_0 | 0x004 | 0x01 |
GPIOX_1 | 0x008 | 0x02 |
GPIOX_2 | 0x010 | 0x04 |
GPIOX_3 | 0x020 | 0x08 |
GPIOX_4 | 0x040 | 0x10 |
GPIOX_5 | 0x080 | 0x20 |
GPIOX_6 | 0x100 | 0x40 |
GPIOX_7 | 0x200 | 0x80 |
上表中X表示不同的 GPIO 組(bank)。後面數字爲其具體的引腳。
下面爲演示示例。
紅燈 高電平亮 GPIO2_7:
himm 0x120D2400 0x80 0x120D2000爲GPIO2基地址,400爲方向,0x80表示bit7爲1
himm 0x120D2200 0x80 接上,200表示GPIO7數據寄存器,80表示bit7爲1
複用GPIO示例:
GPIO8_0 himm 0x112F0020 0x604
GPIO8_1 himm 0x112F0024 0x604
GPIO8_2 himm 0x112F0028 0x504
GPIO8_3 himm 0x112F002C 0x404
設置 GPIO8 指定引腳的方向:
himm 0x120D8400 0x1F
單獨設置各個 GPIO 的方向及電平:
GPIO8_0:
himm 0x120D8400 0x1
himm 0x120D8004 0x1
GPIO8_1:
himm 0x120D8400 0x2
himm 0x120D8008 0x2
GPIO8_2:
himm 0x120D8400 0x4
himm 0x120D8010 0x4
三、himm工具
前面只是介紹寄存器及操作的值,SDK 提示了名爲 himm 的命令行工具,可以使用該工具直接對寄存器地址進行設置。 該工具的原理細節不展開,只描述大概涉及的點:
void * memmap(unsigned long phy_addr, unsigned long size)
fd = open ("/dev/mem", O_RDWR | O_SYNC);
addr = mmap((void *)0, size_in_page, PROT_READ|PROT_WRITE, MAP_SHARED, fd, phy_addr_in_page);
#define DEFAULT_MD_LEN 128
void himm_value(unsigned long ulAddr, unsigned long ulValue)
{
void* pMem = NULL;
pMem = memmap(ulAddr, DEFAULT_MD_LEN);
*(unsigned int*)pMem = ulValue;
}
void gpio_output(int type, int value)
{
switch (type)
{
case GPIO8_0:
if (value == 1)
himm_value(0x120D8004, 1);
else if (value == 0)
himm_value(0x120D8004, 0);
break;
case GPIO8_1:
if (value == 1)
himm_value(0x120D8008, 2);
else if (value == 0)
himm_value(0x120D8008, 0);
break;
case GPIO8_2:
if (value == 1)
himm_value(0x120D8010, 4);
else if (value == 0)
himm_value(0x120D8010, 0);
break;
default:
break;
}
}
四、小結
由上述可知,海思平臺的 GPIO 控制還是比較直觀的,至少在代碼層面可以與手冊直接關聯起來。另外,可以直接在用戶空間進行操作(需其實現的內存映射模塊)。當然也可以自己寫驅動,只是實現相同的功能,但其底層的操作方式,是一樣的。
一般嵌入式 Linux 系統的 GPIO 操作,需要計算某個引腳屬於系統的第幾個 GPIO 號,需要進行換算。海思平臺不再需要,不過,是否也可實現傳統的那種方式,還沒研究。
五、未完事宜
筆者實際上接觸海思僅幾天時間,該平臺的使用和之前做的方法不太一樣,有必須記錄下來。本文沒有涉及 GPIO 的輸入、中斷,等。
六、參考資料
海思 Hi3516DV300 SoC 用戶指南。
SDK 源碼。
https://blog.csdn.net/qingzhuyuxian/article/details/82981613
李遲 2020.6.21 週日 晚