编写驱动代码控制LED灯亮灭

1.头文件(所需寄存器地址) fsmp157a_led_head.c
#ifndef __HEAD_H__
#define __HEAD_H__
//GPIOE_MODER寄存器地址
#define PHY_GPIOE_MODER 0x50006000
//GPIOE_ODR寄存器地址
#define PHY_GPIOE_ODR 0X50006014

//GPIOF_MODER寄存器地址
#define PHY_GPIOF_MODER 0X50007000
//GPIOF_ODR寄存器地址
#define PHY_GPIOF_ODR 0X50007014

//RCC_AHB4ENSETR寄存器地址
#define PHY_RCC 0x50000A28

#endif
2.内核驱动代码(实现编程代码机制)fsmp157a_led_dev.c
#include 
#include 
#include 
#include 
#include 
#include "fsmp157a_led_head.h"

unsigned int *vir_gpioe_moder;
unsigned int *vir_gpioe_odr;
unsigned int *vir_gpiof_moder;
unsigned int *vir_gpiof_odr;
unsigned int *vir_rcc;

char kbuf[128] = "";
//封装操作方法
//int (*open) (struct inode *, struct file *);
//ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
//ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
//int (*release) (struct inode *, struct file *);
int mycdev_open(struct inode *inode, struct file *file)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    return 0;
}

ssize_t mycdev_write(struct file *fiile,const char *ubuf, size_t size, loff_t *lof)
{
    printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
   
    int ret;
    //将用户空间的数据传递到内核
    ret = copy_from_user(kbuf, ubuf, size);
    if(ret)
    {
        printk("copy_from_user is filed\n");
        return -EIO;
    }
    switch(kbuf[0])
    {

        //LED1
        case '1':
            switch(kbuf[1])
            {
                case '0':
                    //关灯逻辑
                    (*vir_gpioe_odr) &= (~(0x1 << 10));
                    break;
                case '1':
                    //开灯逻辑
                    (*vir_gpioe_odr) |= (0x1 << 10);
                    break;
            }
            break;
        //LED2
        case '2':
            switch(kbuf[1])
            {
                case '0':
                    //关灯逻辑
                    (*vir_gpiof_odr) &= (~(0x1 << 10));
                    break;
                case '1':
                    //开灯逻辑
                    (*vir_gpiof_odr) |= (0x1 << 10);
                    break;
            }
            break;
        //LED3
         case '3':
            switch(kbuf[1])
            {
                case '0':
                    //关灯逻辑
                    (*vir_gpioe_odr) &= (~(0x1 << 8));
                    break;
                case '1':
                    //开灯逻辑
                    (*vir_gpioe_odr) |= (0x1 << 8);
                    break;
            }
            break;
    }
    
    return 0;
}

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

//定义一个操作方法结构体对象
struct file_operations fos = {
    .open = mycdev_open,
    .read = mycdev_read,
    .write = mycdev_write,
    .release = mycdev_close,

};

//定义变量,存放major
unsigned int major;

//入口函数
static int __init mycdev_init(void)
{
    //注册设备驱动,申请0-255共256个资源(次设备号)
    major = register_chrdev(0, "mychardev", &fos);
    if(major < 0)
    {
        printk("注册设备驱动失败\n");
        return major;
    }
    printk("注册设备驱动成功:major = %d\n", major);
    
    //物理内存映射到虚拟地址
    //GOIOE_MODER寄存器地址映射
    vir_gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
    if(NULL == vir_gpioe_moder)
    {
        printk("物理内存地址映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    //GOIOE_ODR寄存器地址映射
    vir_gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
    if(NULL == vir_gpioe_odr)
    {
        printk("物理内存地址映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    //GOIOF_MODER寄存器地址映射
    vir_gpiof_moder = ioremap(PHY_GPIOF_MODER, 4);
    if(NULL == vir_gpiof_moder)
    {
        printk("物理内存地址映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    //GOIOF_ODR寄存器地址映射
    vir_gpiof_odr = ioremap(PHY_GPIOF_ODR, 4);
    if(NULL == vir_gpiof_odr)
    {
        printk("物理内存地址映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    //RCC_AHB4ENSETR寄存器地址映射
    vir_rcc = ioremap(PHY_RCC, 4);
    if(NULL == vir_rcc)
    {
        printk("物理内存地址映射失败%d\n", __LINE__);
        return -EFAULT;
    }
    printk("物理内存地址映射成功\n");
    //寄存器初始化工作
    //RCC使能GPIOE/GPIOF组控制器
    (*vir_rcc) |= (0x3 << 4);

    //设置PE10/PF10/PE8引脚为输出模式  GPIOE_MODER[21:20] = 01
    (*vir_gpioe_moder) &= (~(0x3 << 20));
    (*vir_gpioe_moder) |= (0x1 << 20);
    //设置PF10引脚为输出模式  GPIOF_MODER[21:20] = 01
    (*vir_gpiof_moder) &= (~(0x3 << 20));
    (*vir_gpiof_moder) |= (0x1 << 20);
    //设置PE8引脚为输出模式  GPIOF_MODER[17:16] = 01
    (*vir_gpioe_moder) &= (~(0x3 << 16));
    (*vir_gpioe_moder) |= (0x1 << 16);
    
    //设置默认为关灯
    (*vir_gpioe_odr) &= (~(0x1 << 10));
    (*vir_gpiof_odr) &= (~(0x1 << 10));
    (*vir_gpioe_odr) &= (~(0x1 << 8));
    return 0;
}

//出口函数
static void __exit mycdev_exit(void)
{
    //取消内存映射
    iounmap(vir_gpioe_moder);
    iounmap(vir_gpioe_odr);

    iounmap(vir_gpiof_moder);
    iounmap(vir_gpiof_odr);

    iounmap(vir_rcc);

    //注销字符设备驱动
    unregister_chrdev(major, "mychrdev");

}
//声明入口函数
module_init(mycdev_init);
//声明出口函数
module_exit(mycdev_exit);
//声明内核模块遵循GPL协议
MODULE_LICENSE("GPL");
3.用户测试代码(实现代码逻辑)fsmp157a_led_test.c
#include 
#include 
#include 
#include 
#include 

int main(int argc, char const *argv[])
{
    char buf[128] = "";
    int fd = open("/dev/mychrdev", O_RDWR);
    if(fd < 0)
    {
        printf("打开设备文件失败\n");
        return -1;
    }
    printf("打开设备文件成功\n");
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        printf("请选择灯(1 2 3)及开关)1:开灯 0:光灯:");
        fgets(buf, sizeof(buf), stdin);
        buf[strlen(buf) - 1] = '\0';
        write(fd, buf, sizeof(buf));
    }

    return 0;
}

你可能感兴趣的:(学习,Linux驱动)