14 orangepi 内核里控制IO口
来源:互联网 发布:linux怎么显示中文 编辑:程序博客网 时间:2024/05/20 15:59
在linux内核里mmu已经启用,不能直接访问物理地址.必须要把物理地址映射到一个虚拟地址上,然后通过该虚拟地址来访问原物理地址.
物理地址就是硬件上安排好的地址,如配置寄存器的地址.
void *ioremap(cookie,size) //函数用于把指定的物理地址映射到一个虚拟地址上. // cookie用于指定要映射的物理地址, size表示映射的大小范围 // 返回值为映射得到的虚拟地址.iounmap(void *addr) //函数用于取消虚拟地址的映射关系.
地址上的操作,内核里也提供了相应函数:
ioread8(地址)/readb() //读地址上的8位值, readb是比较老的函数 ioread16(地址)/readw() //读地址上的16位值 ioread32(地址)/readl() //读32位值 iowrite8(值, 地址) / writeb //把8位的值写到指定的地址上, writeb是比较老的函数 iowrite16(值, 地址) / writew //把16位的值写到指定的地址上 iowrite32(值, 地址) / writel //把32位的值写到指定的地址上
////////////////////////////
例如实现在驱动模块初始化时led亮灯, 卸载时灭灯.
test.c
#include <linux/init.h>#include <linux/module.h>#include <asm/io.h>// status-led 接在PA15#define BADDR 0x01c20800#define PA_CFG1_OFF 0x04 //PA组IO口的功能配置寄存器1对基地址偏移为4字节#define PA_DATA_OFF 0x10 //PA组IO口的数据寄存器对基地址偏移为0x10字节u8 *vaddr; //用于记录映射得到的虚拟地址static int __init myled_init(void){ u32 val; vaddr = ioremap(BADDR, SZ_4K); //映射寄存器的基地址到一个虚拟地址上. // vaddr加上相应寄存器地址偏移就是对应着寄存器原物理地址 val = ioread32(vaddr+PA_CFG1_OFF) & (~(7<<28)); iowrite32(val|(1<<28),vaddr+PA_CFG1_OFF); // PA15设为输出功能 val = ioread32(vaddr+PA_DATA_OFF); iowrite32(val|(1<<15), vaddr+PA_DATA_OFF); // PA15输出高电平, led亮 printk("myled_init ...\n"); return 0;}static void __exit myled_exit(void){ u32 val; printk("myled_exit ...\n"); val = ioread32(vaddr+PA_DATA_OFF); iowrite32(val & (~(1<<15)), vaddr+PA_DATA_OFF); // PA15输出低电平, led灭 iounmap(vaddr);}module_init(myled_init);module_exit(myled_exit);MODULE_LICENSE("GPL");
//////////////////////////////////////////////////////////////////////////
上面操作IO口的方法非常麻烦,需要查CPU手册,了解配置寄存器的相关配置信息才可以。换了一个CPU,代码几乎又得大改。
这种方法在内核是非常过时的做法了.
linux内核里有标准的GPIO操作方法. 其中有对芯片厂商的要求,芯片厂商需要在内核里实现相关的GPIO控制器的驱动配置, 让内核里的gpiolib(drivers/gpio/目录下)可以统一管理整个芯片的gpio口, 让我们驱动人员可以用内核提供的gpio标准操作函数通过gpiolib来调用控制芯片的io口.
// 另: 整个芯片的各种控制器都是由芯片厂商负责在内核里的驱动,我们驱动人员只是调用它们来实现设备驱动.
gpiolib提供io口的调用函数(可参考内核文档里的gpio.txt):
#include <linux/gpio.h> //里面声明io口的操作函数int gpio_request(unsigned gpio, const char *label);//每个io只能被请求一次,可防止多个驱动来控制同一个IO口void gpio_free(unsigned gpio); //释放已请求的io口int gpio_direction_input(unsigned gpio); //把指定的IO口作输入功能, gpio用于指定具体哪个io口int gpio_direction_output(unsigned gpio, int value); //作输出功能,并根据value的值输出高低电平int gpio_get_value(unsigned gpio); //获取指定IO口的电平void gpio_set_value(unsigned gpio, int value); //设置IO口的电平为value(0/1)int gpio_to_irq(unsigned gpio); //根据io口,获取到它对应的中断号(io口大都有外部中断功能)
//////////////
在内核里用什么具体值来表示一个io口? 这是由芯片厂家来定义的.
一般情况下, io口的定义是在内核源码arch/arm/mach-xxxx/include/mach/gpio.h.
我们的板的io口定义是在: arch/arm/mach-sunxi/include/mach/gpio.h :
49 /* sunxi gpio name space */ 50 #define GPIOA(n) (SUNXI_PA_BASE + (n)) //PA, n表示这组里的第几个IO口 51 #define GPIOB(n) (SUNXI_PB_BASE + (n)) 52 #define GPIOC(n) (SUNXI_PC_BASE + (n)) 53 #define GPIOD(n) (SUNXI_PD_BASE + (n)) 54 #define GPIOE(n) (SUNXI_PE_BASE + (n)) 55 #define GPIOF(n) (SUNXI_PF_BASE + (n)) 56 #define GPIOG(n) (SUNXI_PG_BASE + (n)) 57 #define GPIOH(n) (SUNXI_PH_BASE + (n)) 58 #define GPIOI(n) (SUNXI_PI_BASE + (n)) 59 #define GPIOJ(n) (SUNXI_PJ_BASE + (n)) 60 #define GPIOK(n) (SUNXI_PK_BASE + (n)) 61 #define GPIOL(n) (SUNXI_PL_BASE + (n)) 62 #define GPIOM(n) (SUNXI_PM_BASE + (n)) 63 #define GPION(n) (SUNXI_PN_BASE + (n)) 64 #define GPIOO(n) (SUNXI_PO_BASE + (n)) 65 #define GPIO_AXP(n) (AXP_PIN_BASE + (n))
如果不是标准的套路的话,可以在内核源码里通过搜索gpio口的调用函数的应用来反推出gpio口的宏定义.
////////////////////////
应用:例如还是实现在驱动模块初始化时led亮灯, 卸载时灭灯.
test.c
#include <linux/init.h>#include <linux/module.h>#include <mach/gpio.h> // 芯片io口的宏定义#include <linux/gpio.h> // io口的调用函数#define LED_GPIO GPIOA(15) //PA15static int __init test_init(void){ int ret; ret = gpio_request(LED_GPIO, "myled"); //如请求失败,则表示此io口已被其它驱动使用 if (ret < 0) return ret; gpio_direction_output(LED_GPIO, 1); return 0;}static void __exit test_exit(void){ gpio_set_value(LED_GPIO, 0); gpio_free(LED_GPIO);}module_init(test_init);module_exit(test_exit);MODULE_LICENSE("GPL");
- 14 orangepi 内核里控制IO口
- 10 orangepi裸板控制IO
- 54 OrangePi linux内核里的i2c控制器驱动
- 61 OrangePi Linux内核里的spi控制器驱动
- 03 OrangePi 内核编译
- orangepi zero gpio控制
- 内核安全编程(一)IO控制驱动程序
- Linux内核:IO设备通信的控制方式
- stm32库函数IO口控制
- IO口控制的学习 12.8
- 2812的IO口控制--LED点亮
- 2812的IO口控制--LED点亮
- 4.0 IO口控制LED灯闪烁
- S905串口控制IO口操作.
- 01 TI cc2530的IO口控制
- 基于visual c++之windows核心编程代码分析(24)IO控制、内核通信
- 基于visual c++之windows核心编程代码分析(24)IO控制、内核通信
- IO里的输入
- 最大无法表示成px+qy(x>=0,y>=0)的数
- core核心模块--改变图像对比度和亮度
- 获得对象的方法以及属性
- 使用easyui增加切换子视图
- stl->deque
- 14 orangepi 内核里控制IO口
- 常用的正则表达式判断手机号邮箱等
- 四种实体类类型概念:VO、DTO、DO、PO
- 过滤IE浏览器版本
- 易错点——queue中的入队出队
- 39、平衡二叉树
- webDriver 搜索有道页面
- JavaWeb学习总结(十二)——Session
- js中验证输入数字的方法