Experimenting with an Arduino and a SN76489

SN76489 pinoutThe SN76489 is a sound generator IC. It has quite a distinctive sound, and is almost iconic in its association with some 8-bit computers. It’s what gives the BBC Micro its distinctive boop-bip (which is how I know of it) and is also used in the Sega Master System, Sega Game Gear, and a fair few old arcade machines (such as Mr Do and Wonder Boy).

It produces four-channels of mono sound – “four-channel” meaning that it can play four different notes independently. Actually, it’s three channels of notes, and one of “noise” – which is typically used for percussion, gunfire, explosions, and so on.

They’re still fairly easy to get hold of – eBay, for example. Or you could pull one out of a dead console. I just beg you not to pull one out of a working BBC Micro, though: that would just be wrong.

Controlling the SN76489

To control it, you send it commands. Commands are simple eight-bit bytes. Sending those commands is as simple as putting the byte on the eight data lines, then strobing /WE low to store. It has a chip-select pin (also active low), so you can run it on a shared-bus with other devices if needed. For the purposes of this demonstration it’ll be active all the time, so just tie /CS to 0v. Depending on which datasheet you look at, the /CS (chip select) pin may also be known as /OE (output enable) or /CE (chip enable).

Driving the IC from an Arduino is fairly straightforward – you’ll need eight digital outputs for the byte, and a ninth for /WE. If you’re not an Arduino person then just substitute your processor of choice.

Arduino

To be honest, the wiring is so simple I nearly didn’t bother drawing it. Note that the pin assignments on the Arduino-end are completely arbitrary – they’re just what was convenient when I was building the circuit on breadboard. They match with the code example (see later). Feel free to change them if it makes sense for your circuit.

My circuit, on a breadboard. I'm using an Arduino Nano, which are just like the Uno but cuter and cheaper.

My circuit, on a breadboard. I’m using an Arduino Nano, which is just like the Uno but cuter and cheaper. The black cable you see at the top is where I’m feeding the sound to line-in on a mini hifi.

There is nothing much to read from the IC –  you can send it commands, but you can’t communicate with it to find out any current values (for example). There’s no two-way conversation needed, and this makes it fairly simple to work with. There is a “ready” pin (which goes LOW whilst the IC is processing your last command) but it’s such a quick affair it probably isn’t worth it. Even the BBC Micro doesn’t bother.

Here’s a snippet of Arduino code that demonstrates how you might send it a byte:

void SendByte(byte b)
{
  digitalWrite(PIN_D0, (b&1)?HIGH:LOW);
  digitalWrite(PIN_D1, (b&2)?HIGH:LOW);
  digitalWrite(PIN_D2, (b&4)?HIGH:LOW);
  digitalWrite(PIN_D3, (b&8)?HIGH:LOW);
  digitalWrite(PIN_D4, (b&16)?HIGH:LOW);
  digitalWrite(PIN_D5, (b&32)?HIGH:LOW);
  digitalWrite(PIN_D6, (b&64)?HIGH:LOW);
  digitalWrite(PIN_D7, (b&128)?HIGH:LOW);
  digitalWrite(PIN_NotWE, HIGH);
  digitalWrite(PIN_NotWE, LOW);
  digitalWrite(PIN_NotWE, HIGH);
}

Yes, I know it’s long-winded compared to just bashing the ports directly. I intended this posting to be simple and educational – feel free to optimise away when you have your circuit running.

Obviously you must have defined the PIN_ constants yourself beforehand, and set them up as outputs.

Sound output

Sound comes out of pin 7. The easiest way to hear it might be to connect it to the line-in input on a mini-hifi, or computer speakers, or a headphone amp. If you’re planning on building a doorbell then you’ll need a mini speaker circuit – an easy way would be to look for a circuit based on the LM386 power-amp, which is a little 8-pin IC that only requires a 5-volt supply to function. If you’re feeling especially lazy, you can buy little circuit board amps from eBay that even include screw-terminals to wire your speaker, for only a few quid.

Frequency input

The chip works by modulating a square-wave signal you provide – the frequency isn’t critical, but be aware that if the frequency you generate isn’t exactly the same as whatever hardware you’re used to, then the tones will be off. The BBC Micro uses a frequency of exactly 4 MHz, and I found it no trouble to get hold of 4 MHz oscillator components (eBay again).

Powering on

When the IC is first powered-on, one of the channels will begin to produce a low-tone straight away. (If you have ever used a BBC Micro, you might be interested to know that this is the “boop” of the “boop-bip”.) So when you first power it up and you hear a potentially alarming sound then don’t panic – that sound means it is working! It is up to the host processor to send the sound-off commands.

What to play?

There are already some excellent websites around (including SMS Power’s comprehensive page, the SN76489 datasheet and this page) that describe the 8-bit commands, so I shall not repeat them here. But as simple examples:

SendByte(0x83); SendByte(0x12); // sets channel 0 tone to 0x123
SendByte(0x90); // sets channel 0 to loudest possible
SendByte(0x9F); // sets channel 0 to lowest volume (silencing it)

Note that I can’t tell you what note would be played by 0x123 in the above example, because this depends on the frequency of clock you use as input.

Playing something more impressive

If manually entering SendByte() commands and pauses to play “When the saints go marching in” is your thing then great – you have enough to be getting on with and we’ll see you next year. But for those of us with short attention spans and no musical knowledge – where do we get our data?

Manipulating MIDI on the Arduino is fairly well documented, and there are some interesting projects that do this – great for the musician who wants their thousand-quid electric piano to sound like a thirty-year old 8-bit computer! Have a look at this page or this page, for example.

Or you could buy a rubbish children’s toy keyboard from a carboot sale, and get your Arduino to scan the keyboard and drive the SN76489 that way.

However, I’ve gone a different route. My initial reason for controlling a SN76489 was to build a sort of retro-doorbell for our new house – I had this idea that the doorbell could be the death jingle to Chuckie Egg or the intro music to Repton 3.

So: I added a small amount of extra code to BeebEm (a very mature BBC Micro emulator) running on my Mac, so that as bytes were sent to the emulated SN76489 they would also be logged to a textfile (along with the time they were sent). I then wrote a quick command-line utility to process these numbers and spit them out as C-sourcecode (along with some more meaningful comments), wrote a quick Arduino sketch that sends these bytes with the same timings to a real SN76489 and … hey presto … an authentic retro doorbell which will impress your friends and infuriate your wife!

Here is my Arduino sketch that plays the Chuckie Egg death music repeatedly, by parsing the bytes to be sent as an array of values included in the code:

SN76489 example sketch for Arduino

It would be straightforward to nominate a digital input for the doorbell pushbutton, then house the Arduino and SN76489 with a small amplifier circuit driving a speaker.

Playing in stereo?

Just as an afterthought: the SN76489 IC produces mono sound – what if you want stereo?

To play a note that appears to come from over to one side rather than bang in the middle of your ears, the note must be played at different amplitudes in each ear. So: play it loud in your left ear and quietly in your right will make your brain think the sound is coming from over to the left.

To do this you would add a second IC – then designate one for the left ear, and one for the right. Connect the eight datalines and the /WE line from the Arduino to *both* ICs, then utilise the /CS lines so that when you send data you have first selected which IC should receive it.

You can do this with one extra digital-out from the Arduino, and a NOT gate so that one chip is selected when the line is high, and the other when the line is low.

WithNOTAlternatively, if you want to keep your component-count down and you can afford to use a second digital-out from your Arduino, then just control the /CS lines separately.

WithoutNOT

But of course, to utilise this circuit, you’d need to find some stereo music data.