C GPIO
#19
(08-31-2016, 07:27 AM)KnReLe Wrote: Not sure if this worked yet for you, but I do see one thing here that looks to me like it could be the reason why your /dev/mem -related gpio access doesn't work: the registers in which the various bits are changed in order to control gpio items are 32-bits, while the pointer-arithmetic that is shown here looks like they deal with 64-bit data sizes.

Looking at the documentation in the linked user-manual, page 373. we see how the addresses for the  PB thru PH gpio control space is organized. The base address is 0x1c20800, which as it isn't page aligned means we will have to pass the masked address to mmap() and then add the offset to the returned pointer afterwards.

Next we see that each letter-block of ports has a group of 9 registers each of which are 32 bits or 4 bytes, so the first (non-existent) PA series would have been from 0x00 to 0x23, then PB continues at 0x24-0x47, then PC goes from 0x48--0x6b and so on.  So far so good.

The problems begin with this:
---------------------
gpio = (volatile unsigned long *) p_mem;
------------------------
The type of the pointer variable gpio isn't shown but the cast suggests it is a volatile unsigned long *gpio; Though the numerical value of this (if we were to use printf("%p") to display it) isn't necessarily the original address 0x01c20000 that we used, it is still effectively pointing at this hardware location, which is 0x800 bytes before the gpios.

Now when we add offsets to such a pointer, these offsets get multiplied by 8, since the size of the unsigned long type in the PineA64 is 8, and thus, when performing the access call:

*(gpio + GPIO_REG_OFFSET + 0x48) &= ~(7 << 16);

being equivalent to

gpio[GPIO_REG_OFFSET+0x48] &= ~(7 << 16);

it is like we are changing some bits in an 8-byte variable located at:
(*0x01c20000+8 * (0x800 + 0x48)) = 0x01c24090

which is far beyond the area where these GPIO control registers actually are.  The arithmetic shown seems to expect that the gpio pointers are to 1-byte data however.

Thus to make this work right, the pointer through which we access the GPIOs have to be defined as pointing to some 32-bit integers, while the arithmetic used for adding the offsets and registers will have to be done as if the pointers are aligned at byte boundaries, so the arithmetic I use here treats it as char *, or we can cast them back and forth from unsigned integers of the appropriate size.

To be sure how big things are, in places like this when we do care, the standard types in stdint.h are nice to have.  I got the following C program working, flashing an LED connected to pin 32 on the Pi-2-bus (P32 as it is labeled on the development POT), which is PC4.

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

#define BASE_ADDR 0x01c20000
#define GPIO_REG_OFFSET 0x800

int main()
{
   int fd;
   void *p_mem;
   volatile uint32_t *gpio;    /* The registers in gpio-space are 32-bits wide. */
   unsigned int offset;        /* offsets from 0x800, so need not be that big */
   unsigned int page_size;     /* Page-size from system, it reports 0x1000 here. */
   int j;

   page_size = sysconf(_SC_PAGESIZE);

   fd = open("/dev/mem", O_RDWR | O_SYNC);
   if(fd == -1)
   {
       /* Very likely if you forget to run this as root ... */
       perror("/dev/mem");
       return(0);
   }

   p_mem = mmap(NULL, page_size * 2, PROT_READ | PROT_WRITE, MAP_SHARED, fd, BASE_ADDR);
   if(p_mem == NULL)
   {
       perror("mmap");
       close(fd);
       return(0);
   }

   close(fd);

   offset = GPIO_REG_OFFSET + 0x48;  /* Will aim at the first of the PC control registers, which controls PC7-PC0 */
                                       /* Page 377 in the manual */

   gpio = (volatile uint32_t *) ( (char *) (p_mem) + offset);
   printf("GPIOs at %p\n", gpio);

   *(gpio) &= ~(7 << 16);  /* Set SELECT to 000 for enable or input */
   *(gpio) |= (1 << 16);   /* Set SELECT to 001 for output */

   offset = GPIO_REG_OFFSET + 0x58;  /* Will aim at the the PC data register, which controls state of PC18-PC0 wires */
                                       /* Page 380 in the manual. */
   gpio = (volatile uint32_t *) ( (char *) (p_mem) + offset);
   printf("GPIOs at %p\n", gpio);

   /* flash on and off 20 times */
   for(j = 0; j<20; j++)
   {
       *(gpio) &= ~(0x10);  /* Set bit 4 for PC4 to 0 */
       usleep(500000);
       *(gpio) |= (0x10);   /* Set bit 4 for PC4 to 1 */
       usleep(500000);
   }

   munmap(p_mem, page_size*2);

   return(0);
}

The key thing here is the additions here:

gpio = (volatile uint32_t *) ( (char *) (p_mem) + offset);

where the un-specific pointer p_mem gets cast to a pointer-to-char which has alignment 1, then the offset gets added, and the resulting value is cast to the pointer-to-uint32_t through which we will access the selected 32-bit control or data register.

Hi KnReLe

Thank you for your help man. Very nice and comprehensively answered and also works as you know.

I was also figuring out that one possible way would be immediately after mapping cast void pointer to unsigned int pointer and then to add order number of either of those GPIOs registers. Like normal pointer arithmetic

Problem is there is a hole in manual between the address 0x01c20000 we can map and actual base PIO address. I cannot check how many registers are there. Wink

I saw such a solution for RPI.

However, thank you man Big Grin
  Reply


Messages In This Thread
C GPIO - by igna09 - 06-10-2016, 12:41 PM
RE: C GPIO - by martinayotte - 06-10-2016, 01:52 PM
RE: C GPIO - by igna09 - 06-10-2016, 02:16 PM
RE: C GPIO - by martinayotte - 06-10-2016, 03:10 PM
RE: C GPIO - by martind1983 - 08-24-2016, 09:55 AM
RE: C GPIO - by igna09 - 06-11-2016, 02:51 AM
RE: C GPIO - by martinayotte - 08-25-2016, 07:35 AM
RE: C GPIO - by martind1983 - 08-25-2016, 08:24 AM
RE: C GPIO - by MarkHaysHarris777 - 08-25-2016, 11:17 AM
RE: C GPIO - by martind1983 - 08-29-2016, 01:30 AM
RE: C GPIO - by martind1983 - 08-29-2016, 03:50 AM
RE: C GPIO - by MarkHaysHarris777 - 08-29-2016, 05:25 AM
RE: C GPIO - by martind1983 - 08-31-2016, 03:47 AM
RE: C GPIO - by pfeerick - 08-31-2016, 04:14 AM
RE: C GPIO - by martind1983 - 08-31-2016, 04:36 AM
RE: C GPIO - by MarkHaysHarris777 - 08-29-2016, 05:04 PM
RE: C GPIO - by MarkHaysHarris777 - 08-31-2016, 04:09 AM
RE: C GPIO - by KnReLe - 08-31-2016, 07:27 AM
RE: C GPIO - by martind1983 - 09-01-2016, 05:08 AM
RE: C GPIO - by MarkHaysHarris777 - 09-01-2016, 05:29 AM
RE: C GPIO - by martind1983 - 09-01-2016, 08:04 AM
RE: C GPIO - by KnReLe - 09-01-2016, 08:52 AM
RE: C GPIO - by martind1983 - 09-01-2016, 09:06 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  RPi.GPIO python module for Pine A64/A64+ aquilegia 98 131,610 12-15-2022, 08:40 PM
Last Post: Fadazo
  fm transmitter with gpio weasel18 2 4,829 09-10-2019, 04:28 AM
Last Post: desai_amogh
  How to use dts or other setup to declare gpio pin Interrupt (e.g. a button)? dkebler 1 3,599 06-12-2019, 10:37 AM
Last Post: dkebler
Lightbulb Sample GPIO codes highlighting RPi.GPIO-PineA64 and the PI bus MarkHaysHarris777 6 11,133 06-07-2019, 12:37 AM
Last Post: tllim
Star GPIO, SPI and I2C C++ Lib databit 7 11,216 02-04-2019, 05:45 AM
Last Post: Jeff R
Information Howto: Controlling Pine64 GPIO via the filesystem (sysfs) on linux pfeerick 4 11,856 01-24-2019, 03:36 AM
Last Post: Fifth
  GPIO and SPI SamR1 20 31,608 03-15-2018, 10:32 AM
Last Post: jomoengineer
Question GPIO shockr 7 14,776 03-11-2018, 01:52 AM
Last Post: jomoengineer
  Read GPIO problem shworker 14 21,177 08-17-2017, 01:21 PM
Last Post: martinayotte
  GPIO fiq capability joseph 3 6,097 11-10-2016, 06:07 PM
Last Post: joseph

Forum Jump:


Users browsing this thread: 1 Guest(s)