Tuesday, August 11, 2009

Allen organ project - getting to "Hello, world"

Last time, we got the keypad running. This time, we want to make the display go. The display I chose uses the popular HD44180 controller chip, for which several other Arduino developers have written libraries. But, I observe:

  1. This display is a little bit different from any of the documented ones. It turns out that the 4×20 display is actually a 2×40 display, with the third line being the continuation of the first and the fourth being the continuation of the second.
  2. The four-bit LCD libraries that are out there aren't quite debugged - in fact, one that I examined writes the nybbles in the wrong order - how this ever displays anything but gibberish is beyond me.
  3. I struggle a little with initialization: How to get the chip running in two-line 5×8 character mode, with a 4-bit interface?
Fortunately, solving these problems is a combination of programming and some moving of wires.

Getting the initialization right is the hard part, so let's start there. The issue here is that we're coming up from an unknown state. We don't know what's on the screen, where the cursor is pointing, or what the interface width is. So we need to command a bunch of things. And to do that, since we've wired only four of the display's data bus lines, we need to get the display into 4-bit mode. OK, that's not too hard: writing the nybble 0x2 should do it - change the display from 8-bit to 4-bit, and we're good to send 4-bit commands.

Uhm, no. What if the display was in four-bit mode already? Then we need to write two nybbles to the command register. OK, 0x2 0x8 looks right (4-bit mode, 5x8 characters, two lines).

No, that's not right either! If we started in 8-bit mode, writing the 0x2 will set 4-bit mode, and then 0x8 will be half of the next commmand.

OK, now a light begins to dawn. All of the libraries, including LCD4BIT, begin by setting 8-bit mode several times, delaying in between sending the commands. And their comments don't make it clear why: they all seem to say things like, "the data sheet doesn't say anything about this, but other people do it, and it works." But I get it now: it's to bring the display back to a known state! We could start in one of three possible states: 4-bit mode, 4-bit mode with one nybble of a command sent, or 8-bit mode. Let's just keep sending 0x3 nybbles, and see where it gets us.

Starting from 8-bit mode: 0x3 is interpreted as 0x30 (the other nybble is grounded), and the display goes to 4-bit, 5×8 characters, 1 display line. Then we do the same thing, twice more, leaving the display in that state.

Starting from 4-bit mode: 0x3 0x3 is 0x33, which is still 4-bit, 5×8 characters, 1 display line. (The two least significant bits are ignored.) Then the third 0x3 command is interpreted as 0x30 in 8-bit mode, which is the same as above.

Starting from 4-bit mode with an incomplete command: 0x3 provides the last byte of whatever was being done - taking some unknown action, but that doesn't matter, since we're going to be reinitializing everything. At this point we need a delay to wait for the slowest possible command to finish. The next 0x3 0x3 is a new command, setting 4- bit, 5×8 characters, 1 display line.

So at the end of this sequence, wherever we started, we have the display in 8-bit mode. Now we can put it into 4-bit mode and have everything happy. We just send an 0x2 (interpreted as an 0x20 byte), and now it's 4-bit, 5×8 characters, 1 line. Now from 4-bit mode, we send 0x2 0x8 (interpreted as 0x28) and the display goes to 4-bit, 5×8 characters, 2 lines. Except that when I test it out, it doesn't. Everything else in initialization works, but the display stubbornly remains a 1-line display. Finally, I reread the description of this command in the datasheet, and see the note:

Perform the function at the head of the program before executing any instructions (except for the read busy flag and address instruction). From this point, the function set instruction cannot be executed unless the interface data length is changed.
So how do I set character size and display lines for a 4-bit interface? At this point, I'm tired, and disgusted by the revolting mess, and just crawl into bed.

Fast forward to the shower the next morning...

It occurs to me that DB0-DB3 are ignored in 4-bit mode. I don't need to ground them. And since the only 8-bit mode command I execute intentionally is to change the display mode (either to 8-bit or to 4-bit), I can just hard-wire in the nybble I need. Knowing that there's something I can try raises my mood. I finish the shower singing Sailing 'round Yarmouth, and head off to work with a smile.

Sure enough, when I get home and try wiring DB3 to +5 instead of ground, what do I see with the code in the ZIP archive of auxiliary files?


My project said "hello" to me! I hack in a digital brightness control (even remembering to make its response nonlinear to match the eyeball more closely), and now it can read a keypad and respond to it without being tethered to the computer. Enough tinkering for one evening, now I can spend a little time with the wife and daughter. Yay.

As an afterthought, I also program a few characters into the CGRAM. Describing the length of organ pipes requires at least the vulgar fractions 2/3, 3/5, 1/3 and 1/7. So I know I'm going to want appropriate characters for that. That'll save a few characters of precious screen real estate for each pipe description.

And as a further afterthought, I notice that every time I reset the Arduino, several characters of rubbish show up on the display. A bit of thought reveals that the cause is that the bootloader is flashing the LED on pin 13, which is the same pin that I chose for the ENABLE line of the display. ENABLE gets moved to 14. Another minor annoyance is licked.


Allen organ project - reading the keypad.

The first thing that I tried with the organ project was some code to read the keypad. I looked at http://arduino.cc/, and while I saw a few suggestions, nothing did quite what I wanted. No matter, reading a keypad isn't that hard.

It turns out that the Atmel chip that the Arduino uses is great for this function, because it's got the capability of putting a pull-up resistor on its inputs. So there's no need for any external components - all the rows and columns of the keypad can just be connected with wires. Here's the plan for discovering what keys are pressed at any given moment:

  • Initially, configure all the rows and columns as inputs, but put pull-up resistors on the rows by writing HIGH to them as inputs. In this quiescent state, reading any row pin will see a logic HIGH.
  • When polling the keyboard, switch column 0 to be an output. This will put it into a low-impedance state, and overwhelm the pull-up resistor for any pin where there's a key pressed in column 0. Read each row pin in turn, and record what key, if any is pressed.
  • Set column 0 back to be an input and column 1 to be an output. Then do the same thing with column 2.
  • If no key is pressed, return a constant KP_NOKEY. If multiple keys are pressed, return a constant KP_ROLLOVER. Otherwise, return the number of the key that was pressed (0-9, or one of the constants KP_ASTERISK or KP_OCTOTHORP).
The relevant source code is the kpInit() and kpState() procedures in the file 'terminal/terminal.pde' from ZIP archive of auxiliary files.

Now, it turns out that to read a keypad you need to do a little bit more than just poll the state. You also have to deal with key bounce, which is the fact that the key switch will often open and close many times when being pressed or released. You also have to deal with key rollover, where the operator presses a second key before releasing the first one. (The code I'm presenting here implements "2-key rollover", which handles only the case of two keys pressed at once. Full "n-key rollover" requires diodes in series with the key switches, which this cheap keypad doesn't have. Fortunately, n-key rollover is mostly needed for typewriter-style keyboards and touch typists.)

The kpPoll() function in the source file handles both of these. It is intended to be called often from the scan loop. It determines the current time, and reads the keyboard state. It ignores what it has read, unless the state has not changed at any time during the last 20 milliseconds (KP_DEBOUNCE_MILLIS). This check provides the "debouncing" function that makes sure that key bounce doesn't cause redundant inputs. If the stable state is now different from the last stable state, it's returned - unless it's KP_ROLLOVER, which indicates that multiple keys are pressed at once, or KP_NONE, which indicates that no key is pressed at all. So the return of 0-9 or of KP_ASTERISK or KP_OCTOTHORP indicates that a key was just pressed, and demands response to a user action.

And that's pretty much all there is to reading the keypad. Since the pins are in a scrambled sequence, I keep a little table in PROGMEM of where the rows and columns are, and what order the keys are in. There are also three RAM variables: the last state of the keyboard, the last state that was stable for 20 ms, and the time at which the state last was observed to change.

Next up: writing the display. That bit was a little trickier.


Monday, August 10, 2009

Allen organ project - breadboarding the display terminal

As a first task toward making the card reader enhancement, I decided to start breadboarding the display terminal that will go on the outside of the organ to give me access to the alterable stops.

Breadboard with (from top) RBBB serial programming interface; RBBB for driving LED's; 12-key keypad; Arduino with LadyAda prototyping shield; LCD contrast pot and backlight components; 4x20 LCD.

Earlier posts in this series:

As a temporary mount, I soldered male headers on the keypad and display, and plugged them into a solderless breadboard. I then started wiring up the pins. First comes the keypad.

The two end pins on the keypad have no internal connections, and are not counted in the manufacturer's pin numbering. The remainin pins are:

Keypad PinFunctionArduino pin
1Column 26
2Row 05
3Column 14
4Row 319
5Column 018
6Row 217
7Row 116

You can see from the table that I wired these "around the horn",at one end of the Arduino, skipping over pins 0-1 (the serial port) and 2-3 (which support interrupts, not needed to run the keyboard but maybe needed for something else).

I also plugged in the display at this time. Walking down through the list of pins on the display and trying to decipher the East Asian-flavored English in the datasheets, I wired it up:

Display PinFunctionArduino pin
3Contrast adjustSee below
4Register Select13
10DB3See below
16LED-See below

The contrast adjustment went to the wiper of a 10k pot connected between +5V and ground. Initially, I grounded DB3, but we'll see in a subsequent post why that was wrong. Finally, there was a need for backlight control. You'll noticed I skipped over pin 11 in the table above - that's because I needed a pulse-width modulated output for the backlight. I connected pin 11 through a 1k resistor to the base of a 2N3904 transistor. The emitter went to ground, and the collector went to the LED cathode through a parallel pair of 12Ω resistors. (The data sheet showed 6.8Ω in the test circuit, but I didn't happen to have that size in the junk box.)

With suitable programming, this was enough to light up the display, read the keypad and put gibberish on the screen. The next post or two will get us from gibberish to "Hello, world!" and show how the keyboard is read and the display is managed.

To handle them, you'll probably want to download the ZIP archive of auxiliary files from this project's Fossil repository. You'll find the schematic in there under the name terminal/display.sch (Eagle format) and terminal/display.pdf (Adobe PDF).

Next post: reading from the keyboard.


Saturday, August 8, 2009

Allen organ project - getting stuff.

I also made a little time to do some rough-cut design for the card reader enhancement, at least enough to order some parts. The idea will be to have an Arduino in a box outside with a keypad and display to do operator interface (or perhaps "organist interface"), and a little box piggyback on the card reader to drive the LEDs.

Earlier posts in this series:

I was going to just put the LEDs in the inboard box, and drive them through a printer cable or some such, but my friend Steve made the good suggestion to run them off the RBBB that he gave me, and have a serial link joining the two boards. There's lots less wire that way.

I have on hand an Arduino (with the LadyAda protoshield), an RBBB (with the PC serial interface), and a suitable 9v wall wart - all also thanks to Steve, who had them as scrap from another project that turned out to be a little too big for them. So I'm tentatively looking at a block diagram like this:

The operator interface will use a telephone keypad for the input. It needs a reasonably large display, because there's a bewildering array of stops, with names like "Trompette en Chamade 8'" that need to be presented. So I'm going with 4 lines of 20 characters, which is the largest that the inexpensive HD44180 controller will support.

I need some reasonably bright white LEDs, 3mm diameter. (5 mm is a trifle too large to go into the holes on the card reader.)

So, significant items on the shopping list are:

  • The LED's - 10 needed, plus a few spares.

  • The display - it looks as if SparkFun's LCD-00256 (actually a Xiamen Ocular GDM2004D) is Just The Thing.

  • A telephone keypad - I've got one in junk, but it's really crappy looking and I'd like the finished project to look halfway presentable.

  • Some suitable connectors for the serial link. I'm also planning to power the operator interface box over those connectors. I'm thinking that a 6-pin mini-DIN, like a computer keyboard, should work nicely. And I've got a spare cable for that form factor.

  • Oh yes, and some bits and pieces that I'm running short on (pin headers and the like).

(And to be honest, I ordered all of this stuff last week, and just didn't trouble to blog about it.)


Allen organ project - catching up (UPDATED: Now with photo goodness)

Contrary to what you might think, I haven't been exactly idle on the Allen organ project. A few words on what I've been up to are probably in order.

Earlier posts in this series:

First of all, I've been busy getting the house ready to accommodate things without having a rat's nest of cables on the music room floor. This involved fishing two strands of speaker wire and a strand of Romex to each speaker. The two strands of speaker wire were for the audio and for 12VDC. The strand of Romex was for switched house current. That's what runs the motors that give the Leslie-like "gyrophonic" effects.

What there is behind a speaker
What's behind a speaker - Mini-Twist ML3 receptacle, an existing outlet, and a Keystone panel for audio and DC.

And behind the organ console, I fished up the other ends of all this. So behind each speaker I've got a Mini-Twist ML3 receptacle (I didn't want anyone plugging a lamp into it) and a 4-binding-post Keystone panel. Behind the organ console is a 6-binding post Keystone panel (left speaker, right speaker, and 12VDC to both), and a Mini-Twist ML2 inlet. (An inlet puts power into the wall, just as an outlet takes it out.) The arrangement that they had at the house where we got the organ was scary - the inlet was a lamp plug put on an outlet plate inside-out with some sort of putty; the low-voltage wiring was in the same box with the AC, and so on. The arrangement I have now at least isn't going to haunt my dreams.

What used to be behind the organ console - a cheap lamp plug mounted in reverse using some sort of putty, and two weird 6-pin speaker plugs, also puttied in place. How many code violations can you find in this picture?

The outlets and inlet were designed for panel mount rather than outlet box mount, so I made up nickel-plate switchplates with cutouts for them. A big "thank you" to Carl, K2YR for having the right Greenlee punch for the job!

As I did the ML2's for the various line cords, I discovered that all the AC wiring was badly deteriorated - the gutta-percha insulation unside the line cords crumbled at a touch. So I replaced all that, hacking up a hardware-store extension cord because that's a lot cheaper than the same length of 14 gauge stranded cable. I surely don't know why.

And while I was working inside the speakers, I noticed that the belts that drive the moving parts were also rotten - so I'm going to have to order a new set. OK, so I disassembled the shafts, so that I could unthread the belts to measure them. And as I was taking the brushes off the slip rings, I discovered that they were broken. Oh joy, that's a job that I'll have to get a factory service tech to do - because I can't find that part anywhere. It's a silver graphite brush, 0.125" by 0.25" by 1" with a bevel for the slip rings and a long spring. Oh well, brushes ought to be a maintenance part, so I bet the Allen tech can still get them. I hate to call a tech in for a job I can do myself, though.

So I soldered in a bypass to get power to the speakers (with quick disconnects everywhere so that I just need to yank it out to have the old arrangement back). I can live without the motion effects for a while.

I also tried replacing the burnt-out lamp in the card reader with a junk-box green LED (and current limiting resistor). Nothing doing; the thing still doesn't read cards. Next step on that device will be to replace the green LED with one of the white ones that I just got. More on that in the next post.

Pictures another time. My daughter has got my camera. [UPDATE: I got it back.]