基于GPIO子系统编写LED驱动,编写应用程序进行测试
设置定时器,5秒钟打印一次hello world
text.c
#include<stdlib.h>
#include<stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include<unistd.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char buf[128]={0};
int fd=open("/dev/mychrdev",O_RDWR);
if(fd<0)
{
printf("打开设备文件失败\n");
exit(-1);
}
while(1)
{
//从终端读取
printf("请输入两个字符\n");
printf("第一个字符:1(LED1) 2(LED2) 3(LED3)\n");
printf("第二个字符:0(关灯) 1(开灯)\n");
printf("请输入>");
fgets(buf,sizeof(buf),stdin);
buf[strlen(buf)-1]='\0';
//向设备文件中写
write(fd,buf,sizeof(buf));
}
return 0;
}
mycdev.c
#include <linux/init.h>
#include <linux/module.h>
#include<linux/of.h>
#include<linux/of_gpio.h>
#include<linux/fs.h>
#include<linux/io.h>
#include<linux/gpio.h>
/* myled
{
led1-gpio=<&gpioe 10 0>;
led2-gpio=<&gpiof 10 0>;
led3-gpio=<&gpioe 8 0>;
};
*/
struct device_node *dnode;
unsigned int gpiono;
unsigned int gpiono2;
unsigned int gpiono3;
struct timer_list mytimer;
char kbuf[128]={0};
int major;
//定时器处理函数
void mytimer_function(struct timer_list *timer)
{
//打印
printk("hello world\n");
//再次启用定时器
mod_timer(timer,jiffies+5*HZ);
}
ssize_t mycdev_write(struct file *file, const char *ubuf, size_t size, loff_t *lof)
{
int net = copy_from_user(kbuf, ubuf, size);
if (net)
{
printk("copy_from_user filed\n");
return -EIO;
}
switch(kbuf[0]){
case '1'://LED1
if(kbuf[1]=='0')//关灯
gpio_set_value(gpiono,0);
else
//灯亮
gpio_set_value(gpiono,1);
break;
case '2'://LED2
if(kbuf[1]=='0')//关灯
gpio_set_value(gpiono2,0);
else
//灯亮
gpio_set_value(gpiono2,1);
break;
case '3'://LED3
if(kbuf[1]=='0')//关灯
gpio_set_value(gpiono3,0);
else
//灯亮
gpio_set_value(gpiono3,1);
break;
}
return 0;
}
struct file_operations fops={
.write=mycdev_write,
};
static int __init mycdev_init(void)
{
//字符设备驱动注册
major=register_chrdev(0,"mychrdev",&fops);
if(major<0)
{
printk("字符设备驱动注册失败\n");
return major;
}
printk("字符设备驱动注册成功:major=%d\n",major);
//解析设备树节点信息
dnode=of_find_node_by_path("/myled");
if(dnode==NULL)
{
printk("解析设备树节点失败\n");
return -ENXIO;
}
//获取LED1 GPIO编号
gpiono=of_get_named_gpio(dnode,"led1-gpio",0);
if(gpiono<0)
{
printk("获取GPIO编号失败\n");
return -ENXIO;
}
gpiono2=of_get_named_gpio(dnode,"led2-gpio",0);
if(gpiono2<0)
{
printk("获取GPIO编号失败\n");
return -ENXIO;
}
gpiono3=of_get_named_gpio(dnode,"led3-gpio",0);
if(gpiono3<0)
{
printk("获取GPIO编号失败\n");
return -ENXIO;
}
//申请gpio编号
int ret=gpio_request(gpiono,NULL);
if(ret)
{
printk("申请GPIO编号失败\n");
return -ENXIO;
}
printk("申请GPIO编号成功:%d\n",gpiono);
//申请gpio编号
int ret2=gpio_request(gpiono2,NULL);
if(ret2)
{
printk("申请GPIO编号失败\n");
return -ENXIO;
}
printk("申请GPIO编号成功:%d\n",gpiono2);
//申请gpio编号
int ret3=gpio_request(gpiono3,NULL);
if(ret3)
{
printk("申请GPIO编号失败\n");
return -ENXIO;
}
printk("申请GPIO编号成功:%d\n",gpiono3);
//初始化定时器对象
timer_setup(&mytimer,mytimer_function,0);
mytimer.expires=jiffies+5*HZ;//定时1s;
//注册定时器
add_timer(&mytimer);
//设置GPIO为输出
ret=gpio_direction_output(gpiono,0);
if(ret)
{
printk("GPIO输出设置失败\n");
return -1;
}
//设置GPIO为输出
ret2=gpio_direction_output(gpiono2,0);
if(ret2)
{
printk("GPIO输出设置失败\n");
return -1;
}
//设置GPIO为输出
ret3=gpio_direction_output(gpiono3,0);
if(ret3)
{
printk("GPIO输出设置失败\n");
return -1;
}
// //灯亮
// gpio_set_value(gpiono,1);
// //灯亮
// gpio_set_value(gpiono2,1);
// //灯亮
// gpio_set_value(gpiono3,1);
return 0;
}
static void __exit mycdev_exit(void)
{
//注销定时器
del_timer(&mytimer);
//gpiod_set_value(gpiono,0);
gpio_set_value(gpiono,0);
gpio_set_value(gpiono2,0);
gpio_set_value(gpiono3,0);
//释放GPIO编号
gpio_free(gpiono);
//释放GPIO编号
gpio_free(gpiono2);
//释放GPIO编号
gpio_free(gpiono3);
//注销字符设备驱动
unregister_chrdev(major,"mychrdev");
}
module_init(mycdev_init);
module_exit(mycdev_exit);
MODULE_LICENSE("GPL");