嵌入式开发记录-day27 物理地址到虚拟地址映射及IO控制

1、由于ARM用到的内存管理,所以实际的物理地址不允许人为操作;

  Linux内核基于此,提供了物理地址到虚拟地址映射的接口,以至于访问虚拟地址可以达到访问实际地址相同的结果;

2、通过数据手册·上的物理地址到虚拟地址的映射,控制一个led灯;

3、物理地址及其相关寄存器

  GPL2_0---->LED2 端口对应;

  查看数据手册、原理图KP_COL0--->GPL2_0--->0x1100 0000+0x0100  

  需要用到的寄存器有:

    GPL2CON、GPL2DAT、GPL2PU
    寄存器地址 = Base address + Offset
    GPL2CON = 0x11000000 + 0x0100 = 0x11000100
    GPL2DAT = 0x11000000 + 0x0104
    GPL2PU = 0x11000000 + 0x0108
    需要注意寄存器的位数,有的是32位,有的是16位、8位

4、加载模块led默认点亮,卸载模块led熄灭

  1、用的函数ioremap()

  Linux在io.h头文件中声明了函数ioremap(),用来将I/O内存资源的物理地址映射到核心虚地址空间(3GB-4GB)中(这里是内核空间)

 #define ioremap(cookie,size)           __ioremap(cookie,size,0)

  __ioremap函数原型为(arm/mm/ioremap.c):

  void __iomem * __ioremap(unsigned long phys_addr, size_t size, unsigned long flags);
// 函数是一个宏,物理地址、地址空间大小

  2、driIoremap() 

#include <linux/init.h>
#include <linux/module.h>
#include <asm/io.h>

MODULE_LICENSE("Dual BSD/GPL");
MODULE_AUTHOR("TOPEET");

// 定义物理地址 虚拟地址
volatile unsigned long phys_addr,virtl_addr;
// 定义寄存器地址变量
volatile unsigned long *GPL2CON,*GPL2DAT,*GPL2PU;

 // 1、 寄存器IO端口物理地址到虚拟地址映射初始化
static void GPL2_device_init(void)
{
    phys_addr = 0x11000100;  // 物理地址
    virtl_addr = (unsigned long)ioremap(phys_addr,0x10);  // 物理地址映射位置 开辟16个地址
    GPL2CON = (unsigned long*)(virtl_addr + 0x00);  // 控制寄存器地址
    GPL2DAT = (unsigned long*)(virtl_addr + 0x04);
    GPL2PU  = (unsigned long*)(virtl_addr + 0x08);
}  
// 2、寄存器输出模式、上下拉配置
static void GPL2_device_cfg(void)
{
    // GPL2CON[0] 0x1 = Output 控制寄存器
    // GPL2CON[0] [3:0] 
    *GPL2CON &= 0xfffffff0;
    *GPL2CON |= 0x00000001;   // 配置输出模式
    // 上拉输出  GPL2PU 0x3 = Enables Pull-up GPL2PUD[n] 
    *GPL2PU |= 0x03;
}     
// 3、开启led
static void GPL2_device_on(void)
{
    *GPL2DAT |= 0x01;  // 开启led
}     
// 4、关闭Led 
static void GPL2_device_off(void)
{
    *GPL2DAT &= 0xfe;  // 关闭LED
}

static void led_gpl2_init(void)
{
    printk("func led_gpl2_init");
    GPL2_device_init();   //  寄存器地址初始化
    GPL2_device_cfg();    //  寄存器工作模式配置
    GPL2_device_on();     //  打开LED
    printk("led on...");
}

static void led_gpl2_exit(void)
{
    printk("func led_gpl2_exit...");
    GPL2_device_off();     // 模块卸载时候 关闭LED
    printk("led off...");
}

module_init(led_gpl2_init);
module_exit(led_gpl2_exit);

5、测试结果

  启动板子默认led2是点亮,卸载模块后,led熄灭;

 

posted @ 2020-08-08 16:42  笑不出花的旦旦  阅读(273)  评论(0)    收藏  举报