[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?



  • @volkan-ünal

    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(4
    385) = 0x604
    REGISTER_CTRL2_OFFSET = 386 (32 bit offset) -> hex(4*386) = 0x608

    So 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?


Log in to reply
 

Looks like your connection to Community was lost, please wait while we try to reconnect.