Access GPIO/SPI etc. on Expansion Header

Hi,

with its (freely programmable) expansion connector BeagleBoard Black seems to be a perfect thingy for embedded applications. Since I did not find anything suitable (only a Python library or some JavaScript-based things which all seem to be way to slow for my usage):

Is there a (realtime-capable) library available that gives the possibility to access the expansion header and utilitise it’s SPIs, digital IOs and PWM outputs? With “library” of course every piece of code is meant whatever is out there (so it can be kernel driver based for existing Linux variants, bare-metal code, whatever…)

Thanks!

For SPI, mux the pins in the device tree to enable the SPI0 and or SPI1 interfaces, then reference the Linux kernel documentation:

https://www.kernel.org/doc/Documentation/spi
https://github.com/piranha32/IOoo/blob/master/src/SPI.cpp

I suspect that the “spidev_test.c” file in the kernel or the SPI.cpp is what you are interested in, though the “spidev” file is the documentation on how all each of the pieces work.

For GPIO, there are a few places to look:

http://www.youtube.com/watch?v=wui_wU1AeQc
https://github.com/piranha32/IOoo/blob/master/src/BeagleGoo.cpp
http://www.armhf.com/index.php/using-beaglebone-black-gpios/

PWM has been discussed here on the forums:

https://groups.google.com/forum/#!category-topic/beagleboard/beaglebone-black/wjbOVE6ItNg

When controlling any of the “built-in” features of the BBB, there are generally one of three approaches that you can take:

  1. You can use a kernel device driver to speak directly to the control registers and then control the driver via an ioctl() call on the exposed /dev/* device file(s) for the driver.
  2. You can mmap() /dev/mem into your process’s memory space and change those registers directly. For bare-metal programming, you would talk directly to the memory-mapped registers this way (but without the mmap()).
  3. You can “echo” into and “cat” out of the files in the file system that export out device functionality. For example /sys/device/, /sys/class/gpio/, etc.

If you have a more specific question as to what exactly you want to do, I’m sure someone here can point you to an appropriate discussion on it that has already happened in the BeagleBoard group. A lot of this material has been discussed quite a bit. But, to answer your original question, I have not heard of a single library that does everything. But, there are a lot of examples of each piece that you can certainly stick together to make one.

Andrew

But, to answer your original

question, I have not heard of a single library that does everything.
But, there are a lot of examples of each piece that you can certainly
stick together to make one.

There is one in the process of being developed [1]. SPI and GPIO are
already covered.

[1] GitHub - jackmitch/libsoc: libsoc: C library for interfacing with common SoC peripherals through generic kernel interfaces

Hi Andrew,

I know this is an old forum, but I’ve been stuck trying approach 2, using an mmap to /dev/mem to control the SPI device. Do you know of any working examples?

Specifically, I’m trying to write to SPI0[MCSPI_TX0] with SPI0.D0 configured for output without using a FIFO, but I typically get nothing–no error, but no SPI CLK action either. The CH0STAT register is showing TX to be full, but I don’t know why the system does not initiate the transfer.

Any example configuration code you have would be greatly appreciated.

Thanks,
Patrick

Well, I have gotten it working before using mmap() calls because I had a very specific need for it for a proprietary project that I can’t share the code for, but I was informed (in no uncertain terms) that using mmap() for SPI comms in user space is a bad idea and that I am not a smart person:

https://plus.google.com/109402916922772242647/posts/YUpRgyD1HME

Offhand, I’m guessing that you’re loading a device tree overlay for SPI that specifies the driver “spidev” to be in control of the SPI channels. You’re probably hitting the registers correctly in user space, but the spidev driver is having the power management in the kernel shut down SPI because the spidev driver hasn’t sent a message within the last 2 seconds. In the kernel source, the drivers/spi/spi-omap2-mcspi.c file has the function omap2_mcspi_probe(). This function sets up some power management at the end:

pm_runtime_use_autosuspend(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, SPI_AUTOSUSPEND_TIMEOUT);
pm_runtime_enable(&pdev->dev);

As for an example of doing the transfer, you’ll want to mimic the code in the omap2_mcspi_txrx_pio() function in that same file. Ignore the OMAP2_MCSPI_CHCONF_TURBO paths, as you won’t be hitting any of those. You’ll also need to completely avoid mentioning the spidev in the overlay (only mux the pins) and set all the registers up yourself. Or, you can shut off the power management in the SPI driver (comment out the pm_runtime_enable() call), set up SPI via ioctls() to /dev/spidev from userspace, and then bitbang the registers via mmap(). Either way, mmap()-ing SPI is possible, but you REALLY need to make sure that there isn’t another way to do what you need to do.

In short, you should not be doing it this way. But, if you really want to experiment and learn about the spidev driver in the process, go for it.

Andrew

Well, I have gotten it working before using mmap() calls because I had a very specific need for it for a proprietary project that I can’t share the code for, but I was informed (in no uncertain terms) that using mmap() for SPI comms in user space is a bad idea and that I am not a smart person:

Isnt it funny how when you may ask these people who responded to you post they would not offer any assistance. But as soon as you put up working code for something that works for you, Suddenly everyone is offering their “help”

Personally, I can see several flaws with using mmap in any situation. But if it works for you, and works well. I say to hell with what anyone else says. So long as it’s abstracted, and no one else has to maintain it.

I keep seeing the same text from the same person “how very unlinix like of you” or some such garbage. Sorry, I can not disagree more. First of all, mmap was created for a reason. This reason has nothing to do with critiques on user implementation while using it. Secondly, Linux is about freedom, not one individuals “dictatorship” or misconception of what Linux should be.

Also, I’ve seen some implementations many of the commentators of the post you linked to and . . . yeah let us just say that some of the stuff I have seen is far from perfect. So many of them do not have a leg to stand on when it comes to criticizing someone else’s implementation.

Andrew, anyway you’re probably smart enough to not need my encouragement, but I’d encourage you to keep using mmap, while thinking of alternate methods of achieving the same end goal. While again thinking which method might be better and why. Software development is great for constantly keeping our minds busy while learning new techniques, and technologies. There is always something new to learn, and no one amongst us started off by knowing everything.

To be fair, using spidev to set up SPI and then bitbanging it from userspace is, at best, a very unorthodox approach. It just happened to be suited to the particular problem that I trying to solve. I can completely understand how such an approach would be viewed with some distaste by experienced kernel developers as it is far from the a standard approach to the problem. And they really aren’t wrong. It isn’t the correct way to develop a generalized solution. I was just curious as to whether anyone else had attempted it and what their results were like.

The particular project that required my SPI tinkering finished quite a while ago and it worked like a charm, so I’ll just chalk it up as a learning experience and leave it at that. The BBB, kernel code, etc. are all there for you to play around with. Try crazy stuff out and have fun with it. Some will work out OK and some won’t, but you won’t know until you give it a shot.