驱动开发1

控制三灯循环亮

demo.c

cpp 复制代码
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "myled.h"

#define CNAME "myled"
unsigned int major = 0;
char kbuf[100] = "";

unsigned int* rcc_virt = NULL; //定义rcc虚拟地址
gpio_t* gpioe_virt = NULL; //定义gpioe组虚拟地址
gpio_t* gpiof_virt = NULL; //定义gpiof组虚拟地址

#define LED1_ON (gpioe_virt->ODR |= (0x1 << 10))
#define LED1_OFF (gpioe_virt->ODR &= (~(0x1 << 10)))

#define LED2_ON (gpiof_virt->ODR |= (0x1 << 10))
#define LED2_OFF (gpiof_virt->ODR &= (~(0x1 << 10)))

#define LED3_ON (gpioe_virt->ODR |= (0x1 << 8))
#define LED3_OFF (gpioe_virt->ODR &= (~(0x1 << 8)))

int myled_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

ssize_t myled_write(struct file *file, const char __user *ubuf, size_t size, loff_t *loffs)
{
    int ret;
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    //如果用户想写的数据大小,大于内核空间的数据大小,更正用户写的数据大小
    if(size > sizeof(kbuf)) size = sizeof(kbuf);
    //将用户空间的数据,拷贝到内核空间
    ret = copy_from_user(kbuf,ubuf,size);
    if(ret){
        printk("copy from user is error\n");
        return -EIO;
    }
    //kbuf[0] = 0   kbuf[0] = 1  kbuf[0] = 2 操作哪一盏灯
    // kbuf[1] = 0 灯熄灭 kbuf[1] = 1 灯点亮
    switch(kbuf[0])
    {
        case LED1: //0
            kbuf[1] == 1 ? LED1_ON : LED1_OFF;
        break;
        case LED2: //1
            kbuf[1] == 1 ? LED2_ON : LED2_OFF;
        break;
        case LED3: //2
            kbuf[1] == 1 ? LED3_ON : LED3_OFF;
        break;
    }
    return size;
}

int myled_close (struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);
    return 0;
}

//操作方法结构体
const struct file_operations fops = {
    .open = myled_open,
    .write = myled_write,
    .release = myled_close,
};

//入口
static int __init demo_init(void)
{
    //注册字符设备驱动
    major = register_chrdev(0,CNAME,&fops);
    if(major < 0){
        printk("register chrdev is error\n");
        return -EIO;
    }
    printk("major = %d\n",major); //打印主设备号的值

    //rcc寄存器地址映射
    rcc_virt = ioremap(RCC_MP_AHB4ENSETR,4);
    if(rcc_virt == NULL){
        printk("ioremap rcc is error\n");
        return -EIO;
    }
    //GPIOE组寄存器地址映射
    gpioe_virt = ioremap(GPIOE,sizeof(gpio_t));
    if(gpioe_virt == NULL){
        printk("ioremap gpioe is error\n");
        return -EIO;
    }
    //GPIOF组寄存器地址映射
    gpiof_virt = ioremap(GPIOF,sizeof(gpio_t));
    if(gpiof_virt == NULL){
        printk("ioremap gpiof is error\n");
        return -EIO;
    }

    //LED1灯初始化 PE10
    *rcc_virt |= (0x1 << 4);//使能GPIOE组控制器[4] = 1
    gpioe_virt->MODER &= (~(0x3 << 20));//设置PE10引脚为输出模式 [21:20] = 01
    gpioe_virt->MODER |= (0x1 << 20);
    gpioe_virt->ODR |= (0x1 << 10); //设置PE10引脚输出低电平,LED1熄灭 [10] = 0

    //LED2灯初始化 PF10
    *rcc_virt |= (0x1 << 5);//使能GPIOF组控制器[5] = 1
    gpiof_virt->MODER &= (~(0x3 << 20));//设置PF10引脚为输出模式 [21:20] = 01
    gpiof_virt->MODER |= (0x1 << 20);
    gpiof_virt->ODR |= (0x1 << 10); //设置PF10引脚输出低电平,LED2熄灭 [10] = 0    

    //LED3灯初始化 PE8
    gpioe_virt->MODER &= (~(0x3 << 16));//设置PE8引脚为输出模式 [17:16] = 01
    gpioe_virt->MODER |= (0x1 << 16);
    gpioe_virt->ODR |= (0x1 << 8); //设置PE8引脚输出低电平,LED1熄灭 [8] = 0
    return 0;
}

//出口
static void __exit demo_exit(void)
{
    iounmap(gpioe_virt);//取消GPIOE组寄存器地址映射
    iounmap(gpiof_virt);//取消GPIOF寄存器地址映射
    iounmap(rcc_virt);//取消rcc寄存器地址映射
    //注销字符设备驱动
    unregister_chrdev(major,CNAME);
}

module_init(demo_init); //指定入口地址
module_exit(demo_exit); //指定出口地址
MODULE_LICENSE("GPL"); //许可证

test.c

cpp 复制代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>

int main(int argc,const char * argv[])
{
    char buf[128] = ""; 
    int fd = -1;
    fd = open("/dev/myled",O_RDWR); //打开
    if(fd == -1){
        perror("open is error");
        exit(1);
    }
    //buf[0] = 0  灯熄灭 buf[0] = 1 灯点亮
    while(1)
    {
        buf[0] = 0;
        write(fd,buf,sizeof(buf)); //写
        buf[1] = 1;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);
        buf[1] = 0;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);

        buf[0] = 1;
        write(fd,buf,sizeof(buf)); //写
        buf[1] = 1;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);
        buf[1] = 0;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);
    
        buf[0] = 2;
        write(fd,buf,sizeof(buf)); //写
        buf[1] = 1;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);
        buf[1] = 0;
        write(fd,buf,sizeof(buf)); //写
        sleep(1);
    }
    
    close(fd); //关闭
    return 0;
}

myled.h

cpp 复制代码
#ifndef __MYLED_H__
#define __MYLED_H__

enum led{
    LED1, //0
    LED2, //1
    LED3, //2
};

typedef struct {
    volatile unsigned int MODER;   // 0x00
    volatile unsigned int OTYPER;  // 0x04
    volatile unsigned int OSPEEDR; // 0x08
    volatile unsigned int PUPDR;   // 0x0C
    volatile unsigned int IDR;     // 0x10
    volatile unsigned int ODR;     // 0x14
    volatile unsigned int BSRR;    // 0x18
    volatile unsigned int LCKR;    // 0x1C 
    volatile unsigned int AFRL;    // 0x20 
    volatile unsigned int AFRH;    // 0x24
    volatile unsigned int BRR;     // 0x28
    volatile unsigned int res;
    volatile unsigned int SECCFGR; // 0x30
}gpio_t;

#define  GPIOE   (0x50006000) //GPIOE组基地址
#define  GPIOF   (0x50007000) //GPIOF组基地址 

#define RCC_MP_AHB4ENSETR 0x50000A28 //RCC寄存器的物理地址

#endif
相关推荐
运筹vivo@13 小时前
音频基础到ALSA框架
驱动开发·音频
爱跑马的程序员14 小时前
UMS9620 展锐平台增加一个虚拟陀螺仪
驱动开发·安卓·传感器·展锐·虚拟陀螺·传感器驱动
被遗忘的旋律.15 小时前
Linux驱动开发笔记(二十三)—— regmap
linux·驱动开发·笔记
比奇堡派星星18 小时前
如何新加netlink
linux·驱动开发
电脑小管家20 小时前
DirectX报错怎么办?快速修复游戏和软件崩溃问题
windows·驱动开发·microsoft·计算机外设·电脑
比奇堡派星星2 天前
Linux4.4使用AW9523
linux·开发语言·arm开发·驱动开发
比奇堡派星星2 天前
cmdline使用详解
linux·arm开发·驱动开发
AI时代原住民2 天前
SDD(Spec驱动开发)实战新范式:SDDAgent驱动SDD端到端开发流
驱动开发
比奇堡派星星2 天前
Linux 平台设备驱动框架详解
linux·开发语言·驱动开发
春日见3 天前
python3语法学习
linux·运维·服务器·人工智能·驱动开发