.loc 2 80 2 @ gpi.c:80:2 ldr r1, [sp, #28] str r0, [r1] .loc 2 81 9 @ gpi.c:81:9 ldr r1, [sp, #32] str r0, [r1] .loc 2 82 2 @ gpi.c:82:2 ldr r1, [sp, #28] str r0, [r1] .loc 2 83 9 @ gpi.c:83:9 ldr r1, [sp, #32] str r0, [r1]
#include <stdint.h>#include <stdio.h>#include <stdlib.h>#include <sys/mman.h>#include <sys/stat.h>#include <fcntl.h>
#include <unistd.h>#include <assert.h>
#define GPIO_OE 0x134#define GPIO_SETDATAOUT 0x194#define GPIO_CLEARDATAOUT 0x190
// Hunt these addresses down from ls -al /sys/devices/platform/ocp | grep gpio// You can also pull them from the TI manual (spruh73l.pdf)#define GPIO0_BASE 0x44E07000#define GPIO1_BASE 0x4804C000#define GPIO2_BASE 0x481AC000#define GPIO3_BASE 0x481AE000
#define GPIO_SIZE 0x00001000
#define PIN_17 ((uint32_t)1<<17)
uint32_t ui32Base[] = {GPIO0_BASE, GPIO1_BASE, GPIO2_BASE, GPIO3_BASE};uint8_t volatile * bbGPIOMap[] = {0, 0, 0, 0};
int main(int argc, char *argv[]){ unsigned int ui; uint32_t volatile * gpio_oe_addr = NULL; uint32_t volatile * gpio_setdataout_addr = NULL; uint32_t volatile * gpio_cleardataout_addr = NULL;
int fd = open("/dev/mem", O_RDWR);
for(ui=0; ui<4; ++ui) { bbGPIOMap[ui] = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, ui32Base[ui]); assert(bbGPIOMap[ui] != MAP_FAILED); }
gpio_oe_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_OE); gpio_setdataout_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_SETDATAOUT); gpio_cleardataout_addr = (uint32_t volatile *)(bbGPIOMap[1] + GPIO_CLEARDATAOUT);
*gpio_oe_addr = *gpio_oe_addr & ~PIN_17; while(1) { *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; *gpio_setdataout_addr = PIN_17; *gpio_cleardataout_addr = PIN_17; } //*(uint32_t volatile *)(bbGPIOMap[3] + GPIO_SETDATAOUT) = (uint32_t)1 << 14; //*(uint32_t volatile *)(bbGPIOMap[3] + GPIO_CLEARDATAOUT) = (uint32_t)1 << 14;
close(fd); return 0;}
Optimal would be a sequence of successive stores to the set and clear
register, with the addresses pre-calculated and sitting in registers
(or with a base address and use the str instruction with an immediate
offset).
You might also need to
move the volatile on the variable definitions. I'm not a "C" guru,
but I think:
uint32_t volatile * gpio_setdataout_addr
...is different from:
volatile uint32_t * gpio_setdataout_addr
...you want the uint32_t to be volatile, not the pointer to it.
...but I write C code like a hardware guy who programs in VHDL. :)
Regardless, note that the maximum toggle rate of a GPIO pin using the
PRU is about 12.5 MHz, dictated by the ~40 nS required to execute a
write by the on-chip communication fabric (which means 80 nS period
for a high/low toggle of the pin). This assumes the CPU and the PRU
have similar bandwidth to the L4 fabric, which may or may not be the
case (but I suspect is true).
This is one of those C quirks. It's actually a habit from "const" but it applies to "volatile" as well. Oddly, the qualifiers generally apply to the *left* except under certain circumstances where they can apply right. This gets people into trouble when they specify:volatile uint32_t volatile * blah;Which is actually a *redundant* specifier as opposed to what they wanted:volatile uint32_t * volatile blah;Not every compiler (*especially* embedded ones) will eject a warning on the duplicate declaration specifier. So, I personally always put them on the right to avoid the issue.
--
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 beagleboard...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
I think the actual scope matters more. e.g. global versus local scope. But maybe I'm remembering wrongly as I recall reading something to this effect years ago. Anyway, I find this link the best single resource for explaining what volatile *is* - And . . I'm not trying to start an argument or anything, I just like discussing programming in general.
Incidentally, for a great explanation of why you have a choice of where to place volatile and why you should place it after the data type (for example, int volatile * foo), read Dan Sak's column "Top-Level cv-Qualifiers in Function Parameters" (Embedded Systems Programming, February 2000, p. 63).
On the other hand, in:
int f(char *const p);
the const qualifier is at the top level, so
it is not part of the function’s signa-
ture. This function has the same sig-
nature as:
int f(char *p);