linux gpio物理地址,s3c2440的GPIO口驱动操作中物理地址和虚拟地址解释

在mini2440_leds_misc.c里有这样的一段代码,而纵观整个c文件里面,其实真正核心的代码,我感觉就一句了:

s3c2410_gpio_setpin(led_table[i], !cmd);

而这一句里面,堪称核心的就是s3c2410_gpio_setpin 了。

是百度得来其详细讲解。对于理解arm-linux对于24x0系列开发板的地址映射有着异常强悍的指导意

1

case

MEMDEV_IOCON:

2

/*灯全亮*/

3

for

(

i

=

0

;

i

<

4

;

i

++

)

4

s3c2410_gpio_setpin

(

led_table

[

i

],

!

cmd

);

5

return

0

;

作用:设置相应GPIO口的值,

如pin=S3C2410_GPB5    to=0   则:设置S3C2410_GPB5的输出值为0

如pin=S3C2410_GPB5    to=1 则:设置S3C2410_GPB5的输出值为1

void s3c2410_gpio_setpin(unsigned int pin, unsigned int to)

{

void __iomem *base = S3C2410_GPIO_BASE(pin);

unsigned long offs = S3C2410_GPIO_OFFSET(pin);

unsigned long flags;

unsigned long dat;

local_irq_save(flags);

dat = __raw_readl(base + 0x04);

dat &= ~(1 << offs);

dat |= to << offs;

__raw_writel(dat, base + 0x04);

local_irq_restore(flags);

}

EXPORT_SYMBOL(s3c2410_gpio_setpin);

说明:

1.

S3C2410_GPIO_BASE(pin)-------------

在linux/include/asm/hardware/s3c2410/regs-gpio.h中

#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) +S3C24XX_VA_GPIO)

S3C24XX_VA_GPIO------------

在linux/include/asm-arm/arch-s3c2410/map.h

#define S3C24XX_VA_GPIO       S3C2410_ADDR(0x00E00000)

----GPIO的虚拟偏移地址:

0x00E00000

#define S3C2410_ADDR(x)    (0xF0000000 + (x))

----所有寄存器的虚拟首地址:

0xF0000000

则:

S3C24XX_VA_GPIO =0xF0E0 0000        ----GPIO的虚拟首地址

如:pin = S3C2410_GPB5

而在linux/include/asm/hardware/s3c2410/regs-gpio.h

#define S3C2410_GPB5         S3C2410_GPIONO(S3C2410_GPIO_BANKB, 5)

#define S3C2410_GPIONO(bank,offset) ((bank) + (offset))

#define S3C2410_GPIO_BANKB (32*1)

则:

S3C2410_GPB5 =32*1+5=37

由:

#define S3C2410_GPIO_BASE(pin)   ((((pin) & ~31) >> 1) +S3C24XX_VA_GPIO)

pin = S3C2410_GPB5 = 37

S3C24XX_VA_GPIO =0xF0E0 0000

则:

S3C2410_GPIO_BASE(

S3C2410_GPB5

)   ((((

S3C2410_GPB5

) & ~31) >> 1) +

0xF0E0 0000

)

S3C2410_GPIO_BASE(

37

)   ((((

37

) & ~31) >> 1) +

0xF0E0 0000

)

S3C2410_GPIO_BASE(

37

) =((10 0101 &0 0000)>>1)+0xF0E0 0000

=     1 0000+

0xF0E0 0000

=

0xF0E1 0000

~31主要是为了清除

S3C2410_GPB5

的后5位,

以上表明,linux内核驱动里面操作的都不是GPIO的物理地址,都是对映射之后的虚拟地址进行操作的。

在map中MMU将虚拟地址映射到物理地址中的范围是,

虚拟地址的范围是:0x0000 0000 -------------0x4F00 0000

物理地址的范围是:0x4800 0000--------------0x5B00 001C

#define S3C24XX_VA_GPIO       S3C2410_ADDR(0x00E00000)

#define S3C2400_PA_GPIO       (0x15600000)

#define S3C2410_PA_GPIO       (0x56000000)

#define S3C24XX_SZ_GPIO       SZ_1M

S3C24XX_VA_GPIO

表示:

S3C24XX

GPIO的Virtual Address

S3C2400_PA_GPIO 表示:

S3C2400

GPIO的Physicla Address

S3C2410_PA_GPIO

表示:

S3C2410

GPIO的Physicla Address

S3C24XX_SZ_GPIO       SZ_1M   表示:

S3C24XX每个段(虚拟地址中)划分为1M 如:ARM920T是32位的,则虚拟内存空间为4GB,共划分为4096个1M大小的段

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux,可以通过c语言的编程来操作GPIO,具体方法如下: 1. 包含相应的头文件 在程序开头,需要包含相应的头文件,如下所示: ```c #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/mman.h> #include <stdint.h> ``` 2. 定义GPIO相关的宏 需要定义GPIO相关的宏,如下所示: ```c #define GPIO_BASE_ADDR 0x20200000 #define GPIO_BLOCK_SIZE 4096 #define GPIO_IN 0 #define GPIO_OUT 1 #define GPIO_HIGH 1 #define GPIO_LOW 0 ``` 其GPIO_BASE_ADDR是GPIO的基地址GPIO_BLOCK_SIZE是GPIO区域的大小,GPIO_IN和GPIO_OUT分别表示GPIO的输入输出模式,GPIO_HIGH和GPIO_LOW分别表示GPIO的高低电平。 3. 打开/dev/mem文件 需要打开/dev/mem文件,以便对GPIO进行内存映射,如下所示: ```c int mem_fd; void *gpio_map; volatile uint32_t *gpio; if ((mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) { printf("Error: can't open /dev/mem \n"); exit(-1); } gpio_map = mmap( NULL, // Any address in our space will do GPIO_BLOCK_SIZE, // Map length PROT_READ | PROT_WRITE, // Enable reading & writting to mapped memory MAP_SHARED, // Shared with other processes mem_fd, // File to map GPIO_BASE_ADDR // Offset to GPIO peripheral ); close(mem_fd); if (gpio_map == MAP_FAILED) { printf("Error: mmap failed\n"); exit(-1); } gpio = (volatile uint32_t *)gpio_map; ``` 4. 设置GPIO的输入输出模式 需要设置GPIO的输入输出模式,如下所示: ```c int pin_num = 17; // 设置GPIO的引脚号 int pin_mode = GPIO_OUT; // 设置GPIO的输出模式 // 设置GPIO的输入输出模式 *(gpio + ((pin_num) / 10)) &= ~(7 << (((pin_num) % 10) * 3)); *(gpio + ((pin_num) / 10)) |= (pin_mode << (((pin_num) % 10) * 3)); ``` 其,pin_num表示GPIO的引脚号,pin_mode表示GPIO的输入输出模式。 5. 控制GPIO的高低电平 需要控制GPIO的高低电平,如下所示: ```c int pin_num = 17; // 设置GPIO的引脚号 int pin_value = GPIO_HIGH; // 设置GPIO的电平值 // 控制GPIO的高低电平 if (pin_value == GPIO_HIGH) { *(gpio + 7) = 1 << pin_num; } else { *(gpio + 10) = 1 << pin_num; } ``` 其,pin_num表示GPIO的引脚号,pin_value表示GPIO的电平值,GPIO_HIGH表示高电平,GPIO_LOW表示低电平。 6. 关闭/dev/mem文件 需要在程序结束时,关闭/dev/mem文件,如下所示: ```c munmap(gpio_map, GPIO_BLOCK_SIZE); ``` 以上就是在Linux通过c语言操作GPIO的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值