|
【SINA31s评测】NO.6 资源嗅探和GPIO操作
[复制链接]
趁周末,再更一贴
Linus said:so nvdia,fxxk you
所以linux至今也不完美支持nvidia独立显卡
然后Linus又said:this whole ARM thing is a fxxking pain in the ass
所以linux又有了设备树device tree
设备树的使用过程
简单点理解就是用一个dtsi脚本文件,把外设资源按抬头集中进行预配置
需要使用某个外设资源的时候
就匹配这个外设的抬头,完成这个外设资源的分配
SINA31s有个很有意思的文件,叫sys_config.fex
其实和linux原生的dtsi异曲同工
都是用来按抬头分配硬件资源的脚本文件
文件里头按特定格式,对CPU所有外设进行了配置
比如
外设Twi1(貌似是IIC之类的外设,没有A31S的数据手册,不确定)的初始化信息就在这儿
调用脚本接口函数,就可以对外设Twi1进行匹配
获取到twi1 gpio的配置信息 下面这个是AW官方文档上介绍的脚本匹配函数
GPIO初始化所需要的信息,就填充在script_item_u list的某个子成员中
需要初始化的话,调用到GPIO初始化函数中就ok了
大概就是这么个流程
撸几行代码调试看看
在sys_config.fex文件中增加一个test_led的资源
使用默认1号GPIO配置
补充一下
这个LED在原理图上是GPIOH13管脚
对应底板上的LED4
也就是status LED 编辑完配置文件后,编译内核,打包成img,烧掉
上内核代码
- #include "test.h" static int test_major = 0; static int test_minor = 0; #define led_gpio GPIOH(13) int user_data; static struct class *test_class = NULL; static struct device *test_dev = NULL; //static struct device *test_classdev[4]; static int test_drv_open(struct inode *inode, struct file *file) { test_minor = MINOR(inode -> i_rdev);//取出次设备号 printk(KERN_EMERG"test_drv_open,major=%d,minor=%d.....\n",test_major,test_minor); return 0; } static int test_drv_write(struct file *file,const char __user *buf,size_t count,loff_t* ppos) { int fd; printk(KERN_EMERG"test_drv_write.....\n"); fd = copy_from_user(&user_data,buf,count); // copy_to _user(); if(fd) {printk(KERN_EMERG"Got Nothings....\n");} else {printk(KERN_EMERG"Got user_data = %d..\n",user_data);} for(;user_data > 0;user_data--)//从用户空间获取blink次数 { gpio_direction_output(led_gpio,GPIOF_OUT_INIT_HIGH); printk(KERN_EMERG"LED 0n....\n"); mdelay(150); gpio_direction_output(led_gpio,GPIOF_OUT_INIT_LOW); printk(KERN_EMERG"LED off...\n"); mdelay(150); } return 0; } static int test_drv_release(struct inode* inode, struct file* filp) { printk("test_drv_release.....\r\n"); return 0; } static struct file_operations test_drv_fops = { .owner = THIS_MODULE, .open = test_drv_open, .write = test_drv_write, .release = test_drv_release, }; static int test_drv_init(void) { int err,i; script_item_u *val = NULL; script_item_value_type_e type; test_major = register_chrdev(0, "test_drv", &test_drv_fops);//动态分配系统主设备号 if(test_major == -EBUSY) { printk(KERN_EMERG"Device registed failed...\n"); } else{ printk(KERN_EMERG"Device registed sucess,major = %d\n",test_major ); } test_class = class_create(THIS_MODULE,"test_drv_class");//创建设备类 if(!IS_ERR(test_class)) { err = PTR_ERR(test_class); printk(KERN_ALERT"Sucess to create test class,ERR=%d.\n",err); } test_dev = device_create(test_class,NULL,MKDEV(test_major,0),NULL,"test_led");//创建设备 (单个设备) if(!IS_ERR(test_dev)) { err = PTR_ERR(test_dev); printk(KERN_ALERT"Sucess to create test device,ERR=%d.\n",err); } type = script_get_pio_list("test_led", &val); //获取test_led 外设资源和配置 if(type == 0) {printk(KERN_EMERG"Got item Error...\n");} else { printk(KERN_EMERG"test_led used %d gpio(s)\n",type);//打印GPIO数量 } script_dump_mainkey("test_led");//打印GPIO详细配置 for(i = 0; i < type; i++) { if(gpio_request(val[i].gpio.gpio, NULL) != 0) //申请外设资源 {printk(KERN_EMERG"test_led GPIO[%d] be Used...\n",i);} else {printk(KERN_EMERG"test_led GPIO[%d] request ok...\n",i);} if(sw_gpio_setall_range(&(val[i].gpio), i) != 0)//配置test_led外设 { printk(KERN_EMERG"test_led GPIO[%d] init failed...\n",i); } else {printk(KERN_EMERG"test_led GPIO[%d] init ok...\n",i);} } return 0; } static void test_drv_exit(void) { unregister_chrdev(test_major, "test_led");//注销系统设备号 device_destroy(test_class, MKDEV(test_major,0));//注销设备 单个 class_destroy(test_class);//注销设备类 gpio_direction_output(led_gpio,GPIOF_OUT_INIT_LOW); gpio_free(led_gpio);//释放资源 printk(KERN_EMERG"test_drv_exit.....\n"); } module_init(test_drv_init); module_exit(test_drv_exit); MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("ljj3166");
复制代码
在调用匹配后的结构体填充驱动数之前
记得用gpio_request来申请一下资源
LCD的PWM使用了这个管脚
如果不申请一下的话
驱动执行起来,轻则oops,重则panic至crush
写个应用程序测试一下
- #include <sys types.h=""> #include <sys stat.h=""> #include <string.h> #include <fcntl.h> #include <stdio.h> void print_usage(char *file)//用法 { printf("Usage:\n"); printf("%s <dev> <num>\n",file); printf("eg. \n"); printf("%s led 1\n", file); printf("%s led x\n", file); } int main(int argc,char** argv) { int fd; int val = 255; char filename[20] = "/dev/test_"; printf("hello,world!\n");//测试应用 if (argc != 3) //判断入口参数个数,错误则打印使用方法 { print_usage(argv[0]); return 0; } strcat(filename,argv[1]); fd = open(filename,O_RDWR); //打开对应设备 if (fd < 0) {printf("open %s failed...\n",filename);} else {printf("open %s Ok...\n",filename);} val = atoi(argv[2]); printf("%d\n",val); write(fd, &val, 4);//向驱动程序写入值 return 0; }
复制代码
基本就是测试从命令行获取LED blink的次数
看看运行状态
通过匹配fex文件中的配置insmod后
完成设备的和驱动的注册
并打印LED使用的GPIO的信息及初始化结果
执行应用程序后,Blink起来了
还有邪恶滴动图
到这...
|
赞赏
-
1
查看全部赞赏
-
|