PINE64
C GPIO - Printable Version

+- PINE64 (https://forum.pine64.org)
+-- Forum: PINE A64(+) (https://forum.pine64.org/forumdisplay.php?fid=4)
+--- Forum: Pine A64 Hardware, Accessories and POT (https://forum.pine64.org/forumdisplay.php?fid=32)
+---- Forum: Pi2, Euler and Exp GPIO Ports (https://forum.pine64.org/forumdisplay.php?fid=34)
+---- Thread: C GPIO (/showthread.php?tid=1327)

Pages: 1 2 3


RE: C GPIO - martind1983 - 09-01-2016

(09-01-2016, 05:29 AM)MarkHaysHarris777 Wrote:
(09-01-2016, 05:08 AM)martind1983 Wrote:  Very nice and comprehensively answered and also works as you know.
However, thank you man Big Grin

hi,  just for clarification, in your judgement then, is the current manual correct in what it states ( in regard to this thread ) or does it have omissions that we could document more throughly so that others don't have this issue.

In other words, is the above comprehensive explanation in the manual necessary to make sense of what the current manual states, or is the current manual complete as it stands ( in your opinion )?   Thanks.
Hi Mark

In my opinion. When the programmer uses correct type casting. What I haven't done in my first case you can easily access all registers in the chip. As our colleague implied to us. This works perfectly.

I just wanted to say for example: If PIO address 0x01c20800 would be possible to map (as it is not possible because of page size alignment). It would be easily possible to access any register from PIO peripheral just by adding its order number to mapped PIO address. Let's say

PB_CFG0_REG register you could access by adding 1 to PIO base address what is 0x01c20800, like normal pointer arithmetic. However, as you cannot map PIO base address, you can only map CCU address what is 0x01c20000 and there are not any registers you could manually count like I described in previous lines or maybe it would be possible but it would be laborious. The aforementioned way KnReLe did is very goog and as I said you should be able to access any register in the chip.

I should review my typecasting a bit Big Grin

Thank you to all Smile


RE: C GPIO - KnReLe - 09-01-2016

martind1983
In my opinion. When the programmer uses correct type casting. What I haven't done in my first case you can easily access all registers in the chip. As our colleague implied to us. This works perfectly.

I just wanted to say for example: If PIO address 0x01c20800 would be possible to map (as it is not possible because of page size alignment). It would be easily possible to access any register from PIO peripheral just by adding its order number to mapped PIO address. Let's say

PB_CFG0_REG register you could access by adding 1 to PIO base address what is 0x01c20800, like normal pointer arithmetic. However, as you cannot map PIO base address, you can only map CCU address what is 0x01c20000 and there are not any registers you could manually count like I described in previous lines or maybe it would be possible but it would be laborious. The aforementioned way KnReLe did is very goog and as I said you should be able to access any register in the chip.

I should review my typecasting a bit Big Grin

Thank you to all Smile

(not sure what happened to the quoting )

Actually, if you want to automate the masking and handling of fact that the IO-address is not aligned to the page size, something like this would do:

/* Base address for PB-PH */
#define GPIO_BASE_ADDR_PB 0x01c20800

/* Base address for PL */
#define GPIO_BASE_ADDR_PL 0x01f02c00

Then in the function there could be something like this using variables (or even passing in the port_io_base as an argument):

    uint64_t addr_offset; 
    uint64_t addr_start;      /* page-aligned start-address of mmapped space. */
    uint64_t page_size;      /* Page-size from system, it reports 0x1000 here. */
    uint64_t page_mask;    /* Mask to separate out page-alignment bits */
    uint64_t port_io_base;  /* input GPIOs base-address, doesn't have to be page-aligned */


    port_io_base = GPIO_BASE_ADDR_PB;  /* For example for ports PB-PH */

    page_size = sysconf(_SC_PAGESIZE);     /* 0x1000 */
    page_mask = (~(page_size-1));                /* 0xFFFFFFFFFFFFF000 */
    addr_start = port_io_base & page_mask;     /* gives the page-aligned start address 0x01c20000, last 24 bits are 0 */
    addr_offset = port_io_base & ~page_mask;   /* mask with 0FFF so we get the 0800 offset into the page */

Then to the mmap (after the opening of the file of course)

    p_mem = mmap(NULL, page_size * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start);

Later you aim at the various registers, with the offset included, pretty much the same as before except no longer hardcoded:

    offset = addr_offset + 0x48;  /* Will aim at the first of the PC control registers, which controls PC7--PC0 */
    gpio = (volatile uint32_t *) ( (char *) (p_mem) + offset);

Or slighlty more compact as that extra variable offset isn't really necessary

    gpio = (volatile uint32_t *) ( (char *) (p_mem) + addr_offset + 0x48);

With this masking, this will work on any of the register addresses.


RE: C GPIO - martind1983 - 09-01-2016

(09-01-2016, 08:52 AM)KnReLe Wrote: martind1983
In my opinion. When the programmer uses correct type casting. What I haven't done in my first case you can easily access all registers in the chip. As our colleague implied to us. This works perfectly.

I just wanted to say for example: If PIO address 0x01c20800 would be possible to map (as it is not possible because of page size alignment). It would be easily possible to access any register from PIO peripheral just by adding its order number to mapped PIO address. Let's say

PB_CFG0_REG register you could access by adding 1 to PIO base address what is 0x01c20800, like normal pointer arithmetic. However, as you cannot map PIO base address, you can only map CCU address what is 0x01c20000 and there are not any registers you could manually count like I described in previous lines or maybe it would be possible but it would be laborious. The aforementioned way KnReLe did is very goog and as I said you should be able to access any register in the chip.

I should review my typecasting a bit Big Grin

Thank you to all Smile

(not sure what happened to the quoting )

Actually, if you want to automate the masking and handling of fact that the IO-address is not aligned to the page size, something like this would do:

/* Base address for PB-PH */
#define GPIO_BASE_ADDR_PB 0x01c20800

/* Base address for PL */
#define GPIO_BASE_ADDR_PL 0x01f02c00

Then in the function there could be something like this using variables (or even passing in the port_io_base as an argument):

    uint64_t addr_offset; 
    uint64_t addr_start;      /* page-aligned start-address of mmapped space. */
    uint64_t page_size;      /* Page-size from system, it reports 0x1000 here. */
    uint64_t page_mask;    /* Mask to separate out page-alignment bits */
    uint64_t port_io_base;  /* input GPIOs base-address, doesn't have to be page-aligned */


    port_io_base = GPIO_BASE_ADDR_PB;  /* For example for ports PB-PH */

    page_size = sysconf(_SC_PAGESIZE);     /* 0x1000 */
    page_mask = (~(page_size-1));                /* 0xFFFFFFFFFFFFF000 */
    addr_start = port_io_base & page_mask;     /* gives the page-aligned start address 0x01c20000, last 24 bits are 0 */
    addr_offset = port_io_base & ~page_mask;   /* mask with 0FFF so we get the 0800 offset into the page */

Then to the mmap (after the opening of the file of course)

    p_mem = mmap(NULL, page_size * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, addr_start);

Later you aim at the various registers, with the offset included, pretty much the same as before except no longer hardcoded:

    offset = addr_offset + 0x48;  /* Will aim at the first of the PC control registers, which controls PC7--PC0 */
    gpio = (volatile uint32_t *) ( (char *) (p_mem) + offset);

Or slighlty more compact as that extra variable offset isn't really necessary

    gpio = (volatile uint32_t *) ( (char *) (p_mem) + addr_offset + 0x48);

With this masking, this will work on any of the register addresses.

Thanks KnReLe

Also very nice solution Wink