Reputation: 558
I am writing some user-space drivers using mmap on a dual core ARM A9 to access some HW registers inside an FPGA. We have a custom SPI block that talks to another chip which we access HW registers inside that chip. I wrote a C++ class for my SPI "Driver" to basically break down reads/writes from/to addresses inside the external chip. I use mmap to access the SPI that is inside the FPGA (only occupies about 100bytes of memory space (0xFF20_2000 -> 0xFF20_007F)).
When I call the SPI class (and I only do this once for the driver) it goes through and performs a mmap open for the base address of the SPI HW.
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);
}
I have the SPI HW registers built as a struct/union for easy(ier) bit manipulations (I've X'd out things that could be considered proprietary, but are irrelevant for the question).
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
As part of the init/constructor I have a spi_regs struct pointer that gets assigned
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;
Whenever I want to do a read or write, I now simply call spi.read(addr) or spi.write(addr, data) to perform the operation.
This seems to work just fine, but occasionally after a bunch of read/writes I begin to get errors
"ERROR: could not open "/dev/mem"...".
Now this is something that is in the cfg_mmap() task. However I only call this once as part of the constructor. In this particular test I am setting up multiple different settings and running through each of them and resetting the external part inbetween (but not the SPI that I'm controlling with the mmap). I essentially have a for loop but the constructor of the SPI class is PRIOR to the for loop.
As a quick test while I was typing this, I change the error message in my cfg_mmap task to
"ERROR: blah could not open "/dev/mem"..."
then during the run I get this
<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:~#
Is it possible that /dev/mem is getting overloaded or something like that? I've done some scouring in my code, I can't for the life of me find where I'm calling the SPI class more than once (the program isn't that complicated).
Upvotes: 0
Views: 1079
Reputation: 205
If I assume that you class is called "spi_op" you may need to create spi_op::~spi_op() (so called "destructor") with a "munmap(virtual_base,MMAP_PAGE_SIZE)" and "close(fd)" instruction. So it may be a topic of destructor : see https://www.tutorialspoint.com/cplusplus/cpp_constructor_destructor.htm for example. If you proper use munmap() and close() you should not run into this problem anymore.
Upvotes: 1