zoukankan      html  css  js  c++  java
  • Linux驱动入门(二)操作硬件

    copy from :https://blog.csdn.net/weixin_42462202/article/details/99949396

    Linux驱动入门(二)操作硬件
    文章目录
    Linux驱动入门(二)操作硬件
    一、通用做法
    ioremap
    iounmap
    寄存器读写
    二、gpiolib
    gpio.h
    gpiolib.c
    三星平台提供的gpio-cfg
    三、总结
    一、通用做法
    玩过单片机的朋友应该懂得如何操作寄存器

    举个例子,例如现在想往寄存器地址0xFF223440写数据,在单片机编程中的做法如下

    volatile unsigned int *reg = (unsigned int*)0xFF223440;
    *reg = val;

    在Linux中做法也是类似,只不过Linux不可以直接访问寄存器地址,而要经过映射后才能访问,下面开始介绍

    ioremap
    映射地址

    /*
    * cookie:表示要映射的地址
    * size:表示要映射的地址范围
    */
    ioremap(cookie,size)

    例如上面要操作寄存器0xFF223440,在Linux的做法如下

    volatile unsigned int *reg = ioremap(0xFF223440, 4);
    *reg = val;

    当然在映射前要先申请request_region(start,n,name)地址空间,不过这不是必须的

    在映射完地址后,当驱动程序退出时,不再使用此地址,需要使用iounmap取消映射

    iounmap
    取消地址映射

    /*
    * cookie:映射后的地址
    */
    iounmap(cookie)

    例如上面的例子中,在驱动程序退出时,需要调用

    iounmap(reg);

    在取消映射后,如果先前有申请地址空间,那么就需要释放申请的地址空间release_region(start,n)

    寄存器读写
    在上面的例子中,读写寄存器通过直接访问指针,而内核中提供了一套宏定义来读写寄存器

    readb(c) //读8位
    readw(c) //读16位
    readl(c) ///读32位

    writeb(v,c) //写8位
    writew(v,c) //写16位
    writel(v,c) //写32位

    二、gpiolib
    上面介绍的是通用的做法,可以访问和设置任意的寄存器

    内核中对于gpio的设置,提供了更加简便的方法-gpiolib

    gpiolib是一套对gpio的操作函数,有了这些函数,就可以简化对gpio进行操作,而不需要直接通过寄存器来操作

    当然gpiolib仅限于操作gpio,如果要操作非gpio相关的寄存器(例如lcd控制器,摄像头控制器等),那么还是要使用上面讲的通用方法,下面开始介绍gpiolib

    gpio.h
    对于每一款芯片,大多在移植的时候都有对应一个gpio.h文件

    对于每一款芯片,大多在移植的时候都有对应一个gpio.h文件

    以三星平台的S5PV210为例,gpio.h位于archarmmach-s5pv210includemachgpio.h

    其中定义了一系列的gpio相关的宏

    S5PV210_GPA0(_nr)
    S5PV210_GPA1(_nr)
    S5PV210_GPB(_nr)
    ...

    ​ 可以使用这些宏定义,通过gpiolib提供的函数来操作gpio

    gpiolib.c
    gpiolib.c位于driversgpiogpiolib.c,其中定义了一系列的gpio操作函数,gpio的操作函数需要搭配gpio.h中的宏定义使用

    int gpio_request(unsigned gpio, const char *label)
    void gpio_free(unsigned gpio)
    int gpio_direction_input(unsigned gpio)
    int gpio_direction_output(unsigned gpio, int value)
    int gpio_get_value(unsigned gpio)
    void gpio_set_value(unsigned gpio, int value)
    int gpio_to_irq(unsigned gpio)

    gpio_request

    申请gpio,在使用gpio前,应该先申请gpio,当然这并不是必须的

    gpio_free

    释放gpio,用于释放被申请了的gpio

    gpio_direction_input

    设置gpio为输入

    gpio_direction_output

    设置gpio为输出,并设置gpio高低电平

    gpio_get_value

    获取gpio的高低电平

    gpio_set_value

    设置gpio的高低电平

    gpio_to_irq

    获取gpio对应的外部中断

    如果我们设置S5PV210的GPIOA0的第四个引脚为高电平,我可以这样做

    /* 申请 */
    gpio_request(S5PV210_GPA0(3), "m_gpio");

    /* 设置 */
    gpio_direction_output(S5PV210_GPA0(3), 1);

    /* 不需要时释放 */
    gpio_free(S5PV210_GPA0(3));

    从上面的操作函数中,可以看到,gpio-lib仅支持设置gpio为输入或者输出,但要知道,有些gpio是可以复用成其他功能的(例如摄像头接口的gpio等),下面是从S5PV210的datasheet中截图的

    可以看到GPE0-0不仅可以设置为Input(输入模式)和Output(输出模式),还可以复用为CAM_A_PCLK(摄像头接口A的像素时钟引脚)

    那么如果没有其他的支持,我们就需要使用通用的方式来配置寄存器,为此,三星平台再提供了一套操作gpio的函数

    三星平台提供的gpio-cfg
    文件位于archarmplat-samsungincludeplatgpio-cfg.h

    其中的操作函数分为三类,第一类配置gpio,第二类设置gpio引脚状态,第三类设置gpio的驱动强度

    配置gpio

    #define S3C_GPIO_INPUT (S3C_GPIO_SPECIAL(0)) //输入
    #define S3C_GPIO_OUTPUT (S3C_GPIO_SPECIAL(1)) //输出
    #define S3C_GPIO_SFN(x) (S3C_GPIO_SPECIAL(x)) //复用功能

    int s3c_gpio_cfgpin(unsigned int pin, unsigned int to); //配置
    unsigned s3c_gpio_getcfg(unsigned int pin); //获取配置

    例如上述例子,如果要设置GPE0-0为摄像头接口A的像素时钟引脚,那么就这么配置

    s3c_gpio_cfgpin(S5PV210_GPE0(0), S3C_GPIO_SFN(2));

    设置引脚状态

    #define S3C_GPIO_PULL_NONE ((__force s3c_gpio_pull_t)0x00) //悬空
    #define S3C_GPIO_PULL_DOWN ((__force s3c_gpio_pull_t)0x01) //下拉
    #define S3C_GPIO_PULL_UP ((__force s3c_gpio_pull_t)0x02) //上拉

    int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull);
    s3c_gpio_pull_t s3c_gpio_getpull(unsigned int pin);

    设置引脚驱动强度

    #define S5P_GPIO_DRVSTR_LV1 ((__force s5p_gpio_drvstr_t)0x00)
    #define S5P_GPIO_DRVSTR_LV2 ((__force s5p_gpio_drvstr_t)0x01)
    #define S5P_GPIO_DRVSTR_LV3 ((__force s5p_gpio_drvstr_t)0x10)
    #define S5P_GPIO_DRVSTR_LV4 ((__force s5p_gpio_drvstr_t)0x11)

    s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin);
    s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr);

    三、总结
    使用通用的方法可以设置任意寄存器,只是比较麻烦
    使用gpiolib可以较为方便地配置gpio,但仅限于gpio,如果需要设置非gpio,还是需要使用通用地方法
    内核提供的gpiolib只能配置gpio为输入或者输出,其他功能(例如复用引脚,设置上下拉等)无法通过gpiolib设置,三星平台提供了另一套函数设置
    ————————————————
    版权声明:本文为CSDN博主「JT同学」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/weixin_42462202/article/details/99949396

    Always Believe Something Beauitful Will Be Happen
  • 相关阅读:
    GitLab 内存使用优化
    记一次 GitLab 的迁移过程
    MAC 最全快捷键
    IDEA中通过Java调用Python脚本报错
    远程服务调用PRC发展史
    分布式&微服务传送门
    (11)MySQL进阶篇SQL优化(InnoDB锁问题排查与解决)
    不懂物理的前端不是好的游戏开发者(一)—— 物理引擎基础
    京东购物小程序 | Taro3 项目分包实践
    浅谈树模型与集成学习-从决策树到GBDT
  • 原文地址:https://www.cnblogs.com/Oude/p/12455803.html
Copyright © 2011-2022 走看看