我能在不同空间下操作寄存器,快学起来!

简介: 我能在不同空间下操作寄存器,快学起来!

大家好,我是Vincent。

大家都知道在linux中操作寄存器,都是驱动去做的。

但其实,驱动层、应用层和shell中都是可以操作寄存器的。

Linux驱动操作寄存器

首先在设备树里定义一个节点,例如:

uart0: serial@10010000 {
   compatible = "sifive,uart0";
   reg = <0x0 0x10010000 0x0 0x1000>;
   status = "okay";
}

@符号后面是寄存器的基地址,然后填写compatiblereg属性,status属性设置为okay

reg属性中,第二参数为寄存器基址,与@符号后面的地址对应,第四个参数是映射的大小。

驱动中操作:

#define OFFSET  0x60 //某个寄存器的偏移地址
static int my_probe(struct platform_device *pdev)
{
    struct resource *res;
    void __iomem *base;
    u32 regval;
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    base = devm_ioremap_resource(&pdev->dev, res);
    //寄存器读写
    regval = readl(base + OFFSET);//读寄存器
    regval |= (1 << 0);//赋值
    writel(regval, base + OFFSET);//写寄存器
    return 0;
}

先调用platform_get_resource获取IORESOURCE_MEM资源,就是获取了设备树中的reg属性,返回的resource结构体中包含了起始地址和结束地址。然后调用devm_ioremap_resource映射这个资源,就能得到一个虚拟地址。后续对该虚拟地址的操作,就等同于对寄存器物理地址的操作。

读写寄存器,可以调用readlwritel函数。先读取寄存器的值放到临时变量中,赋值后,再一次性写入。

应用层操作寄存器

驱动中操作寄存器,需要先进行映射将物理地址转为虚拟地址。

但如果想在应用层中操作寄存器,也是可以实现的。

应用层中只需打开/dev/mem设备节点,然后用mmap映射寄存器地址就可以访问了。

例如,应用层读取物理地址为0x40000000的值:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#define MAP_SIZE 0x80000
#define base 0x40000000
int main(int argc, char **argv)
{
  int fd = open("/dev/mem",O_RDWR|O_NDELAY);
    if (fd < 0)
    {
        printf("open /dev/mem error!\n");
        return -1;
  }
    void *map_base = mmap(NULL,MAP_SIZE,PROT_READ|PROT_WRITE,MAP_SHARED,fd,base);
    if (map_base == MAP_FAILED)
    return -1;
    printf("%x \n",*(volatile unsigned int*)(map_base));
    close(fd);
    munmap(map_base,MAP_SIZE);
  return 0;
}

注意,内核必须将CONFIG_STRICT_DEVMEM=y配置选项打开才有/dev/mem节点

shell中操作寄存器

shell中操作寄存器可以使用devmem命令.

devmem命令其实就是上述应用层操作寄存器生成的可执行文件,只不过busybox已经帮我们实现了。

devmem命令格式:

Usage: devmem ADDRESS [WIDTH [VALUE]]
Read/write from physical address
 ADDRESS Address to act upon
 WIDTH Width (8/16/...)
 VALUE Data to be written

ADDRESS:物理地址

WIDTH:位宽,32位、64位等等

VALUE:要写入的值

例如,读取32位寄存器0x40200000的值:

devmem 0x40200000 32

向32位寄存器0x40200000写入0x12345678

devmem 0x40200000 32 0x12345678

end

关注我,回复【加群】,进入嵌入式技术交流群,一起交流学习~

猜你喜欢

机遇:我是如何走向Linux驱动的...

入职Linux驱动工程师后,我才知道的真相......

一个Linux驱动工程师必知的内核模块知识

Linux内核中常用的数据结构和算法

Linux内核中常用的C语言技巧

Linux内核基础篇——常用调试技巧汇总

Linux内核基础篇——动态输出调试

Linux内核基础篇——printk调试

Linux内核基础篇——initcall

嵌入式Linux充电站

作者Vincent,分享一些嵌入式Linux、内核、RISC-V等知识。学习、沉淀、分享,才能有所获。

74篇原创内容

公众号

收录于合集 #Linux驱动

30

上一篇当我用几道题考了一遍做Linux驱动的同事......下一篇嵌入式BSP工程师到底是干嘛的?

喜欢此内容的人还喜欢

那些只有芯片原厂才能做的驱动开发工作

 

嵌入式Linux充电站

相关文章
|
存储 编译器 C语言
C语言,数据在内存中的存储。——保姆级教学
C语言,数据在内存中的存储。——保姆级教学
|
3月前
|
C语言
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
C语言—内存函数的实现和模拟实现(内存函数的丝绸之路)
35 0
|
3月前
|
存储 算法 Unix
操作系统复习篇一分大小单双方式方法
用户程序访问操作系统的程序和数据 • 地址映射:逻辑地址转换为物理地址 • 内存扩充(虚拟存储技术):请求调入功能、置换功能 设备管理功能一分大小单双方式方法 《罔 F C W 2 3 ●VIP》【企鹅Q1344-687】 • 缓冲管理:缓冲区机制 • 设备分配 • 设备处理:设备驱动程序 主要任务:完成I/O请求、提高CPU和I/O设备的使用率 文件管理功能 • 文件存储空间的管理 • 目录管理:按名存取 • 文件的读/写管理和保护:文件的读/写管理、文件保护
|
3月前
|
存储 固态存储 数据中心
魔幻存储空间:计算机存储器全解析
魔幻存储空间:计算机存储器全解析
78 0
|
3月前
|
存储 缓存 Linux
内存系列学习(三):ARM处理器地址变换过程
内存系列学习(三):ARM处理器地址变换过程
100 0
|
3月前
|
缓存 Linux Shell
内存系列学习(八):终章-结束又是开始
内存系列学习(八):终章-结束又是开始
51 0
|
9月前
|
编译器 C语言
【C语言航路】第十三站:动态内存管理(上)
【C语言航路】第十三站:动态内存管理
65 0
|
9月前
|
程序员 C语言 C++
【C语言航路】第十三站:动态内存管理(下)
【C语言航路】第十三站:动态内存管理
42 0
|
11月前
简单聊聊 ABAP 变量消耗的内存空间这个话题的试读版
简单聊聊 ABAP 变量消耗的内存空间这个话题的试读版
|
存储 C语言
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(2)?
【C语言进阶】纳尼?这样学数据在内存中的存储竟然如此简单(2)?
236 0