Fast GPIO access via memory

Discussion about Parallella (and Epiphany) Software Development

Moderators: amylaar, jeremybennett, simoncook

Fast GPIO access via memory

Postby tif » Thu Sep 10, 2015 4:08 am

Dear Parallella Community.

As I understood from https://github.com/parallella/parallella-utils/blob/master/docs/para_gpio.md the maximum GPIO speed is approximately 70 kHz.
I was aiming for something between 2 and 3 MHz. Obviously a bit of optimisation will not provide the 30-fold improvement.

So I thought I'd try accessing the memory directly. But when I use Sven Andersson's dev-mem-test (http://svenand.blogdrive.com/files/gpio-dev-mem-test.c) the memory contents do not change:

Code: Select all
linaro@linaro-nano:~/kubuntu/experiments$ sudo ./gpio-dev-mem-test -g 0xE000A040 -o 1
page_addr: e000a000
page_offset: 00000040
linaro@linaro-nano:~/kubuntu/experiments$ sudo ./gpio-dev-mem-test -g 0xE000A040 -i
page_addr: e000a000
page_offset: 00000040
gpio dev-mem test: input: 00000000
linaro@linaro-nano:~/kubuntu/experiments$ sudo ./gpio-dev-mem-test -g 0xE000A060 -i
page_addr: e000a000
page_offset: 00000060
gpio dev-mem test: input: 00000000


This is the same for all the enable, direction or output_data writes to all banks. Also the scope does not show any action on the GPIOs.

Is there some major flaw in my thinking? Any pointers to where I can RTFM or what else I could try are appreciated!

PS:
If I use the porcutest.cpp (which is using the device tree) I can see the GPIOs wiggle on my custom daughter card. So the electrical setup seems to be OK.

[edit]
Just wanted to add that I got the memory addresses from the Zynq manual (ug585-Zynq-7000-TRM.pdf) App B19 / p. 1348.
The base address 0xe000a000 fits with the defined gpio in the device tree.
The register 0xe000a040 is of type rw.
I made sure the access is via correctly aligned pages.

"This register controls the value being output when the GPIO signal is configured as an output. All 32bits of
this register are written at one time. Reading from this register returns the previous value written to either
DATA or MASK_DATA_{LSW,MSW}; it does not return the value on the device pin."

Nothing explains why it does not accept the written values. I even took the GPIO out of the device tree (which should not be necessary) without any difference in behaviour.
When I write to the registers of ttc1 the written data is accepted without problems.

[edit 20150916]
Thanks to those who bothered reading through my post. Just adding what I have found out so far.
Image
This is what I get from porcutest. At the beginning you can see some 50 Hz noise. Then some toggeling. (1V/div, 1 ms/div)

Userspace
I tried to access the 0xe000a000 via mmap in userspace. /proc/wxyz/maps looks to me like the mapping was successful:
Code: Select all
b6fb5000-b6fb6000 rw-s e000a000 00:05 1027       /dev/mem

Writing to it does not provoke any reaction. Reading registers returns 0 for all banks and kinds.

Kernelspace
I tried to access the 0xe000a000 via ioremap in kernel space. On insmod I get some reaction when configuring bank_2 to output:
Image
You can see again the 50 Hz noise (which is not surprising on a high-z port) but then no toggeling. (2V/div, 200 ms/div)

[edit 20150930]
Success with access in kernel space at last! Interestingly the ports react in a single ended configuration. (The documentation and browsing through the FPGA code made me expect them to behave in differential configuration by default.)
In case you are here because of the same problem you may want to check the clock enable register:
Code: Select all
#define CLK_ENABLE_BASE 0xF8000000
#define CLK_ENABLE_ADDRESS 0x0000012C
#define CLK_ENABLE_GPIO   (1 << 22)

Yet, in my system with GPIO in the device tree it is enabled by default.

I got it working in kernel space via ioremap:
Code: Select all
#define GPIO_CONTROLLER_ADDRESS 0xE000A000
#define GPIO_OUTPUT_DATA_BANK_2 (GPIO_CONTROLLER_ADDRESS + 0x00000048)
#define GPIO_INPUT_DATA_BANK_2 (GPIO_CONTROLLER_ADDRESS + 0x00000068)

gpioOutputRegister2 = (u32*) ioremap(GPIO_OUTPUT_DATA_BANK_2, 4);
gpioInputRegister2 = (u32*) ioremap(GPIO_INPUT_DATA_BANK_2, 4);

Three of my differential pairs do not react to stimulation of any of the four banks. Strange but no show stopper as I can re-route signals going to test points.

Unluckily, my problem isn't solved yet. Even though using the hrtimers, I stopped tinkering when I didn't reach much more than 60 kHz (with a bad jitter). I was aiming for the lower MHz range.
Next brilliant idea was to use one Epiphany core and do the sampling there. As far as I read in the documentation, DMA or memory access in general is only possible to RAM, not to registers or remapped IO. My experiments with the Chronicles 6 examples seem to prove this point.
Please correct me if I am wrong on this.

So my last attempt to use this hardware is to do the stimulation and sampling in FPGA logic and provide the data as registers.
Last edited by tif on Fri Sep 11, 2015 4:29 am, edited 1 time in total.
tif
 
Posts: 5
Joined: Thu Sep 10, 2015 3:03 am

Return to Programming Q & A

Who is online

Users browsing this forum: No registered users and 5 guests