tiny4412開發板LED燈驅動寫法
阿新 • • 發佈:2019-01-06
簡介
led燈成本很低,操控簡單,在嵌入式產品中不可或缺,可以作為除錯標識,狀態指示等等,高階用法還可以作為呼吸燈進一步增強其美觀性。本章介紹只控制led
燈的亮滅,tiny4412
開發板有四個LED
燈在核心板上供使用者操作,led燈亮滅靠cpu
IO
口輸出電平,具體操控看實際電路。
電路圖
在tiny4412開發板上,led燈電路如下:
與CPU連線如下:
可以看到CPU相應引腳輸出相關電平,就可以控制燈的亮滅,cpu引腳輸出低電平led燈亮,接下來就是操作相關暫存器,這些暫存器與GPM4相關,一個是控制暫存器,一個是資料暫存器。
命令暫存器
資料暫存器
驅動程式碼
//驅動程式碼
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/init.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include<linux/fs.h>
#include<linux/cdev.h>
#include<linux/kdev_t.h>
#include<linux/slab.h>
#include<linux/device.h> //增加自動建立裝置標頭檔案
#include<linux/uaccess.h>
//定義字元裝置結構體
static struct cdev *leddriver_cdev;
//定義裝置號(包含主次)
static dev_t leddriver_num=0;
//定義裝置類
static struct class *leddriver_class;
//定義裝置結構體
static struct device *leddriver_device;
//定義錯誤返回型別
static int err;
//定義裝置名稱
#define LEDDRIVER_NAME "myled"
#define GPM4CON_ADDR 0x110002E0
#define GPM4DAT_ADDR 0X110002E4
static volatile unsigned long *gpm4con=NULL;
static volatile unsigned long *gpm4dat=NULL;
#define GPM4CON *gpm4con
#define GPM4DAT *gpm4dat
static
ssize_t leddriver_read(struct file *file, char __user *usr, size_t size, loff_t *loft)
{
unsigned char LED_STATUE;
copy_from_user(&LED_STATUE,usr,1);
printk("leddriver read is %d\r\n",LED_STATUE);
switch(LED_STATUE)
{
case 10:GPM4DAT |= (0x1<<0);break;
case 11:GPM4DAT &=~(0X1<<0);break;
case 20:GPM4DAT |= (0x1<<1);break;
case 21:GPM4DAT &=~(0X1<<1);break;
case 30:GPM4DAT |= (0x1<<2);break;
case 31:GPM4DAT &=~(0X1<<2);break;
case 40:GPM4DAT |= (0x1<<3);break;
case 41:GPM4DAT &=~(0X1<<3);break;
}
return 0;
}
ssize_t leddriver_write (struct file *file, const char __user *usr, size_t size, loff_t *loft)
{
printk("leddriver write is ok\r\n");
return 0;
}
int leddriver_open (struct inode *node, struct file *file)
{
printk("files open is success\r\n");
return 0;
}
int leddriver_release (struct inode *node, struct file *file)
{
printk("leddriver close is success\r\n");
return 0;
}
//檔案操作函式結構體
static struct file_operations leddriver_fops={
.owner=THIS_MODULE,
.open=leddriver_open,
.release=leddriver_release,
.read=leddriver_read,
.write=leddriver_write,
};
static __init int ldedriver_init(void)
{
//分配字元裝置結構體,前面只是定義沒有分配空間
leddriver_cdev=cdev_alloc();
//判斷分配成功與否
if(leddriver_cdev==NULL)
{
err=-ENOMEM;
printk("leddriver alloc is err\r\n");
goto err_leddriver_alloc;
}
//動態分配裝置號
err=alloc_chrdev_region(&leddriver_num, 0, 1, LEDDRIVER_NAME);
//錯誤判斷
if(err<0)
{
printk("alloc leddriver num is err\r\n");
goto err_alloc_chrdev_region;
}
//初始化結構體
cdev_init(leddriver_cdev,&leddriver_fops);
//驅動註冊
err=cdev_add(leddriver_cdev,leddriver_num,1);
if(err<0)
{
printk("cdev add is err\r\n");
goto err_cdev_add;
}
//建立裝置類
leddriver_class=class_create(THIS_MODULE,"led_class");
err=PTR_ERR(leddriver_class);
if(IS_ERR(leddriver_class))
{
printk("leddriver creat class is err\r\n");
goto err_class_create;
}
//建立裝置
leddriver_device=device_create(leddriver_class,NULL, leddriver_num,NULL, "leddevice");
err=PTR_ERR(leddriver_device);
if(IS_ERR(leddriver_device))
{
printk("leddriver device creat is err \r\n");
goto err_device_create;
}
//led燈暫存器配置
gpm4con=ioremap(GPM4CON_ADDR, 4);
gpm4dat=ioremap(GPM4DAT_ADDR, 4);
GPM4CON &= ~(0XFFFF<<0);
GPM4CON |= (0x1111<<0);
GPM4DAT |= (0XF<<0);
printk("leddriver init is success\r\n");
return 0;
err_device_create:
class_destroy(leddriver_class);
err_class_create:
cdev_del(leddriver_cdev);
err_cdev_add:
unregister_chrdev_region(leddriver_num, 1);
err_alloc_chrdev_region:
kfree(leddriver_cdev);
err_leddriver_alloc:
return err;
}
static __exit void leddriver_exit(void)
{
//取消對映
iounmap(gpm4con);
iounmap(gpm4dat);
device_destroy(leddriver_class,leddriver_num);
class_destroy(leddriver_class);
cdev_del(leddriver_cdev);
unregister_chrdev_region(leddriver_num, 1);
printk("leddriver is exit\r\n");
}
module_init(ldedriver_init);
module_exit(leddriver_exit);
MODULE_LICENSE("GPL");
app程式碼
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
unsigned char LED_STATUE,shi;
int ge;
int led_fp;
led_fp = open(argv[1],O_RDWR);
// LED_STATUE=(unsigned char)atoi(argv[2]);
while(1)
{
for(shi=1;shi<=4;shi++)
{
for(ge=1;ge>=0;ge--)
{
LED_STATUE=shi*10+ge;
read(led_fp,&LED_STATUE,1);
sleep(1);
}
}
}
close(led_fp);
}
Makefile
KERN_DIR = /zhangchao/linux3.5/linux-3.5
all:
make -C $(KERN_DIR) M=`pwd` modules
cp:
cp ./* /zhangchao/rootfs/zhangchao
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += led.o
說明
雖然呼叫read write函式,來實現對燈的控制,並不符合函式操作規範,這裡的led燈並不能看做是一個檔案操作,並沒有體現出linux一切皆檔案,並不符合標準的檔案操作方法,規範化寫法將在後面給出。