Linux笔记(二)控制一个LED


前言

提示:这里可以添加本文要记录的大概内容:

LED的控制就是控制LED点亮和熄灭。原理图如下。LED0连接到CPU 的GPIO。当IO输出高电平DS0熄灭,当IO输出低电平DS0点亮。,
在这里插入图片描述


一、Linux IO 控制

Linux系统下,在IMX6ULL平台控制一个IO的电平还是比较简单,操作几个相关的寄存器就可以了。
第一 配置控制IO时钟使能,使能以后相当于激活了IO的功能,关闭IO的时钟,就是关闭了IO的功能。
第二 配置IO的复用功能,因为较复杂CPU的一个IO有很多功能,一个IO是UART的TX、RX管脚、II2C的管脚、SPI的管脚、GPIO的管脚,所以必须根据要实现功能配置IO。控制LED当然是GPIO功能。
第三 配置IO的电气配置。IMX6ULL的在电气方面可选择余地非常大,上拉、下拉、推挽、输出电阻配置等等。
第四 配置IO的方向,即配置为输出还是输入,控制LED当然是输出。
第五 控制IO的输出电平,输出高电平LED熄灭,输出低电平LED点亮。

二、IMX6ULL LED控制相关寄存器

在这里插入图片描述
通过浏览原理图,LED0与L17管脚相连接。控制LED的IO就是GPIO1_03。对GPIO1_03配置完成后,控制输出电平就可以完成LED的亮和灭的控制。

1.时钟配置

在这里插入图片描述
在这里插入图片描述
CCM_CCGR1的26-27是gpio1 clock 使能控制,置为"11",gpio1的CLK就会使能。

2.选择IO复用功能为GPIO

在这里插入图片描述
(IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器可以配置gpio1_io03的功能,设定为ALT5(5),该管脚就配置成gpio.可以作为一般IO使用

3.配置IO的电气特性

在这里插入图片描述
在这里插入图片描述
IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03 配置0x10B0,配置的功能如下:
*bit 16:0 HYS关闭
*bit [15:14]: 00 默认下拉
*bit [13]: 0 kepper功能
*bit [12]: 1 pull/keeper使能
*bit [11]: 0 关闭开路输出
*bit [7:6]: 10 速度100Mhz
*bit [5:3]: 110 R0/6驱动能力
*bit [0]: 0 低转换率

3.配置IO方向

在这里插入图片描述
GPIO1_GDIR 的bit3设置为1,配置为输出。

4.输出电平控制寄存器

在这里插入图片描述
GPIO1_DR 寄存器bit3写入1,输出高电平。写入0,输出低电平。

三、IMX6ULL LED驱动

代码如下(示例):
-`#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>
/***************************************************************
Copyright © ALIENTEK Co., Ltd. 1998-2029. All rights reserved.
文件名 : led.c
作者 : 左忠凯
版本 : V1.0
描述 : LED驱动文件。
其他 : 无
论坛 : www.openedv.com
日志 : 初版V1.0 2019/1/30 左忠凯创建
**************************************************************/
#define LED_MAJOR 200 /
主设备号 /
#define LED_NAME “led” /
设备名字 */

#define LEDOFF 0 /* 关灯 /
#define LEDON 1 /
开灯 */

/* 寄存器物理地址 */
#define CCM_CCGR1_BASE (0X020C406C)
#define SW_MUX_GPIO1_IO03_BASE (0X020E0068)
#define SW_PAD_GPIO1_IO03_BASE (0X020E02F4)
#define GPIO1_DR_BASE (0X0209C000)
#define GPIO1_GDIR_BASE (0X0209C004)

/* 映射后的寄存器虚拟地址指针 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO03;
static void __iomem *SW_PAD_GPIO1_IO03;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

/*

  • @description : LED打开/关闭
  • @param - sta : LEDON(0) 打开LED,LEDOFF(1) 关闭LED
  • @return : 无
    */
    void led_switch(u8 sta)
    {
    u32 val = 0;
    if(sta == LEDON) {
    val = readl(GPIO1_DR);
    val &= ~(1 << 3);
    writel(val, GPIO1_DR);
    }else if(sta == LEDOFF) {
    val = readl(GPIO1_DR);
    val|= (1 << 3);
    writel(val, GPIO1_DR);
    }
    }

/*

  • @description : 打开设备
  • @param - inode : 传递给驱动的inode
  • @param - filp : 设备文件,file结构体有个叫做private_data的成员变量
  •  			  一般在open的时候将private_data指向设备结构体。
    
  • @return : 0 成功;其他 失败
    */
    static int led_open(struct inode *inode, struct file *filp)
    {
    return 0;
    }

/*

  • @description : 从设备读取数据
  • @param - filp : 要打开的设备文件(文件描述符)
  • @param - buf : 返回给用户空间的数据缓冲区
  • @param - cnt : 要读取的数据长度
  • @param - offt : 相对于文件首地址的偏移
  • @return : 读取的字节数,如果为负值,表示读取失败
    */
    static ssize_t led_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
    {
    return 0;
    }

/*

  • @description : 向设备写数据

  • @param - filp : 设备文件,表示打开的文件描述符

  • @param - buf : 要写给设备写入的数据

  • @param - cnt : 要写入的数据长度

  • @param - offt : 相对于文件首地址的偏移

  • @return : 写入的字节数,如果为负值,表示写入失败
    */
    static ssize_t led_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
    {
    int retvalue;
    unsigned char databuf[1];
    unsigned char ledstat;

    retvalue = copy_from_user(databuf, buf, cnt);
    if(retvalue < 0) {
    printk(“kernel write failed!\r\n”);
    return -EFAULT;
    }

    ledstat = databuf[0]; /* 获取状态值 */

    if(ledstat == LEDON) {
    led_switch(LEDON); /* 打开LED灯 /
    } else if(ledstat == LEDOFF) {
    led_switch(LEDOFF); /
    关闭LED灯 */
    }
    return 0;
    }

/*

  • @description : 关闭/释放设备
  • @param - filp : 要关闭的设备文件(文件描述符)
  • @return : 0 成功;其他 失败
    */
    static int led_release(struct inode *inode, struct file *filp)
    {
    return 0;
    }

/* 设备操作函数 */
static struct file_operations led_fops = {
.owner = THIS_MODULE,
.open = led_open,
.read = led_read,
.write = led_write,
.release = led_release,
};

/*

  • @description : 驱动出口函数

  • @param : 无

  • @return : 无
    */
    static int __init led_init(void)
    {
    int retvalue = 0;
    u32 val = 0;

    /* 初始化LED /
    /
    1、寄存器地址映射 */
    IMX6U_CCM_CCGR1 = ioremap(CCM_CCGR1_BASE, 4);
    SW_MUX_GPIO1_IO03 = ioremap(SW_MUX_GPIO1_IO03_BASE, 4);
    SW_PAD_GPIO1_IO03 = ioremap(SW_PAD_GPIO1_IO03_BASE, 4);
    GPIO1_DR = ioremap(GPIO1_DR_BASE, 4);
    GPIO1_GDIR = ioremap(GPIO1_GDIR_BASE, 4);

    /* 2、使能GPIO1时钟 /
    val = readl(IMX6U_CCM_CCGR1);
    val &= ~(3 << 26); /
    清楚以前的设置 /
    val |= (3 << 26); /
    设置新值 */
    writel(val, IMX6U_CCM_CCGR1);

    /* 3、设置GPIO1_IO03的复用功能,将其复用为

    • GPIO1_IO03,最后设置IO属性。
      */
      writel(5, SW_MUX_GPIO1_IO03);

    /*寄存器SW_PAD_GPIO1_IO03设置IO属性
    *bit 16:0 HYS关闭
    *bit [15:14]: 00 默认下拉
    *bit [13]: 0 kepper功能
    *bit [12]: 1 pull/keeper使能
    *bit [11]: 0 关闭开路输出
    *bit [7:6]: 10 速度100Mhz
    *bit [5:3]: 110 R0/6驱动能力
    *bit [0]: 0 低转换率
    */
    writel(0x10B0, SW_PAD_GPIO1_IO03);

    /* 4、设置GPIO1_IO03为输出功能 /
    val = readl(GPIO1_GDIR);
    val &= ~(1 << 3); /
    清除以前的设置 /
    val |= (1 << 3); /
    设置为输出 */
    writel(val, GPIO1_GDIR);

    /* 5、默认关闭LED */
    val = readl(GPIO1_DR);
    val |= (1 << 3);
    writel(val, GPIO1_DR);

    /* 6、注册字符设备驱动 */
    retvalue = register_chrdev(LED_MAJOR, LED_NAME, &led_fops);
    if(retvalue < 0){
    printk(“register chrdev failed!\r\n”);
    return -EIO;
    }
    return 0;
    }

/*

  • @description : 驱动出口函数

  • @param : 无

  • @return : 无
    /
    static void __exit led_exit(void)
    {
    /
    取消映射 */
    iounmap(IMX6U_CCM_CCGR1);
    iounmap(SW_MUX_GPIO1_IO03);
    iounmap(SW_PAD_GPIO1_IO03);
    iounmap(GPIO1_DR);
    iounmap(GPIO1_GDIR);

    /* 注销字符设备驱动 */
    unregister_chrdev(LED_MAJOR, LED_NAME);
    }

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE(“GPL”);
MODULE_AUTHOR(“zuozhongkai”);
`
在此我百分之百使用了原子的代码,ioremap( )和iounmap( )

总结

一个IO的驱动,主要是理解IO控制的配置和控制就可以了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值