樹莓派3B的地址映射問題堪稱新手噩夢,我用幾步給大家演示一下
在設備驅動程序的開發過程中,我們通常需要跟硬體地址打交道。在不帶作業系統的嵌入式平台上(譬如單片機,STM32等),我們直接操作的是硬體物理地址。但是在基於Linux的嵌入式平台上,我們需要與作業系統打交道。作業系統操作的是虛擬地址,因此我們有將物理地址映射成為虛擬地址的操作。
我使用的硬體平台是樹莓派Raspberry Pi 3 Model B,處理器晶片是BCM2837。我想用樹莓派直接控制引腳電平高低(簡單的GPIO操作)。官方沒有提供BCM2837晶片手冊,但是提供了BCM2835晶片手冊。BCM2837架構是在BCM2835上做了改變,但是基本不變。下載BCM2835的手冊,看其地址映射【第4頁】。
從這個圖標中我們可以看到三個地址,一個是ARM虛擬地址,一個是ARM物理地址。它們之間通過ARM MMU來映射。還有一個是VC CPU總線地址。這是我們直接操作寄存器的地址,VC CPU總線地址通過VC/ARM MMU與ARM物理地址進行映射。我現在是要操作GPIO,我們來看看GPIO的地址映射。
首先我們需要知道BCM2835的IO基址裝載在0x20000000,但是BCM2837有一點不同是裝載在0x3F000000,這可以從官方文檔獲知:Raspberry Pi Documentation - Raspberry Pi Hardware。
那麼現在IO在VC CPU總線上的基址是0x7E000000,在物理地址上的基址是0x3F000000。
我麼來看操作GPIO的寄存器,現在假設我需要操作GPIO2,輸出高電平。查閱BCM2835晶片手冊【89-90頁】:
我們只需要操作GPFSEL0寄存器(GPIO0-GPIO9的功能選擇寄存器),GPSET0寄存器(設置GPIO0-GPIO31高電平寄存器)。現在只需要獲取這兩個寄存器的地址即可。
我們發現GPFSEL0寄存器VC CPU總線地址是0x7E200000,相對基址偏移0x00200000,那麼ARM物理地址也是偏移這麼多,其ARM物理地址是0x3f200000。同理,GPSET0的ARM物理地址是0x3f20001C。我們在嵌入式Linux中,可以使用mmap函數或者ioremap函數將這兩個ARM物理地址映射成虛擬地址,就等同於直接操作GPIO硬體地址了。
///插播一條:我自己在今年年初錄製了一套還比較系統的入門單片機教程,想要的同學找我拿就行了免費的,私信我就可以哦~點我頭像黑色字體加我也能領取哦///
歡迎大家有問題一起交流,指出其中的不足之處,謝謝大家。