Archive

Archive for the ‘BeagleBone’ Category

Console Based UI Development on BeagleBone

April 21, 2012 1 comment

When experimenting with various devices on the BeagleBone I often get to a point with my test programs where streaming output messages (i.e. printf) to a console is no long feasible. What’s really needed at that point is a UI that displays current state information such as the value of a GPIO pin. Depending on which OS the BeagleBone is running there are a variety of graphic user interfaces (GUI) available for use. But GUI’s are never simple and with the BeagleBone you either needs to invested in a display or use X/Windows to display the GUI on another personal computer. Another alternative is to use a console based UI.

The Angstrom release of Linux that ships with the BeagleBone includes the curses and it’s newer incarnation ncurses. If you’re familiar with C programming getting a ncurses application up and running will only take a few minutes. Here is a very simple ncurses program.

poll.c

#include <ncurses.h>

void main() {
initscr();
mvprintw(5, 3, "Hello world!");
getch();
endwin();
}

Compile it with …

gcc poll.c -lncurses -o poll

Executing poll will display “Hello world!” starting at Y, X position 5, 3 on the console and then wait for a key hit before exiting.

The next step is to monitor something. The BeagleBone pulses one of its LED’s like a heart beat. poll has been adapted to monitor if the brightness value is on (255) or off (0) and count the number of times it catches it on.

poll.c

#include <ncurses.h>
#include <stdio.h>
#include <stdlib.h>

void monitor(FILE *fp) {
        int run = 1;
        int count = 0;

        nodelay(stdscr, true);
        noecho();

        mvprintw(1, 1, "brightness:");
        mvprintw(2, 1, "     count:");

        while (run) {
                char buffer[16];
                memset(buffer, 0, sizeof(buffer));

                fseek(fp, 0, 0);
                fread(buffer, sizeof(char), sizeof(buffer), fp);

                int value = atoi(buffer);
                if (value != 0) {
                        count++;
                }

                mvprintw(1, 12, "%-3s", (value != 0 ? "on" : "off"));
                mvprintw(2, 12, "%d", count);

                int c = getch();
                switch(c) {
                        case 'q':
                                run = 0;
                                break;
                }
        }
}

void main() {
        char *file = "/sys/class/leds/beaglebone::usr0/brightness";
        FILE *fp;
        if ((fp = fopen(file, "r")) == NULL) {
                fprintf(stderr, "error: cannont open %s\n", file);
        }
        else {
                initscr();
                monitor(fp);
                endwin();

                fclose(fp);
        }
}

The program opens the sys-fs file that will provide the brightness value. After initializing ncurses it goes into a loop that reads the brightness value, increments the count if the LED is on, outputs the data, and checks if the user has hit the quit (‘q’) key.

The call to nodelay() prevents getch() from blocking and noecho() configures ncurses not to echo key hits.

Running poll.

When running poll I noticed that it seems to stagger at times. The application will noticeably pause on occasion. Since the application has to share clock cycles with the other applications it only gets a slice of CPU time. The size of the slice will vary over time and depends on what other things the CPU is being asked to execute. Linux provides the nice command which specifies the application’s priority on the kernel’s run queue. Running poll with a nice of -20 (the maximum) significantly improved its responsiveness.

As a next step I’ve been exploring how to use ncurses to create an application that treats input from a device (i.e. push button) wired to a BeagleBone expansion pin as UI input. For example, pressing a push button would be like pressing a key on the keyboard. More on that in the future.

 

 

Advertisements
Categories: BeagleBone

BeagleBone, GPIO, & IRQ

April 15, 2012 9 comments

My last BeagleBone post looked at interfacing the the bone with an incremental rotary encoder. I wasn’t satisfied with the polling loop I used to read inputs from the encoder so I began investigating alternate methods. While reviewing the sysfs GPIO documentation I noticed that …

Inputs can often be used as IRQ signals, often edge triggered but sometimes level triggered. Such IRQs may be configurable as system wakeup events, to wake the system from a low power state.

Later in the documentation it states …

/sys/class/gpio/gpioN/ …

“value” … reads as either 0 (low) or 1 (high). … If the pin can be configured as interrupt-generating interrupt and if it has been configured to generate interrupts (see the description of “edge”), you can poll(2) on that file and poll(2) will return whenever the interrupt was triggered. If you use poll(2), set the events POLLPRI and POLLERR. If you use select(2), set the file descriptor in exceptfds. After poll(2) returns, either lseek(2) to the beginning of the sysfs file and read the new value or close the file and re-open it to read the value.

“edge” … reads as either “none”, “rising”, “falling”, or “both”. Write these strings to select the signal edge(s) that will make poll(2) on the “value” file return.

This file exists only if the pin can be configured as an interrupt generating input pin.

If all this is truly working on the bone then it’s a better method than polling in user space. It should eliminate a bunch of context switching between kernel and user space  in my current code. I had to try this out.

Using poll(2), with a properly configured GPIO, my code could now react to changes generated by the encoder rather than continually polling it on my own. For simplicity I configured the GPIO’s using some shell commands.

echo 70 > /sys/class/gpio/export
echo 71 > /sys/class/gpio/export

echo in > /sys/class/gpio/gpio70/direction
echo in > /sys/class/gpio/gpio71/direction

echo both > /sys/class/gpio/gpio70/edge
echo both > /sys/class/gpio/gpio71/edge

Using a the following C program I monitored a incremental rotary encoder wired to a BeagleBone.

#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdio.h>

#define A 0
#define B 1

void dump_value(int fd) {
        char buffer[1024];
        lseek(fd, 0, 0);

        int size = read(fd, buffer, sizeof(buffer));
        buffer[size] = NULL;

        printf("\t\t size: %d  buffer: %s\n", size, buffer);
}

void dump_event(int fd, struct pollfd *pfd) {
        short revents = pfd->revents;

        printf("revents: 0x%04X\n", revents);
        if (revents & POLLERR) {
                printf("\t POLLERR  errno: %d\n", errno);

                if (errno == EAGAIN) {
                        printf("\t\t EAGAIN\n");
                }
                if (errno == EINTR) {
                        printf("\t\t EINTR\n");
                }
                if (errno == EINVAL) {
                        printf("\t\t EINVAL\n");
                }
        }

        if (revents & POLLHUP) {
                printf("\t POLLHUP\n");
        }

        if (revents & POLLNVAL) {
                printf("\t POLLINVAL\n");
        }

        if (revents & POLLIN) {
                printf("\t POLLIN\n");

                dump_value(fd);
        }
        if (revents & POLLPRI) {
                printf("\t POLLPRI\n");

                dump_value(fd);
        }
        if (revents & POLLOUT) {
                printf("\t POLLOUT\n");
        }
        if (revents & POLLRDNORM) {
                printf("\t POLLNORM\n");
        }
        if (revents & POLLRDBAND) {
                printf("\t POLLRDBAND\n");
        }
        if (revents & POLLWRNORM) {
                printf("\t POLLWRNORM\n");
        }
        if (revents & POLLWRBAND) {
                printf("\t POLLWRBAND\n");
        }
}

int get_lead(int fd) {
        int value;
        lseek(fd, 0, 0);

        char buffer[1024];
        int size = read(fd, buffer, sizeof(buffer));
        if (size != -1) {
                buffer[size] = NULL;
                value = atoi(buffer);
        }
        else {
                value = -1;
        }

        return value;
}

void main() {
        int fd[2];

        fd[A] = open("/sys/class/gpio/gpio70/value", O_RDONLY);
        fd[B] = open("/sys/class/gpio/gpio71/value", O_RDONLY);

        struct pollfd pfd[2];

        pfd[A].fd = fd[A];
        pfd[A].events = POLLPRI;
        pfd[A].revents = 0;

        pfd[B].fd = fd[B];
        pfd[B].events = POLLPRI;
        pfd[B].revents = 0;

        int lead[2];
        while (1) {
                int ready = poll(pfd, 2, -1);
                printf("ready: %d\n", ready);

                if (pfd[A].revents != 0) {
                        printf("\t Lead A\n");
                        //dump_event(fd[A], &pfd[A]);
                        lead[A] = get_lead(fd[A]);
                }
                if (pfd[B].revents != 0) {
                        printf("\t Lead B\n");
                        //dump_event(fd[B], &pfd[B]);
                        lead[B] = get_lead(fd[B]);
                }

                printf("\t\t A: %d  B: %d\n", lead[A], lead[B]);
        }
}

Using a timeout of -1 the poll will wait indefinitely. The code is simply waiting for an edge event to occur. That would be one of the encoder leads transitioning from low to high or high to low. This produced the following output when I turned the encoder knob.

ready: 2
         Lead A
         Lead B
                 A: 1  B: 1
ready: 1
         Lead A
                 A: 0  B: 1
ready: 1
         Lead B
                 A: 0  B: 0
ready: 1
         Lead A
                 A: 1  B: 0
ready: 1
         Lead B
                 A: 1  B: 1

In the above example, both leads start out on a detent. As I rotate the knob clockwise lead A goes low and then lead B does the same. At this point the knob is half way between detents. As rotation continues A goes high and then B follows. The knob has settled on the next detent.

I noticed two interesting artifacts.

  1. The first poll will always returns immediately with values for all the GPIO’s being polled.
  2. When I turned the knob quickly I did see some polls return changes on both GPIO’s. This means an intermediate state was lost. This isn’t a fatal problem. It just has to be accounted for when monitoring the encoder’s phases and calculating its position.
  3. Once the GPIO value is read it can’t be read again until another edge event occurs. If you try the read function will fail.

I’d like to see how well this new code can keep up with a fast turning encoder. Since nothing is being buffered by the sysfs GPIO kernel driver there’s a very good chance that the user space code still can’t service the edge events quickly enough.

At some point soon I’ll refactor the rotary code in my BeagleBone library to reflect this method.

BeagleBone with a Rotary Encoder

April 11, 2012 8 comments
Rotary Encoder

PEC11 Incremental Encoder

I’ve been looking at a variety of potential input devices for my BeagleBone. adaruit packages a PEC11 Series – 12 mm Incremental Encoder and I decide to give it a try.

This encoder requires ground on the center lead and provides “output” on the two outside leads. As you turn (click) the encoder knob from one detent to another the output leads will signal either high or low. Combining the output from those leads gives you the relative position of the knob. Monitoring the changes in those output tells you if the encoder has been turned clockwise or counter clockwise.

BeagleBone with Rotary Encoder

BeagleBone with Rotary Encoder

I grounded the encoder using a ground pin from the BeagleBones expansion header and wired the two output leads to a GPIO pin of their own. I could now read the value (signal) from each output lead. All this is pretty straight forward stuff when using a BeagleBone. Now for the fun stuff.

I’m using the sysfs GPIO interface to read output from the encoder. This means that I have to set the direction of the GPIO to “in”. Polling the GPIO’s value returns either a “1” or “0”. As you turn the encoder the value of each GPIO will change from 1 to 0 and then back to zero. But they transition from one value to another at different positions as the encoder turns. This is called a quadrature outputs.

Quadrature Output Table

Quadrature Output Table

This quadrature output table is taken from the PEC11’s data sheet. For the untrained (like me) this diagram is a bit tough to understand at first. When the encoder is positioned on a detent both the A and B leads will signal low. As the encoder is turned clockwise (CW) the A lead will start to signal high and then B lead will follow with a high signal. As the encoder continues to turn the A signal goes low and the B signal follows as the encoder arrives at the next detent. The opposite occurs if the encoder is turned counter clockwise (CCW). These signal pairs are called Gray code.

Another twist is that low signal from an encoder lead results in the GPIO’s value returning 1 (ON). A high signal returns a GPIO value of 0 (OFF). These tables describes the Gray code sent from the encoder and the associated values from the GPIO’s.

Clockwise
Encoder Gray Code GPIO Values
Phase A B A B
1 0 0 1 1
2 1 0 0 1
3 1 1 0 0
4 0 1 1 0
Counter Clockwise
Encoder Gray Code GPIO Values
Phase A B A B
1 0 0 1 1
2 0 1 1 0
3 1 1 0 0
4 1 0 1 1

An incremental rotary encoder such as this cannot represent it’s absolute position.  It just signals it’s position relative to the last detent it was on. Tracking the signal changes as it transitions from one detent to another will identify when the encoder travels clockwise or counter clockwise. This encoder has 24 detents (segments).

I wrote a program that constantly polls the two GPIO’s connected to the encoder’s A/B leads. With a very simple finite state machine (a switch statement) I was able to track the rotary of the encoder’s knob. Here’s some of the C++ code.

Rotary::Rotary(unsigned a, unsigned b) : _position(0) {
        A = new GPIO(a);
        B = new GPIO(b);

        A->direction("in");
        B->direction("in");
}

unsigned Rotary::phase() {
    unsigned a = A->value();
    unsigned b = B->value();

    a = (a == 0) ? 1 : 0;
    b = (b == 0) ? 1 : 0;

    return (a << 1) | b;
}

#define DETENT   0
#define CW_1     1
#define CW_2     2
#define CW_3     3
#define CCW_1   -1
#define CCW_2   -2
#define CCW_3   -3

void *Rotary::monitor(void *arg) {
        Rotary *rotary = static_cast<Rotary *>(arg);
        int state = DETENT;
        int last = -1;

        while (rotary->run_state) {
                int value = rotary->phase();

                if (value != last) {
                        switch (state) {
                        case DETENT:
                                if (value == 2) {
                                        state = CW_1;
                                }
                                else if (value == 1) {
                                        state = CCW_1;
                                }
                                break;
                        case CW_1:
                                if (value == 0) {
                                        state = DETENT;
                                }
                                else if (value == 3) {
                                        state = CW_2;
                                }
                                break;
                        case CW_2:
                                if (value == 2) {
                                        state = CW_1;
                                }
                                else if (value == 1) {
                                        state = CW_3;
                                }
                                break;
                        case CW_3:
                                if (value == 1) {
                                        state = CW_2;
                                }
                                else if (value == 0) {
                                        state = DETENT;
                                        rotary->_position++;
                                }
                                break;
                        case CCW_1:
                                if (value == 0) {
                                        state = DETENT;
                                }
                                else if (value == 3) {
                                        state = CCW_2;
                                }
                                break;
                        case CCW_2:
                                if (value == 1) {
                                        state = CCW_1;
                                }
                                else if (value == 2) {
                                        state = CCW_3;
                                }
                                break;
                         case CCW_3:
                                if (value == 3) {
                                         state = CCW_2;
                                }
                                else if (value == 0) {
                                         state = DETENT;
                                         rotary->_position--;
                                }
                          }

                          last = value;
                  }
        }
}

This source code is available at github.

When run in a hard loop the monitor code will consistently track the knobs rotation. I spun the knob as quickly as I could and was unable to make the program miscount detents (clicks). Later when I ran the code in a thread I did see some missed detents.

Finally, you can plug this encoder into a breadboard but it doesn’t go in easily and is prone to pop out.

Categories: BeagleBone, C++ Tags: , ,

BeagleBone – Stepping Out

April 3, 2012 2 comments

A stepper motor is an electro mechanical device which converts electrical pulses into discrete mechanical movements. The shaft or spindle of a stepper motor rotates in discrete step increments when electrical pulses are applied to it in the proper sequence. The motors rotation has several direct relationships to these applied input pulses. The sequence of the applied pulses is directly related to the direction of motor shafts rotation. The speed of the motor shafts rotation is directly related to the frequency of the input pulses and the length of rotation is directly related to the number of input pulses applied.

That’s quite the explanation. Most anything that requires motion control will use a step motor. So how do we get a BeagleBone to work a step motor?  We need four things:

  1. Step Motor – The motor steps (rotates) when the power is applied to the motor’s windings.
  2. Driver – The driver receives a command, interprets it, and send the necessary power to the step motor to achieve a step.
  3. Controller- A device (microprocessor) capable of sending a command to the driver.
  4. User Interface (UI) – A physical or virtual device that provides a user with effective interaction and control of the step motor.
Stepper Motor Driver Board ULN2003 for Arduino/AVR/ARM

Stepper Motor Driver Board ULN2003 for Arduino/AVR/ARM

There are all sorts of variations when it comes to integrating these four pieces. For example you could run a UI on a BeagleBoard that communicates, using one of a number of methods (i.e. USB, Ethernet), with a dedicated controller. That controller is cabled to a driver which in turn is wired to a motor. All well and good but I wanted a simpler and cheaper example.

In this example the BeagleBone will provide the UI and controller. The initial UI will be a shell script. While not very interactive it’s demonstrates that everything works. I’ll get more sophisticated later. The BeagleBone’s GPIO interface will be used to send commands to the driver.

I picked up an inexpensive driver and step motor intended for use with an Arduino. The driver board accepts a four bit command from an controller and in turn applies the necessary power pulse to step the motor. At the heart of the driver is a ULN2003AN integrated circuit. The board can supply between 5V to 12V to the motor from an independent power supply. It also has a bank of LED’s that correspond to the input signals received from the controller. They provide a nice visual when stepping.

Some step motor details:

  • Model: 28KYJ-48
  • Voltage: 5VDC
  • Phase: 4
  • Step Angle: 5.625° (1/64)
  • Reduction ratio: 1/64
It takes 4096 steps to rotate the spindle 360°. It is impossible to see a single step. When testing it pays to have something distinct on the spindle to show it is turning.

Physically connecting BeagleBone to the driver board is straight forward. Pick a free GPIO pin on the expansion header and run a wire from it to one of the input pins on the driver board. The driver board requires power. I tried powering it from the 5V and ground pins on expansion header P9, and an independent 5V power supply. Each worked well. Having wired a GPIO pin to the driver board you can use Linux’s sysfs GPIO interface to use it. Set the GPIO pin high and the corresponding LED on the driver board will illuminate. Set it low and the LED turns off.

Completing the wiring and toggling the LED’s did take long. Here’s now I wired the BeagleBone to the driver.

BeagleBone Drive Board
Signal Nane Pin Pin
VDD_5V  P9.3 +
GND  P9.1
GPIO1_6 p8.3 IN1
GPIO0_27 p8.17 IN2
GPIO1_15 p8.15 IN3
GPIO1_13 p8.11 IN4

The motor steps when a specific combination of wires running to the motor are powered. This is just a pulse of power. Just enough to get the motor to step. This driver and motor use a very simple protocol. Applying a signal to an input pin causes power to be sent to the motor on a corresponding wire.

Stepper Motor Driver Board ULN2003 for Arduino/AVR/ARM

Stepper Motor Driver Board

MCU IO Code Wire Color
IN1  A Blue
IN2  B Pink
IN3  C Yellow
IN4  D Orange

The motor steps when specific combinations of its wires are powered and the same combination is used to signal the driver. Discovering the correct stepping commands took a lot of searching on the Internet. The vast majority of information describes Arduino examples that rely on underlying Arduino libraries. I finally found this link and within a few minutes my motor was stepping.

The following codes define the step commands.

8 Step : A – AB – B – BC – C – CD – D – DA
4 Step : AB – BC – CD – DA (Usual application)

Step Command IN4 IN3 IN2 IN1
A 01H 0 0 0 1
AB 03H 0 0 1 1
B 02H 0 0 1 0
BC 06H 0 1 1 0
C 04H 0 1 0 0
CD 0CH 1 1 0 0
D 08H 1 0 0 0
DA 09H 1 0 0 1

Here’s a shell script that will step my motor one full rotation.

#!/bin/sh

timeout=10000

in1=38 # GPIO1_6  (p8.3)
in2=27 # GPIO0_27 (p8.17)
in3=47 # GPIO1_15 (p8.15)
in4=45 # GPIO1_13 (p8.11)

AB() {
        echo high > /sys/class/gpio/gpio$in1/direction
        echo high > /sys/class/gpio/gpio$in2/direction
        echo low > /sys/class/gpio/gpio$in3/direction
        echo low > /sys/class/gpio/gpio$in4/direction
}
BC() {
        echo low > /sys/class/gpio/gpio$in1/direction
        echo high > /sys/class/gpio/gpio$in2/direction
        echo high > /sys/class/gpio/gpio$in3/direction
        echo low > /sys/class/gpio/gpio$in4/direction
}

CD() {
        echo low > /sys/class/gpio/gpio$in1/direction
        echo low > /sys/class/gpio/gpio$in2/direction
        echo high > /sys/class/gpio/gpio$in3/direction
        echo high > /sys/class/gpio/gpio$in4/direction
}

DA() {
        echo high > /sys/class/gpio/gpio$in1/direction
        echo low > /sys/class/gpio/gpio$in2/direction
        echo low > /sys/class/gpio/gpio$in3/direction
        echo high > /sys/class/gpio/gpio$in4/direction
}

off() {
        echo low > /sys/class/gpio/gpio$in1/direction
        echo low > /sys/class/gpio/gpio$in2/direction
        echo low > /sys/class/gpio/gpio$in3/direction
        echo low > /sys/class/gpio/gpio$in4/direction
}

test() {
        for input in $in1 $in2 $in3 $in4
        do
                echo high > /sys/class/gpio/gpio$input/direction
                sleep 1
                echo low > /sys/class/gpio/gpio$input/direction
        done
}

step=0

while [ $step -lt 4096 ]
do
        echo "step: $step"

        AB
        usleep $timeout

        BC
        usleep $timeout

        CD
        usleep $timeout

        DA
        usleep $timeout

        step=`expr $step + 8`
done

off

Let’s see it in action.

Categories: BeagleBone Tags:

BeagleBone – How hot is it?

April 1, 2012 21 comments

TMP36 Temperature Sensor

I picked up a TMP36 – Analog Temperature sensor from adafruit. Time to see how to connect it to a my BeagleBone.

This sensor provides a voltage output that is linearly proportional to the Celsius (centigrade) temperature.

The TMP36 is specified from −40°C to +125°C, provides a 750 mV output at 25°C, and operates to 125°C from a single 2.7 V supply.

You calculate the temperature with the following forumula:

Temperature = ((Vout in mV) – 500mV) / 10.

I can use one of the BeagleBone’s analog to digital (ADC) interfaces to read the ouput from the TMP36. Things to get a little complicated because the ADC inputs are only 1.8V interfaces and the TMP36 is a 2.7V interface. If the temperature got hot enough the TMP36 could push enough voltage to potentially fry the ADC input. Since things won’t get that hot I’ll not worry about it. My tests won’t get an output from the TMP36 anywhere near 1.8V.

The TMP36 will be powered by pin 3 (3.3V) on expansion header P9. Ground can go to any of the ground pins on the expansion headers. I’ll use pin 1 on expansion header P8 for ground. The analog output will go to ADC interface AIN1 – pin 40 on expansion header P9. The BeagleBone’s ADC interfaces return a 12 bit value which will range from 0 to 4095.

BeagleBone with Temperature Sensor

BeagleBone with Temperature Sensor

Programming will again use the Linux’s sysfs. /sys/devices/platform/tsc provides access to the ADC interfaces. There are eight AIN files representing the eight ADC interfaces. To make things interesting their number scheme starts at 1 where as the symbolic name in the BeagleBone manual start at 0.

SIGNAL
NAME
AIN File Name
AIN0 /sys/devices/platform/tsc/ain1
AIN1 /sys/devices/platform/tsc/ain2
AIN2 /sys/devices/platform/tsc/ain3
AIN3 /sys/devices/platform/tsc/ain4
AIN4 /sys/devices/platform/tsc/ain5
AIN5 /sys/devices/platform/tsc/ain6
AIN6 /sys/devices/platform/tsc/ain7
AIN7 /sys/devices/platform/tsc/ain8

I can easily read the digital value of AIN1 from the shell using:

#cat /sys/devices/platform/tsc/ain2
1670

In this case I got back a value of 1670. Using a simple formula I can convert that value to the temperature.

Step Description Example
1 Read the digital value from the ADC interface. #cat /sys/devices/platform/tsc/ain2
1670
2 Convert the digital value to millivolts.
(value / 4096) * 1800mV
(1670 / 4096) * 1800mV = 733.8867mV
3 Convert the millivolts to Celsius temperature.
(millivolts – 500mV) / 10
(733.8867mV – 500mv) / 10 = 23.38867°C
4 Convert Celsius to Fahrenheit.
(Celsius * 9.0 / 5.0) + 32.0
(23.38867°C * 9 / 5) + 32 = 74.09961°F

Time for some C code.

#include
#include

double CtoF(double c) {
        return (c * 9.0 / 5.0) + 32.0;
}

double temperature(char *string) {
        int value = atoi(string);
        double millivolts = (value / 4096.0) * 1800;
        double temperature = (millivolts - 500.0) / 10.0;
        return temperature;
}

void main() {
        int fd = open("/sys/devices/platform/tsc/ain2", O_RDONLY);

        while (1) {
                char buffer[1024];
                int ret = read(fd, buffer, sizeof(buffer));
                if (ret != -1) {
                        buffer[ret] = NULL;
                        double celsius = temperature(buffer);
                        double fahrenheit = CtoF(celsius);
                        printf("digital value: %s  celsius: %f  fahrenheit: %f\n", buffer, celsius, fahrenheit);
                        lseek(fd, 0, 0);
                }
                sleep(1);
        }

        close(fd);
}

This program will loop indefinitely. Once a second it will read the/sys/devices/platform/tsc/ain2 which is the ADC (AIN1) interface connected to the TMP36. If it gets back a value the program will then calculate the temperature and print it out. It’s all pretty straight forward. A couple of notable things:

  • The string returned by the read is not null terminated.
  • After a read the file descriptor needs to be rewound to the start of the file using lseek.
Here’s some sample output.


digital value: 1658 celsius: 22.861328 fahrenheit: 73.150391
digital value: 1655 celsius: 22.729492 fahrenheit: 72.913086
digital value: 1661 celsius: 22.993164 fahrenheit: 73.387695
digital value: 1667 celsius: 23.256836 fahrenheit: 73.862305
digital value: 1657 celsius: 22.817383 fahrenheit: 73.071289
digital value: 1657 celsius: 22.817383 fahrenheit: 73.071289
digital value: 1663 celsius: 23.081055 fahrenheit: 73.545898
digital value: 1661 celsius: 22.993164 fahrenheit: 73.387695
digital value: 1657 celsius: 22.817383 fahrenheit: 73.071289

Categories: BeagleBone Tags:

BeagleBone GPIO Programming

March 31, 2012 3 comments

According to the BeagleBone System Resource Manual (SRM) the board has:

A maximum of 66 GPIO pins are accessible from the expansion header. All of these pins are 3.3V and can be configured as inputs or outputs. Any GPIO can be used as an interrupt and is limited to two interrupts per GPIO Bank for a maximum of eight pins as interrupts.

These pins are distributed across both expansion headers (P8 & P9) and their locations are well documented in the SRM. As described in a previous article, Linux provides a virtual file system called sysfs as a programming interface to system resources such as GPIO. The blink.js script that’s supplied with BeagleBoard’s Ångström’s Linux distribution will blink the User 3 LED and toggle GPIO1_6, which is located on the third pin of expansion header P8, high and low.

This article describes my experience getting an LED to blink using GPIO1_6.

Before I get into my LED project I want to note that I’m a typical software guy. I understand basic circuitry but my knowledge of electronics rapidly diminishes after that. So there are aspects of this journey that I’m discovering for the first time.  Most BeagleBone articles don’t detail the circuitry nor explain the electronics behind it. They assume the audience knows that stuff and focus on the BeagleBone part of things. I’m going to get into those details because I had to learn them before I could get this simple example to work.

LED Circuit

LED Circuit

An LED circuit is about a simple as it gets but still a bit of a learning experience for me.

  1. There are different kinds of LED’s. I picked up a standard red diffused 1 3/4 sized LED.
  2. The resistor is really important. Forget the resistor and you’ve created a short circuit. Not only will be burn out the resistor and your fingers it can damage the BeagleBone. The type of resistor you’ll need will depend on things like voltage and LED type. The resistor can be placed before or after the LED.
  3. An LED will only light with correct electrical polarity. You have to plug it in the right way.
GPIO Output to LED

GPIO Output to LED

I’m going to use GPIO1_6 as the power source for the LED circuit. When I set it high 3.3V will be supplied to the circuit and the LED will blink on. Setting GPIO1_6 low turns off the power the the LED will blink off.

Including a resistor in the circuit is a must. Knowing exactly what kind of resistor takes some testing. If you are in a hurry you can use 1k ohm (1/4 W – 5%) resistor. You’ll get a dim light but you’ll know it is safe.

Calculating the optimal type of resistor requires three values:

  • The source voltage. Since I’m using a GPIO pin it should be 3.3V.
  • The LED voltage. I used a multi-meter to get a value of 1.6V.
  • The LED current. Which after a lot of trial and error using a multi-meter comes in at 20mA.

Now to the formula.  The resistor value, R is given by: R = (VS – VL) / I

VS = supply voltage
VL = LED voltage
I = LED current

In my case this worked out to be 100ohm. There are all sorts of nifty calculators on the Internet. I used this one at LED Center to do the calculation for me.

This shows how I wired the circuit.

BeagleBone LED Circuit

BeagleBone LED Circuit

The red wire is plugged into GPIO1_6. That GPIO pin provides the power when it is set high. I’ve put a 100ohm resistor in front of the red LED. I could have put it after. You need wire the LED’s polarity correctly. If you wire it backwards the LED will not illuminate. The yellow wire runs to an expansion header GND pin and completes the circuit.

On the programming side we toggle GPIO1_6 on and off by using its sysfs interface. If I run blink.js both the User 3 LED and my red LED will blink. I wrote a shell script blink.sh to do the same thing.

#!/bin/sh

echo 38 > /sys/class/gpio/export

while :
do
  echo 1 > /sys/class/leds/beaglebone::usr3/brightness
  echo high > /sys/class/gpio/gpio38/direction
  sleep 1
  echo 0 > /sys/class/leds/beaglebone::usr3/brightness
  echo low > /sys/class/gpio/gpio38/direction
  sleep 1
done

/sys/class/gpio/gpio38 does not exist by default. You create it by writing the GPIO port number to /sys/class/gpio/export. You can remove it by writing the same number to /sys/class/gpio/unexport.

Here’s a video of it in action.

Categories: BeagleBone Tags:

Puppy’s First Month

March 31, 2012 Leave a comment

My BeagleBone, along with some other goodies, arrived about a month ago. March was a busy month and while I did have some time to play with the little guy I didn’t have time to write about it. The few articles cover a variety of things that I experienced so far.

Adafruit Beagle Bone Starter Pack

Adafruit Beagle Bone Starter Pack

I purchased adafruit’s BeagleBone Starter Pack. That turned out to be a good choice. It made things plug and play for a software guy like me. I didn’t have to fuss with finding the right power supply. The puppy and half size breadboard are easily mounted onto a simple plexiglass plate that nicely keeps everything together.

I plugged the power supply and a network cable into the BeagleBone and within a minute I could access it using ssh. Neat! Here are the various access points:

  • ssh (port 22) – for access to a shell
  • bone101 (port 80) – small server written in node.js serving up an intro presentation
  • GateOne (port 443) – access to a shell through Firefox or Chrome
  • Cloud9 IDE (port 3000) – text editor and debugger for node.js applications through Firefox, Chrome or Safari
Being a programmer I really wanted to make the BeagleBone do something. After lots of Goggling I decided to start with blinking an LED. GigaMegaBlog has some very good articles on the BealgeBone. Beaglebone Coding 101: Blinking an LED was a very good starting place. It describes how to use the cloud9 IDE to some fun things with an LED. 

The cloud9 IDE is an online development environment for Javascript and Node.js applications as well as HTML, CSS, PHP, Java, Ruby and 23 other languages. The blink.js script demonstrates how to blink the User 3 LED on the board. That worked all and well but I’m not interested in writing JavaScript and blink.js hides how things work. So I started digging and it turns out that blink.js is using Linux’s sysfs.

sysfs is an implementation of a virtual file system. It exposes system devices to user space using a file system topology model. At the base of the topology are logical device groupings such as bus, class, and devices. Within those groupings there can be more logical groupings. Eventually the topology reaches a node that represents a physical device. Under the physical device node there can be nodes representing sub-devices or actions.

The LED’s on the board can be driven using sysfs:

  • /sys/class/leds provides interfaces to the User LED’s.
  • /sys/class/leds/beaglebone::usr3 represents an instance of the User 3 LED.
  • /sys/class/leds/beaglebone::usr3/brightness represent an action that can be performed on the User 3 LED. In this case you can:
    • Write a value (0, 1) to the file. That will set the LED to on (1) or off (1).
    • Read a value from the file. It will return the brightness (0, 1) of the LED.

The following shell script will blink the User 3 LED.

#!/bin/sh
while :
do
  echo 1 > /sys/class/leds/beaglebone::usr3/brightness
  sleep 1
  echo 0 > /sys/class/leds/beaglebone::usr3/brightness
  sleep 1
done

You’ll notice that blink.js is actually toggling two LED’s (ledPin, ledPin2). This is a bit confusing because only one LED is blinking. In fact both “pins” are set to set high and then low. But only one pin (ledPin2 = bone.USR3) actually has an LED attached to it. The other (ledPin = bone.P8_3) is a General Purpose Input/Output (GPIO) port that’s not connected to anything at this point. Even more interesting is that all the User LED’s are controlled by a GPIO port. But you can’t use the sysfs GPIO interface to control them. If you try you’ll get a “Device or resource busy” error. I suppose that’s because the sysfs-leds driver has grabbed it first.

Here’s how bone.P8_3 maps to sysfs-gpio. P8_3 is pin 3 on expansion header P8. According to the BeagleBone manual this is signal name GPIO1_6. From the signal name we can calculate the GPIO port number. In this case it is 38 (1 x 32 + 6). The first number is an offset of size 32. The second number is an offset from that number. Just multiple the first number by 32 and then add the second number. It’s all kind of confusing and it gets to be more fun when you bring in mux’ing.

Here’s now to access GPIO port 38 using sysfs:

  • /sys/class/gpio provides an interface to GPIO ports.
  • /sys/class/gpio/gpio38 is an instance of GPIO port 38. BeagleBone has 66 of these ports.
  • /sys/class/gpio/gpio38/direction represents an action that can be performed on GPIO port 38. In this case you can write a value (“high”, “low”) to the file. That will set the GPIO port to that value.
  • /sys/class/gpio/gpio38/value represents an action that can be performed on GPIO port 38. In this case you can read a value (“0”, “1”) from the file. It return the GPIO port’s value.

By the way, /sys/class/gpio/gpio38 isn’t there by default. You have to create it by writing the port number to /sys/class/gpio/export. For example:

echo 38 > /sys/class/gpio/export

You can find more on this at:


Categories: BeagleBone Tags: