嵌入式系统011-LEDS驱动

目标:LED硬件原理简单介绍
LED管脚的调用、赋值以及配置
编写简单应用调用LED管脚,并测试
三极管(NPN)
电流控制电流源
三极端CE间的电阻可变,可以吧Rce看成一个可调电阻,可调电阻的变量是电源
IO管脚拉高之后,BE之间达到一定电流,可变电阻Rce就从无限大降低到大概几百欧。
高电平灯亮,低电平灯灭
在这里插入图片描述

头文件

.Linux中申请GPIO的头文件
include/linux/gpio.h
三星平台的GPIO配置函数头文件
arch/arm/plat-samsung/include/plat/gpio-cfg.h
包括三星素有处理器的配置函数
三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件
arch/arm/mach-exynos/include/mach/gpio.h
GPIO管脚拉高低配置参数等等
配置参数的宏定义应该在arch/arm/plat-samsung/include/plat/gpio-cfg.h文件中
三星平台4412平台,GPIO宏定义头文件。已经包含在头文件gpio.h中
arch/arm/mach-exynos/include/mach/gpio-exynos4.h
包括4412处理器所有的GPIO的宏定义

LED管脚的调用、赋值以及配置

linuxGPIO申请好书和赋值函数
gpio_request
gpio_set_value
三星平台配置GPIO函数
s3c_gpio_cfgpin
GPIO配置输出模式的宏变量
S3C_GPIO_OUTPUT
使用这些函数和宏定义变量,将devicenode_linux_module.c改写为leds.c
编写简单应用调用LED管脚
将内核中的LED驱动去掉,重新编译内核,烧写到开发板
将invoke_hello.c改写为invoke_leds.c
简单修改编译文件,编译
arm-none-linux-gnueabi-gcc -o invoke_leds invoke_leds.c -static

介绍几个可以复用为GPIO的管脚

对程序简单的分析

在这里插入图片描述
在这里插入图片描述

部分GPIO介绍

在这里插入图片描述

在这里插入图片描述

编译简单程序测试

1.将leds.c修改为gpios.c,可以控制32个GPIO
2.修改Makefile文件
3.将invoke_leds.c修改为invoke_gpios.c
4.编译应用arm-none-linux-gnueable-gcc -o invoke_gpios invoke_gpios.c -static
5.在开发板上加载测试
小结
通过对普通GPIO的操作,大家可以了解到,学习取得的过程中,很大一部分时间是用于熟悉库函数的使用
一、无论什么驱动都没有想象的那么难,一般性的方法都是先了解和掌握和对应驱动相关的库函数。
二、在掌握驱动库函数的基础上,掌握Linux架构,驱动就自然些出来或者很容易就移植成功。

编写一个灯闪烁的应用和驱动程序:

开发板LED灯led的IO
网络:KP_COL0
IO:EXYNOS4_GPL2(0)
1.新建应用程序

root@ubuntu:/home/topeet/android4.0/Code/leds_1# vim invoke_leds.c 

#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

main(){
	int fd;
	char *hello_node = "/dev/hello_ctl";
	
/*O_RDWR只读打开,O_NDELAY非阻塞方式*/	
	if((fd = open(hello_node,O_RDWR|O_NDELAY))<0){
		printf("APP open %s failed",hello_node);
	}
	else{
		printf("APP open %s success",hello_node);
		ioctl(fd,1,1);
		sleep(3);
		ioctl(fd,0,1);
		sleep(3);
		ioctl(fd,1,1);
	}
	
	close(fd);
}
arm-none-linux-gnueable-gcc -o invoke_leds invoke_leds.c -static

生成可执行文件:inboke_leds
2.新建驱动程序

root@ubuntu:/home/topeet/android4.0/Code/leds_1# vim leds.c
#include <linux/init.h>
#include <linux/module.h>

/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>

/*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
/*三星平台的GPIO配置函数头文件*/
/*三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件*/
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>
/*三星平台4412平台,GPIO宏定义头文件*/
#include <mach/gpio-exynos4.h>

#define DRIVER_NAME "hello_ctl"
#define DEVICE_NAME "hello_ctl"


MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");

static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
	printk("cmd is %d,arg is %d\n",cmd,arg);
	
	if(cmd > 1){
		printk(KERN_EMERG "cmd is 0 or 1\n");
	}
	if(arg > 1){
		printk(KERN_EMERG "arg is only 1\n");
	}
	
	gpio_set_value(EXYNOS4_GPL2(0),cmd);
	
	return 0;
}

static int hello_release(struct inode *inode, struct file *file){
	printk(KERN_EMERG "hello release\n");
	return 0;
}

static int hello_open(struct inode *inode, struct file *file){
	printk(KERN_EMERG "hello open\n");
	return 0;
}

static struct file_operations hello_ops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
	.unlocked_ioctl = hello_ioctl,
};

static  struct miscdevice hello_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &hello_ops,
};


static int hello_probe(struct platform_device *pdv){
	int ret;
	
	printk(KERN_EMERG "\tinitialized\n");
	
	ret = gpio_request(EXYNOS4_GPL2(0),"LEDS");
	if(ret < 0){
		printk(KERN_EMERG "gpio_request EXYNOS4_GPL2(0) failed!\n");
		return ret;
	}
	
	s3c_gpio_cfgpin(EXYNOS4_GPL2(0),S3C_GPIO_OUTPUT);
	
	gpio_set_value(EXYNOS4_GPL2(0),0);
	
	misc_register(&hello_dev);
	
	return 0;
}

static int hello_remove(struct platform_device *pdv){
	
	printk(KERN_EMERG "\tremove\n");
	misc_deregister(&hello_dev);
	return 0;
}

static void hello_shutdown(struct platform_device *pdv){
	
	;
}

static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
	
	return 0;
}

static int hello_resume(struct platform_device *pdv){
	
	return 0;

3.新建Makefile

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += leds.o

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
        make -C $(KDIR) M=$(PWD) modules
                
#make clean执行的操作是删除后缀为o的文件
clean:
        rm -rf *.o                                   

4.Make
将 应用可执行程序invoke_leds和驱动文件leds.ko用U盘拷贝到开发板

telnet 192.168.1.230
root
su
mount /dev/udisk /mnt/usb1
cp /mnt/usb1/leds.ko /
cp /mnt/usb1/invoke_leds /

在这里插入图片描述

编写控制开发板LED、扩展IO、摄像头接口、WIFI接口GPIO的应用和驱动程序:

开发板所有的GPIO口

/*数组中有32个引出到端子或者模块的IO,还有类似sd卡等也是可以作为GPIO,
其它引到连接器但是没有使用的GPIO等等*/
/*SCP管脚编号和POP的稍微有点不同,下面是SCP的*/
static int led_gpios[] = {
	/*led的两个IO,网络是KP_COL0,VDD50_EN*/
	EXYNOS4_GPL2(0),EXYNOS4_GPK1(1),
	/*蜂鸣器的1个IO,网络是MOTOR_PWM*/
	EXYNOS4_GPD0(0),
	/*矩阵键盘的8个IO,网络是CHG_FLT,HOOK_DET,CHG_UOK,XEINT14_BAK,
     GM_INT1,6260_GPIO1,CHG_COK,XEINT29/KP_ROW13/ALV_DBG25*/
	EXYNOS4_GPX1(0),EXYNOS4_GPX1(3),EXYNOS4_GPX1(5),EXYNOS4_GPX1(6),
	EXYNOS4_GPX3(0),EXYNOS4_GPX2(6),EXYNOS4_GPX2(7),EXYNOS4_GPX3(5),
	/*摄像头的14个IO,网络是CAM_MCLK,CAM2M_RST,CAM2M_PWDN,
CAM_D5,CAM_D7,CAM_D6,CAM_D4,CAM_D3,CAM_D2,CAM_D1,
CAM_PCLK,CAM_D0,CAM_VSYNC,CAM_HREF。
I2C_SDA7,I2C_SCL7也是可以设置为GPIO,不过总线一般不要去动它*/
	EXYNOS4212_GPJ1(3),EXYNOS4_GPL0(1),EXYNOS4_GPL0(3),EXYNOS4212_GPJ1(0),
	EXYNOS4212_GPJ1(2),EXYNOS4212_GPJ1(1),EXYNOS4212_GPJ0(7),EXYNOS4212_GPJ0(6),
	EXYNOS4212_GPJ0(5),EXYNOS4212_GPJ0(4),EXYNOS4212_GPJ0(0),EXYNOS4212_GPJ0(3),
	EXYNOS4212_GPJ0(1),EXYNOS4212_GPJ0(2),
	/*WIFI模块的7个IO,WIFI_D3,WIFI_CMD,WIFI_D1,WIFI_CLK,WIFI_D0,WIFI_D2,GPC1_1*/
/*串口RX和TX等也是可以设置为GPIO,一般不要动它*/
	EXYNOS4_GPK3(6),EXYNOS4_GPK3(1),EXYNOS4_GPK3(4),EXYNOS4_GPK3(0),
	EXYNOS4_GPK3(3),EXYNOS4_GPK3(5),EXYNOS4_GPC1(1),
};

1.新建应用程序

root@ubuntu:/home/topeet/android4.0/Code/leds_gpio# vim leds_gpio.c 
#include <stdio.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>

#include <string.h>

#define GPIOS 32


int main(int argc , char **argv){
	int fd,i,cmd=2;
	char *hello_node = "/dev/hello_gpio";
	char *cmd0 = "0"; 
	char *cmd1 = "1";
	
	printf("argv[0] is %s;argv[1] is %s;",argv[0],argv[1]);
	
	if(strcmp(argv[1], cmd0) == 0){
		cmd = 0;
		printf("cmd is 0!\n");
	}
	if(strcmp(argv[1], cmd1) == 0){
		cmd = 1;
		printf("cmd is 1!\n");
	}
	
/*O_RDWR只读打开,O_NDELAY非阻塞方式*/	
	if((fd = open(hello_node,O_RDWR|O_NDELAY))<0){
		printf("APP open %s failed!\n",hello_node);
	}
	else{
		printf("APP open %s success!\n",hello_node);
		for(i=0;i<GPIOS;i++){
			ioctl(fd,cmd,i);
			printf("APP ioctl %s ,cmd is %d,i is %d!\n",hello_node,cmd,i);
		}
	}
	
	close(fd);
}

编译:

arm-none-linux-gnueable-gcc -o invoke_leds invoke_leds.c -static

2.新建驱动程序

root@ubuntu:/home/topeet/android4.0/Code/leds_gpio# vim leds_gpioall.c
#include <linux/init.h>
#include <linux/module.h>

/*驱动注册的头文件,包含驱动的结构体和注册和卸载的函数*/
#include <linux/platform_device.h>
/*注册杂项设备头文件*/
#include <linux/miscdevice.h>
/*注册设备节点的文件结构体*/
#include <linux/fs.h>

/*Linux中申请GPIO的头文件*/
#include <linux/gpio.h>
/*三星平台的GPIO配置函数头文件*/
/*三星平台EXYNOS系列平台,GPIO配置参数宏定义头文件*/
#include <plat/gpio-cfg.h>
#include <mach/gpio.h>
/*三星平台4412平台,GPIO宏定义头文件*/
#include <mach/gpio-exynos4.h>

#define DRIVER_NAME "hello_ctl"
#define DEVICE_NAME "hello_gpio"


MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");




/*led的两个IO,网络是KP_COL0,VDD50_EN*/
/*蜂鸣器的1个IO,网络是MOTOR_PWM*/

/*矩阵键盘的8个IO,网络是CHG_FLT,HOOK_DET,CHG_UOK,XEINT14_BAK,
GM_INT1,6260_GPIO1,CHG_COK,XEINT29/KP_ROW13/ALV_DBG25*/

/*摄像头的14个IO,网络是CAM_MCLK,CAM2M_RST,CAM2M_PWDN,
CAM_D5,CAM_D7,CAM_D6,CAM_D4,CAM_D3,CAM_D2,CAM_D1,
CAM_PCLK,CAM_D0,CAM_VSYNC,CAM_HREF。
I2C_SDA7,I2C_SCL7也是可以设置为GPIO,不过总线一般不要去动它*/

/*WIFI模块的7个IO,WIFI_D3,WIFI_CMD,WIFI_D1,WIFI_CLK,WIFI_D0,WIFI_D2,GPC1_1*/
/*串口RX和TX等也是可以设置为GPIO,一般不要动它*/

/*数组中有32个引出到端子或者模块的IO,还有类似sd卡等也是可以作为GPIO,
其它引到连接器但是没有使用的GPIO等等*/
/*SCP管脚编号和POP的稍微有点不同,下面是SCP的*/
static int led_gpios[] = {
	/*led的两个IO,网络是KP_COL0,VDD50_EN*/
	EXYNOS4_GPL2(0),EXYNOS4_GPK1(1),
	/*蜂鸣器的1个IO,网络是MOTOR_PWM*/
	EXYNOS4_GPD0(0),
	/*矩阵键盘的8个IO,网络是CHG_FLT,HOOK_DET,CHG_UOK,XEINT14_BAK,
     GM_INT1,6260_GPIO1,CHG_COK,XEINT29/KP_ROW13/ALV_DBG25*/
	EXYNOS4_GPX1(0),EXYNOS4_GPX1(3),EXYNOS4_GPX1(5),EXYNOS4_GPX1(6),
	EXYNOS4_GPX3(0),EXYNOS4_GPX2(6),EXYNOS4_GPX2(7),EXYNOS4_GPX3(5),
	/*摄像头的14个IO,网络是CAM_MCLK,CAM2M_RST,CAM2M_PWDN,
CAM_D5,CAM_D7,CAM_D6,CAM_D4,CAM_D3,CAM_D2,CAM_D1,
CAM_PCLK,CAM_D0,CAM_VSYNC,CAM_HREF。
I2C_SDA7,I2C_SCL7也是可以设置为GPIO,不过总线一般不要去动它*/
	EXYNOS4212_GPJ1(3),EXYNOS4_GPL0(1),EXYNOS4_GPL0(3),EXYNOS4212_GPJ1(0),
	EXYNOS4212_GPJ1(2),EXYNOS4212_GPJ1(1),EXYNOS4212_GPJ0(7),EXYNOS4212_GPJ0(6),
	EXYNOS4212_GPJ0(5),EXYNOS4212_GPJ0(4),EXYNOS4212_GPJ0(0),EXYNOS4212_GPJ0(3),
	EXYNOS4212_GPJ0(1),EXYNOS4212_GPJ0(2),
	/*WIFI模块的7个IO,WIFI_D3,WIFI_CMD,WIFI_D1,WIFI_CLK,WIFI_D0,WIFI_D2,GPC1_1*/
/*串口RX和TX等也是可以设置为GPIO,一般不要动它*/
	EXYNOS4_GPK3(6),EXYNOS4_GPK3(1),EXYNOS4_GPK3(4),EXYNOS4_GPK3(0),
	EXYNOS4_GPK3(3),EXYNOS4_GPK3(5),EXYNOS4_GPC1(1),
};

#define LED_NUM		ARRAY_SIZE(led_gpios)


static long hello_ioctl( struct file *files, unsigned int cmd, unsigned long arg){
	printk("cmd is %d,arg is %d\n",cmd,arg);
	
	switch(cmd)
	{
		case 0:
		case 1:
			if (arg > LED_NUM) {
				return -EINVAL;
			}

			gpio_set_value(led_gpios[arg], cmd);
			break;

		default:
			return -EINVAL;
	}
	
	gpio_set_value(led_gpios[2], 0);
	
	return 0;
}

static int hello_release(struct inode *inode, struct file *file){
	printk(KERN_EMERG "hello release\n");
	return 0;
}

static int hello_open(struct inode *inode, struct file *file){
	printk(KERN_EMERG "hello open\n");
	return 0;
}

static struct file_operations hello_ops = {
	.owner = THIS_MODULE,
	.open = hello_open,
	.release = hello_release,
	.unlocked_ioctl = hello_ioctl,
};

static  struct miscdevice hello_dev = {
	.minor = MISC_DYNAMIC_MINOR,
	.name = DEVICE_NAME,
	.fops = &hello_ops,
};


static int hello_probe(struct platform_device *pdv){
	int ret,i;
	
	printk(KERN_EMERG "\tinitialized\n");
	
	for(i=0; i<LED_NUM; i++)
	{
		ret = gpio_request(led_gpios[i], "LED");
		if (ret) {
			printk("%s: request GPIO %d for LED failed, ret = %d\n", DRIVER_NAME,
					i, ret);
			}
		else{
			s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT);
			gpio_set_value(led_gpios[i], 1);			
		}
	}

	gpio_set_value(led_gpios[2], 0);
	
	misc_register(&hello_dev);
	if(ret<0)
	{
		printk("leds:register device failed!\n");
		goto exit;
	}
	return 0;

exit:
	misc_deregister(&hello_dev);
	return ret;
	return 0;
}

static int hello_remove(struct platform_device *pdv){
	int i;
	
	printk(KERN_EMERG "\tremove\n");
	
	for(i=0; i<LED_NUM; i++)
	{
		gpio_free(led_gpios[i]);
	}
	
	misc_deregister(&hello_dev);
	return 0;
}

static void hello_shutdown(struct platform_device *pdv){
	
	;
}

static int hello_suspend(struct platform_device *pdv,pm_message_t pmt){
	
	return 0;
}

static int hello_resume(struct platform_device *pdv){
	
	return 0;
}

struct platform_driver hello_driver = {
	.probe = hello_probe,
	.remove = hello_remove,
	.shutdown = hello_shutdown,
	.suspend = hello_suspend,
	.resume = hello_resume,
	.driver = {
		.name = DRIVER_NAME,
		.owner = THIS_MODULE,
	}
};


static int hello_init(void)
{
	int DriverState;
	
	printk(KERN_EMERG "HELLO WORLD enter!\n");
	DriverState = platform_driver_register(&hello_driver);
	
	printk(KERN_EMERG "\tDriverState is %d\n",DriverState);
	return 0;
}


static void hello_exit(void)
{
	printk(KERN_EMERG "HELLO WORLD exit!\n");
	
	void free_irq(unsigned int irq,void *dev_id);
	
	platform_driver_unregister(&hello_driver);	
}

module_init(hello_init);
module_exit(hello_exit);

3.新建Makefile编译、执行

#!/bin/bash
#通知编译器我们要编译模块的哪些源码
#这里是编译itop4412_hello.c这个文件编译成中间文件itop4412_hello.o
obj-m += leds_gpioall.o

#源码目录变量,这里用户需要根据实际情况选择路径
#作者是将Linux的源码拷贝到目录/home/topeet/android4.0下并解压的
KDIR := /home/topeet/android4.0/iTop4412_Kernel_3.0

#当前目录变量
PWD ?= $(shell pwd)

#make命名默认寻找第一个目标
#make -C就是指调用执行的路径
#$(KDIR)Linux源码目录,作者这里指的是/home/topeet/android4.0/iTop4412_Kernel_3.0
#$(PWD)当前目录变量
#modules要执行的操作
all:
        make -C $(KDIR) M=$(PWD) modules
                
#make clean执行的操作是删除后缀为o的文件
clean:
        rm -rf *.o

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值