EBC Exercise 10 Flashing an LED

The "Hello World" program is the traditional first program for many classes. Flashing an LED is the embedded equivalent. Here we will explore a few ways to flash and LED on the Beagle and explore General Purpose I/O (gpio) along the way. These calls will be done from the command line of the Beagle, so there is no need for the host computer.

gpio via the Shell Command Line and sysfs
(Note: Draw the new diagrams with this.)

The easiest way to do general purpose I/O (gpio) on the Beagle is through a terminal window and a shell prompt. In Linux, almost everything is treated as a file, even things that aren't files. In our class we'll use a virtual file system called sysfs. sysfs exposes the drivers for the hardware so you get easily use them.

Try this, open a terminal and type:

beagle$ cd /sys beagle$ ls -F block/ bus/  class/  dev/  devices/  firmware/  fs/  kernel/  module/  power/

Here we see several directories that represent hardware we can control. Explore a bit and see what you find.

Now try:

beagle$ cd /sys/class beagle$ ls -F backlight/ firmware/     lcd/       mtd/           scsi_disk/   ubi/ bdi/       gpio/         leds/      net/           scsi_host/   udc/ block/     graphics/     mbox/      power_supply/  sound/       uio/ bluetooth/ hwmon/        mdio_bus/  regulator/     spi_master/  usbmon/ bsg/       i2c-adapter/  mem/       rfkill/        spidev/      vc/ dma/       i2c-dev/      misc/      rtc/           thermal/     vtconsole/ drm/       input/        mmc_host/  scsi_device/   tty/         watchdog/

Explore some. What do you find? In graphics you will see the frame buffer supported by the processor. In sound you'll see the alsa sound devices.

Flashing the user LEDs
The Beagle Black has four user LEDS, user0 - user3, that you can control. Try this:

beagle$ cd /sys/class/leds beagle$ ls -F beaglebone:green:usr0 beaglebone:green:usr2 beaglebone:green:usr1 beaglebone:green:usr3

Here you see the directories for controlling each of the usr LEDs. By default, usr0 flashes a heartbeat pattern and usr1 flashes when the micro SD card is accessed. Let's control usr0.

beagle$ cd beagleboard\:\:usr0 beagle$ ls -F brightness device@  max_brightness  power/  subsystem@  trigger  uevent

See what's in brightness, max_brightness and trigger by using the  command. For example:

beagle$ cat trigger none nand-disk mmc0 [heartbeat]

This shows trigger can have 4 values. The present value is heartbeat. Check the LED, is it beating? You can stop the heartbeat via:

beagle$ echo none > trigger beagle$ cat trigger [none] nand-disk mmc0 heartbeat

Did it stop beating? You can now turn it on and off with:

beagle$ echo 1 > brightness beagle$ echo 0 > brightness

Is it responding correctly?

The Bone has more trigger options. Try:

beagle$ cat trigger [none] mmc0 timer heartbeat backlight gpio default-on beagle$ echo timer > trigger brightness delay_on  max_brightness  subsystem  uevent delay_off  device    power           trigger beagle$ echo 100 > delay_on beagle$ echo 900 > delay_off

What does this do?

Adding your own LED - bone
It's not hard to use the gpio pins to control your own LED. All you need is an LED and a 220&Omega; resistor. Here's a picture of how it's wired. We are just doing the LED at the top of the breadboard for now.



So how do you know where to connect it? The BeagleBone System Reference Manual has the details. Figure 3 on page 18 of RevA5.01 shows:



There at two expansion headers, P8 and P9. Look at the bottom of the left header and you'll see it's labeled P9. Table 11 on page 59 shows the pinout for P9.



On the first photo above you can see that pin 1 (Ground) is wired to the - bus and pin 3 (3.3V) is wired to the + bus. The 220&Omega; resistor is wired to the - bus and the other end is attached to the negative lead of the LED. The positive lead is attached to pin 12 which, as shown in Table 11, is attached to gpio1_28. The gpio pins are in banks of 32 each, so to find the gpio number to use on the Beagle, use 1*32+28=60. Here's how you turn it on

beagle$ cd /sys/class/gpio beagle$ ls export gpiochip0  gpiochip32  gpiochip64  gpiochip96  unexport

Presently no gpio pins are visible. You need to tell it which pin to export

beagle$ echo 60 > export beagle$ ls gpio60 gpiochip0  gpiochip32  gpiochip64  gpiochip96

Notice gpio60 has appeared. All we need to do is tell it which direction and then turn it on.

beagle$ cd gpio60 beagle$ echo out > direction beagle$ echo 1 > value

Your LED should be on! When you are done you can unexport the pin and it will disappear. beagle$ cd .. beagle$ echo 60 > unexport

Reading a switch - bone
Now that you have an LED working, wiring in a switch is easy. The picture above shows a push button switch wired in at the bottom of the P9 header. Attach the + bus to one pole on the switch with a wire. The other end of the switch is attached to pin 42 which is gpio0_7.

Based on what you saw above, show how to read the switch.

Once you have the switch and LED working you can use the following scripts to play with them.

beagle$ cd ~/exercises/gpio beagle$ ./togglegpio.sh 60 0.1

The LED should be blinking on and off.

beagle$ ./readgpio.sh 7

Push the pushbutton and see what happens.

How can this work without a pulldown resistor? It turns out the Bone has an internal pulldown (and up) resistor that can be software enabled. Try:

beagle$ cd /sys/kernel/debug/omap_mux beagle$ ls ain0              gpmc_ad2        lcd_data3      mii1_txd2 ain1              gpmc_ad3        lcd_data4      mii1_txd3 ain2              gpmc_ad4        lcd_data5      mii1_txen ain3              gpmc_ad5        lcd_data6      mmc0_clk ain4              gpmc_ad6        lcd_data7      mmc0_cmd ain5              gpmc_ad7        lcd_data8      mmc0_dat0 ain6              gpmc_ad8        lcd_data9      mmc0_dat1 ain7              gpmc_ad9        lcd_hsync      mmc0_dat2 board             gpmc_advn_ale   lcd_pclk       mmc0_dat3 ecap0_in_pwm0_out gpmc_ben0_cle   lcd_vsync      rmii1_refclk emu0              gpmc_ben1       mcasp0_aclkr   spi0_cs0 emu1              gpmc_clk        mcasp0_aclkx   spi0_cs1 gpmc_a0           gpmc_csn0       mcasp0_ahclkr  spi0_d0 gpmc_a1           gpmc_csn1       mcasp0_ahclkx  spi0_d1 gpmc_a10          gpmc_csn2       mcasp0_axr0    spi0_sclk gpmc_a11          gpmc_csn3       mcasp0_axr1    uart0_ctsn gpmc_a2           gpmc_oen_ren    mcasp0_fsr     uart0_rtsn gpmc_a3           gpmc_wait0      mcasp0_fsx     uart0_rxd gpmc_a4           gpmc_wen        mdio_clk       uart0_txd gpmc_a5           gpmc_wpn        mdio_data      uart1_ctsn gpmc_a6           i2c0_scl        mii1_col       uart1_rtsn gpmc_a7           i2c0_sda        mii1_crs       uart1_rxd gpmc_a8           lcd_ac_bias_en  mii1_rxclk     uart1_txd gpmc_a9           lcd_data0       mii1_rxd0      usb0_drvvbus gpmc_ad0          lcd_data1       mii1_rxd1      usb1_drvvbus gpmc_ad1          lcd_data10      mii1_rxd2      vrefn gpmc_ad10         lcd_data11      mii1_rxd3      vrefp gpmc_ad11         lcd_data12      mii1_rxdv      xdma_event_intr0 gpmc_ad12         lcd_data13      mii1_rxerr     xdma_event_intr1 gpmc_ad13         lcd_data14      mii1_txclk gpmc_ad14         lcd_data15      mii1_txd0 gpmc_ad15         lcd_data2       mii1_txd1 beagle$ ls | wc 125    125    1220

Here you will find a list of how all the pin muxes are set. There are some 125 of them! How do you find which one is gpio0_7?

beagle$ grep gpio0_7 * ecap0_in_pwm0_out:name: ecap0_in_pwm0_out.gpio0_7 (0x44e10964/0x964 = 0x0027), b NA, t NA ecap0_in_pwm0_out:signals: ecap0_in_pwm0_out | uart3_txd | spi1_cs1 | pr1_ecap0_ecap_capin_apwm_o | spi1_sclk | mmc0_sdwp | xdma_event_intr2 | gpio0_7

ecap0_in_pwm0_out is the file that contains gpio0_7. Look up gpio0_7

beagle$ cat ecap0_in_pwm0_out name: ecap0_in_pwm0_out.gpio0_7 (0x44e10964/0x964 = 0x0027), b NA, t NA mode: OMAP_PIN_INPUT_PULLDOWN | OMAP_MUX_MODE7 signals: ecap0_in_pwm0_out | uart3_txd | spi1_cs1 | pr1_ecap0_ecap_capin_apwm_o | spi1_sclk | mmc0_sdwp | xdma_event_intr2 | gpio0_7

It's set to be a PULLDOWN. Sectiion 9.2.2.2, Page 877 of the AM335x Technical Reference manual discusses Pull Selection and tells which bits do what. The 0x0027 is the code that says which MODE is used and how the pull up/down resistor is set. (There seems to be a mismatch between the manual and the bone. The manual says bit 3 of 0x0027 enables the pull up/down.  Bit 3 isn’t set, but the pull down is working.)

You can switch the gpio pin to pullup. Try

beagle$ echo 0x0037 > ecap0_in_pwm0_out beagle$ cat ecap0_in_pwm0_out name: ecap0_in_pwm0_out.gpio0_7 (0x44e10964/0x964 = 0x0037), b NA, t NA mode: OMAP_PIN_INPUT_PULLUP | OMAP_MUX_MODE7 signals: ecap0_in_pwm0_out | uart3_txd | spi1_cs1 | pr1_ecap0_ecap_capin_apwm_o | spi1_sclk | mmc0_sdwp | xdma_event_intr2 | gpio0_7

Does it act like a pullup resistor is attached?

Challenge

 * Can you modify the scripts above to read the switch and turn the LED on and off?
 * Rewire your switch to work with a pullup resistor.

Analog in - bone
(This is based on this.)

The bone has eight Analog Inputs. Several are exposed on P9. They are labeled AIN in table 11 above. How many do you find?

The AIN pins are sampled at 12 bits and 100k samples per second. The input voltage is between 0 and 1.8V. Fortunately, both voltages are available on P9.

The photo above shows a small potentiometer wired to the bone. One end goes to the analog ground (pin 34), the other analog 1.8V (pin 32). The wiper is attached to AIN5 which is pin 36.

You interact with the analog in much like the gpio, but it appears in a different location. How do you find that location? One approach is the find command.

beagle$ find / -name ain5 /sys/devices/platform/omap/tsc/ain5 /sys/kernel/debug/omap_mux/ain5 ^C

I used Ctrl-C to interrupt since it already found what I wanted.

beagle$ cd /sys/devices/platform/tsc beagle$ ls ain1 ain3  ain5  ain7  driver    power      uevent ain2 ain4  ain6  ain8  modalias  subsystem

There are the various analog inputs, but watch out. This interface starts numbering at 1 and Table 11 starts at 0, so to read AIN5 you need to look at ain6!

beagle$ cat ain6 1185

(Unfortunately the interface doesn't print a RETURN after the value.) Change the pot and rerun the cat. What's the min and max value you get? Is it 12 bits?

Challenge
Rewrite the scripts from before to read an AIN pin and continuously display it's value.

Reading a gpio pin with an Oscilloscope - xM
You can easily access many of the gpio pins via the Main Expansion Header. Page 107 of the BeagleBoard-xM System Reference Manual has this figure.

Unfortunately the gpio pins don't appear here. It turns out the processor has more internal I/O lines than it has physical pins. Each physical pin can can be connected to up to 8 internal lines. BeagleBoardPinMux does a nice job of explaining it all. The big clue is here BeagleBoardPinMux which references Table 22 on page 108 of the -xM System Reference Manual.



Note that gpio130 appears on pin 21 of the Expansion Header. Also note that pins 27 and 28 are ground. Attach your scope probe to these. Now, let's put a signal on the pin.

beagle$ cd /sys/class/gpio beagle$ ls -F export     gpiochip128@  gpiochip192@  gpiochip64@  unexport gpiochip0@ gpiochip160@  gpiochip32@   gpiochip96@

Notice there is no folder for gpio130. Create it with:

beagle$ echo 130 > export beagle$ ls -F export   gpiochip0@    gpiochip160@  gpiochip32@  gpiochip96@ gpio130@ gpiochip128@  gpiochip192@  gpiochip64@  unexport

Update your exercises folder and cd to gpio directory.

beagle$ cd beagle$ cd exercises/gpio beagle$ git pull beagle$ gedit togglegpio.sh

Can you tell what the program is doing? Try running it:

beagle$ togglegpio 130 0.05

Note that if you are the root user (which is the default case for Angstrom), you will have to type the following command:

beagle$ ./togglegpio 130 0.05

The first argument tells which gpio port to toggle, the second tells how long to delay between toggling. In this example 0.05 s is 50 ms, which should give a period around 100ms. Measure the signal on an oscilloscope.

Measuring a gpio pin on an Oscilloscope
Answer the following questions about gpio measurements.


 * 1) What's the min and max voltage?
 * 2) What period is it?
 * 3) How close is it to 100ms?
 * 4) Why do they differ?
 * 5) Run htop and see how much processor you are using.
 * 6) Try different values for the sleep time (2nd argument). What's the shortest period you can get? Make a table of the values you try and the corresponding period and processor usage.
 * 7) How stable is the period?
 * 8) Try launching something like mplayer. How stable is the period?
 * 9) Try cleaning up togglegpio and removing unneeded lines.  Does it impact the period?
 * 10) togglegpio uses bash (first line in file).  Try using sh.  Is the period shorter?
 * 11) What's the shortest period you can get?

Toggling the LEDs
Modify togglegpio (call it toggleLED) to toggle the LEDs. Can you get the LED to appear to dim by changing the duty cycle of the toggling?

User Button to gpio 130
Write a shell script that reads the User Button and outputs it value on gpio pin 130.

Count the User Button Presses
Write a shell script that displays a count of the number of times the User Button has been pressed.

Copy gpio 130 to gpio 131
Write a shell script that copies the value of gpio pin 130 to gpio pin 131. How much CPU time does it take? What's the delay from the time the input changes until the output changes? How constant is the delay?

Reading the Keyboard and Mouse
Try this:

beagle$ cd /sys/class/input beagle$ ls -F beagle$ evtest /dev/input/event2 Hit ctrl-C to stop

Now move your mouse around, or try you keyboard. My mouse is plugged into the bottom left USB port and event2 responds to it. Where do your keyboard and mouse appear?

Reading the User Button
(Note: This may not work on some versions of the OS. In these versions another program is controlling the gpio port that the User button is attached to.)

The Beagle has a couple of push buttons. One reboots the whole board. Use with care. One is for you to use, it's to the right of the Reset button, between the two stacks of USB ports.

It's attached to gpio port 4. You can read it via:

beagle$ cd /sys/class/gpio beagle$ ls -F export   gpio133@  gpio137@  gpio141@      gpiochip160@  gpiochip96@ gpio130@ gpio134@  gpio138@  gpio162@      gpiochip192@  unexport gpio131@ gpio135@  gpio139@  gpiochip0@    gpiochip32@ gpio132@ gpio136@  gpio140@  gpiochip128@  gpiochip64@

Notice there is no gpio4. Here's how you can create it, set it to an input port and read its value:

beagle$ echo 4 > export beagle$ ls beagle$ cd gpio4 beagle$ echo in > direction beagle$ cat value

Try holding down the switch and doing  again. Does the value change? There's a shell script called readgpio that repeatedly reads the switch.

beagle$ readgpio 4

Try pushing the switch. Does it work? Hit ctrl-C to stop. Look at readgpio. How does it work?

beagle$ which readgpio beagle$ cp /usr/bin/readgpio ~ beagle$ gedit ~/readgpio

Resources

 * 1) Here is wh1ts article on flashing an LED.  It is referenced in the readgpio file that comes on the Beagle.
 * 2) This Make magazine article has a few more details.
 * 3) Here in a gpio reference for Linux in general. It includes sample 'C' code for flashing at 1 Hz.
 * 4) Here is a posting in the Beagle Google group about gpio.
 * 5) Here is some information about gpio from the kernel point of view.
 * 6) Here is some info on a GPIO Event Driver
 * 7) Here is info on how to set edge to falling and poll the pin.
 * 8) Here is the kernel Documentation on gpio.