Forums » Software Development »
Simple example needed
Added by Steven Hill over 11 years ago
I am using the MityDSP L-138F Industrial development board. I am not finding the examples for that board given in the MDK_2013-05-15 very useful. Is there a simple project that would show the use of the FPGA GPIO core, for example, that would read and write a couple of bits, and maybe generate an interrupt from an input bit? Such a project would be very helpful in understanding how to use the FPGA cores from the ARM processor.
Replies (7)
RE: Simple example needed - Added by Michael Williamson over 11 years ago
Is your ARM processor going to run linux?
RE: Simple example needed - Added by Steven Hill over 11 years ago
Yes, I'm looking for an example similar to the Hello World ARM/DSP project...
RE: Simple example needed - Added by Michael Williamson over 11 years ago
Hi Steven,
My understanding is that you have your own FPGA IP and want to control it (including catching an interrupt) from a linux user space application. Linux (and most non-RT OS's) doesn't really provide a direct way to do this. Normally, FPGA register/interrupt control is done using a kernel module, which has direct access to physical memory and can register interrupt handlers. This module would then need to provide a device interface (such as a character device supporting open(), read(), write(), select(), etc.) that application code can open and access.
If you are interested in accessing FPGA memory space from a user space application, it is possible by memory mapping the register space in using /dev/mem (normally not allowed, but as root or an embedded process is possible -- but "dangerous" in that you can blast any memory you want...). An example of mapping in the memory space to the FPGA to access registers is located in the MDK/examples/mmap_demo. (Note: you need to edit the makefile to change the include path to "../../sw/common/fpga" and add "-DFPGA_MAX_CORES=16" to the compile command to build in that directory). However, interrupt handling is not possible without some level of kernel code to register for the interrupt.
All of the FPGA interfacing via linux for the FPGA (for the IP Critical Link provides) is included in the MDK/sw/ARM/linux/drivers/fpga. The fpga_ctrl.c file is the driver that provides the capability to load the FPGA and sets up basic memory mapping and handles interrupts from the FPGA. It behaves like a "bus device", and our FPGA cores register into it. Each of the other .c files in that folder represent a driver for a provided core. Those drivers register into the fpga_ctrl.c when they are loaded. Because our framework shares 2 interrupt lines (using an interrupt vector), the interrupts are handled by the fpga_ctlr.c device and routed to the other drivers based on the vector numbers.
If you are using our framework to load up the fpgas and have a core that plugs into this framework, you need to copy one of these .c files and implement your driver and follow along to handle interrupts. Unfortunately, all of our drivers hook into some linux kernel abstractions (e.g., the SPI abstraction, the TTY abstraction, the I2C abstraction, etc.).
I will think a bit about an example for linux for custom FPGA IP to see if something simple can be created for you.
If you are not familiar with linux device drivers, you might check out the link below, it's pretty good and has some examples of drivers, etc.
I'm sorry I'm not giving you a "simple" .c file, but the linux OS puts some barriers for direct hardware access (for better or for worse) that makes this a little involved for interrupts.
-Mike
RE: Simple example needed - Added by Steven Hill over 11 years ago
OK, I am probably going to have a lot of questions. To start with:
1. What IDs are available to use for my core?
2. Do you have a walk-through of creating and using a new core?
3. Is it correct to assume that if a new core is added that the linux kernel has to be re-built?
RE: Simple example needed - Added by Steven Hill over 11 years ago
I just thought of another question. Not being familiar with linux, I am wondering what abstraction I might be able to hook into. My device is very simple: there are a number of offsets to which values must be written, and there is one input pin (to the FPGA) which indicates overheating and which must raise an interrupt.
RE: Simple example needed - Added by Michael Williamson over 11 years ago
Answers to questions:
1. The reserved FPGA id's are in the file: $MDK/sw/common/fpga/core_ids.h. I would use core ID 255 and count down for additional ones.
2. Not really. Normally we suggest that you start (for the FPGA) with the gpio.vhd core. I agree we need a better example for the driver. I have an action to improve this. Sorry for the inconvenience.
3. If you create a new core and want to write an ARM/linux driver for it, you don't necessarily have to modify the kernel. The cores are designed to be kernel modules, so you can load them without actually rebuilding the kernel. As long as your kernel driver uses the same (and unique) core ID as the FPGA core, then the framework will marry your new core with your new driver when the module is loaded and the FPGA device is probed (this happens when you send a "3" to the command sysfs file describe in programming the fpga).
For your situation, there are 2 ways you could go that would avoid having to develop any significant kernel code or modules.
Option 1¶
Create 2 cores. 1 core is your custom core. The other is a basic GPIO core with 1 GPIO input. Route your interrupt line to the GPIO input of the GPIO core. This will allow you to use the already built FPGA gpio driver to get at the interrupt condition using the kernel gpiolib via sysfs (about half way down in the page), and access your basic FPGA registers using /dev/mem as mentioned above using the mmap_demo software as a reference.
A code snippet for monitoring GPIO pin state changes ("interrupts") is shown below. I've removed the error handling for simplicity. Note, in a setup script I run the command to export the IO pin by running "echo 126 > /sys/class/gpio/export" and "echo both > /sys/devices/virtual/gpio/gpio126/edge" to export the GPIO pin and set up interrupt routing per the website mentioned above. If you are using the FPGA driver, I believe the first GPIO pin would be 144.
fd_set set; struct timeval to; int err_fid; int state; char buff[20]; int err_fid = open("/sys/devices/virtual/gpio/gpio126/value", O_RDONLY); int max_fd = err_fid; while(1) { FD_ZERO(&set); FD_SET(err_fid, &set); to.tv_sec = 0; to.tv_usec = 500000; rv = select(max_fd+1, NULL, NULL, &set, &to); if (rv > 0) { /* state change on pin */ lseek(err_fid, 0, SEEK_SET); read(err_fid, buff, 20); /* really only need first byte */ state = buff[0]-'0'; /* state of pin */ } else { /* likely a timeout, check errno and press on */ } } /* end of while */ close(err_fid);
Option 2¶
Create your custom core. Route your interrupt pin to one of the unused connections between the FPGA and OMAP-L138 that has a GPIO capable L138 pin (e.g., one of the UPP control pins). In this case, you might need to rebuild the kernel to ensure that the pin-mux setting for the selected pin is setup as a GPIO pin, then your software architecture would be the same as in option 1.
RE: Simple example needed - Added by Steven Hill over 11 years ago
Thanks for the help. I decided to take a very simple approach and use mmap to access the FPGA, based on the mmap example. Instead of an interrupt, I will just poll - I don't really need the response speed of an interrupt.