1. 程式人生 > >【linux】驅動-4-LED晶片手冊分析

【linux】驅動-4-LED晶片手冊分析

[toc] --- ## 前言 * 參考: * **《IMX6ULLRM(6ULL使用者手冊).pdf》** * [李柱明部落格](https://www.cnblogs.com/lizhuming/p/14588172.html) ## 4. LED晶片手冊分析 本章節記錄實現LED暫存器配置,晶片手冊分析。 ### 4.1 記憶體管理單元MMU 簡單介紹一下MMU。 #### 4.1.1 MMU的功能 功能: * 將**虛擬地址**翻譯為**實體地址**。 * 管理、保護記憶體。 不同的程序有各自的虛擬地址空間,某個程序中的程式不能修改另外一個程序所使用的實體地址,以此使得程序之間互不干擾,相互隔離。 作用: * **保護記憶體**:MMU給一些指定的記憶體設定了讀寫許可權。存在於頁表中。當有程式操作該記憶體時,MMU會查詢頁表中的許可權繼續匹配。 * **實現虛擬地址到實體地址的轉換**:CPU可以執行在虛擬的記憶體當中,虛擬記憶體一般要比實際記憶體大很多,使得CPU可以執行比較大的應用程式。(*原理可百度*) ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115237554-1656767208.png) #### 4.1.2 TLB的作用 TLB(Translation Lookaside Buffer)。 **問題**:當只有一級頁表進行地址轉換的時候,CPU每次讀寫資料都需要訪問兩次記憶體, 第一次是訪問記憶體中的頁表,第二次是根據頁表找到真正需要讀寫資料的記憶體地址; 如果使用兩級了表,那麼CPU每次讀寫資料都需要訪問3次記憶體。。。這樣就很繁瑣。 **解決**:MMU最先訪問TLB,假設TLB中包含可以直接轉換此虛擬地址的地址描述符, 則會直接使用這個地址描述符檢查許可權和地址轉換,如果TLB中沒有這個地址描述符, MMU才會去訪問頁表並找到地址描述符之後進行許可權檢查和地址轉換, 然後再將這個描述符填入到TLB中以便下次使用。 ### 4.2 地址轉換函式 對映函式:**`ioremap()`**。 取消對映函式:**`iounmap()`**。 #### 4.2.1 ioremap函式 函式原型:**`void __iomem *ioremap(phys_addr_t paddr, unsigned long size)`** * 引數: * **paddr**:被對映的 IO 起始地址(實體地址)。 * **size**:需要對映的空間大小,以**位元組**為單位。 * 返回值: * 一個指向 **__iomem** 型別的指標,當對映成功後便返回一段虛擬地址空間的起始地址。 通過返回的虛擬空間起始地址可以對記憶體進行讀寫。為了提高平臺的可移植性,建議使用以下讀寫函式: ```c unsigned int ioread8(void __iomem *addr) unsigned int ioread16(void __iomem *addr) unsigned int ioread32(void __iomem *addr) void iowrite8(u8 b, void __iomem *addr) void iowrite16(u16 b, void __iomem *addr) void iowrite32(u32 b, void __iomem *addr) ``` 與以上函式相似的函式:**`writeb、writew、writel、readb、readw、readl`**。 注意:其中 **write*x*** 與 **iowrite*x*** 的區別是,**write*x*** 不進行端序檢查。 #### 4.2.2 iounmap函式 函式原型:**`void iounmap(void *addr)`** * 引數: * **addr**:需要取消 **ioremap** 對映之後的起始地址(*虛擬地址*)。 ### 4.3 LED驅動 已知: * 以 IMX6 為例。 * RGB引腳分別為 **GPIO1_IO04、GPIO4_IO20、GPIO4_19**。 簡要步驟: 1. 檢視原理圖,分析出 LED 是低電平亮還是高電平亮。找出對應的 **GPIO**。 2. 對 **GPIO** 暫存器進行操作:*(暫存器表在 **《IMX6ULLRM(6ULL使用者手冊).pdf》** 中查詢)* 1. **使能時鐘**:使能 **GPIO** 對應的時鐘; 2. **引腳複用**:設定引腳複用為 **GPIO**; 3. **引腳屬性**:配置引腳屬性(上下拉、速率、驅動能力); 4. **控制引腳**:控制**GPIO**引腳,輸出高低電平。 3. 分層、分離: 1. 上層為系統,模組的出入口函式。 2. 下層為硬體:分離: 1. 各種板卡, 提供不同的引腳資料。 2. 驅動實現。 #### 4.3.1 配置GPIO時鐘 暫存器表在 **《IMX6ULLRM(6ULL使用者手冊).pdf》** 中查詢。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115253949-1916981679.png) 由圖可知,**GPIO1** 的時鐘是由暫存器 **CCM_CCGR1** 中的 **[27-26]** bit控制。 該暫存器地址為:**Address: 20C_4000h base + 6Ch offset = 20C_406Ch**。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115301204-80210944.png) 暫存器值配置參考上圖。 使能 **GPIO1**時鐘:暫存器 **CCM_CCGR1** 中的 **[27-26]** bit 配置為 **[27-26]: 0b11**。 #### 4.3.2 配置引腳複用 配置引腳複用為 **GPIO**。 檢視手冊 **IOMUX** 章節。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115308488-472868224.png) 由上圖可以看出,暫存器 **IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO04** **[3-0]** 設定為 **0b0101** 時。**GPIO1_IO04** 就配置為 **GPIO1** 模式。 #### 4.3.3 引腳屬性 配置引腳屬性。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115314659-1972622433.png) * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115322030-1024213617.png) 由上圖得,暫存器為 **IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO04**。地址為 **Address: 20E_0000h base + 2F8h offset = 20E_02F8h** 分析: * **HYS**(bit16):用來使能遲滯比較器 。 * **PUS**(bit15-bit14):用來設定上下拉電阻大小。 * **PUE**(bit13):當 IO 作為輸入的時候,這個位用來設定 IO 使用上下拉還是狀態保持器。 * **PKE**(bit12):用來使能或者禁止上下拉/狀態保持器功能。 * **ODE**(bit11):IO 作為輸出的時候,此位用來禁止或者使能開漏輸出。 * **SPEED**(bit7-bit6):當 IO 用作輸出的時候,此位用來設定 IO 速度。 * **DSE**(bit5-bit3):當 IO 用作輸出的時候用來設定 IO 的驅動能力。 * **SRE**(bit0):設定壓擺率。 把該暫存器配置為:**0x1F838**,即為 **1 1111 1000 0011 1000**。 #### 4.3.4 引腳控制 參考 **《IMX6ULLRM(6ULL使用者手冊).pdf》** 中的 **28.5 GPIO Memory Map/Register Definition** 章節。 控制引腳輸入還是輸出。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115332362-1110684811.png) * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115337651-2022976533.png) 由上圖可知,GPIO1的資料基地址為 **Base address = 0x0209C000**。 而 **GPIOx_GDIR** 地址為 **Base address + 4h = 0x0209C004** 輸出高低電平。 * ![](https://img2020.cnblogs.com/blog/2085252/202103/2085252-20210328115343075-441031672.png) 地址為 **Base address = 0x0209C000**。 當該引腳配置為 **GPIO OUTPUT MODE** 時,即可通過設定該引腳來輸出高低電平。 同時,該引腳在 **GPIO** 模式時,不管 **OUTPUT** 還是 **INPUT**。都可以通過讀該暫存器值來判斷該引腳的高低電平。