[Onion Omega2] Direct GPIO register access problem
-
Hello everyone.
I have some problems with my Onion. I'm trying to access device registers via mmap function. I've successfully map PWM registers (address: 0x10005000). I can write and read from these registers.
But when I try to change address to 0x10000600 (GPIO access registers) with the same code I can read, but write fails with message Segmentation fault.
I tried to unload all GPIO modules with no effect.
Here is my code (without headers):int main(int argc, char *argv[])
{uint32_t alloc_mem_size, page_mask, page_size; volatile uint32_t *mem_pointer, *virt_addr; const uint32_t mem_address = 0x10000600; const uint32_t mem_size = 0x600; page_size = 4096; alloc_mem_size = (((mem_size / page_size) + 1) * page_size); page_mask = (page_size - 1); int mem_dev = open("/dev/mem", O_RDWR | O_SYNC); mem_pointer = mmap(NULL, alloc_mem_size, PROT_READ | PROT_WRITE, MAP_SHARED, mem_dev, (mem_address & ~page_mask) ); virt_addr = (mem_pointer + (mem_address & page_mask)); int i=0; close(mem_dev); printf("Memory dump before\n"); for(i=0; i<10;i=i+2) { printf("GPIO memory address=0x%016x: 0x%016x\n", virt_addr+i, *(virt_addr+i)); } // Set GPIO_0 direction bit (*(virt_addr))|=(1<<0); printf("Memory dump after\n"); for(i=0; i<10;i=i+2) { printf("GPIO memory address=0x%016x: 0x%016x\n", virt_addr+i, *(virt_addr+i)); }
}
Help please
-
Where did you get the 0x10000600 number from?
Take a look at my GPIO management code:
https://github.com/Patryk27/Omega2-GPIO/blob/master/gpio.h
-
@Krzysztof-Skiba said in [Onion Omega2] Direct GPIO register access problem:
x10000600
I found in Mediatek MT7688 Datasheet page 109:
https://labs.mediatek.com/en/download/50WkbgbH"Module name: GPIO Base address: (+10000600h)"
Edit: Got it! Seems that datasheet info is incorrect.
Thanks for help!
-
@Patryk-Wychowaniec Hi Patryk , when i look into the datasheet , i see this adress for GPIO_CTRL_0 32
10000600
How can you write your code ? any datasheet?
-
Hi!
I have already responded you on GitHub, but to keep conversation here complete, I am also copy-pasting that response (https://github.com/Patryk27/Omega2-GPIO/issues/3) here:
I initially followed code written by the Omega team (https://github.com/OnionIoT/fast-gpio/blob/master/include/fastgpioomega2.h#L12) and I haven't really faced it with the documentation.
I believe the reason is that later we're doing a
mmap
call, which has to be page-aligned (which 0x10000600 is not), but it could be also a mistake in the MT7688's documentation.
-
static const int REG_BLOCK_ADDR = 0x10000000; static const int REGISTER_CTRL0_OFFSET = 384; // 32 bit reg offset !!! static const int REGISTER_CTRL1_OFFSET = 385; // 32 bit reg offset !!! static const int REGISTER_CTRL2_OFFSET = 386; // 32 bit reg offset !!! static const int REGISTER_DATA0_OFFSET = 392; // 32 bit reg offset !!! static const int REGISTER_DATA1_OFFSET = 393; // 32 bit reg offset !!! static const int REGISTER_DATA2_OFFSET = 394; // 32 bit reg offset !!! static const int REGISTER_DSET0_OFFSET = 396; // 32 bit reg offset !!! static const int REGISTER_DSET1_OFFSET = 397; // 32 bit reg offset !!! static const int REGISTER_DSET2_OFFSET = 398; // 32 bit reg offset !!! static const int REGISTER_DCLR0_OFFSET = 400; // 32 bit reg offset !!! static const int REGISTER_DCLR1_OFFSET = 401; // 32 bit reg offset !!! static const int REGISTER_DCLR2_OFFSET = 402; // 32 bit reg offset !!!
and then
Gpio::baseAddress = (uint32_t *) mmap(0, 1024, PROT_READ | PROT_WRITE, MAP_FILE | MAP_SHARED, memHandle, Gpio::REG_BLOCK_ADDR);
and then
void Gpio::writeToRegister(uint16_t registerOffset, uint32_t value) { *(Gpio::baseAddress + registerOffset) = value;}
you are basically mapping to a 32 bit pointer...
so your offsets are in fact equivalent to the following address:REGISTER_CTRL0_OFFSET = 384 (32 bit offset) -> hex(4384) = 0x600
REGISTER_CTRL1_OFFSET = 385 (32 bit offset) -> hex(4385) = 0x604
REGISTER_CTRL2_OFFSET = 386 (32 bit offset) -> hex(4*386) = 0x608So the documentation is correct...
Be careful with pointer arithmetic...
-
This post is deleted!
-
@Krzysztof-Skiba said in [Onion Omega2] Direct GPIO register access problem:
virt_addr = (mem_pointer + (mem_address & page_mask));
this is wrong...
mem_pointer is already pointing to mem_address...
your line basically makes mem_pointer point to address
0x10000600 + (0x10000600*4 & page_mask) = .... SEG FAULT....
To Fix: change
const uint32_t mem_size = 0x600;
to
const uint32_t mem_size = 0x600+0xAC;
const uint32_t mem_address = 0x10000600;
to
const uint32_t mem_address = 0x10000000;
and
virt_addr = (mem_pointer + (mem_address & page_mask));
to
virt_addr = (mem_pointer + (mem_size/sizeof(uint32_t) );
-
@Alex-Costea Thanks for reply , but i dont understand properly.
you mean that 384 (32 bit offset) -> hex(4384) = 0x600 , but how?What about Gpio::baseAddress + registerOffset?