How to access register using mamp in TI AM335x CPU
Base on Beaglebone Black
C
Library development note
Author : Cai , Meng-Lun ,
(VegetableAvenger) , 2013/12/19
Introduction
:
這份筆記紀錄了BBBio library的開發過程,提供了一個基本的簡介來使用mmap函數,同時這份筆記也提供了一些流程,透過mmap來存取Device memory map,這份筆記提供了一個簡約的方法,在user space來存取I/O,以下過程均以C語言開發。
This
note contain :
mmap basic introduction.
Memory mapped I/O
Memory map of ARM Cortex-A8 (AM335x)
Access memory map register via C
mmap
basic introduction :
mmap 的精要解釋如下:
map files or devices into memory .
在檔案的R/W中,在read/write的function中都存在一個緩衝區,當使用這些指令時,資料均需透過這個緩衝區才能實際的R/W到對應的檔案之中,而透過mmap可以免去這個過程,把檔案當作記憶體般的存取,加快了檔案存取的速度,以下部落格提供了圖文並茂的解釋,歡迎各位閱讀:
http://stenlyho.blogspot.tw/2008/08/zero-copy.html
Memory
mapped I/O :
I/O與memory共用記憶體空間,不用特別的指令來存取I/O,以記憶體讀寫的方式來進行I/O port的存取,在本文中使用的是ARM的核心,TI AM335X,便提供這種方式來進行I/O port的存取。
透過
memory mapped I/O的方式,許多外接元件或是module,都可以透過memory access的方式來進行存取,從C語言的角度來看,則是只需要用指標就可以存取這些記憶體,只要知道mapped的範圍,便可以存取裝置,在使用上非常直覺。
圖1、Memory mapped I/O
Memory
map of ARM Cortex-A8 (AM335x)
這篇筆記使用的是TI AM335X的SoC,其spec可以從網路上載到:
http://www.ti.com/product/am3359
圖2、Memory map sample (USBSS)
圖2的表格中清楚標明了USB sub system的memory map範圍,而以Block為名是因為每一個裝置均由多個register控制,而這些register為一個群組,即為一群Block,以USBSS (0x4740_0000~0x4740_0FFF)為例,此Block內含的register列在page 2283,session 16.5.10,table 16-29,內含約42個左右的register來表明各種狀態(由命名大概可推測為interrupt相關的操作),如圖3列出其中一部份 :
圖3、Block registers(USBSS)
而這些register才是真正用來存取device的關鍵,以SYSCONFIG register為例,其詳細列在page.2288,session
16.5.4之中,如圖4所示,可以看出其資料布局的方式,同時也解釋這個Register的詳細作用,像是bit0用來resetUSB
module,bit
8~11用來控制clock等。
圖4、SYSCONFIG register
上述一個簡單的memory map查表,用來尋找USB subsystem對應的memory map位址,同時瞭解其對應位址下的register的意義,而詳細的操作方法,則需要參閱相對應的章節,才可以正確的操作device。
Access
memory map register via C
在此章節將介紹如何透過C來進行memory
map的方法,同時將上述所提到的SYSCONFIG register的資料read出來,詳細的code放在github上:
程式碼主要分為2個部份:
-
使用mmap 映射記憶體
- 存取register
1.
使用mmap映射記憶體
首先需要先定義要映射的記憶體空間與映射長度,以SUBSS為例,由圖2可知,其start address 為0x4740_0000 (hex),end address為0x4740_0FFF,故可知此block的length為0x1000,透過這些資訊,定義2個define:
#define
USBSS_ADDR 0x47400000 #define USBSS_LEN 0x1000 |
int memh
= 0; volatile unsigned int *USBSS_p = NULL; memh=open("/dev/mem", O_RDWR); USBSS_p = mmap(0, USBSS_LEN, PROT_READ | PROT_WRITE, MAP_SHARED, memh, \ USBSS_ADDR); |
Mr. Shickadance:"mem is a character device file that is an image of the main memory
of the computer. It may be used, for example, to examine (and even patch) the
system. Byte addresses in mem are interpreted as physical memory
addresses."
接著再透過mmap函數來進行memory mapped,將其map為R/W模式,同時使用MAP_SHARED,而非MAP_PRIVATE,因為存取的是device,是公用的裝置,若是同時有2個程式mmap,使用MAP_PRIVATE沒辦法得知對方的存取動作;剛剛定義的USBSS_LEN與USBSS_ADDR則是做為map length和offset。
注意在這裡使用了volatile修飾詞,因為存取的是實際上的裝置,為了避免在暫存器上產生的誤動作,因此使用此修飾詞,讓每次存取時都到記憶體中拿資料,而不要透過暫存器。
接著再透過指標存取的方式,到SYSCONFIG這個register上read資料:
volatile unsigned int *reg = NULL ;
reg=(void
*)USBSS_p + SYSCONFIG;
printf("USBSS - SYSCONFIG register
: %X (hex)\n", *reg);
|
在筆者平台顯示的值為0x14,在根據page.2288,session 16.5.4的描述可以得知此值代表:打開usb0~1的clock,no-idle、no-standby的模式。
挑個小筆誤:標題應該是 Beaglebone,不是 Beagleboen
回覆刪除哈哈 已修改 謝謝提醒!
刪除