分类: 嵌入式
2015-05-08 16:37:45
2440GPIO 共130个复用管脚,分为9组,PortA只能作为输出。
PE0-PE7在掉电模式(power down mode)作为唤醒信号,必须设为终端模式(interrupt mode)
下面是GPIO的control register:
Port A:
Port B:
PortC:
PortD:
PortE:
PortF:
PortG:
PortH:
PortJ:
在内核驱动中,不能直接使用上面的物理地址,需要使用虚拟地址或者使用系统中提供的函数,先说一下使用函数和函数的解读:
函数位于源码/arch/arm/plat-s3c24xx目录下的gpio.c中:
void s3c2410_gpio_cfgpin(unsigned int pin, unsigned int function):设置管脚功能,调用:
s3c2410_gpio_cfgpin(S3C2410_GPB(5),S3C2410_GPB_OUTPUT);初始化GPB5为输出;
2440中关于虚拟地址和物理地址的计算
在2440中,寄存器的虚拟地址是由一个虚拟地址的首地址加上一个偏移地址得到。
虚拟地址的基地址,在linux/include/asm-arm/plat-s3c/map.h目录下定义:
A、#define S3C_ADDR_BASE (0xF4000000)
虚拟地址定义为:
B、 #define S3C_VA_IRQ S3C_ADDR(0x00000000) /* irq controller(s) */
#define S3C_VA_SYS S3C_ADDR(0x00100000) /* system control */
#define S3C_VA_MEM S3C_ADDR(0x00200000) /* memory control */
#define S3C_VA_TIMER S3C_ADDR(0x00300000) /* timer block */
#define S3C_VA_WATCHDOG S3C_ADDR(0x00400000) /* watchdog */
#define S3C_VA_UART S3C_ADDR(0x0100 0000) /* UART */
又定义:
C、 #ifndef __ASSEMBLY__
#define S3C_ADDR(x) ((void __iomem __force *)S3C_ADDR_BASE + (x))
#else
#define S3C_ADDR(x) (S3C_ADDR_BASE + (x))
#endif
上面定义可得:虚拟地址(B定义的)=虚拟基地址(A)+偏移地址(B后面的十六进制数)
物理地址定义为:
#define S3C24XX_VA_UART S3C_VA_UART
#define S3C2410_PA_UART (0x50000000)
#define S3C24XX_SZ_UART SZ_1M
#define S3C_UART_OFFSET (0x4000)
就可得到物理地址是0x50000000de uart的虚拟地址是
VA=0xF4000000+0x0100 0000=0xF500 0000;
GPIO的偏移地址是从PortA的地址开始算起,物理地址是0x5600 0000,又有定义:
#define S3C2410_PA_GPIO (0x56000000)
#define S3C24XX_VA_GPIO ((S3C24XX_PA_GPIO - S3C24XX_PA_UART) + S3C24XX_VA_UART)
#define S3C24XX_SZ_GPIO SZ_1M
所以UA_PA =(0x5600 0000-0x5000 0000)+0xF500 0000=0xFB00 0000
= 偏移地址+虚拟地址基地址
=(0x5600 0000-0x5000 0000 +0x0100 0000 )+0xF400 00000;由上面就可以得出PA的虚拟地址
但是IO一共有九组,所以如果想求其他管脚的虚拟地址,需要加上相对于PortA的偏移。VA_PB_CON=VA_PA+0x10。这样就可以像裸机那样通过寄存器操作IO。