As mentioned above. Here is a summary of the issue and its resolution. I am
posting it here so that anybody else that runs into this might be able to
find it with a search.
BASIC PROBLEM: Using /dev/mem with a mmap() call to access the GPIOs in
banks 2 and 3 fail with a bus error. Identical access to the GPIO's in
banks 0 and 1 works just fine.
SOLUTION: Access to the GPIO banks 2 and 3 fails because the clocks
CM_PER_GPIO2_CLKCTRL and CM_PER_GPIO3_CLKCTRL are not enabled. These can
readily be enabled by accessing memory location 0x44e00000 (see the TRM)
and turning them on. If you do that, access to the GPIO2 and 3 at locations
0x481AC000 and 0x481AE000 will be successful.
EXPLANATION and EXAMPLES
Example C code for memory mapped access to the GPIOs is below – it assumes
we wish to access GPIO_BANK_1
int fd = open("/dev/mem", O_RDWR | O_SYNC);
if (fd < 0)
{
printf("Could not open GPIO memory fd\n");
return 0;
}
volatile ulong *gpio;
int gpioBank = 0x4804C000;
int sizeToFetch =0xfff;
gpio = (ulong*) mmap(NULL, sizeToFetch, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, gpioBank);
if (gpio == MAP_FAILED)
{
printf ("GPIO Mapping failed\n");
close(fd);
return 0;
}
// offset 0 is the GPIO_REVISION field
// expected value is 0x50600801
int gpioRevision = gpio[0];
printf("bank %04x, gpioRevision = %04x\n", gpioBank, gpioRevision);
munmap((void*)gpio,sizeToFetch);
close(fd);
Accessing GPIO_BANK_2 or GPIO_BANK_2 will, in most circumstances, result in
a failure with a “Bus error” message on the call to
int gpioRevision = gpio[0];
Everything else works fine, the /dev/mem file opens and the mmap() call is
successful but access to any value in the mapped meory will fail. It seems
that this is due to the clock which is used to shift the physical pin state
into the GPIO_BANK bit is not enabled by default.
One way to get around this is to note that using SYSFS to export any GPIO
in that bank (echo 105 > /sys/class/gpio/export) will enable the clock on
that BANK and all subsequent accesses via mmap() will succeed.
The other way is to enable the clock yourself. This is done by writing to a
memory location and hence requires yet another mmap() on /dev/mem. The
relevant memory location is 0x44e00000 and the offset of interest is
entitled CM_PER_GPIO?_CLKCTRL (where the ? Is 1, 2, or 3 for GPIO_BANK_1,2
or 3). If you wish to look this up in the TRM, search for
CM_PER_GPIO2_CLKCTRL – it is in Section 8 – which deals with the Power
Clock and Reset Managment. Here is some sample code that will properly set
the CM_PER_GPIO2_CLKCTRL register.
uint32_t *clock_gpio2;
clock_gpio2 = (uint32_t *) mmap(NULL, 0x1000, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0x44E00000);
// 0xb0 is CM_PER_GPIO2_CLKCTRL as given in the TRM, use 0xb4 for GPIO_3
(see the TRM)
int offsetInMemory = 0xb0;
// get the value, we divide by 4 because it is a byte offset
int memValue = clock_gpio2[(offsetInMemory/4)];
// print it – it will probably be 0x030000 if the clock has never been
enabled
printf("Value = %04x\n", memValue);
// now set it, this enables the memory
clock_gpio2[(offsetInMemory/4)] = 0x02;
Once the clock has been set as above, the previous C code will be able to
access the GPIO_BANK via a statement like.
int gpioRevision = gpio[0];
On my system GPIO_BANK_1 was already enabled, but GPIO_BANK_2 and
GPIO_BANK_3 needed to be enabled.
--
For more options, visit http://beagleboard.org/discuss
---
You received this message because you are subscribed to the Google Groups
"BeagleBoard" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.