關於IO記憶體

2021-10-04 15:59:09 字數 3750 閱讀 3534

外設的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)

演變流程:裸機**–>驅動**

//第一形態

*(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);

我的githu

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虛擬記憶體分為使用者空間和核心空間,使...