在寫 driver 時,最基本的動作通常是練習控制簡單的 I/O 動作讓某個裝置起作用。
在此便解釋如何控制,以及一些簡單的範例,取自:
- 現代嵌入式系統開發專案實務:菜鳥成長日誌與專案經理的私房菜
- linux-ldp-v1.2
操作 memory mapping register I/O
- Memory Mapping Register: 寫驅動程式時,要控制接在 CPU 外部的晶片勢必是透過 CPU 的 PIN 腳,可能只是單純的將 GPIO pin 設為 high/low 來控制外部的 chip,同理外部的設備也可以透過 GPIO pin 將訊號傳給 CPU;或者驅動程式可以透過某種通訊協定來控制 I/C,例如 SPI 或 I2C等。但無論是何種 protocol,CPU 和 外部 chip 之間的資料與命令傳遞還是得透過 CPU 的 pin 腳。
- 程式寫法
*(volatile unsigned char *)(0x302CF)=0x00;
- register 其實是一個位址,使用指標就可以對其設值或取值,要注意的是一定要用 volatile 關鍵字,否則 compiler 的最佳化功能很可能會把某些程式當作是沒意義的。
範例
- 以下為一 LED driver example
/* drv_LED.c
}
- 假設 CPU 用 P1 這樣 pin 與 LED 相接
- 當 P1 為 high/low 時, LED 會 on/off
*/
void drv_init_LED(void)
{
//設定 P1 為 output pin
*(volatile unsigned char*)0x200023 |= 0x02; //0000 0010
//default: P1 is low, LED off
*(volatile unsigned char*)0x200022 &= ~0x02; //1111 1101
}
void drv_LED_off()
{
//set P1 is low, LED off
*(volatile unsigned char*)0x200022 &= ~0x02; //1111 1101
}
void drv_LED_on()
{
//set P1 is low, LED off
*(volatile unsigned char*)0x200022 |= 0x02; //0000 0010
- 解釋 *(volatile unsigned char*)0x200022 |= 0x02;
void drv_LED_on(void)
{
volatile unsigned char data; // value of register context
volatile unsigned char* reg; // the point to register
reg = (volatile unsigned char*) 0x200022;
data = *reg; // get the value of the register in 0x200022
data = data | 0x2; // set 1 to 2th bit
*reg = data; // set the new data to register
}
- linux-ldp-v1.2 例子
-
omap_writel((omap_readl(OMAP2_CONTROL_PBIAS_1) | 0x6) & ~0x1, OMAP2_CONTROL_PBIAS_1);
-
/*
* Functions to access the OMAP IO region
*
* NOTE: - Use omap_read/write[bwl] for physical register addresses
* - Use __raw_read/write[bwl]() for virtual register addresses
* - Use IO_ADDRESS(phys_addr) to convert registers to virtual addresses
* - DO NOT use hardcoded virtual addresses to allow changing the
* IO address space again if needed
*/
#define omap_readb(a) (*(volatile unsigned char *)IO_ADDRESS(a))
#define omap_readw(a) (*(volatile unsigned short *)IO_ADDRESS(a))
#define omap_readl(a) (*(volatile unsigned int *)IO_ADDRESS(a))
#define omap_writeb(v,a) (*(volatile unsigned char *)IO_ADDRESS(a) = (v))
#define omap_writew(v,a) (*(volatile unsigned short *)IO_ADDRESS(a) = (v))
#define omap_writel(v,a) (*(volatile unsigned int *)IO_ADDRESS(a) = (v)) -
#define IO_OFFSET 0x90000000
#define IO_ADDRESS(pa) ((pa) + IO_OFFSET) /* Works for L3 and L4 */
-