• 5、映射的思考


    学习了 GPIO_newbule 之后,一血关于映射上面的问题总结。

    1、映射方法

        实现映射的方法是通过:ioremap ,IO_ADDRESS 这两种方法,实现物理和虚拟地址的映射,它们返回的结果就是虚拟地址了,但是这两种方法的区别是:

    ioremap : 动态映射,一般是在外围的控制器的地址。当 映射的时间,是当加载相对应函数的是,才完成映射的操作。

    IO_ADDRESS  : 静态映射,一般是寄存器资源映射上,映射的时间是,当系统启动的时候,就完成映射的操作,

    1.1、IO_ADDRESS  的映射

       物理地址 = 基址 + 偏移地址,所以使用 IO_ADDRESS   进行地址映射的时候,存在两种映射,既直接使用物理地址映射和先对基址映射之后,再加上偏移地址,这两种映射的最终地址,都是一样的。

    方法一:

    #define IOConfig         IO_ADDRESS(0x200f0000) //IO复用寄存器

    #define HW_REG(reg) *((volatile unsigned int *)(reg))

    HW_REG(IOConfig + 0x138) = 0;

        上面的代码,是实现 200f_0000 基址地址的映射之后,再加上偏移地址。

    方法二:

    writel(0, IO_ADDRESS(0x200F0138));

        实现是对物理地址做完映射之后,进行写入 0 的操作。

       两种方法,经过验证,最终得到的虚拟地址是完全一样的,本平台使用的是 海思的 HI3518平台,所以关于 IO_ADDRESS 的定义是位于

    Io.h (archarmmach-hi3518includemach)  这里,里面看到 IO_ADDRESS 定义为:

    #define __io(a)        __typesafe_io(a)
    #define __mem_pci(a)    (a)

    #define HI3518_IOCH1_PHYS 0x10000000 /* 0x1000_0000 ~ 0x1020_0000 */
    #define HI3518_IOCH2_PHYS 0x20000000 /* 0x2000_0000 ~ 0x2020_0000 */
    #define HI3518_IOCH1_SIZE 0x200000
    #define HI3518_IOCH2_SIZE 0x700000

    #define HI3518_IOCH1_VIRT 0xFE000000
    #define HI3518_IOCH2_VIRT (HI3518_IOCH1_VIRT + HI3518_IOCH1_SIZE)

    /*
    *         physical addr       <--->         virtual addr
    * [0x1000_0000 ~ 0x1020_0000) <---> [0xFE00_0000 ~ 0xFE20_0000)
    * [0x2000_0000 ~ 0x2070_0000) <---> [0xFE20_0000 ~ 0xFE90_0000)
    */
    #define IO_IOCH1_OFFSET        (HI3518_IOCH1_VIRT - HI3518_IOCH1_PHYS)
    #define IO_IOCH2_OFFSET        (HI3518_IOCH2_VIRT - HI3518_IOCH2_PHYS)

    #define IO_ADDRESS(x) ((x) >= HI3518_IOCH2_PHYS ? (x) + IO_IOCH2_OFFSET
                            : (x) + IO_IOCH1_OFFSET)

    1.3、计算虚拟地址

    当IO_ADDRESS(0X200F0000) = (0X200F0000) + IO_IOCH2_OFFSET
        = (0X200F0000) + (HI3518_IOCH2_VIRT - HI3518_IOCH2_PHYS)
        = (0X200F0000) + (HI3518_IOCH2_VIRT - 0x20000000)
        = (0X200F0000) + (0xFE000000 + 0x200000) - 0x20000000
        = FE2F0000  
       
    所以,IO_ADDRESS(0X200F0000) + 0x138 = FE2F0138

    当当IO_ADDRESS(200F0138) = (200F0138) + IO_IOCH2_OFFSET
        = 200F0138 + (HI3518_IOCH2_VIRT - HI3518_IOCH2_PHYS)
        = 200F0138 + (HI3518_IOCH1_VIRT + HI3518_IOCH1_SIZE) - 0x20000000
        = 200F0138 + 0xFE000000 + 0x200000 - 0x20000000
        = FE2F0138

       可见最终的虚拟地址,都一样的。

    1.4、虚拟地址的操作

        对已经完成虚拟地址操作之后,需要对这个地址操作的时候,有以下方法:

    void writeb(unsigned value, address);   // 8位

    void writew(unsigned value, address);  // 16 位

    void writel(unsigned value, address); // 32 位

        这些写入函数,完成写 value 到 address 的地址,address 地址都是已经完成映射的虚拟地址

    unsigned readb(address);

    unsigned readw(address);

    unsigned readl(address);

        读出函数,是将虚拟地址 address 处,读出寄存器的值。

    #define HW_REG(reg) *((volatile unsigned int *)(reg))

    HW_REG(IOConfig + 0x138) = 0;

        通过,宏代码的方法实现寄存器的写入

    #define GPIO0_6_DIR        IO_ADDRESS(0x20140000+ 0x400)

    flag = HW_REG(GPIO0_6_DIR);

        完成寄存器数据的读出。

    1.5、通过报错的方法寻找头文件

        笔者,想寻找关于 IO_ADDRESS 是在那个头文件定义的,经过朋友指点才找到,但是还有通过重复定义的方法,编译器会提供相关的信息,其实就可以找到。

        在函数里面,自己定义 IO_ADDRESS ,而头文件包含的地方,也是存在 IO_ADDRESS  的,所以就出现了重复定义的错误,当编译的时候,就会报错:

    /home/carlos/3516C/driver/gpio_newBlue/gpio.c:168: warning: "IO_ADDRESS" redefined
    arch/arm/mach-hi3518/include/mach/io.h:25: note: this is the location of the previous definition

        可见,与真正的头文件是在,arch/arm/mach-hi3518/include/mach/io.h,达到我们的目的

  • 相关阅读:
    PHP函数篇详解十进制、二进制、八进制和十六进制转换函数说明
    TP5安装workerman版本的坑
    下载git2.2.1并将git添加到环境变量中
    RedHat安装git报错 expected specifier-qualifier-list before ‘z_stream’
    Git出现fatal: Unable to find remote helper for 'https'
    ThinkPHP5实现定时任务
    php一行代码获取本周一,本周日,上周一,上周日,本月一日,本月最后一日,上月一日,上月最后一日日期
    git 查看日志记录
    程序员必读之软件架构 读书笔记
    centos7 安装桌面
  • 原文地址:https://www.cnblogs.com/qxj511/p/5468901.html
Copyright © 2020-2023  润新知