我的內核學習筆記15:海思Hi3516平臺GPIO使用記錄

本文介紹海思平臺 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 週日  晚

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章