【Linux驱动】【手把手配置3568寄存器】点亮RK3568的一颗LED

【硬件】

3568的LED9 :引脚 GPIO0 B7

【配置GPIO的复用】

 找配置复用关系的寄存器基地址、偏移地址、对应配置的GPIO。

查找:io -r -4 0xfdc2000c 系统设置的默认值

结果为1,意思是只有bit 0是1,其他全都为0。所以系统默认就是配置GPIO功能,所以可以不用设置复用GPIO。

【配置GPIO的方向 Direction Register】

查找对应IO配置:io -r -4 0xfdd60008 的默认值(GPIO基地址为0xfdd60000,GPIOB地址偏移8位:0xfdd60008

结果为:0000c064

二进制 : 1100 0000 0110 0010

bit 15为1 ,所以默认已经配置为输出了

【配置GPIO数据寄存器】

查找对应IO配置:io -r -4 0xfdd60000 的默认值

结果为:8000c040

可知bit15 默认为1

PB7写1对应的数据寄存器地址:   8000c040

【问】B7的写使能位是哪一位?

bit31。

PB7写0对应的数据寄存器地址:80004040

PS   :   bit15设置为0(PB7写0),B7对应控制位bit31必须使能1(写使能) 

【驱动】 

#define GPIO_DR 0xFDD60000

struct device_test{
    dev_t dev_num;
    static int major = 0;
    static int minor = 0;
    struct cdev cdev_test;
    struct class *class;
    struct device *device;
    char kbuf[32];  //模拟内核寄存器的数据
    
    /************************/
    unsigned int *vir_gpio_dr; //保存GPIO寄存器虚拟地址用的
};

/* 然后定义结构体变量 */
struct device_test dev1;

static int moduleparam_init()
{
           int ret;
           ret = alloc_chrdev_region(&dev1.dev_num,0,1,"HELLO");  
           if(ret<0){
                goto err_chrdev;
           }
           printk("alloc_chrdev_region ok\n");  
           dev1.major_num =MAJOR(dev1.dev_num); //将主设备号取出来
           dev1.minor_num = MINOR(dev1.dev_num);//将次设备号取出来
           printk("major_num = %d\n", dev1.major_num);//打印传入进来的主设备号
           printk("minor_num = %d\n", dev1.minor_num);//打印传入进来的次设备号
           
           dev1.cdev_test.owner = THIS_MODULE;
           cdev_init(dev1.cdev_test, &cdev_file_operations);
           
           ret = cdev_add(&dev1.cdev_test, dev1.dev_num, 1);
           if(ret<0){
                goto err_chradd;
           }
           
          dev1.class = class_creat(THIS_MODULE, "test");
           /* 判断创建类有没有失败 */
           if(IS_ERR(dev1,device)){
               ret = PTR_ERR(dev1,device);
               goto err_class_creat;           
           }
           
           dev1.device = device_creat( dev1.class,NULL, dev1.dev_num,,NULL,"test")  
            /* 判断创建类有没有失败 */
           if(IS_ERR(dev1.device)){
               ret = PTR_ERR(dev1,device);
               goto err_device_creat;           
           }                    
           return 0;
           
           dev1.vir_gpio_dr = ioremap(GPIO_DR, 4);
            if(IS_ERR(dev1.vir_gpio_dr)){
               ret = PTR_ERR(dev1.vir_gpio_dr);
               goto err_ioremap;           
           }                    

err_ioremap:
    iounmap(GPIO_DR); //要取消虚拟映射的地址

err_device_creat:  //设备添加失败,意味着设备类添加成功,就要把这个类删掉
    class_destroy( dev1.class);
err_class_creat: //类添加失败,意味着字符设备添加成功,就要把这个字符设备删掉
    cdev_del(& dev1.cdev_test);  //销毁字符设备        
err_chradd: //添加cdev失败,意味着添加设备号成功,就要释放这个设备号
    unregister_chrdev_region( dev1.dev_num,DEVICE_NUMBER);//注销设备号
err_chrdev:
     return ret;
}

关键:

static ssize_t cdev_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    struct device_test *test_dev = (struct device_test *)file->private_data;
    test_dev->kbuf = {0};
    if(copy_from_user( test_dev->kbuf, buf ,sizeof(buf))!= 0);
    {
       printk("copy_from_user error !\n");
       return -1;
    }
    if(test_dev -> kbuf[0] == 1){
        *(test_dev->vir_gpio_dr) = 0x8000c040;
        else if{
        *(test_dev->vir_gpio_dr) = 0x80004040;        
        }   
    }
    return 0;            
}

static void hello_exit(void)
{
  unregister_chrdev_region( dev1.dev_num,DEVICE_NUMBER);//注销设备号
  cdev_del(& dev1.cdev_test);  //销毁字符设备
  
  device_destroy( dev1.class, dev1.dev_num);
  class_destroy( dev1.class);
  iounmap(GPIO_DR);
  printk("gooodbye! \n");
}

【APP】

int main(int argc, char *argv[])
{
   int fd;
   char buf[32] = {0};
   
   fd1 = open("/dev/test", HELLO);  /* 打开设备节点1 */
   if(fd < 0)
   {
       perror("open error \n");
       return fd;   
   }   
   buf[0] = atoi(argv[1]);
   write(fd, buf, sizeof(buf));

   close(fd);  
   return 0;  
}

【实验效果】

./a.out 1 可以实现点灯

./a.out 0 可以实现灭灯

  • 21
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"手把手Linux驱动3-之字符设备架构详解,有这篇就够了"是一篇文章,它是《一口Linux》公众号中的驱动部分的一部分。这篇文章主要讲解了Linux内核中的字符设备架构。在Linux中,一切皆文件,所有的硬件设备操作都被抽象成文件的操作。因此,如果应用层要访问硬件设备,它必须调用与硬件对应的驱动程序。这篇文章详细介绍了字符设备的概念、字符设备驱动的结构以及字符设备驱动的注册和注销过程。阅读这篇文章可以帮助读者深入了解Linux驱动开发中字符设备的相关知识。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [公众号一口Linux驱动部分源码汇总.rar](https://download.csdn.net/download/daocaokafei/12740588)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [手把手Linux驱动3-之字符设备架构详解,有这篇就够了](https://blog.csdn.net/daocaokafei/article/details/108172338)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值