外設的sfr(特殊功能暫存器)
編址與記憶體的編址是同乙個位址空間,叫做io記憶體。
linux 核心執行後,開啟了mmu(記憶體管理單元)
,所以不能直接訪問 cpu 的實體地址,也就是說,不能直接使用實體地址訪問系統的 io 記憶體。必須將實體地址轉換為虛擬位址,核心通過虛擬位址來訪問系統的 io 記憶體。
有mmu的晶元:x86、arm9以上的cpu
無mmu的晶元:微控制器、arm cortex-m系列
驅動模組的編寫與硬體是息息相關的,所以第一步應該分析硬體電路;(尋找io資源)
控制相關狀態,如led驅動模組的gpio引腳輸出狀態等等;
申請物理記憶體區–>對映得到虛擬位址–>對虛擬位址進行控制;
步驟:記憶體的申請和對映同樣是初始化函式中完成;
//宣告資源指標
static struct resource *led_res;
//宣告io記憶體對映指標
static void __iomem *gpioe_base_va;
static void __iomem *gpioe_out_va;
static void __iomem *gpioe_outenb_va;
static void __iomem *gpioe_altfn0_va;
static void __iomem *gpioe_altfn1_va;
static void __iomem *gpioc_base_va;
static void __iomem *gpioc_out_va;
static void __iomem *gpioc_outenb_va;
static void __iomem *gpioc_altfn0_va;
static void __iomem *gpioc_altfn1_va;
......
...//入口函式
static int __init gec6818_led_init(void)
//io記憶體的動態對映,將物理位址對映到虛擬位址
//ioremap(cookie,size)
gpioe_base_va = ioremap(0xc001e000, 0x28); //對映基址
if(null == gpioe_base_va) //對映失敗
led_res = request_mem_region(0xc001c000, 0x28, "gpioc");
if(null == led_res)
gpioc_base_va = ioremap(0xc001c000, 0x28); //對映基址
if(null == gpioc_base_va) //對映失敗
//位址偏移
gpioe_out_va = gpioe_base_va; //gpioeout 0xc001e000
gpioe_outenb_va = gpioe_base_va + 0x04; //gpioeoutenb 0xc001e004
gpioe_altfn0_va = gpioe_base_va + 0x20; //gpioealtfn0 0xc001e020
gpioe_altfn1_va = gpioe_base_va + 0x24; //gpioealtfn1 0xc001e024
gpioc_out_va = gpioc_base_va; //gpiocout 0xc001c000
gpioc_outenb_va = gpioc_base_va + 0x04; //gpiocoutenb 0xc001c004
gpioc_altfn0_va = gpioc_base_va + 0x20; //gpiocaltfn0 0xc001c020
gpioc_altfn1_va = gpioc_base_va + 0x24; //gpiocaltfn1 0xc001c024
printk("<3>""device num: %d\n", major(led_dev_num));
printk("<3>""device last num: %d\n", minor(led_dev_num));
return 0;
err_ioremap_c:
release_mem_region(0xc001c000, 0x28); //釋放物理記憶體區
err_request_mem_region_c:
iounmap(gpioe_base_va);
err_ioremap:
release_mem_region(0xc001e000, 0x28); //釋放物理記憶體區
......
...return ret;
}
申請物理記憶體區 request_mem_region() 標頭檔案: #include**原型:
引數作用
start
物理起始位址
n申請記憶體區的大小,以位元組為單位
name
自定義記憶體區的名字,若申請成功,就可以在/proc/iomem當中找到該名字
返回值成功:返回非null指標,失敗:返回null指標
釋放物理記憶體區 release_mem_region() 標頭檔案: #include**原型:
引數作用
start
物理起始位址
len申請記憶體區的大小,以位元組為單位
返回值無
io記憶體的動態對映 ioremap() 標頭檔案: #include**原型:
引數作用
offset
要對映的物理記憶體區的起始位址
size
實體地址的範圍
返回值虛擬位址的指標
解除io記憶體的動態對映 iounmap() 標頭檔案: #include**原型:
引數作用
cookie
虛擬位址的指標
返回值無
具體應用如下:
演變流程:裸機**–>驅動**static int led_open(struct inode *inode, struct file *file)
我的githu//第一形態
*(volatile unsigned int *)gpioc_altfn1_va&=~(3<<2);
*(volatile unsigned int *)gpioc_altfn1_va|= (1<<2);
//第二形態
int addr;
addr = ioread32(gpioc_altfn1_va)&(~(3<<2));
addr |= 1<<2;
iowrite32(addr, gpioc_altfn1_va);
//第三形態
iowrite32((ioread32(gpioc_altfn1_va)&(~(3<<2)))|(1<<2),gpioc_altfn1_va);
I O記憶體記憶體操作
i o記憶體記憶體操作 訪問暫存器和訪問普通的sdram是不同的。特殊暫存器在2410上對映在虛擬位址的0xf0000000開始的地方。具體可以參考map.h的定義。define ioread8 p define ioread16 p define ioread32 p define iowrite...
I O埠和I O記憶體
每種外設都通過讀寫暫存器進行控制,大部分外設都有幾個暫存器,不管在記憶體位址空間還是在i o位址空間,這些暫存器的訪問位址是連續的。在硬體層,記憶體區域和io區域沒有概念上的區別 他們都通過向位址匯流排和控制匯流排傳送電平訊號進行訪問,再通過資料匯流排讀寫資料。儘管硬體暫存器和記憶體非常相似,但程式...
I O埠與I O記憶體
埠的概念 裝置通過系統匯流排上的介面與cpu相連,介面電路中含有多種暫存器,cpu向裝置讀寫資料實際上是向介面上的暫存器讀寫資料,這些暫存器稱為i o埠。乙個介面通常包含控制埠,資料埠,狀態埠。對於x86平台,實體地址就是匯流排位址。linux中,程序中的4gb虛擬記憶體分為使用者空間和核心空間,使...