Original Image - http://falstaff.agner.ch/wp-content/uploads/2013/05/beaglebone-black.jpg

TI eQEP Driver Tutorial

About a year ago I wrote a driver for the enhanced quadrature encoder pulse decoder unit (eQEP) resident in the TI AM33xx series system on a chips.  The unit allows one to attach a quadrature encoder to the SoC directly and have it handle counting the encoder ticks, versus needing an external controller such as an Arduino.  Both the Beaglebone and Beaglebone Black have 3 eQEP units, but unfortunately only eQEP1 and eQEP2 are broken out on the original Beaglebone.  eQEP 0 can be used without conflicts with built in hardware on the Beaglebone Black, but due to multiplexing, eQEP 1 can only be enabled when HDMI is disabled and eQEP 2 requires either the HDMI or the eMMC to be disabled.  Previously, the only interface with the driver was via the sysfs interface, making writing software around the driver fairly simple, but the textual interface was rather slow.  After multiple requests to add a device node based interface I figured i might as well go and do it.  In order to clean things up, I’m refactoring the driver, and since this is one of the rare examples of a practical kernel module I’ve decided to take the opportunity and put together a tutorial on writing a kernel module.

For simplicity’s sake, I’m going to assume you have an ARM cross compiler installed.  If you are running on Ubuntu, the arm compilers are in the standard repositories (arm-linux-gnueabihf-gcc/g++), otherwise you can grab the Linaro toolchain, which is what I use.  You’ll also need to compile the kernel so we can build modules against it.  The kernel used by the majority of the community for Ubuntu and Debian is Robert C Nelson’s - https://github.com/RobertCNelson/linux-dev.  I’m using the am33x-v3.8 branch, which at the time of writing builds the v3.8.13-bone52 kernel.  There are a plethora of tutorials on building the kernel, my favorite of which is Derrek Molly’s - https://www.youtube.com/watch?v=HJ9nUqYMjqs.  This video is a bit dated, but if you replace “git checkout am33x-v3.2 -b am33x-v3.2″ with “git checkout am33x-v3.8 -b am33x-v3.8″ the instructions are practically identical.

We need to setup some boilerplate code at first.

#include 
#include <linux/printk.h>
#include <linux/types.h>

// Include the configured options for the kernel
#include <generated/autoconf.h>

// Called when the module is loaded into the kernel
static int __init eqep_init(void)
{
    printk(KERN_INFO "[TIeQEP] Module Loaded");

    // Successfully initialized
    return 0;
}

// Called when the module is removed from the kernel
static void __exit eqep_exit(void)
{
    printk(KERN_INFO "[TIeQEP] Module Exited");
}

// Tell the compiler which functions are init and exit
module_init(eqep_init);
module_exit(eqep_exit);

// Module information
MODULE_DESCRIPTION("TI eQEP driver");
MODULE_AUTHOR("Nathaniel R. Lewis");
MODULE_LICENSE("GPL");

At the core of every kernel module are two methods - init and exit.  Init is called when the module is loaded into the kernel and exit is called when the module is removed.  For testing purposes, we’ve just stuck printk calls (print kernel) into those methods.  module_init() and module_exit() are macros which setup the passed function as the corresponding kernel module method.

In order to load this into the kernel, we have to compile it first.  Writing a makefile for a kernel module is a little different than most,  as we technically need to build in the kernel directory.  After building the kernel as mentioned above, the actual kernel lives in linux-dev/KERNEL.

obj-m = tieqep.o
KDIR := /home/nathaniel/Programming/linux-dev/KERNEL
ccflags-y = -I/home/nathaniel/Programming/linux-dev/KERNEL

all:
    make -C $(KDIR) M=$(shell pwd) ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules

clean:
    make -C $(KDIR) M=$(shell pwd) clean

Replace “/home/nathaniel/Programming/linux-dev/KERNEL” with where you kernel was built.  Also, this make file assumes the name of the kernel module is tieqep.c.  After running make, you will get a file named tieqep.ko.  Boot up your beaglebone and copy this file to it.  To insert to kernel module, run “sudo insmod tieqep.ko” and to remove it run “sudo rmmod tieqep.ko”.  Here is the log from my beaglebone.

debian@arm:~$ ls
bin tieqep.ko
debian@arm:~$ sudo insmod tieqep.ko
[sudo] password for debian:
[ 43.064141] [TIeQEP] Module Loaded
debian@arm:~$ dmesg | tail
[ 14.464018] hub 2-0:1.0: TT requires at most 8 FS bit times (666 ns)
[ 14.464028] hub 2-0:1.0: power on to power good time: 10ms
[ 14.464068] hub 2-0:1.0: local power source is good
[ 14.464160] hub 2-0:1.0: enabling power on all ports
[ 14.564117] hub 2-0:1.0: state 7 ports 1 chg 0000 evt 0000
[ 14.564178] hub 2-0:1.0: hub_suspend
[ 14.564206] usb usb2: bus auto-suspend, wakeup 1
[ 14.636179] CAUTION: musb: Babble Interrupt Occurred
[ 14.755082] gadget: high-speed config #1: Multifunction with RNDIS
[ 43.064141] [TIeQEP] Module Loaded
debian@arm:~$ sudo rmmod tieqep.ko
[ 52.082653] [TIeQEP] Module Exited
debian@arm:~$ dmesg | tail
[ 14.464028] hub 2-0:1.0: power on to power good time: 10ms
[ 14.464068] hub 2-0:1.0: local power source is good
[ 14.464160] hub 2-0:1.0: enabling power on all ports
[ 14.564117] hub 2-0:1.0: state 7 ports 1 chg 0000 evt 0000
[ 14.564178] hub 2-0:1.0: hub_suspend
[ 14.564206] usb usb2: bus auto-suspend, wakeup 1
[ 14.636179] CAUTION: musb: Babble Interrupt Occurred
[ 14.755082] gadget: high-speed config #1: Multifunction with RNDIS
[ 43.064141] [TIeQEP] Module Loaded
[ 52.082653] [TIeQEP] Module Exited
debian@arm:~$

In the next post I’ll go over the device tree and writing the platform device driver component.

Original image - http://elinux.org/images/d/d8/BBxM-400.jpg

Beagleboard xM @ 1 GHz

Over the past couple of days, I’ve been reading on the beagleboard.org boards about the upcoming 3.11-rc2 kernel and the new features it brings for the OMAP SoCs.  For the Beagleboard xM, one of the more important new features is the ti-abb-regulator (adaptive body bias) driver, which allows an OMAP SoC to adjust its core voltage dynamically.  Combined with the smart reflex class 3 driver (which has been in the kernel since 3.6), the Beagleboard xM can achieve safe and stable operation at 1 GHz – finally.  Its been a long time coming considering the last time 1 GHz was supported was kernel 3.0.28 back in early 2012.  The process of enabling 1 GHz operating comes in 4 parts.

First, since the TI abb driver bindings are for the device tree based boot only, we need to bring in some resources for the device tree (https://github.com/Teknoman117/beagleboardxm-kernel/blob/v3.11.x/patches/drivers/0005-ARM-dts-omap-clock-bindings-driver.patch).  The abb driver requires a reference to the system clock, as in hardware that what drives it.  I began to code one up myself, and then looking for information on that, I stumbled into a post from April 2013 (http://lkml.indiana.edu/hypermail/linux/kernel/1304.1/04079.html) containing such a driver.  So I pulled that resource in which provides the ability to bring in the OMAP clocks references into the device tree.

Second, we dive into the device tree.  We now need to add the system clock binding to our definition of the omap3 CPU (https://github.com/Teknoman117/beagleboardxm-kernel/blob/v3.11.x/patches/omap/0014-ARM-dts-omap3-add-clock-bindings-to-dts.patch).  I just created references to the required clock for the system clock, and then according to this post (http://lkml.indiana.edu/hypermail/linux/kernel/1304.1/04074.html) one needs to add a reference to the CPU dpll1 clock for the cpu frequency driver.

Third, we need to modify the power management startup for the omap processor (https://github.com/Teknoman117/beagleboardxm-kernel/blob/v3.11.x/patches/omap/0015-ARM-dts-omap-boot-support-cpu0-cpufreq.patch).  By default, it will only load a cpu-freq driver when performing a non-dts based boot.  This is a problem.  So we tell the power management driver to always initialize the cpu-freq system and modify the initialize function to load the legacy cpu-freq driver when performing a non-dts boot and to load the new cpu0-cpufreq SoC generic driver if performing a dts based boot.

Fourth, we need to add the abb bindings for the beagleboard xm into omap3-beagle-xm.dts (https://github.com/Teknoman117/beagleboardxm-kernel/blob/v3.11.x/patches/omap/0016-ARM-dts-omap3-beagle-xm-add-opp1g-abb-bindings.patch).  This consists of two modifications, 1) adding the ti-abb-regulator driver and 2) adding the frequency and core voltage values for OPP1G, the 1 GHz operating point of the OMAP36xx/OMAP37xx CPUs.  After this modification, the beagleboard xM can boot supporting 1 GHz under the device tree based boot.

Screenshot of the cpu-freq info for these patches

beagleboard_xm_1ghz

These patches have been merged into the https://github.com/RobertCNelson/armv7-multiplatform v3.11.x branch, so to build a kernel, checkout the v3.11.x branch

nathaniel@Sedenion:~> git clone https://github.com/RobertCNelson/armv7-multiplatform.git

nathaniel@Sedenion:~> git checkout origin/v3.11.x -b v3.11.x

and then follow the standard build instructions provided in the README.

After you build the kernel, you need to modify the uEnv.txt file to enable the dts based boot.  At the bottom of  uEnv.txt, comment out this line

uenvcmd=run boot_classic; run device_args; bootz 0×80300000 0×81600000:${initrd_size}

and uncomment this line.

uenvcmd=run boot_ftd; run device_args; bootz 0×80300000 0×81600000:${initrd_size} 0x815f0000

When I was messing around, the bootloader seemed to fail to detect the dtb to use for the current board, so you can force it by adding this line at the beginning of the file

 fdtfile=omap3-beagle-xm.dtb

There is still an annoying issue currently, not with the operating frequency, but with the USB ports on the board.  The sprz319 erratum patch has not yet been ported to 3.11 yet, so until I finish that, not stable usb ports.  It probably will take a few hours, but it shouldn’t be so hard.  Happy coding!

Edit: I have ported the sprz319 erratum patch to the beagleboard xM - https://github.com/Teknoman117/beagleboardxm-kernel/blob/v3.11.x/patches/omap_sprz319_erratum_v2.1/0001-hack-omap-clockk-dpll5-apply-sprz319e-2.1-erratum-kernel-3.11-rc2.patch.  Make sure to uncomment it in patch.sh before running build_kernel.sh.  It is disabled by default because it breaks support for the older Beagleboard (not xM) series.

Edit: This patch is still working for the kernel 3.13.x development branch!

Python – as the system shell

I have absolutely no idea if this is useful for anyone (embedded systems?), but I was creating a user on the new OS image i’m using for my Beagleboard xM and wondered what would happen if I specified python as the login shell for a user.  So anyway, it worked, and you get the python shell when you log into the system.

python_user_create

bb-hcsr04-featured

Using a Beaglebone with an HC-SR04 sonar

Over the last couple of days, now that Robogames 2013 has come and gone, I’ve been working on projects that are more experiments than anything else.  A few weeks before Robogames, I noticed that there were sonars for real cheap on http://www.wrighthobbies.com/.  At the time I didn’t realize that these were all over the internet and are essentially a cheap Chinese knockoff of devices like the Ping))) and SRF04/5.  These sonars are dirt cheap, buying in bulk from Ebay can lead gets you prices approaching $1.50 a unit.  Seems insane, considering I’ve bought a 5 pack of Ping)))s for $100, but one can by a pack of 10 of these little guys for $15.  Needless to say I didn’t have high expectations for them.  So I ordered a couple so that I could test against my collection of Ping)))s and SRF04s.  Much to my surprise, they perform just as well as the Ping))) and the SRF04.  I don’t know how long they will be available at this price, so I ordered a whole lot more of them.  Their interface is the same as an SRF05, and you can connect the trigger pin and the echo pin and use only one I/O line per sonar, giving it the same interface as a Ping))). 

One of my personal side projects is the Beaglebot, a small, tabletop or hardwood roving bot that I want to entirely operate using the Beaglebone, as in, without external AVRs, arduinos, etc.  So I set out to understanding Linux kernel development so that I could write kernel drivers for all of my hardware.  I was very happy to discover that kernel module development is actually really easy, nothing like driver development is with Windows.  Within a week I had an LED driven by PWM and you could control its max brightness and blink rate from sysfs.  At this point I was feeling confident enough to tackle driving a sonar from my Beaglebone.  My testing of the sonars previously had used an Arduino Uno and interrupts to keep the CPU free from having to wait on the sonars to respond and to be able to do stuff during measurements, etc.  This is exactly how you should write drivers for operating systems.  So I wrote my sonar driver.  And when I loaded it up and debugged it as best I could, I was disheartened that I could not get the sonar working properly, for I was getting extremely variant or random measurements.  With all of my experience with microcontrollers, my thought had been that interrupt handlers would execute when interrupts occurred, but it’s a bit more complicated than that.  Interrupts aren’t handled immediately, but rather put onto a queue which is sorted by priority and processed sequentially.  This is not good for a device where its input is time dependent.  So I began to explore other options and discovered that the Beaglebone has two high speed microcontroller cores, known as PRUs (Programmable Realtime Units), built into the CPU that can access the entirety of the memory map, meaning that they can access all of the memory, all of the IO, and the communications buses.  They both have an interrupt to the CPU so that they can signal when they’ve completed some action, in this case, that the sonar has taken a reading.  Before toying with the code, we have to hook up the sonar to the Beaglebone.  The HC-SR04 is a 5V device, and will not operate at any less than that.  As the beaglebone, along with every other ARM Cortex based system, has a maximum voltage of 3.3V, we have to protect the beaglebone from the sonar.  Essentially all I did for this was connect an NPN transistor between one of the beaglebone’s IO pins and ground.  This is fine considering that each of the IO lines on the beaglebone has a configurable pullup or pulldown resistor, we just have to note that the signal is now inverted.  The base of the transistor is connected through a 220 ohm resistor to the echo line of the sonar.  From experimenting, turns out 3.3V is enough to cause the sonar to trigger, so we can hook one of the beaglebone’s IO lines right up to the trigger pin.  The schematic is essentially this

bb-hcsr04-circuit-diagram

And this is what the  setup looks like

bb-hcsr04-circuit

bb-hcsr04-occillosope

The software I have provided on github assumes that the sonar’s trigger is using GPIO1_6 and the inverted echo signal is on GPIO1_7.  The operation of the HC-SR04 sonar is fairly straight forward.  One sends a trigger pulse of at least 10 microseconds.  The device then waits for the echo line to activate (in our inverted case, high to low transition) and measures the time from there until it deactivates (low to high in our case).  This time is the round trip flight time of the sonar pulse.  Divide this number by 58, and you have the distance to target in centimeters.

The code on the Beaglebone side is a bit less straightforward.  Unfortunately there is no higher level language available for the PRU than PRU Assembler.  Oh well I suppose.  The guide on how to use the sample code is here on my github: https://github.com/Teknoman117/beaglebot/tree/master/hcsr04-demo  In the mean time, here is a YouTube video of my sonar code in action

kybernetes-robogames2012

Kybernetes at Robogames 2013

Kybernetes is a test platform for autonomous navigation I developed with the Robotics Society of UC Merced.  Up until recently, I’ve been the only person on the project, however our recent increase in membership means Kybernetes will serve as an important resource for educating new members in electronics, sensor systems, localization, and mapping.

Please ignore the outburst of “ran out of power” in the video, I was jumping to conclusions since I was running on a two hours of sleep and countless cups of coffee.

The robotics society placed second in the Robomagellan competition, getting within seven feet of the goal cone.  We didn’t manage to complete the course for two major reasons – power problems and the vision system.  The power problem reinforced an important lesson, that electric motors cause serious amount of electrical noise in single power supply systems.  Because of the filtering in the switching regulator leading to the electronics, we avoided the classic issue where “gunning it” would reset the computers.  The major issue at the competition was that anytime the motors generated a spike (speeding up, slowing down rapidly), the servos would jerk to one of their extremes before accepting any control input again. This problem is evident at the beginning of the video where the robot makes a sudden right turn as it starts. We had only been testing on paved areas on campus and the dry, short grass in the UCM quad. The wet and tall grass at Robogames was the first time we observed the issue, and we spent the next hour or so patching in the servo power straight to the battery instead of through the main motor ESC’s battery eliminator circuit. We didn’t do this earlier because the battery supplied a voltage above the rated value for the servos (8.4V battery, 7.2V servos), but for the course of the competition at least, we didn’t blow up the servos.

Solving the power issue consumed the time I had allotted to calibrating our vision system for the conditions of the Robomagellan course. We solved the issue right before we were called up for our first run of the day. I hadn’t even put in the course coordinates yet, so I ran the heading lock test, hoping that Kybernetes would at least follow a straight course and put some distance between the starting point and the goal cone. Since the robot would not stop automatically (it was just following the heading it was pointing when the program started), I stopped the run with our failsafe remote. We were around 40 meters from the goal cone, about half the distance to it from the starting cone.

After walking and plotting a course for Kybernetes to take during the lull between rounds, I loaded the coordinates for our next run. When our time came, I put Kybernetes in the starting position, started the navigation program, and prayed. Camp called for the start of the run and off Kybernetes went, following the course I plotted perfectly.  It drove to the point at which it previously stopped, made a hard right towards the goal cone, and opened the throttle (well, the electronic equivalent of it anyways).  Its hard to see in the video, but it hit the transition between the grass and pavement pretty harshly, tilting the front up about 45 degrees, sending it about four inches into the air.  It landed on its wheels and continued all the way up to the cone, stopping seven feet of it.  In all honesty I was a little sad it didn’t continue, but since the vision was disabled, it was instructed to stop after predicting its distance to target within the error radius of the GPS.

In the end, there were things that could have been done better, but I went home that day knowing that Kybernetes had done everything it was instructed to do flawlessly.  If you want to check out the software written to control Kybernetes, check out the “kybernetes” repository on my GitHub.

Kybernetes Software:

https://github.com/Teknoman117/kybernetes

C++ Plugins with Boost::Function on Linux

Over the past few weeks, one of the concepts that I’ve been experimenting with is plugin architecture.  The idea of having a core application which can be extended by shared objects without recompiling the core program.  Or, possibly, a way of defining more services in an application based around plugins.  What I’ve done so far hasn’t been much, but, I haven’t spent much time working on it.  When I started out on researching it, one of the things I wanted was to be able to was define a C++ object in a plugin and be able to instantiate that object in the main program.  So, this is what I have come up with.  There are three parts of this solution: the plugin class definition in plugin.hpp, the plugin in someplugin.cpp, and the loader code in loader.cpp.  I’ve also included a CMakeLists.txt file to compile it with cmake.

plugin.hpp

#ifndef _PLUGIN_HPP_
#define _PLUGIN_HPP_

#include <string>

namespace plugins
{
  class Plugin 
  {  
  public:
    virtual std::string toString() = 0;
  };
}

#endif

awesomeplugin.cpp

#include "plugin.hpp"

namespace plugins
{
  class AwesomePlugin : public Plugin
  {  
  public:
    // A function to do something, so we can demonstrate the plugin
    std::string toString()
    {
      return std::string("Coming from awesome plugin");
    }
  };
}

extern "C" 
{
  // Function to return an instance of a new AwesomePlugin object
  plugins::Plugin* construct()
  {
    return new plugins::AwesomePlugin();
  }
}

loader.cpp

#include <iostream>
#include <vector>
#include <dlfcn.h>
#include <boost/function.hpp>

#include "plugin.hpp"

typedef std::vector<std::string>             StringVector;
typedef boost::function<plugins::Plugin* ()> pluginConstructor;

int main (int argc, char** argv)
{
  // Assemble the names of plugins to load
  StringVector plugins;
  for(int i = 1; i < argc; i++)
  {
    plugins.push_back(argv[i]);
  }

  // Iterate through all the plugins and call construct and use an instance
  for(StringVector::iterator it = plugins.begin(); it != plugins.end(); it++)
  {
    // Alert that we are attempting to load a plugin
    std::cout << "Loading plugin \"" << *it << "\"" << it->c_str() << std::endl;

    // Load the plugin's .so file
    void *handle = NULL;
    if(!(handle = dlopen(it->c_str(), RTLD_LAZY)))
    {
      std::cerr << "Plugin: " << dlerror() << std::endl;
      continue;
    }
    dlerror();

    // Get the pluginConstructor function
    pluginConstructor construct = (plugins::Plugin* (*)(void)) dlsym(handle, "construct");
    char *error = NULL;
    if((error = dlerror()))
    {
      std::cerr << "Plugin: " << dlerror() << std::endl;
      dlclose(handle);
      continue;
    }

    // Construct a plugin
    plugins::Plugin *plugin = construct();
    std::cout << "[Plugin " << *it << "] " << plugin->toString() << std::endl;
    delete plugin;

    // Close the plugin
    dlclose(handle);
  }

  return 0;
}

CMakeLists.txt

# Project Stuff
cmake_minimum_required (VERSION 2.6)
project (PluginDemo)

# Default Options
add_definitions("-std=c++0x")

# Find Boost
find_package(Boost REQUIRED)
include_directories(${Boost_INCLUDE_DIRS})

# Pull in the project includes
include_directories(${PROJECT_SOURCE_DIR}/include)
set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)
set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
set(LIBS ${LIBS} pthread boost_thread rt)

# Build the plugin experiment
add_executable(pluginloader src/loader.cpp)
target_link_libraries(pluginloader ${LIBS} dl)
add_library(awesomeplugin SHARED src/awesomeplugin.cpp)

Basically create a directory with the folders bin, lib, and src. Put loader.cpp, awesomeplugin.cpp, and plugin.hpp in src, and CMakeLists.txt in the directory. Open a terminal and run “cmake . && make”. Run the pluginloader program and pass it the path to the plugin’s .so in the lib folder. Here is the output from my computer.

nathaniel@XtremePC:~/Programming/Experimentation> cmake .
– The C compiler identification is GNU
– The CXX compiler identification is GNU
– Check for working C compiler: /usr/bin/gcc
– Check for working C compiler: /usr/bin/gcc — works
– Detecting C compiler ABI info
– Detecting C compiler ABI info – done
– Check for working CXX compiler: /usr/bin/c++
– Check for working CXX compiler: /usr/bin/c++ — works
– Detecting CXX compiler ABI info
– Detecting CXX compiler ABI info – done
– Boost version: 1.46.1
– Configuring done
– Generating done
– Build files have been written to: /home/nathaniel/Programming/Experimentation
nathaniel@XtremePC:~/Programming/Experimentation> make
Scanning dependencies of target awesomeplugin
[ 50%] Building CXX object CMakeFiles/awesomeplugin.dir/Plugins/awesomeplugin.cpp.o
Linking CXX shared library lib/libawesomeplugin.so
[ 50%] Built target awesomeplugin
Scanning dependencies of target pluginloader
[100%] Building CXX object CMakeFiles/pluginloader.dir/Plugins/loader.cpp.o
Linking CXX executable bin/pluginloader
[100%] Built target pluginloader
nathaniel@XtremePC:~/Programming/Experimentation> bin/pluginloader lib/libawesomeplugin.so
Loading plugin “lib/libawesomeplugin.so”
[Plugin lib/libawesomeplugin.so] Coming from awesome plugin
nathaniel@XtremePC:~/Programming/Experimentation>

- Teknoman117