【PHYTEC开发板试用体验】2 实现一个酷炫霓虹灯_Part-B

描述

本文来源电子发烧友社区,作者:jf_00240724, 帖子地址:https://bbs.elecfans.com/jishu_2284706_1_1.html

今天我们接上一篇继续,需要做两个事情。第一个是重写驱动,第二个是开发霓虹灯应用程序。

第一章 重写驱动
一.1. 知识储备
一.1.1. 卸载驱动 
一.1.1.1. linux加载/卸载驱动有两种方法


一.1.1.1.1. modprobe

这里我们主要用这个。

注:在使用这个命令加载模块前先使用depmod -a命令生成modules.dep文件,该文件位于/lib/modules/$(uname -r)目录下;modprobe命令智能地向内核中加载模块或者从内核中移除模块,可载入指定的个别模块,或是载入一组相依的模块。modprobe会根据depmod所产生的依赖关系,决定要载入哪些模块。若在载入过程中出错,modprobe会卸载整组的模块。

载入模块的命令:

(1) 载入指定的模块:modprobe drv.ko

(2) 载入全部模块:modprobe -a

卸载模块的命令:modprobe -r drv.ko

modprobe命令用于智能地向内核中加载模块或者从内核中移除模块。

modprobe可载入指定的个别模块,或是载入一组相依的模块。modprobe会根据depmod所产生的相依关系,决定要载入哪些模块。若在载入过程中发生错误,在modprobe会卸载整组的模块。

选项

-a或--all:载入全部的模块;

-c或--show-conf:显示所有模块的设置信息;

-d或--debug:使用排错模式;

-l或--list:显示可用的模块;

-r或--remove:模块闲置不用时,即自动卸载模块;

-t或--type:指定模块类型;

-v或--verbose:执行时显示详细的信息;

-V或--version:显示版本信息;

-help:显示帮助。

参数                模块名:要加载或移除的模块名称。


实例

查看modules的配置文件:modprobe -c

这里,可以查看modules的配置文件,比如模块的alias别名是什么等。会打印许多行信息,例如其中的一行会类似如下:

alias symbol:ip_conntrack_unregister_notifier ip_conntrack

列出内核中所有已经或者未挂载的所有模块:modprobe -l

这里,我们能查看到我们所需要的模块,然后根据我们的需要来挂载;其实modprobe -l读取的模块列表就位于/lib/modules/`uname -r`目录中;其中uname -r是内核的版本,例如输出结果的其中一行是:

/lib/modules/2.6.18-348.6.1.el5/kernel/net/netfilter/xt_statistic.ko

挂载vfat模块:modprobe vfat

这里,使用格式modprobe 模块名来挂载一个模块。挂载之后,用lsmod可以查看已经挂载的模块。模块名是不能带有后缀的,我们通过modprobe -l所看到的模块,都是带有.ko或.o后缀。

移除已经加载的模块:modprobe -r 模块名

这里,移除已加载的模块,和rmmod功能相同。

一.1.1.1.2. rmmod

这个卸载命令不会把其依赖模块一同卸掉,所以这里我们只作简单介绍。
一.1.2. Linux驱动框架

接下来,我们开始重新写驱动,linux系统下写驱动,其实就是配置相应的硬件寄存器,那本章的霓虹灯驱动,也就是对imX 8的GPIO进行配置,由于裸机实验不同的是,并且驱动要符合linux驱动框架,下面我们来先理解了解一下linux的驱动框架。

一.1.2.0.1. 地址映射

linux的驱动,并不能够直接操作寄存硬件寄存器,而是需要通过MMU即内存管理单元,它的主要功能是
一、以完成虚拟空间的物理空间的映射
二、内存保护设置存储器的访问权限,设置虚拟存储空间的缓冲特性

这里我们会用到两个函数ioremap,iounmap,它们分别是用来获取物理地址空间对应的虚拟地址,和卸载时释放掉之前所做的映射

一.1.2.0.2. linux内存访问函数

对于arm来说,只有IO内存,linux内核建议使用一组操作函数来对映射后的内存进行读写操作
一、读操作函数
<

1 u8 readb(constvolatilevoid __iomem *addr)

2 u16 readw(constvolatilevoid __iomem *addr)

3 u32 readl(constvolatilevoid __iomem *addr)

>

readb、readw和readl这三个函数分别对应8bit、16bit和32bit读操作,参数addr就是要读取写内存地址,返回值就是读取到的数据。

二、写操作函数

<

1void writeb(u8 value,volatilevoid __iomem *addr)

2void writew(u16 value,volatilevoid __iomem *addr)

3void writel(u32 value,volatilevoid __iomem *addr)

>

writeb、writew和writel这三个函数分别对应8bit、16bit和32bit写操作,参数value是要写入的数值,addr是要写入的地址。

接下来我们开始搭建一个linux驱动框架:
<

#include "linux/init.h"

#include "linux/module.h"

#include "linux/fs.h"

#include "linux/types.h"

// struct inode 声明在 linux/fs.h 中

// struct file 声明在 linux/fs.h 中

int led_open (struct inode *i, struct file *f)

{

    // printk 声明在 linux/printk.h 中

    printk("led open!rn");

    return 0;

}

int led_release (struct inode *i, struct file *f)

{

    printk("led release!rn");

    return 0;

}

// ssize_t 定义在 linux/types.h 中

// __user 定义在 linux/compiler.h 中

// size_t 定义在 linux/types.h 中

// loff_t 定义在 linux/types.h 中

ssize_t led_read (struct file *f, char __user *b, size_t c, loff_t * l)

{

    printk("led read!rn");

    return 0;

}

ssize_t led_write (struct file *f, const char __user *b, size_t c, loff_t *l)

{

    printk("led write!rn");

    return 0;

}

// 声明在 linux/fs.h 头文件中

static struct file_operations fops = {

    .open = led_open,

    .release = led_release,

    .read = led_read,

    .write = led_write,

};

/* 驱动入口函数 */

static int __init led_init(void)

{

    /* 入口函数具体内容 */

    int retvalue = 0;

    // 声明在 linux/fs.h 头文件中

    retvalue = register_chrdev(200,"chrdev",&fops);

    if(retvalue < 0){

        /* 字符设备注册失败 */

    }

    return 0;
}

/* 驱动出口函数 */

static void __exit led_exit(void)

{

    /* 出口函数具体内容 */

    // 声明在 linux/fs.h 头文件中

    unregister_chrdev(200,"chrdev");

}

// 声明在 linux/init.h 头文件中

/* 将上面两个函数指定为驱动的入口和出口函数 */

module_init(led_init);

module_exit(led_exit);

// 声明在 linux/module.h 头文件中

MODULE_LICENSE("GPL");

>

这只是一个驱动框架没有实际内容。

一.2. 硬件准备

接下来我们要找到电路原理图,和主芯片的操作手册从而找到LED灯对应的哪一个引脚以及其对应的寄存器。

在如下链接中我们找到这样一句话,好吧,原来他并不是GPIO控制的,而是一个iic芯片PCA9533中转控制的,不得不说这个硬件设计让人匪夷所思啊。

Multicolor (RGB) LED (D24)

The phyBOARD-Pollux provides one multicolor (RGB) LED (D24) (see phyBOARD-Pollux Components (Top)). The LEDs are connected to a LED driver (NXP PCA9533/01) controlled by I2C2 bus.

https://www.phytec.de/cdocuments ... wareManual-LEDsLEDs

一.3. 软件-实操

一.3.1. 驱动卸载

基于以上的知识储备,本来想尝试一下卸载得掉leds这个驱动?但最终发现不是我们以上准备的驱动框架,而是sysfs的驱动框架,稍微研究一下,发现有点难度,值得针对性的再写一篇。

在此我们就不去卸载了。

一.3.2. 驱动编写

等研究好了sysfs驱动框架后,再实操一遍iic驱动编写。

第二章 应用程序

二.1. 代码

这里直接上代码:
二.1.1. Leds_app.h
<

typedef enum{

    LED1_RED = 1,

    LED2_GREEN,

    LED3_BULE

}LED_ID;

int leds_control(LED_ID led_id,unsigned char brightness)

>
二.1.2. Leds_app.c

<

int leds_control(LED_ID led_id,unsigned char brightness)

{

    int fd = 0;

    int ret = 0,len;

    /*this buffer size is sufficient to store file path */

    char buf[128];

    //printf("enter leds_controlrn");

    snprintf(buf, sizeof(buf), "/sys/class/leds/user-led%d/brightness",led_id);

    fd = open(buf, O_RDWR);

    if(fd < 0){

        printf("Can't open file %srn", buf);

        return -1;

    }

    len = snprintf(buf, sizeof(buf),"%d", brightness);

    ret =  write(fd, buf, len);

    if (ret < 0)

            perror("sysfs_led_write:");

    ret = close(fd);

    if(ret < 0){

        printf("Can't close file for led%drn", led_id);

        return -1;

    }

   // printf("leave  leds_controlrn");

    return 0;

}

>
二.1.3. Main.c

<

#include

#include

#include

#include "stdio.h"

#include "leds_app.h"

int main(int argc, char *argv[])

{

    int led1_value,led2_value,led3_value;

    while (1) {

        led1_value = rand()%255;

        led2_value = rand()%255;

        led3_value = rand()%255;

        printf("led1:%3d led2:%3d led3:%3dn",led1_value,led2_value,led3_value);

        leds_control(LED3_BULE,0);

        leds_control(LED1_RED,led1_value);

        sleep(0.9);

        //leds_control(LED1_RED,0);

        leds_control(LED2_GREEN,led2_value);

        sleep(0.8);

        leds_control(LED2_GREEN,0);

        leds_control(LED3_BULE,led3_value);

        sleep(0.5);

}
}

>
二.2. Log

打印出如下log

<

10:48:51: Starting /opt/HelloQuick/bin/HelloQuick ...

Warning: Identity file  not accessible: No such file or directory.

QML debugging is enabled. Only use this in a safe environment.

led1:163 led2:151 led3:162

led1: 85 led2: 83 led3:190

led1:241 led2:252 led3:249

led1:121 led2:107 led3: 82

led1: 20 led2: 19 led3:233

led1:226 led2: 45 led3: 81

led1:142 led2: 31 led3: 86

led1:  8 led2: 87 led3: 39

led1:167 led2:  5 led3:212

...

>
二.3. 看效果:
请观看底部视频



霓虹灯效果

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分