LED分层,分离的程设设计

韦东山老师视频地址

本文是对视频内容的个人学习记录。

具体请查看百问网资料,嵌入式linux应用开发手册v5.1,这里简单描述下

        分层:在leddrv驱动程序中,把led操作部分抽象出来,设计成led_operations对象,所以我们就不用管硬件部分的工作,只知道这个对象,然后就可以进行引脚的初始化和操作。

struct led_operations{
    void (*map)(void);          //引脚映射
    void (*unmap)(void);        //引脚解映射
    int (*init)(int which);     //初始化
    int (*ctl)(int which,char state);   //操作引脚输出高低电平
};

        分离:led是属于gpio的操作,假如有实现了一个板子的所有gpio相关配置chip_demo_gpio.c,我们只需要指定需要用到的那些引脚资源就行。

struct led_resource
{
    int pin[LED_NUM];
};

资源指定实现

        led_resource.h的内容,实现led_resource这个对象类型和 get_led_resource函数声明。

#ifndef MY_LED_RESOURCE
#define MY_LED_RESOURCE

#define GROUP(x) (x>>16)
#define PIN(x)    ((x)&(0xffff))
#define GROUP_PIN(g,p)  ((g<<16)|(p))

#define LED_NUM  2

struct led_resource
{
    int pin[LED_NUM];
};

struct led_resource * get_led_resource(void);

#endif

        board_A_led.c内容,具体指定资源和get_led_resource函数的实现,get_led_resource是为了给其他文件调用,以达到资源的指定。

#include "led_resource.h"

static struct led_resource board_A_led={
    .pin[0]=GROUP_PIN(5,3),
    .pin[1]=GROUP_PIN(3,3)
};

struct led_resource * get_led_resource(void){
    return &board_A_led;
}

led_operations的实现

        led_opr.h实现led_operations对象类型的定义和get_board_led_opr的声明,get_board_led_opr是给leddrv.c调用。

#ifndef MY_LED_OPR
#define MY_LED_OPR

struct led_operations{
    void (*map)(void);
    void (*unmap)(void);
    int (*init)(int which);
    int (*ctl)(int which,char state);
};

struct led_operations* get_board_led_opr(void);

#endif

        chip_demo_gpio.c实现led_operations的具体操作和get_board_led_opr的实现。

#include "led_opr.h"
#include "led_resource.h"

#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/uaccess.h>

static  struct led_resource* led_rsc=NULL;

/* registers */
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

// GPIO5_GDIR 地址:0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR 地址:0x020AC000
static volatile unsigned int *GPIO5_DR;


//which指定板子上的那个led灯
static int board_A_gpio_init(int which){
    if(!led_rsc){
        led_rsc=get_led_resource();
    }
    printk("init gpio: group %d, pin %d\n", GROUP(led_rsc->pin[which]), PIN(led_rsc->pin[which]));

    switch(GROUP(led_rsc->pin[which])){
        case 3:
        {
            printk("init pin of group 3 ...\n");
            break;
        }

        case 5:
        {
            printk("init pin of group 5 ...\n");

            *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;
	        *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;

	        *GPIO5_GDIR |= (1<<3);

            break;
        }

    }
    return 0;
}

static int board_A_gpio_ctl(int which,char state){
    printk("set led %d: group %d, pin %d\n", state ? 1 : 0, GROUP(led_rsc->pin[which]), PIN(led_rsc->pin[which]));
	switch(GROUP(led_rsc->pin[which]))
	{
		case 3:
		{
			printk("set pin of group 3 ...\n");
			break;
		}
       
        case 5:
		{
			printk("set pin of group 5 ...\n");
            if (state)
            {       
                *GPIO5_DR &= ~(1<<3);/* set gpio to let led on */
            }
            else
            {                
                *GPIO5_DR |= (1<<3);  /* set gpio to let led off */
            }
			break;
		}
	}
    return 0;
}

void board_map(void){
     /* ioremap */
	// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址:0x02290000 + 0x14
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
	
	// GPIO5_GDIR 地址:0x020AC004
	GPIO5_GDIR = ioremap(0x020AC004, 4);
	
	//GPIO5_DR 地址:0x020AC000
	GPIO5_DR  = ioremap(0x020AC000, 4);
}


void board_unmap(void){
    iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);
}

static struct led_operations led_opr={
    .map=board_map,
    .unmap=board_unmap,
    .init=board_A_gpio_init,
    .ctl=board_A_gpio_ctl,
};


struct led_operations* get_board_led_opr(void){
    return &led_opr;
}

leddrv驱动代码

#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>
#include <linux/kernel.h>
#include <asm/io.h>

#include "led_opr.h"
#include "led_resource.h"

#define BUF_SIZE 1024

#define MIN(x,y) ((x)<(y)?(x):(y))

extern struct led_operations* get_board_led_opr(void);
char ker_buf[BUF_SIZE];

static int major=0;
static struct class *led_class;
static struct led_operations *led_opr;

ssize_t led_write (struct file *file, const char __user *usr_buf, size_t size, loff_t *off_set){
    struct inode *inode=file_inode(file);
    int minor=iminor(inode);
    int state;

    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    copy_from_user(&state,usr_buf,1);

    led_opr->ctl(minor,state);

    return 0;
}
int led_open (struct inode *inode, struct file *file){
    int minor;
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    minor=MINOR(inode->i_rdev);

    led_opr->init(minor);

    return 0;
}
int led_close(struct inode *inode, struct file *file){
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);

    return 0;
}

static struct file_operations led_drv={
    .owner=THIS_MODULE,
    .open=led_open,
    .release=led_close,
    .write=led_write,
};

static int __init led_init(void){
    int i=0;
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);

    led_opr=get_board_led_opr();
    led_opr->map();
    major=register_chrdev(0,"myled",&led_drv);
    led_class=class_create(THIS_MODULE,"myled_class");
    for(i=0;i<LED_NUM;++i){
        device_create(led_class,NULL,MKDEV(major,i),NULL,"myled%d",i);
    }
    return 0;
}

static void __exit led_exit(void){
    int i;
    printk("%s %s line %d\n",__FILE__,__FUNCTION__,__LINE__);
    led_opr->unmap();
    for(i=0;i<LED_NUM;++i){
        device_destroy(led_class,MKDEV(major,i));
    }
    class_destroy(led_class);
    unregister_chrdev(major,"led");

}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL"); 

makefile

# 1. 使用不同的开发板内核时, 一定要修改KERN_DIR
# 2. KERN_DIR中的内核要事先配置、编译, 为了能编译内核, 要先设置下列环境变量:
# 2.1 ARCH,          比如: export ARCH=arm64
# 2.2 CROSS_COMPILE, 比如: export CROSS_COMPILE=aarch64-linux-gnu-
# 2.3 PATH,          比如: export PATH=$PATH:/home/book/100ask_roc-rk3399-pc/ToolChain-6.3.1/gcc-linaro-6.3.1-2017.05-x86_64_aarch64-linux-gnu/bin 
# 注意: 不同的开发板不同的编译器上述3个环境变量不一定相同,
#       请参考各开发板的高级用户使用手册

all:
	make -C $(KERN_DIR) M=`pwd` modules 
	$(CROSS_COMPILE)gcc -o ledtest ledtest.c 

clean:
	make -C $(KERN_DIR) M=`pwd` modules clean
	rm -rf modules.order
	rm -f ledtest

100ask_led-y := leddrv.o chip_demo_gpio.o board_A_led_res.o
obj-m	+= 100ask_led.o


copy:
	cp 100ask_led.ko ledtest /home/book/nfs

修改linux窗口打印级别

echo "7 4 1 7" > /proc/sys/kernel/printk

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值