风雨同行 发表于 2024-6-22 13:02:29

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

【硬件】

3568的LED9 :引脚 GPIO0 B7
【设置GPIO的复用】

https://img-blog.csdnimg.cn/direct/0f97fd983c214590bbe9d2fcd45dd9de.png
    找设置复用关系的寄存器基地址、偏移地址、对应设置的GPIO。
查找:io -r -4 0xfdc2000c 系统设置的默认值
结果为1,意思是只有bit 0是1,其他全都为0。所以系统默认就是设置GPIO功能,所以可以不消设置复用GPIO。
【设置GPIO的方向 Direction Register】

https://img-blog.csdnimg.cn/direct/1624cc6b925540e983427993729394b3.png
查找对应IO设置:io -r -4 0xfdd60008 的默认值(GPIO基地址为0xfdd60000,GPIOB地址偏移8位:0xfdd60008)
结果为:0000c064
二进制 : 1100 0000 0110 0010https://img-blog.csdnimg.cn/direct/eb3d2467f6fe45508a92b63564aac30f.png
bit 15为1 ,所以默认已经设置为输出了。

【设置GPIO数据寄存器】

https://img-blog.csdnimg.cn/direct/475b6f5e42ee4fca8afdf2f6f676fb51.png
查找对应IO设置:io -r -4 0xfdd60000 的默认值
结果为:8000c040
可知bit15 默以为1
   PB7写1对应的数据寄存器地址:   8000c040
【问】B7的写使能位是哪一位?https://img-blog.csdnimg.cn/direct/eb3d2467f6fe45508a92b63564aac30f.png

bit31。https://img-blog.csdnimg.cn/direct/bab8e46bd12f4cbdbe42724e155e5f96.png
   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;//模拟内核寄存器的数据
   
    /************************/
    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 == 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 = {0};
   
   fd1 = open("/dev/test", HELLO);/* 打开设备节点1 */
   if(fd < 0)
   {
       perror("open error \n");
       return fd;   
   }   
   buf = atoi(argv);
   write(fd, buf, sizeof(buf));

   close(fd);
   return 0;
} 【实行效果】

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

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: 【Linux驱动】【手把手设置3568寄存器】点亮RK3568的一颗LED