嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > 我能在不同空间下操作寄存器,快学起来!

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

点击上方“嵌入式Linux充电站”,选择“置顶/星标公众号”

福利干货,第一时间送达

大家好,我是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


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

猜你喜欢