c++ - 几次访问后,mmap 因无法打开/dev/mem 而死

标签 c++ c embedded embedded-linux

我正在双核 ARM A9 上使用 mmap 编写一些用户空间驱动程序,以访问 FPGA 内的一些硬件寄存器。我们有一个自定义 SPI block ,它与另一个芯片通信,我们访问该芯片内的硬件寄存器。我为我的 SPI“驱动程序”编写了一个 C++ 类,基本上分解了外部芯片内部地址的读/写操作。我使用 mmap 访问 FPGA 内部的 SPI(仅占用大约 100 字节的内存空间(0xFF20_2000 -> 0xFF20_007F))。

当我调用 SPI 类(我只为驱动程序执行一次)时,它会经过并为 SPI 硬件的基地址执行打开的 mmap。

void spi_op::cfg_mmap(){

    if( ( this->fd = open( "/dev/mem", ( O_RDWR | O_SYNC ) ) ) == -1 ) {
        printf( "ERROR: could not open \"/dev/mem\"...\n" );
        this->error = 1;
        return;
    }

    uint32_t map_addr_base = this->addr_base & MMAP_BASE_MASK;

    this->virtual_base = mmap( NULL, MMAP_PAGE_SIZE, ( PROT_READ | PROT_WRITE ), MAP_SHARED, this->fd, map_addr_base );

    if( this->virtual_base == MAP_FAILED ) {
        printf( "ERROR: mmap() failed...\n" );
        close( this->fd );
        this->error = 1;
        return;
    }

    //To initialize to the proper pointer in the event not on a page boundary
    this->virtual_base += (SPI_MASTER_ADDR_BASE - map_addr_base);
}

我将 SPI 硬件寄存器构建为结构/union ,以便于(更)进行位操作(我已经排除了可以被视为专有但与问题无关的东西)。

union spi_regs_reg1 {
    struct {
        volatile uint32_t xxxx: 32;
    } bits;
    volatile uint32_t word;
};

union spi_regs_reg2 {
    struct {
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
        volatile uint32_t xxxx: 1;
    } bits;
    volatile uint32_t word;
};

struct spi_regs_regs {
    union spi_regs_blockid spi_regs_reg1;
    union spi_regs_gnrlsta spi_regs_reg2;
    blah blah blah

作为初始化/构造函数的一部分,我有一个被分配的 spi_regs 结构指针

void spi_op::spi_master_init(){

    this->cfg_mmap();

    spi_regs = (struct spi_regs_regs *)(this->virtual_base);


    //an Example of how I can now access the bits in the HW registers
    //Assert the RESET
    spi_regs->spi_regs_reg.bits.spi_reset = 1;

每当我想进行读取或写入时,我现在只需调用 spi.read(addr) 或 spi.write(addr, data) 即可执行操作。

这似乎工作得很好,但偶尔在一堆读/写之后我开始出错

"ERROR: could not open "/dev/mem"...". 

现在这是 cfg_mmap() 任务中的内容。但是,我只将其作为构造函数的一部分调用一次。在这个特定的测试中,我正在设置多个不同的设置并运行每个设置并重置中间的外部部分(但不是我用 mmap 控制的 SPI)。我基本上有一个 for 循环,但 SPI 类的构造函数先于 for 循环。

作为我在键入此内容时的快速测试,我将 cfg_mmap 任务中的错误消息更改为

"ERROR: blah could not open "/dev/mem"..."

然后在运行过程中我得到了这个

<normal prints from my code>
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: could not open "/dev/mem"...
ERROR: blah could not open "/dev/mem"...
Segmentation fault
root@arria10:~# 

/dev/mem 是否可能重载或类似的情况?我已经在我的代码中进行了一些搜索,我终其一生都找不到我不止一次调用 SPI 类的地方(该程序并没有那么复杂)。

最佳答案

如果我假设您的类名为“spi_op”,您可能需要创建带有“munmap(virtual_base,MMAP_PAGE_SIZE)”和“close(fd)”的 spi_op::~spi_op()(所谓的“析构函数”)操作说明。所以它可能是析构函数的主题:参见https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm例如。如果您正确使用 munmap() 和 close(),您应该不会再遇到这个问题。

关于c++ - 几次访问后,mmap 因无法打开/dev/mem 而死,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44642557/

相关文章:

c++ - vector 不从 cin 获取输入

c++ - 基于时间的循环和基于帧的循环

c# - 开发数学库

困惑为什么通过引用传递 char** 没有按预期工作

C 计算欧拉数的精度低于预期

networking - 如何远程控制嵌入式设备

c - 用 C 编写注释的更好方法是什么?

c++ - 使用 glTexCoordPointer() 的问题

C Linux - 不写整数

c - 从 'uint8_t* {aka unsigned char*}' 到 'const char*' [-fpermissive] 的无效转换