A Simple Realtime Application on the PandaBoard:
A 10 KHz Square Wave

This post contains code that creates a 10 KHz square wave on one of the GPIO pins of a PandaBoard running the real-time Linux extensions. It is a proof of concept showing that the PandaBoard is suitable for real time applications.

The code used in this example is based on the swave.c program from the kernel.org RT wiki, which is located here: https://rt.wiki.kernel.org/articles/s/q/u/Squarewave-example.html.

For instructions on how to run realtime Linux on your PandaBoard, refer to the tutorial that I posted on the Homebrew Robotics Club wiki titled “Installing Ubuntu With Real Time Patches On The PandaBoard.”

 

Code

The following code is all that you need to create the square wave. Save the code in a file called swave_panda.c.

// file: swave_panda.c
/* compile using  "gcc -o swave_panda swave_panda.c -lrt -Wall"  */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sched.h>
#include <sys/io.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

#define NSEC_PER_SEC    1000000000

/* using clock_nanosleep of librt */
extern int clock_nanosleep(clockid_t __clock_id, int __flags,
      __const struct timespec *__req,
      struct timespec *__rem);

static inline void tsnorm(struct timespec *ts) {
    while (ts->tv_nsec >= NSEC_PER_SEC) {
        ts->tv_nsec -= NSEC_PER_SEC;
        ts->tv_sec++;
    }
}

int main( int argc, char** argv )
{
    struct timespec t;
    struct sched_param param;
    int interval=50000;  // 50000ns = 50us, cycle duration = 100us

    int fd;
    char zero_string[] = "0";
    char one_string[] = "1";
    char buffer[32];
    unsigned char value = 0;

    // Enable GPIO_32, which comes out pin 18 of J6. A list of available GPIOs
    // can be found in the PandaBoard System Reference Manual.
    {
        if ((fd = open("/sys/class/gpio/export", O_WRONLY | O_NDELAY, 0)) == 0) {
            printf("Error: Can't open /sys/class/gpio/export.\n");
            exit(1);
        }   
        strcpy( buffer, "32" );
        write( fd, buffer, strlen(buffer) );
        close(fd);
        printf("Added GPIO 32.\n");
    }

    // Set the direction of the GPIO to "out."
    {
        if ((fd = open("/sys/class/gpio/gpio32/direction", O_WRONLY | O_NDELAY, 0)) == 0) {
            printf("Error: Can't open /sys/class/gpio/gpio32/direction.\n");
            exit(1);
        }
        strcpy( buffer, "out" );
        write( fd, buffer, strlen(buffer) );
        close(fd);
        printf("Direction set to out.\n");
    }

    // Open the "value" node. We will write to it later.
    {
        if ((fd = open("/sys/class/gpio/gpio32/value", O_WRONLY | O_NDELAY, 0)) == 0) {
            printf("Error: Can't open /sys/class/gpio/gpio32/value.\n");
            exit(1);
        }   
        printf("Value opened for writing.\n");
    }

    if ( argc >= 2 && atoi(argv[1]) > 0 ) {
        printf("Using realtime, priority: %d.\n",atoi(argv[1]));
        param.sched_priority = atoi(argv[1]);
        // Enable realtime fifo scheduling.
        if(sched_setscheduler(0, SCHED_FIFO, &param)==-1){
            perror("Error: sched_setscheduler failed.");
            exit(-1);
        }
    }
    if ( argc >= 3 )
        interval=atoi(argv[2]);

    clock_gettime(0,&t); // Get current time.
    t.tv_sec++;          // Start after one second.

    while (1) {
        // wait untill next shot.
        clock_nanosleep(0, TIMER_ABSTIME, &t, NULL);
        if(value) {
            write( fd, one_string, 1 );
            //printf("...value set to 1...\n");
        } else {
            write( fd, zero_string, 1 );
            //printf("...value set to 0...\n");
        }
        value = !value;
        // Calculate next shot.
        t.tv_nsec+=interval;
        tsnorm(&t);
   }
   return 0;
}

Compile the program with the following command:

gcc -o swave_panda swave_panda.c -lrt

To run the program with a real time priority of 90, enter the following command:

sudo ./swave_panda 90

 

Hardware Setup

To view the output on a oscilloscope, connect the probe to pin 18 on J6. You can find ground on pins 27 and 28 of J3.

 

Results

After you run the program and connect your oscilloscope probe to pin 18, you should see a 10 KHz square wave, as shown in the following image.

The square wave is solid even when the system is under moderate load. Under heavy load, I can see a jitter of a few microseconds. I have yet to determine from where the jitter originates. I don’t know if there is some uncertainty in the kernel or if there is a uncertain amount of delay in the userspace GPIO drivers. None of my robots operate in conditions that are dangerous to humans or property, so I will probably be able to tolerate an uncertainty of a few microseconds. If you are designing a surgical robot, for example, a few microseconds of uncertainty might be too much. I will be investigating if this little bit of observed jitter can be reduced or eliminated.

 

More Informaion

I am interested in creating more realtime applications for the PandaBoard. If you have any experience creating such programs and you have any advice to offer or you would like to exchange ideas, please send me an email or add a comment to this post.

7 comments to A Simple Realtime Application on the PandaBoard:
A 10 KHz Square Wave

  • Andrés

    Excellent article 😀

    I have a question tho. I’m currently working with the pandaboard running Android 4.0.3, so far it has worked pretty well and the apps I’m building run smooth with almost no problems.

    Recently I began to code an application and I need to make use of the GPIO ports the pandaboard has. I could successfully run a script which generates a square signal of 100 Hz (low freq) but the signal is not consistent at all, this makes me think it is due to the kernel not being a real-time one. Do you know if it is any possibility to patch my android build with a real-time kernel?

    Hope you could give me a hand on this 😀

    • Osman Eralp

      Moving to a real time kernel will definitely help. A Linux OS can sometimes “go away” for a hundred(s) milliseconds doing things like file clean up. This will cause jitter even on your slow square wave. You would first need to find the source for your build. If it is built on the source from kernel.org, you have a chance at being able to apply the real time patches. Unfortunately, I have not tried this for Android, so I can’t provide any specific advice. Sorry!

  • Andrés

    Thank you Osman for replying so fast!

    I will try to find the way to patch my already built kernel. I guess moving to a RT kernel should not interfere with Android, but I will let you know if I’m successfull at this.

    Again, you were of a lot of help, now I have a clue on what to do in order to make my app to work as intended.

    Rgds
    Andrés

  • Norm

    Hey Osman,

    I am trying to apply the real time kernel on my Pandaboard ES and I am running into some problems when using the following command:

    $ git clone git://dev.omapzoom.org/pub/scm/integration/kernel-ubuntu.git

    When installing via minicom the system freezes and I have to manually reboot (i.e. unplug the pandaboard). When I tried the command directly in the Pandaboard I received an error saying the git file is corrupt at a specific line. Is there another method or file I can use to apply a real-time kernel to the Pandaboard? Thanks. Any help is appreciated.

    • Osman Eralp

      It can take 30 minutes to clone the git repository even with a fast connection. Does the PandaBoard have an internet connection? How long did you wait? Did you see messages like this:

      <4> …/tmp $ git clone git://dev.omapzoom.org/pub/scm/integration/kernel-ubuntu.git
      Cloning into ‘kernel-ubuntu’…
      remote: Counting objects: 2881668, done.
      remote: Compressing objects: 100% (434576/434576), done.
      Receiving objects: 1% (32365/2881668), 12.61 MiB | 778 KiB/s

      • Norm

        To make sure I did everything right I followed the instruction at:

        http://hbrobotics.org/wiki/index.php?title=Installing_and_Configuring_Ubuntu_on_the_PandaBoard

        I came up with the same problem. The PandaBoard does have an internet connection. To make sure that I was doing everything correctly I waited 30min. I do see a similar message as you posted. This time I performed the clone directly from the PandaBoard. It has been frozen for over 20min at:

        Receiving object: 37% (1072458/2881668), 432.31MiB | 1.57 MiB/s

        The cursor is not flashing and the objects received has not changed so I am assuming that the system is frozen but I don’t know why. I am relatively new to the Linux system and so I am not sure how to proceed.

        • Osman Eralp

          There might be a hardware problem. I had a PandaBoard that reset itself when the wifi had been on for more than about 10 minutes. I think it was overheating. If you are using wifi, try switching to a cable.

          Another idea is to take the SD card out of the PB, and mount the card on another Ubuntu system. Clone the git repository on the other system, and then copy it to the SD card in a location that you will be able to access when you put the card back in the PB.