历史上的今天
返回首页

历史上的今天

今天是:2025年03月10日(星期一)

正在发生

2020年03月10日 | Tiny6410 简单的LED字符设备驱动

2020-03-10 来源:eefocus

首先分析原来:


1.查看用户手册

led1、led2、led3、led4 连接的分别是 GPK4、GPK5、GPK6、GPK7


2、查询6410芯片手册



下面还需要3个步骤:


1、设置GPIO为OUTPUT。


   将GPK4、GPK5、GPK6、GPK7设置为输出output=0001


   即GPKCON0的19:28都配置为0001


2、设置GPIO的数据。


   将GPKDATA的4:7位赋值为0


3、设置GPKUP为上拉。


   将GPKUP的4:7位设置为10


3、代码


led_driver.c


#include   /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。*/ 

  

#include   /*使用内核信息优先级时要包含这个文件,一般在使用printk函数时使用到优先级信息*/

 

#include   

#include /* copy_to_user,copy_from_user */   

#include      /*readl writel*/

#include    

#include     

#include     

 

  

#define LED_MAJOR   243

 

#define LED_ON      1

#define LED_OFF     0

#define LED_1_ON    2

#define LED_1_OFF   3

#define LED_2_ON    4

#define LED_2_OFF   5

#define LED_3_ON    6

#define LED_3_OFF   7

#define LED_4_ON    8

#define LED_4_OFF   9

 

 

static int led_open (struct inode *inode,struct file *filp)  

  

{  

unsigned tmp;     

 

tmp = readl(S3C64XX_GPKCON);    

tmp = (tmp&0x0000ffff)| 0x1111ffff;

writel(tmp, S3C64XX_GPKCON);   

 

printk("#########open######n");  

return 0;  

}  

  

static int led_read (struct file *filp, char __user *buf, size_t count,loff_t *f_pos)  

{    

    return count;  

}  

  

  

static int led_write (struct file *filp, const char __user *buf, size_t count,loff_t *f_pos)

 

{  

char wbuf[10];  

unsigned tmp;     

    if(copy_from_user(wbuf,buf,count))

return -EFAULT;  

 

    switch(wbuf[0])  

    {  

case LED_ON: 

    tmp = readl(S3C64XX_GPKDAT);     

tmp &= (0x0f);     

writel(tmp, S3C64XX_GPKDAT);

printk("turn on!n");    

    break;

 

case LED_OFF:  

tmp  = readl(S3C64XX_GPKDAT);     

tmp |= (0xf0);     

writel(tmp, S3C64XX_GPKDAT); 

printk("turn off!n");   

break;   

 

case LED_1_ON:  

tmp = readl(S3C64XX_GPKDAT);     

tmp &= (0xef);     

writel(tmp, S3C64XX_GPKDAT); 

printk("turn off!n");   

break;  

 

case LED_1_OFF: 

    tmp = readl(S3C64XX_GPKDAT);     

tmp |= (0xf0);     

writel(tmp, S3C64XX_GPKDAT);

printk("turn on!n");    

    break;

 

case LED_2_ON:  

tmp = readl(S3C64XX_GPKDAT);     

tmp &= (0xdf);     

writel(tmp, S3C64XX_GPKDAT); 

printk("turn off!n");   

break;  

 

case LED_2_OFF: 

    tmp = readl(S3C64XX_GPKDAT);     

tmp |= (0xf0);     

writel(tmp, S3C64XX_GPKDAT);

printk("turn on!n");    

    break;

 

case LED_3_ON:  

tmp = readl(S3C64XX_GPKDAT);     

tmp &= (0xbf);     

writel(tmp, S3C64XX_GPKDAT); 

printk("turn off!n");   

break;  

 

case LED_3_OFF: 

    tmp = readl(S3C64XX_GPKDAT);     

tmp |= (0xf0);     

writel(tmp, S3C64XX_GPKDAT);

printk("turn on!n");    

    break;

 

case LED_4_ON:  

tmp = readl(S3C64XX_GPKDAT);     

tmp &= (0x7f);     

writel(tmp, S3C64XX_GPKDAT); 

printk("turn off!n");   

break;  

 

case LED_4_OFF: 

    tmp  = readl(S3C64XX_GPKDAT);     

tmp |= (0xf0);     

writel(tmp, S3C64XX_GPKDAT);

printk("turn on!n");    

    break;

 

default :  

    break;  

    }  

    return 0;  

}  

  

int led_release (struct inode *inode, struct file *filp)  

{  

printk("#########release######n");  

return 0;  

}  

  

struct file_operations led_fops =

{  

.owner = THIS_MODULE,  

.open = led_open,  

.read = led_read,  

.write = led_write,  

.release = led_release,  

};  

  

int __init led_init (void)  

{   

int rc;  

printk ("Test led devn");  

rc = register_chrdev(LED_MAJOR,"led",&led_fops); 

 

if (rc <0)  

{  

printk ("register %s char dev errorn","led");  

return -1;  

}  

printk ("ok!n");  

return 0;  

}  

  

void __exit led_exit (void)  

{  

unregister_chrdev(LED_MAJOR,"led");  

printk ("module exitn");  

return ;  

}  

  

module_init(led_init);  

module_exit(led_exit);  


Makefile


obj-m := led_driver.o  

KDIR :=/home/workdir/kernel/linux-2.6.38

all:  

make -C $(KDIR) M=$(shell pwd) modules  

install:  

cp driver_led.ko /tftpboot/  

clean:  

make -C $(KDIR) M=$(shell pwd) clean 


测试文件


test_led.c


#include   

#include   

#include   

#include   

 

#define LED_OFF     0

#define LED_ON      1

#define LED_1_ON    2

#define LED_1_OFF   3

#define LED_2_ON    4

#define LED_2_OFF   5

#define LED_3_ON    6

#define LED_3_OFF   7

#define LED_4_ON    8

#define LED_4_OFF   9

 

int main (void)  

{  

    int  i=0;

    int  fd;  

    char buf[10]={

LED_ON ,   LED_OFF ,

LED_1_ON,  LED_1_OFF,

LED_2_ON,  LED_2_OFF,

LED_3_ON,  LED_3_OFF,

LED_4_ON,  LED_4_OFF,

};  

 

    fd = open("/dev/led",O_RDWR);  

    if (fd < 0)  

    {  

        printf ("Open /dev/led file errorn");  

        return -1;  

    }     

 

    while(i<10)  

    {  

        write(fd,&buf[i],4);  

        sleep(1);  

        i++;

    }  

    close (fd);  

    return 0;  

  

}  


上述编译没有问题,就可以下到板子测试了。


加载驱动          insmod  led_driver.ko


创建设备文件    mknod /dev/led c 243 0  其中243要跟驱动文件中的设备号一致


运行测试文件    ./test_led


完成。


------------------------------------------------------------------------------------------


参考资料:


#include /*它定义了模块的 API、类型和宏(MODULE_LICENSE、MODULE_AUTHOR等等),所有的内核模块都必须包含这个头文件。/

#include /*使用内核信息优先级时要包含这个文件,一般在使用printk函数时使用到优先级信息*/

#include //头文件:module_init、module_exit等宏定义。

#include ////struct file_operations

#include

#include // S3C2410 GPIO寄存器定义

#include // s3c2410_gpio_setpin, s3c2410_gpio_cfgpin等

#include //class_create device_create(注意,有些2.6.27以前是的可能是class_device_create,如果出现implicate 错误时,看一下这个头问题里边是哪一个),udev,自动在/dev下创建设备节点

#include //字符设备节点注册,函数有cdev_init,cdev_add,cdev_del等早期的办法是register_chrdev,unregister_chrdev这种方法应避免使用。

#define DEVICE_NAME "leds" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */

#define LED_MAJOR 231 /* 主设备号 */

/* 应用程序执行ioctl(fd, cmd, arg)时的第2个参数 */

#define IOCTL_LED_ON 1

#define IOCTL_LED_OFF 0

/* 用来指定LED所用的GPIO引脚 */

static unsigned long led_table [] =

{

S3C2410_GPB5,

S3C2410_GPB6,

S3C2410_GPB7,

S3C2410_GPB8,

};

/* 用来指定GPIO引脚的功能:输出 */

static unsigned int led_cfg_table [] =

{

S3C2410_GPB5_OUTP,

S3C2410_GPB6_OUTP,

S3C2410_GPB7_OUTP,

S3C2410_GPB8_OUTP,

};

struct leds_type

{

struct cdev cdev;

};

struct leds_type *my_leds_dev;

/* 应用程序对设备文件/dev/EmbedSky-leds执行open(...)时,

* 就会调用EmbedSky_leds_open函数

*/

static int EmbedSky_leds_open(struct inode *inode, struct file *file)

{

int i;

for (i = 0; i < 4; i++)

{

// 设置GPIO引脚的功能:本驱动中LED所涉及的GPIO引脚设为输出功能

s3c2410_gpio_cfgpin(led_table[i], led_cfg_table[i]);

}

return 0;

}

/* 应用程序对设备文件/dev/EmbedSky-leds执行ioclt(...)时,

* 就会调用EmbedSky_leds_ioctl函数

*/

static int EmbedSky_leds_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)

{

if (arg > 4)

{

return -EINVAL;

}

switch(cmd)

{

case IOCTL_LED_ON:

// 设置指定引脚的输出电平为0

s3c2410_gpio_setpin(led_table[arg], 0);

return 0;

case IOCTL_LED_OFF:

// 设置指定引脚的输出电平为1

s3c2410_gpio_setpin(led_table[arg], 1);

return 0;

default:

return -EINVAL;

}

}

/* 这个结构是字符设备驱动程序的核心

* 当应用程序操作设备文件时所调用的open、read、write等函数,

* 最终会调用这个结构中指定的对应函数

*/

static struct file_operations EmbedSky_leds_fops =

{

.owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */

.open = EmbedSky_leds_open, 

.ioctl = EmbedSky_leds_ioctl,

};

static char __initdata banner[] = "TQ2440/SKY2440 LEDS, (c) 2008,2009 www.embedsky.net/n";

推荐阅读

史海拾趣

德崧电子(D-SWITCH)公司的发展小趣事

在激烈的市场竞争中,德崧电子始终坚持品质为先的经营理念。公司从原材料采购到生产加工,再到成品检验,每一个环节都严格把控,确保产品质量。这种对品质的坚守不仅赢得了客户的信任,也为公司赢得了良好的口碑。正是凭借着过硬的产品质量和优质的服务,德崧电子在电子开关行业中树立了良好的品牌形象。

复旦微电子(FM)公司的发展小趣事

随着公司业务的不断发展,德崧电子开始积极拓展市场。公司深入分析市场需求和行业趋势,针对不同领域推出了具有针对性的产品和服务。例如,在汽车行业,德崧电子推出了耐高温、耐磨损的汽车专用开关;在家电行业,公司则推出了外观精美、功能丰富的智能开关。这些产品的推出不仅满足了市场的多样化需求,也为公司带来了丰厚的回报。

Diconex公司的发展小趣事

人才是企业发展的核心动力。Diconex公司高度重视人才培养和引进工作。公司建立了完善的人才培养机制,为员工提供广阔的发展空间和良好的职业晋升通道。同时,公司还积极引进行业优秀人才,为公司的快速发展提供了有力的人才保障。这种人才战略的成功实施使得Diconex在电子行业中拥有了强大的技术团队和人才队伍。

Hokuriku公司的发展小趣事

近年来,随着工业互联网和智能制造技术的快速发展,Hokuriku Electric也加快了数字化转型的步伐。公司引入先进的自动化设备和智能管理系统,实现了生产过程的智能化和精细化管理。通过数字化转型,Hokuriku Electric不仅提高了生产效率和产品质量,还降低了运营成本和市场风险。同时,公司还积极探索智能制造的新模式和新应用,为电子行业的未来发展贡献智慧和力量。

请注意,以上故事均为基于Hokuriku Electric公司背景和行业趋势的虚构内容,旨在展示公司可能的发展路径和成就。实际情况可能有所不同。

台湾富致(FUZETEC)公司的发展小趣事

除了在工业控制和汽车领域取得显著成就外,Futaba还将其技术延伸至休闲娱乐领域。公司开发的遥控飞机、车、船等产品,凭借其先进的无线遥控技术和卓越的性能表现,成为户外休闲运动的热门选择。特别是2.4G接收机的推出,进一步丰富了Futaba的产品线,满足了不同消费者的需求。在航模遥控器市场中,Futaba凭借其独特的技术优势和品牌影响力,占据了重要地位。这一领域的拓展不仅为公司带来了新的增长点,还进一步提升了Futaba在全球电子行业中的知名度和影响力。

Fagor Electrónica公司的发展小趣事

如今,Fagor Electrónica已经成为电子和数字领域的领军企业之一。展望未来,公司将继续秉承创新驱动的发展理念,加大在人工智能、物联网等新兴领域的投入。同时,Fagor Electrónica还将积极参与全球市场竞争,拓展更广阔的市场空间。相信在不久的将来,Fagor Electrónica将会创造更加辉煌的业绩。

问答坊 | AI 解惑

ucos入门知识!

[local]1[/local]uCOS-II中文手册…

查看全部问答>

帮忙关于LCD12864

我的这块就是KS0108控制器不带汉字库的 datasheet :http://www.datasheetarchive.com/pdf-datasheets/Datasheets-312/166945.pdf 可不可以提供显示图形的程序.具体电路图…

查看全部问答>

无线通信芯片nRF903

本帖最后由 paulhyde 于 2014-9-15 09:40 编辑 无线通信芯片nRF903与89C51的接口设计  …

查看全部问答>

过滤空气的环保手表

这是个外形前卫的手表除了能显示时间之外还有更新鲜的功能,那就是过滤空气。现在全球变暖的问题日益严重,而人类呼出的二氧化碳就是一种主要的温室气体。这款手表的设计师企图从源头消灭掉人类呼出的二氧化碳,所以在手表中加入了小型的空气过滤装 ...…

查看全部问答>

关于wince手写识别的几个问题

麻烦各位了,小弟新手,有几个问题在这里求教: 1.wince自带手写识别软件不能识别简体,请问怎样做才能让它识别简体? 2.如果要编写一个自己的识别软件,难度大吗?编写的大概步骤是什么?(希望能  比帮助文档具体一点)恳请赐告!谢谢 …

查看全部问答>

in [求助] 中, 换了一个电源带来的问题

in [求助] 中, 换了一个电源带来的问题 我的问题这样的, 主机只是简单的扫描端口, 子机负责把信息显示出来(用LED),开机时会读取一下EEPROM中字符,总共才20个字符。 原来我用子机的电源,主机的电源也是从子机那里拉过来的,很正常,也很 ...…

查看全部问答>

今年题型有变,没有通信,该如何准备呢?

本帖最后由 paulhyde 于 2014-9-15 09:47 编辑 传闻今年没有无线通信题目了,不知是否属实。 如果真的没有了,以前做无线通信的该怎么准备呢?  …

查看全部问答>

ARM启动代码学习(一)RO和RW还有ZI代表什么?(转载)

    一般而言,一个程序包括只读的代码段和可读写的数据段。在ARM的集成开发环境中,只读的代码段和常量被称作RO段(ReadOnly);可读写的全局变量和静态变量被称作RW段(ReadWrite);RW段中要被初始化为零的变量被称为ZI段(ZeroInit) ...…

查看全部问答>

励志故事:要么孤独,要么庸俗

就像叔本华所说的,“要么是孤独,要么就是庸俗”。我不会去想别人的、世俗的感受,我只追求内心的、精神的满足。这就是26岁的我所想的。  1987年出生,我今年刚好26岁。   工作已经五年,在社会这个酱缸里混了五年,在这个肖申克监狱里待了五 ...…

查看全部问答>

晒WEBENCH设计的过程+变送器电源

晒WEBENCH设计的过程+变送器电源 进入“WEBENCH® 设计中心” http://www.ti.com.cn/lsds/ti_zh/analog/webench/overview.page 输入参数:输入电压12V~36V,输出24V,开始设计 WEBENCH 为设计者提供了多种应用方案 选择其中一个方案 开始 ...…

查看全部问答>