历史上的今天
返回首页

历史上的今天

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

正在发生

2020年03月10日 | tiny4412内核自带led驱动分析

2020-03-10 来源:eefocus

内核版本:linux-3.5 

平台:tiny4412


一、关于混杂设备

此版本内核led驱动使用的是混杂设备misc,具体misc.c的实现路径:linux-3.5/drivers/char/misc.c


这就很大程度简化了我们的驱动代码,没有发现ldd3中提到的各种字符设备注册函数,而是发现了一个misc_register函数(共用的注册函数),这说明led设备是作为杂项设备出现在内核中的,在内核中,misc杂项设备驱动接口是对一些字符设备的简单封装,他们共享一个主设备号,有不同的次设备号,共享一个open调用,其他的操作函数在打开后运用linux驱动程序的方法重载进行装载。


二、关于gpio:

查找tiny4412的datasheet以及pcb电路图。


1、查找I/O口对应引脚:

 这里写图片描述 

从图中我们可以看出,四个led灯分别对应四个i/o口1,2,3,4。 

所以可以创建结构体来保存:


static int led_gpios[] = {

    EXYNOS4X12_GPM4(0),

    EXYNOS4X12_GPM4(1),

    EXYNOS4X12_GPM4(2),

    EXYNOS4X12_GPM4(3),

};


2、查看led电路图:

 这里写图片描述 

由电路图可知当led为低电平时,led灯被点亮。。。且为输出模式。


s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT); //设置为输出模式

gpio_set_value(led_gpios[i], 1); //将引脚设置为高电平,默认为全灭


3、相关gpio函数:

1、int gpio_request(unsigned gpio, const char *label);

    获得并占有 GPIO port 的使用权,由参数 gpio 指定具体 port,非空的lables指针有助于诊断。主要是告诉内核这地址被占用了。当其它地方调用同一地址的gpio_request就会报告错误,该地址已被申请。在/proc/mem应该会有地址占用表描述。

这种用法的保护作用前提是大家都遵守先申请再访问,有一个地方没遵守这个规则,这功能就失效了。好比进程互斥,必需大家在访问临界资源的时候都得先获取锁一样,其中一个没遵守约定,代码就废了。


2、void gpio_free(unsigned gpio);//释放 GPIO port 的使用权,由gpio 指定具体 port。

例2:gpio_free(RK29_PIN0_PA0);//释放GPIO0_A0


3、int gpio_direction_input(unsigned gpio);//设置输入模式

例3:gpio_direction_input (RK29_PIN0_PA0);//把GPIO0_A0设置为输入



4、int gpio_direction_output(unsigned gpio, int value);//设置输出模式

例4:gpio_direction_output(RK29_PIN0_PA0,GPIO_LOW);//把GPIO0_A0设置为输出口,且其电平拉低。   


5、int gpio_get_value(unsigned gpio);//获取电平值

 例5:ret = gpio_get_value (RK29_PIN0_PA0);// 读取GPIO0_A0的电平,并赋值给变量ret。


6、void gpio_set_value(unsigned gpio, int value);设置引脚电平值

gpio_set_value (RK29_PIN0_PA0, GPIO_HIGH);// 设置RK29_PIN0_PA0电平为高。



7、 int gpio_pull_updown(unsigned gpio,unsigned value);

        value = 0, normal

        value = 1, pull up

        value = 2, pull down

例7、gpio_pull_updown(RK29_PIN0_PA0,1)上拉

       int gpio_cansleep(unsigned gpio);

支持这种gpio的平台为了通过在这个函数中返回非零来区分其它类型的gpio(需要一个已经被  gpio_request申请的gpio号)为了访问这些端口,定义了另一组函数接口:


8、 int gpio_get_value_cansleep(unsigned gpio);

        void gpio_set_value_cansleep(unsigned gpio, int value);只能在允许睡眠的上下文中访问这些端口,比如线程化的中断中,


9、 static inline int gpio_is_valid(int number)//判断GPIO是否有效,有效返回0


10、 int gpio_export(unsigned gpio, bool direction_may_change);//返回0成功


void gpio_unexport();  //返回0成功


int gpio_export_link(struct device *dev, const char *name, unsigned gpio) 

//创建到导出GPIO的 sysfs link  ,第一个参数是在哪个dev下创建,第二个是参数名字,第三个是gpio编号 


具体可参考: 

http://blog.csdn.net/andrinux/article/details/38725619 

http://blog.sina.com.cn/s/blog_a6559d9201015vx9.html


三、驱动代码分析:

流程:初始化(注册misc设备)—>定义fops结构体与misc结构体—>实现fops中相关函数—>把fops绑定到misc结构体—>注销misc设备。


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include


#include

#include

#include



#define DEVICE_NAME "leds"     //设备名


static int led_gpios[] = {

    EXYNOS4X12_GPM4(0),

    EXYNOS4X12_GPM4(1),

    EXYNOS4X12_GPM4(2),

    EXYNOS4X12_GPM4(3),

};


#define LED_NUM     ARRAY_SIZE(led_gpios)



//因为是低电平点亮,但是这里我们cmd的值传入1点亮led灯,这是为了照顾惯性思维,当然,也可以让它传入0变亮。

static long tiny4412_leds_ioctl(struct file *filp, unsigned int cmd,

        unsigned long arg)

{

    switch(cmd) {

        case 0:

        case 1:

            if (arg > LED_NUM) {

                return -EINVAL;

            }


            gpio_set_value(led_gpios[arg], !cmd); //取反,所以传入1后点亮

            //printk(DEVICE_NAME": %d %dn", arg, cmd);

            break;


        default:

            return -EINVAL;

    }


    return 0;

}


//fops的实现,无需加入open,使用misc.c中共用的open

static struct file_operations tiny4412_led_dev_fops = {

    .owner          = THIS_MODULE,

    .unlocked_ioctl = tiny4412_leds_ioctl, //led控制函数

};


//混杂设备结构体,将fops绑定到其中

static struct miscdevice tiny4412_led_dev = {

    .minor          = MISC_DYNAMIC_MINOR,

    .name           = DEVICE_NAME,

    .fops           = &tiny4412_led_dev_fops,

};


//初始化:申请I/O口--->设置为输出模式--->默认设置全灭

static int __init tiny4412_led_dev_init(void) {

    int ret;

    int i;


    for (i = 0; i < LED_NUM; i++) {

        ret = gpio_request(led_gpios[i], "LED"); //获得并占有 GPIO port 的使用权

        if (ret) {

            printk("%s: request GPIO %d for LED failed, ret = %dn", DEVICE_NAME,

                    led_gpios[i], ret);

            return ret;

        }


        s3c_gpio_cfgpin(led_gpios[i], S3C_GPIO_OUTPUT); //设置为输出模式

        gpio_set_value(led_gpios[i], 1); //将引脚设置为高电平,默认为全灭

    }


    ret = misc_register(&tiny4412_led_dev); //注册混杂设备


    printk(DEVICE_NAME"tinitializedn");


    return ret;

}


static void __exit tiny4412_led_dev_exit(void) {

    int i;


    for (i = 0; i < LED_NUM; i++) {

        gpio_free(led_gpios[i]); //释放 GPIO port 的使用权

    }


    misc_deregister(&tiny4412_led_dev); //注销混杂设备

}


module_init(tiny4412_led_dev_init);

module_exit(tiny4412_led_dev_exit);


MODULE_LICENSE("GPL");

MODULE_AUTHOR("FriendlyARM Inc.");


四、测试用例:

#include

#include

#include

#include

int main(int argc, char **argv)

{

    int on;

    int led_no;

    int fd;

/* 检查 led 控制的两个参数,如果没有参数输入则退出。 */

    if (argc != 3 || sscanf(argv[1], "%d", &led_no) != 1 || sscanf(argv[2],"%d", &on) != 1 ||on < 0 || on > 1 || led_no < 0 || led_no > 3)  

    {

        fprintf(stderr, "Usage: leds led_no 0|1n");

        exit(1);

    }

/*打开/dev/leds 设备文件*/

    fd = open("/dev/leds0", 0);

    if (fd < 0) {

        fd = open("/dev/leds", 0);

    }


    if (fd < 0) {

        perror("open device leds");

        exit(1);

    }

/*通过系统调用 ioctl 和输入的参数控制 led*/

    ioctl(fd, on, led_no);  

/*关闭设备句柄*/

    close(fd);

    return 0;

}


交叉编译后将a.out拷贝到开发板。


运行:(第一个参数表示第led 0/1/2/3,第二个参数1表示开启,0表示关闭) 

./a.out 1 1 //开启第二盏灯 

./a.out 2 0 //关闭第三盏灯

推荐阅读

史海拾趣

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

随着技术的不断进步和市场需求的不断变化,Fagor Electrónica开始将其业务范围扩展到更广泛的电子和数字领域。公司不断推出新的产品和服务,以满足不同客户的需求。同时,Fagor Electrónica还积极拓展国际市场,将其产品销往世界各地。这一时期的多元化发展和市场拓展为公司带来了更大的商业机会和更广阔的市场前景。

Acculin Inc公司的发展小趣事

Acculin Inc最初是一家专注于电子元器件研发的小型企业。随着物联网和智能家居的兴起,公司敏锐地捕捉到了市场的机遇,开始研发一款低功耗、高集成度的传感器芯片。经过数年的努力,Acculin成功推出了这款芯片,并凭借出色的性能获得了市场的认可。随后,公司逐渐扩大了产品线,涵盖了多个电子领域,成为行业内技术创新的领军者。

启英泰伦(Chiplntelli)公司的发展小趣事

启英泰伦(Chiplntelli)公司成立于2015年,专注于人工智能语音芯片及配套应用解决方案的研发。在公司创立初期,团队面临了众多技术挑战和市场竞争。然而,他们凭借对技术的深刻理解和不懈追求,成功推出了第一代深度神经网络语音AI芯片CI1006,这款芯片在行业内被认定为首创。这一重要里程碑为启英泰伦的发展奠定了坚实的基础,也标志着公司在人工智能语音芯片领域的正式起步。

Custom LeatherCraft Manufacturing Co Inc公司的发展小趣事

在快速发展的同时,CLC也关注环保和可持续发展。他们采用环保材料和生产工艺,减少对环境的影响。同时,他们还积极推动循环利用和废物减量化措施,努力实现绿色生产。这些努力不仅提升了品牌形象,也为公司的长期发展奠定了基础。

国炬(GOOGLL)公司的发展小趣事
OTL电路也是一种无输出变压器的功放电路,但它通常需要一个输出电容来耦合输出信号。相比OCL电路,OTL电路的输出阻抗较高,低频响应较差,但电路结构相对简单且成本较低。
DCX-CHOL Enterprises公司的发展小趣事

随着公司规模的扩大和市场竞争的加剧,DCX-CHOL Enterprises意识到品质管理的重要性。公司投入大量资源提升生产线自动化水平,引进先进的品质检测设备,并建立了严格的质量管理体系。这些措施有效地提高了产品的品质稳定性和可靠性,赢得了客户的信赖。同时,公司还注重员工培训和技能提升,培养了一支高素质、专业化的技术和管理团队。

问答坊 | AI 解惑

今年的大学生电子竞赛题目,大学生做的出来???

本帖最后由 paulhyde 于 2014-9-15 09:38 编辑 我看了半天,要我在3天3夜做出来,不可想象。 我都3年研发经验了,而且参加过05年的电子竞赛,是天津市2等奖。 可是,看到现在的题目,我怀疑是大学生能做出来的吗??? 如果真能大学生自己做出 ...…

查看全部问答>

盘点2009:中国光伏十大年度关键词

这个世界已经越来越有方向感,一群远见的精英思想正在汇聚成一张清晰的低碳线路图,供人类未来抵达。拯救地球环境,不能或缺中国力量。2009年度,中国光伏正在赶往一条叫做社会责任的低碳大道上。…

查看全部问答>

Camera 应用开发

平台:6410+WINCE6.0 新开一个贴,再讨论一下这个CAMERA应用开发,因为本人一直是做驱动的,现在要写应用,而且是COM接口的directshow,所以有很多东西要向大家请教,    用640X480分辩进行preview 和 拍照都没有问题,但是,我驱动给di ...…

查看全部问答>

讨论 WINCE5 2440 中堆和栈的分配问题

在一个线程中定义一个数组, 大小为320*240*8 定义1:U8 cData[320*240*8];   这个应该存在系统的stack里面,结果data abort失败了,提示就是stack的问题,于是重新 定义2:U8 *cData = new U8[320*240*8]  ,这个没有问题 ...…

查看全部问答>

无线遥控控制直流电机

按键控制无线遥控发送是脉冲 现在我想对接收板接收到无线模块发送的信号进行分析 1.如果只是单个脉冲电机就微动一下 2.如果是连续的脉冲,电机就保持转动状态,再发一个脉冲,电机才停止 现在不知道如何判断发送的是单个脉冲还是连续脉冲 请高 ...…

查看全部问答>

楼主,我能不能用DMA实现这个功能

我用双路AD同步采集,采集后的数据通过DMA传送的一个32位数组空间内,采集100次,100次后AD采样自动从从数组的开始位置存放。是不数不能实现这个功能啊?我怎么做不出来啊,我的数据只能采集16个,而且数据好像不是按我的要求去转换不同的通道…

查看全部问答>

TI 原厂LM3S8962板上调试部分的 CPLD 起到什么样的作用呢

TI  原厂LM3S8962板上调试部分的 CPLD 起到什么样的作用呢? 设计调试仿真器的时候,是否可以不用它?…

查看全部问答>

F2812断货原因

请问F2812为什么出现断货,什么时候恢复正常…

查看全部问答>

Unix环境高级编程 习题

附录A   函数原型 497附录B   其他源代码 512附录C   习题答案 518…

查看全部问答>