It's not listed on the microcontrollers page, because I class it way outside the embedded category, though within "small computing", but I also own a Raspberry Pi.
The Pi, if you haven't clicked that link, is a credit-card sized computer, ARMed with a Broadcom SoC, running at 700MHz, with 256Mb of RAM, an SD card interface for holding the operating system,
composite video and analogue audio outputs, HDMI out, wired ethernet, and two USB ports.
It's also really cheap, at about £30, although you will need certain accessories to make any use of it. You'll need power, in the form of a microusb phone charger typically (look for 1 amp and above supplies), you'll need an SD card (2Gb is realistically the minimum to install the versions of linux available). You'll probably want to connect it to the internet, so you'll need an ethernet cable or a carefully selected wireless card. You may, of course, want a mouse and a keyboard- so you might also want a USB hub- be sure to get a powered one, as the Pi can't supply the full 500mA and won't power an external hard drive, say. As far as displays go, you can use an old television (repurposing old televisions in poorer places is why it has composite video out in this day and age), or a brand new (high def)
television, over HDMI.
Apart from the price, what attracted me was the GPIO header. General Purpose Input/Output pins are those on a microcontroller that you can easily set high or low, or read the state of. The physical pin can often be told to do something more specialised, such as be a USB interface, or an Analogue-to-Digital Converter. This is not something you tend to see on full-blown microprocessors, but the ARM chip used on the Pi has a foot in both camps, and the pins have been brought out from the chip onto a 2 x 13 pin header.
Cleverer people than me have written sample code for getting at the pins in C, Python, Ruby, and there's even a /sys interface exposed by the linux kernel that you can get at with simple shell scripting. I chose C.
I wanted to make use of the 2 x 16 character dot-matrix LCD displays I had. Many of these are available from various manufacturers for a few pounds based off a clone of the Hitachi HD44780 chip. There are libraries for the Arduino for this, and I found a simpler one written for the MSP430Gxxx chips which I though was ideal to port to the Pi, as I could more or less do a find and replace on the pin-changing code. I figured this could be really handy when running the Pi "headless" (without a display) to at least see what its IP address was.
Step One - Volts
Step one on the hardware side- check it is compatible, electrically. These LCD displays, unlike the other common option, phone displays, are usually 5 volts. The Pi has a 5 volt pin, but is otherwise resolutely 3.3V, and its IO pins are not 5V tolerant.
5V appearing on those pins can easily damage the chip, possibly killing it. It's not an expensive board, but breaking one can mean (as of the moment) a long wait for a replacement.
By grounding (connecting directly to ground) the LCD module's RW pin, we can set and keep it in read-only mode. That is to say, the module only ever receives data from the Pi. We set the voltages with the Pi, and the LCD module reads them- thus we will never see "high voltage" 5V on any control or data line. You can perform level conversion with resistors, transistors, specialised ICs, but obviating them is cheaper and simpler still!
Step Two - Pin Assignments
The other important option is that it will be set up in 4 bit mode. Although we will input 8 bit characters, we will transfer those in two chunks, the high 4 bits, then the low, saving us four GPIO pins. Other than that, we need 5V power, ground, and two control lines, named EN and RS.
The selection of which GPIO pins would be
used was dictated primarily by a desire to avoid using any pins with useful and specific alternate functions, such as I2C, SPI, serial, etc. Thankfully, there were four such pins in a (numeric) row, GPIO22 to 25, slightly simplifying the code. In version 1.0.3, I allow for arbitrary pins to be used for the D4 to D7, even further increasing your chances of picking pins to your needs.
In the diagram above, red is 5V, black is ground (0V). Blue is RS, Green is EN. Orange is D4, the lowest bit of the 4 bit interface, yellow is D5, brown D6, and purple is D7. The grey
wire is the wiper of the potentiometer, setting the contrast via the VO pin. RW is the black wire (because it is grounded) between the blue and green wires of RS and EN).
Note that I have swapped the pins on the Pi used for RS and EN around, purely to make the wiring diagram easier to read. This swapping is reflected in v1.0.1 of the code.
Step Three - The code
The code came from 3 sources. There was the MSP430 code, which I found here: http://www.circuitvalley.com/2011/12/16x2-char-lcd-with-ti-msp430-launch-pad.html
The second was the code to memory-map the IO, and to set and clear GPIO pins, by Pi experts Gert and Dom, and I found it here: http://elinux.org/Rpi_Low-level_peripherals
The third, more minor source was the Arduino LiquidCrystal library, which was
used to double-check a few timing and command issues, plus it is where I copied all the command code #defines, to make my code easier to follow.
I also have to thank my good friend John Honniball for his invaluable help and coffee (and so-so tea...damn but that man needs to go on a brewing course).
One thing you may notice, comparing them is that the MSP430 has a register which you write to with the pin states- 0 for low, 1 for high. The Pi doesn't have this, and instead requires you to write to one register for setting pins (any 1s set the pin, driving it high, 0s are ignored), and one pin to clear pins (any 1s clear the pin, driving it low, 0s are ignored).
So what was a single action on the MSP430, is two on the Pi. This is no hindrance to use here, as the data pins, which we may have to set and clear to the new pattern, are not read until a rising edge (transition from low to high, 0 to 1) on the EN line.
The other change
concerns the timings. In the MSP430 code this was done with a busy loop, a for loop set for enough iterations to waste time until it is safe to perform another command. By skimping on reading from the LCD module, we cannot know when it has completed a command, so we abide by the maximum times as stated in the datasheet. These may well be much longer that necessary, but getting it wrong might mean 0.0001% of the time a bit is lost, and the display corrupts.
So given that the busy loop wasn't calibrated for the Pi, and that a Pi may be overclocked in some cases, and that it is running a multi-tasking OS where other processes may take up CPU time, I used usleep() for my timings instead.
I rewrote the function that displays integers to accommodate the larger numbers an int can hold, and to make it a bit more consistent. Pointless though, as I fall back to printf for other purposes...
The code is a work in progress, but it's hopefully useful already. When it starts up (I'
ve set it to run on boot with a line in /etc/rc.local) it displays eth0's IP address (useful for locating it to ssh into) on the top line, and on the lower line it displays the uptime, system load, the free space percentage of the root partition, and the current time of day. These cycle every four seconds. When the program is killed with a control-c (SIGINT), it clears the display before exiting. When the program received SIGTERM (such as when the system shuts down), it prints "Shutting down...". I'd like to know when it really has halted, in practice I have to wait, a guessed-at 10 seconds before removing power.
I intend to add a few more display options, such as number of logged in users, etc, and perhaps read from a button to pause the display. I like the idea of a rotary encoder, but to reliably read it would require extra hardware- not that a microcontroller is expensive...
Version 1.0.5 has added multiple displays as an option by supplying pin assignments to lcdInit(), after I saw what
Gordon Henderson had done- as he pointed out, the modules only pay any attention to their data lines when the enable pin is blipped, so all you need for any extra displays, is one extra pin for a dedicated enable pin. All the other pins can be shared. That's what my main.c does, although it merely prints a static message to the second display. If you haven't got a second display, don't worry, even if you leave the code in, no harm will come, since the software does no reading of the modules.
This was compiled on the Pi running Raspbian Wheezy (although works fine with Debian Squeeze too). If you have that installed, you should have a working C build environment. Just unpack the .tar.gz ("tar zxf lcd-1.0.5.tar.gz" will do the trick) file, enter the created directory, and type "make". This will create an executable called "lcdinfo". Wire up your LCD module if
you haven't already, as it is only initialised once, when the program starts. Because it accesses the GPIO pins, you need to run it as root, the superuser. Typing "sudo ./lcdinfo" will achieve that.