After looking at several sample Buffalo DAC projects I decided that I didn’t like the LCD screens most people were using. I had a Sansa Clip a few years back that used a very crisp OLED display – a quick search on Mouser and I found an inexpensive 20×4 NewHaven OLED (NHD-0420DZW-AY5-ND) that looked like it was HD44780 compatible.
After reading a bunch of forum posts complaining about this display, I stumbled across someone who had tweaked the standard Arduino LiquidCrystal library to make it compatible with the OLED timing parameters: http://www.elcojacobs.com/controlling-an-oled-character-display-with-arduino/. I swapped his library for LiquidCrystal and – huzzah! – my DAC was humming along with a beautiful OLED display.
The next step was to minimize the number of pins I was using on my Arduino using an I/O port expander. By using the two i2c pins (A4 and A5) on the Arduino, a port expander gives you 8 outputs. The downside is that the port expander makes things considerably slower – too slow to be usable. So I was excited to find the LiquidTWI library as it promised to speed things up by “bursting” all 8 pins at once, rather than trying to address each pin serially: http://blog.lincomatic.com/?p=956.
And it worked! Sort of. I had to tweak the timing parameters again, but Elco had already shown me how to do that.
Everything worked perfectly except for custom characters – which is something the HiFiDuino code uses to display the volume. You might be able to print one or two custom characters, but the display would ultimately go into WTF mode and you’d have to restart it.
I tried a very long “delay()” when custom characters were being written, but regardless of how long I waited, nothing helped. As far as I could tell, the problem has something to do with the D7 pin on OLED display, which serves both as an input to the OLED and an output that indicates when the DAC is busy. According to the datasheet, you are supposed to poll the busy pin and only write a command when the busy pin tells you the OLED has finished processing.
So, by hacking the Adafruit MCP23008 library, I was able to implement a function that reads the busy pin. We only need to use this function when we are writing/creating custom characters, so it really doesn’t slow things down too much. And the library takes care of invoking the function when necessary, so it’s invisible to anyone using the library.
BUT, BUT, BUT …
The volume display is tied to the movement of the rotary encoder, which uses an interrupt to indicate when it is being turned. It seems the delay that the readBusy() function creates wreaks some havoc with the rotary encoder functionality, so a quick spin of the encoder doesn’t register. So after all that, I’ve reverted back to directly connecting the OLED to the Arduino.
But maybe somebody else can benefit from the library I wrote. If so, grab the code here: https://github.com/tharmas/LiquidJWM