个人原创,转载请注明原文出处
http://blog.csdn.net/u011897065/article/details/41307339
参考文章:
http://blog.csdn.net/embbnux/article/details/17712547
首先先说下大致步骤:
1)、电路连接
2)、内核字符设备驱动编写
3)、Makefile和Kconfig添加
4)、编译内核
5)、复制内核到SD卡
6)、树莓派上编写相应的C程序调用系统API驱动LED
一、电路连接
首先先看树莓派B+GPIO口接口图:
首先看GPIO_LED连接电路:我的Led分别连接到GPIO4,GPIO8,GPIO9,GPIO10,GPIO11,GPIO23,GPIO24,GPIO18
实物图:
二、Rpi字符设备驱动编写
在树莓派Linux /drivers/char路径下新建Led.c,编写程序。
/*
-------------------------------------------------------------------
*File name : Led.c
*Author : SSC_学行者
*Discription: 树莓派Led字符设备驱动文件。
-------------------------------------------------------------------
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DEVICE_NAME "Pi_Led"
#define DRIVER_NAME "pi_led"
//class声明内核模块驱动信息,是UDEV能够自动生成/dev下相应文件
static dev_t pi_led_devno; //设备号
static struct class *pi_led_class;
static struct cdev pi_led_class_dev;
struct gpio_chip *gpiochip;
//Led GPIO引脚定义
#define led_1 (4u )
#define led_2 (8u )
#define led_3 (9u )
#define led_4 (10u)
#define led_5 (11u)
#define led_6 (23u)
#define led_7 (24u)
#define led_8 (18u)
static unsigned char pin_table[8]={led_1,led_2,led_3,led_4,led_5,led_6,led_7,led_8};
//这部分函数为内核调用后open的设备IO操作,和裸板程序一样
int open_flag=0;
static int pi_led_open(struct inode *inode, struct file *filp)
{
printk("Open led ing!\n");
if(open_flag ==0){
open_flag =1;
printk("Open led success!\n");
return 0;
}
else{
printk("Led has opened!\n");
}
return 0;
}
//这部分函数为内核调用后ioctl的设备IO操作,和裸板程序一样
static long pi_led_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
unsigned char i ;
unsigned char data;
for(i = 0 ; i < 8 ; i ++ ){
data = (cmd&0x01);
if(i>7)
i = 7 ;
gpiochip->set(gpiochip, pin_table[i], data);
cmd >>= 1 ;
}
return 0;
}
static int pi_led_release(struct inode *inode,struct file *file){
printk("Led has release!\n");
return 0;
}
//file_operations使系统的open,ioctl等函数指针指向我们所写的led_open等函数,
//这样系统才能够调用
static struct file_operations pi_led_dev_fops = {
.owner =THIS_MODULE,
.open =pi_led_open,
.unlocked_ioctl = pi_led_ioctl,
.release = pi_led_release,
};
static int is_right_chip(struct gpio_chip *chip, void *data)
{
if (strcmp(data, chip->label) == 0)
return 1;
return 0;
}
//内核加载后的初始化函数.
static int __init pi_led_init(void)
{
struct device *dev;
int major; //自动分配主设备号
major = alloc_chrdev_region(&pi_led_devno,0,1,DRIVER_NAME);
//register_chrdev 注册字符设备使系统知道有LED这个模块在.
cdev_init(&pi_led_class_dev, &pi_led_dev_fops);
major = cdev_add(&pi_led_class_dev,pi_led_devno,1);
//注册class
pi_led_class = class_create(THIS_MODULE,DRIVER_NAME);
dev = device_create(pi_led_class ,NULL,pi_led_devno,NULL,DRIVER_NAME);
gpiochip = gpiochip_find("bcm2708_gpio", is_right_chip);
gpiochip->direction_output(gpiochip, led_1, 1);
gpiochip->direction_output(gpiochip, led_2, 1);
gpiochip->direction_output(gpiochip, led_3, 1);
gpiochip->direction_output(gpiochip, led_4, 1);
gpiochip->direction_output(gpiochip, led_5, 1);
gpiochip->direction_output(gpiochip, led_6, 1);
gpiochip->direction_output(gpiochip, led_7, 1);
gpiochip->direction_output(gpiochip, led_8, 1);
gpiochip->set(gpiochip, led_1, 1);
gpiochip->set(gpiochip, led_2, 1);
gpiochip->set(gpiochip, led_3, 1);
gpiochip->set(gpiochip, led_4, 1);
gpiochip->set(gpiochip, led_5, 1);
gpiochip->set(gpiochip, led_6, 1);
gpiochip->set(gpiochip, led_7, 1);
gpiochip->set(gpiochip, led_8, 1);
printk("pi led init ok!\n");
return 0;
}
//内核卸载后的销毁函数.
void pi_led_exit(void)
{
gpio_free(led_1);
gpio_free(led_2);
gpio_free(led_3);
gpio_free(led_4);
gpio_free(led_5);
gpio_free(led_6);
gpio_free(led_7);
gpio_free(led_8);
device_destroy(pi_led_class,pi_led_devno);
class_destroy(pi_led_class);
cdev_del(&pi_led_class_dev);
unregister_chrdev_region(pi_led_devno, 1);
printk("pi led exit ok!\n");
}
module_init(pi_led_init);
module_exit(pi_led_exit);
MODULE_DESCRIPTION("Rasp Led Driver");
MODULE_AUTHOR("SSC_学行者
MODULE_LICENSE("GPL");
三、Maklefile和Kconfig内容添加
在 /drivers/char目录下的Makefile中添加一下语句:
obj-$(CONFIG_FB_LED) += Led.o
在相同目录下的Kconfig中添加一下语句:
config FB_LED
tristate "LED connected to Raspberry Pi GPIO support"
depends on FB
select FB_SYS_FILLRECT
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
select FB_DEFERRED_IO
help
This driver is for Leds.
SSC_学行者.
四、内核编译
使用menuconfig来编译
在Linux文件夹下:
选择编译选项:
make ARCH=arm CROSS_COMPILE=../RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi- menuconfig
开始编译:
make ARCH=arm CROSS_COMPILE=../RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi- -j3
转换内核格式:
cd ../RpiTools/mkimage/
./imagetool-uncompressed.py ../../RpiLinux/arch/arm/boot/zImage
五、拷贝内核到SD卡上
首先先备份SD卡中的kernel.img(也可以直接删除),将mkimage目录下的内核(kernel.img)拷贝到SD中。
六、在树莓派上编写C程序测试
#include
#include
#include
#include
#include
//左移函数
unsigned char corr(unsigned char data)
{
unsigned char _data;
_data = data ;
_data <<= 1;
data &=0x80;
if(data)
_data += 1 ;
return _data ;
}
int main(void)
{
int data=0xfe;
int led_no;
int fd;
int i;
fd = open("/dev/pi_led", 0);
if (fd < 0) {
fd = open("/dev/pi_led", 0);
}
if (fd < 0) {
perror("open device led");
exit(1);
}
for(i=0;i<=7;i++){
ioctl(fd,data, led_no);
corr(data);
sleep(1);
}
close(fd);
return 0;
}