HTM(A)A — Charlie DeTar


Final Project: A Journey Through Microcontroller Audio

The Plan

dpa deploy image posing the finished parts sampler board image sampler board image

My original plan for a final project, way back in week 1, was to build a internet-connected drum that counted politically sensitive numbers. After thinking on that for a while, I decided instead to implement the Democratic Public Address System, a peer-to-peer PA system. However, after struggling for a week and a half with Siggi and David to get the radio module working, we gave up on Saturday night (around the last time I had any sleep). So, combined with some problems I had making audio amplifiers that didn't suck, I asked Neil for suggestions to salvage a final project, the night before it was due. He suggested something I had actually had interest in doing before, which made me all the more excited to do it - to implement something akin to a VOIP over Internet Zero - the thinnest, cheapest digital audio communication possible.

Components

There are 4 major hardware components, and at least one major software component, which were necessary for this project: microphone in, speaker out, memory (enough for audio), radio, and fast com to shuttle audio data between the different components of the system. For the purposes of this page, I'll summarize the lessons learned from those exercises in my descriptions here.

Previous Work

I have had an audio bias throughout the class. I worked on microphone input for the input devices class, and made a not-quite-successful stab at building a simple audio sampler with speaker for the output devices class. Also, the previous version of this page might be of interest.

0. Initial Design: Modularity

In Week 6, Neil provided us with hello.mic.45.cad, a simple tiny45 based microphone input board. I successfully used his design for that project, but when I tried to apply the same microphone circuit to a mega88 based board it resulted in lots of problems: first and foremost, the mega88 only has a single-ended ADC without gain, and only offers either a 1.1V or 5V reference. Consequently, the mic circuit from the hello mic board which relied on these features no longer works on the mega88. The tiny44 has the 20x gain stage, but does not have the 2.6V reference, only the 1.1V reference. The memory I needed, however, used a 4-pin SPI interface, leaving not enough pins to do differential gain, speaker out, a button in, an LED out, and radio communication. The tiny44 has enough, but just barely - leaving no pins left over for serial communication to a computer for debugging.

I asked Neil about this, and he recommended that rather than trying to modify amplifier or voltage division circuits to suit larger processors, I should just modularize the project and use the tiny45 for microphone, and other processors for the other parts. After thinking for a long time I settled on the following architecture:

planned architecturefirst working proof of concept

There are 4 distinct modules, all connected by a 4-wire bus that provides power, ground, and two com lines. I separated the tasks into input-output pairs: audio i/o, user i/o (button and light), and radio i/o. The center module coordinates communication between the others and memory.

1. Microphone Board

microphone board

The microphone board is basically Neil's hello mic with a 4-wire connector (with an altered pinout) to provide power, ground, data in (speaker data) and data out (microphone data), and an additional 4-wire connector to the planned amplifier board that would drive the speaker.

After building the board and trying to interface it with Neil's mosfet speaker hack, I found that the sound was terrible. There was a lot of noise, and it seemed to be feeding back very easily. To isolate what the problems were, Neil suggested I get audio samples into a computer to play it back, and also send audio from a computer to test the speaker.

My first task was to get audio in to a computer from the board. That way, I could guage the quality of the microphone circuit and see if it needed modification. My code simply converted an ADC sample, then sent it over serial to the computer. To try to improve the sampling rate, I did the putchar for the previous sample while converting the next sample (asm code, python code for sample acquisition). The next task was to convert the list of 8-bit numbers to an audio file I could listen to. This proved to be remarkably cumbersome to do. After putzing around with some python audio libraries and finding them to be poorly documented and not very featureful. So, I reused some old java code to generate audio files.

The results - in order of improving quality by increasing sampling rates (by removing operations from the main loop above): test 0, test 1, test 2, test 3, test 4. The last test actually sounds rather decent, and comes in around 10kHz for the sampling rate, which is about the maximum possible rate using 115200 kbps RS-232 as a data transfer format. I considered this good enough for now, and moved on to the speaker.

2. Speaker

Using the same audio I had just recorded, a python script to send serial data, and a little junction board to do serial voltage and pin position conversion to interface with my audio board, I succeded in getting audio out of the computer and into the speaker. And, it sounded like sh*t. So I decided I would need some serious speaker and amplifier improvements to get the loud room-filling PA style sound I desired.

First, I tried to build an amp using an H-bridge, going on this maxim article as a reference. Siggi helped me with a logical not (inverter) for the second input to the H-bridge, and to understand better what the difference between N-mosfets and P-mosfets are, and how H-bridges work. Were would I be without Siggi?

H-bridge board H-bridge sketch

Perhaps there's a mistake in the circuit, but it sounded terrible, even quieter than Neil's transistor hack. Also, the 5-volt regulator necessary to match the H-bridge's power with the PWM power was not sufficient for the current draw of the H-bridge, and heated up a great deal. Then to top it off, working late at night, I accidentally plugged a battery into the speaker socket on the board, and the soul of the H-bridge wafted into the heavens in a little puff.

Next, I tried ordering some audio amps from Digikey. After perusing their thousands of offerings, I settled on the Phillips TDA7052A 1-watt 8-pin SOIC amp, which come in at only $0.81 each for 25. After yet another brief consultation with Siggi, we came up with this basic sketch of a diagram for a circuit with the amp:

Audio amp first wrong sketch

It turns out that this sketch was wrong, though - it misinterprets the function of the volume control pin. Rather than acting as a sink, the volume control pin actually sources current, and the resistor you put between it and ground governs the volume level (shorted to ground means no volume, infinite resistance means maximum volume). Once I figured this out and made a large number of modifications to my circuit, I started getting some sound.

Audio amp first wrong board modifications sketch Audio amp first wrong board modifications sketch

The amp's performance was still very poor. It heated up very easily, and was consistently drawing 200+ milliamps to produce relatively quiet sounds. I added a low-pass filter to the PWM on the theory that the consistently maximum voltage values might be straining the amp, but it made little difference.

3. Master board

The intent of the master board was to communicate between the 3 different child boards - one for audio i/o, one for radio i/o, and one for user i/o (buttons/lights). I would communicate with each using a 2-wire interface. I did my initial design using an ATtiny44:

Tiny, version 1

tiny44 trunk

I backed out on this design when I realized that the tiny44 had not quite enough pins, and also lacked a dedicated SPI interface (only a USI interface which Siggi, David and I failed to get working for the radio, though in hindsight that is probably due to the radio chip's non-standard SPI implementation - see below). Consequently, I switched to a mega-based board.

Mega, version 1

trunk mega sketch trunk mega v1

Initially, I intended to run the mega-based version solely on 3.3v power, since I was only going to run it up to 8MHz anyway (it maxes out at 16MHz, and thus can't use the 20MHz crystals the lab had), and the memory chip it interfaces with requires 2.7v to 3.6v only. When I plugged the board in for the first time, I used a bench supply, and was surprised to see its current limiter kick in immediately and the voltage drop. Unsure why this might be the case, I did a bunch of signal testing and didn't find any shorts. Everything seemed to be connected in the right order to the right places. After about a half hour of this checking, I decided to just plug a battery in to see what would happen. POOF! My regulator went up in a flame and smoke! I quickly unplugged, and tried to salvage the board. It was only the regulator that died, the rest seemed fine. At first, I was mad at Siggi who had set up the bench supply, thinking he had connected the power backwards. But of course, it was me - I had drawn my schematic with the power MTA connector on backwards. Oops.

Not to be discouraged, I popped off the power connector and reversed it, and added a new regulator, and the board seemed to function fine. However, I couldn't get any serial connection to the computer. Try as I might, I would get nothing but zeros. I feared that the 3.3V signal might be too low to qualify as a high voltage without a line-driver for RS-232, and decided to build a new board with a 5V power connection to the microcontroller and 3.3V to the memory.

Mega, version 2

In the second version, already fearing based on my microphone tests that com protocols between microporcessors was going to limit my sampling rate, I connected the audio-out pin to a PWM-capable pin so that I could potentially do audio directly from the master board. I also connected the radio-in pin to an external interrupt capable pin (INT1) and the button-in to the other external interrupt pin (INT0) so I would be ready to do interrupt driven com. When I went to test this new board, it also could not communicate to the computer. Then I realized a dumb bug, I was not writing to the txbyte register before calling putchar. It turns out the 3.3V version and 5V version of the board were fine for RS-232.

The Curious Voltage Problem

With my new 5v/3.3v board, I noticed something strange - the 3.3V regulator seemed to have 4 or more volts coming out of it. I tried a couple different regulators, and they all behaved the same. But when I removed the memory chip from the board, the regulator would output 3.3v, as expected. After ruminating on this for a while, I hypothesized that the 5V provided by the microcontroller on the SPI pins connected to the memory chip was causing the memory chip to bleed voltage. When I swapped out the microcontroller's 5V regulator with another 3.3V regulator, the problem went away.

4. Memory

In order to record more than a fraction of a second of audio, you need much more memory than the microcontrollers (even the megas) have on board. I managed to get the Atmel AT45DB011B working shortly after the output devices assignment (assembly code, cad file), but found that this memory had a fundamental problem for recording audio: the AT45DB line of flash memory operate with one or more buffers between input and the main memory. In order to write data to memory, you first write to the buffer, then commit the buffer to memory. In the case of the lower-end AT45DB011B, the chip only has a single buffer. Consequently, after filling the write buffer, you must wait while that buffer is committed to a page before writing any more samples. Writing to the buffer is fast (faster than needed for audio sampling), but committing the buffer to a page of memory takes longer than the sampling rate, and consequently there would be glitches in the audio.

By contrast, the AT26F004 does not use a buffer for writing, but writes directly to the flash memory. This operation is slow (it turns out to be sampling-rate limiting at 8MHz), but at least it is consistent, resulting in no audio hiccups. Hence, I ordered a bunch of these chips to use instead of the AT45DB011B's that the CBA had kicking around.

This turned out to be setting myself up for an incredible amount of work - about 2-3 days of solid debugging. It seems that this ends up being the problem with any new chip I set out to use - I have to get intimate with the data sheet and learn all of its quirks before I can get it to work.

The friggin' chip has Four (4) layers of write protection. You'd think that they'd want to make it possible to write to memory, no? Why so much write protection? Do they expect people to use the chips with all kinds of random voltages coming over the SPI lines (with chip select held low, of course) which just happens to key in 8-bit opcodes to overwrite data? Sheesh!
  1. Write Protect pin. This must be held high to write. I didn't intend to use it, so I tied it to VCC.
  2. Write Enable. In order to write to memory, or the status register, or unprotect sectors, or do anything but read, apparently, you have to clock in the Write Enable opcodes.
  3. Sector Protection. Every sector (what constitutes a "sector" is somewhat under-defined in the datasheet) is "protected" every time you power up the chip. You have to explicitly unprotect each sector (in addition to write enable and the write protect pin) in order to write data.
  4. Sector Protection Protection. Just in case the above wasn't enough, there's a register to disallow any changes to the protection status of a sector.

For a long time, after verifying with certainty that I was in fact communicating with the chip (I could read the status register, and consistently read the same random data from the same addresses), I still could not seem to be able to unprotect all the sectors (the status register showed only "some sectors were unprotected" after I attempted to iteratively unprotect every one). I scoured the net for any code to run the memory, and finally found the tuxaudio project which had C-code for driving the chip. This helped show me that I had misread the datasheet with regard to the memory addresses corresponding to the sectors, I was off by one digit, consequently failing to unprotect the sectors, and failing to write properly. After fixing this and a couple other bugs, I got it to work. Here's assembly code for driving the memory chip - memory_test.asm and at26f004.asm.

Radio

Siggi, David and I spent a great deal of time working on getting either of two radio modules working - the IA4421and a Nordic Radio module). Here's David's write up, and Siggi's. In short, we spent a very great deal of time working on both, and were unsuccessful. We managed to make each produce a spike on the spectrum analyzer, but were never able to decode messages. A lot of our work consisted of translating Pic-centric C code from examples provided by the respective developers into Atmel assembler for our boards, then lots of debugging and efforts to figure out what the problem could be. I intend to continue this work in January 2008 to get some kind of wireless transmission working.

Communication Protocols

It became clear early on in doing audio tests with a computer that serial communication was my sampling-rate bottleneck. At 115200 baud, at optimal rates, you can only get 15,200 bytes per second. If you have to do any other operations during that time, the sampling rate drops proportionally. Two-way communication (such as from the microphone processor to the master processor, then out to the memory chip, or from the memory chip to the master processor, then out to the audio board) substantially reduces the transfer rates further. I figured that if I could get an interrupt-driven putchar and getchar running, I could do SPI communication and serial communication simultaneously for higher sampling rates.

In hindsight, this was probably a waste of time. Serial communication is much slower than synchronous methods, and consequently is probably not worth the trouble of speeding rather than developing a fast synchronous scheme (e.g., one with a dedicated clock pin). Also, I later decided to buck the whole issue by using an op-amp board for microphone and piping it straight to the ADC of the master, and thus avoiding serial communication of audio altogether. At any rate, I did get interrupt driven putchar working here; this file also has a not yet functional interrupt-driven getchar that I had almost finished debugging when I realized how pointless it was.

Pulling It All Together: Triage and Last Minute Changes

By Friday 2 days before the assignment was due, I still did not have memory, radio transmission, or particularly loud amplification working. I knew that if I could get any 2 of those working, I would have something decent to show on Monday, but it was slow going. On Saturday I finally knocked out the memory (yay!), and then started working more on amplification and on the boxes to put things in. I also decided to ditch the microphone processor board, in favor of a simple mic amp board:

mic amp

The mic amp let me just do ADC from the master, and not worry about audio-rate communication within a unit. I adapted the schematic for the op-amp for the mic from Neil's hello.mic.44.cad.

grassroots wood cut

I found a neat woodcut on the internet to use on my boxes. On Saturday, I designed very simple boxes in Omax Layout, then ported them over to correl draw to cut out on the lasercutter. I glued them together, not taking the time to hone sizes for press-fit.

On Sunday I video-conferenced with Neil at home to ask for his suggestions of how to make the amplifier louder, and he recommended that what I do for my final project was not the original plan, but to do something akin to Voice Over IP - basically, digital transmission of real-time voice data between at least 2 clients, with extra perks being things like multiple client addressing. While this wouldn't use the memory I had spent so much time taming, it at least seemed possible and interesting.

the two finished units the two finished units

By Sunday morning at 4AM, I had a second set of boards milled and stuffed and debugged and running, inside slightly reorganized boxes, communicating in real time to each other with alternating putchar and getchar at a serial rate of around 150000 baud, for an effective sampling rate of about 8KHz (not horrible, but not great - especially since I didn't have very aggressive low pass filters on the microphone; much aliasing apparent).

(here's a lovely sleep-deprived video of me testing the units, as everyone else in the room sleep-deprivedly furiously debugs their stuff at 4AM monday)

I then turned to communication protocols, trying to speed my data transmission for better sound quality, and to get them working a bit more smoothly (none of these changes worked, and I reverted to the 4am version of the code for the presentation). I made long cables to connect the units together. I managed to get the amps just loud enough that you could hear them if you put the speaker up to your ear.

Future

I'm still going to finish the DPA as originally planned (with wireless transmission), as well as some other fun applications with these platforms. I've gotten the amps working much more loudly now partially by accident - they only draw around 100-200 milliamps and can fill a room with sound (I'm putting a 5k resistor and 1uF capacitor in line between the PWM signal and the amp's input, but I don't understand why this works). The future is bright for microcontroller audio. Yay.

File list

If you want a file related to my final project... it will be in the following list.

Index of /classes/MIT/863.07/people/charlie/final

Icon  Name                    Last modified      Size  Description
[DIR] Parent Directory - [IMG] IMG_5394.JPG 10-Dec-2007 12:06 1.7M [IMG] IMG_5394_300x200.JPG 10-Dec-2007 12:06 10K [IMG] IMG_5395.JPG 10-Dec-2007 12:06 1.2M [IMG] IMG_5395_300x200.JPG 10-Dec-2007 12:06 9.8K [   ] MVI_5398.AVI 17-Dec-2007 12:49 15M [TXT] _index.html 22-Dec-2007 19:35 26K [IMG] architecture_plan.jpg 22-Dec-2007 19:35 1.1M [IMG] architecture_plan_30..> 22-Dec-2007 19:35 7.2K [DIR] asm/ 22-Dec-2007 19:35 - [   ] audio-io.cad 10-Dec-2007 12:06 59K [   ] audio-io.comp-to-spe..> 10-Dec-2007 12:06 3.9K [   ] audio-io.comp-to-spe..> 10-Dec-2007 12:06 496 [   ] audio-io.comp-to-spe..> 10-Dec-2007 12:06 6.9K [   ] audio-io.micthru.asm 17-Dec-2007 12:49 3.9K [   ] audio-io.micthru.hex 17-Dec-2007 12:49 500 [   ] audio-io.micthru.lst 17-Dec-2007 12:49 7.0K [   ] audio-io.speaker.wav..> 10-Dec-2007 12:06 3.7K [   ] audio-io.speaker.wav..> 10-Dec-2007 12:06 724 [   ] audio-io.speaker.wav..> 10-Dec-2007 12:06 7.0K [   ] audio-io.thrutrunk.asm 10-Dec-2007 12:06 3.9K [   ] audio-io.thrutrunk.hex 10-Dec-2007 12:06 508 [   ] audio-io.thrutrunk.lst 10-Dec-2007 12:06 6.9K [   ] audio-io2.cad 10-Dec-2007 12:06 59K [IMG] audio_amp_sketch_wor..> 22-Dec-2007 19:35 1.2M [IMG] audio_amp_sketch_wor..> 22-Dec-2007 19:35 6.8K [IMG] audio_amp_sketch_wro..> 22-Dec-2007 19:35 1.2M [IMG] audio_amp_sketch_wro..> 22-Dec-2007 19:35 6.6K [IMG] audio_amp_working.jpg 22-Dec-2007 19:35 1.1M [IMG] audio_amp_working_30..> 22-Dec-2007 19:35 9.9K [   ] audiotiny-micthru.asm 10-Dec-2007 12:06 3.7K [   ] audiotiny-micthru.hex 10-Dec-2007 12:06 500 [   ] audiotiny-micthru.lst 10-Dec-2007 12:06 6.6K [   ] audiotiny.cad 10-Dec-2007 12:06 57K [IMG] audiotiny2.png 10-Dec-2007 12:06 9.3K [   ] audiotiny2.rml 10-Dec-2007 12:06 64K [   ] button.cad 17-Dec-2007 12:49 56K [   ] charlie.mic.44.cad 10-Dec-2007 12:06 58K [IMG] deploy.png 19-Nov-2007 11:50 43K [IMG] deploy_300x200.png 19-Nov-2007 11:50 23K [IMG] dumb_audio.png 17-Dec-2007 12:49 2.9K [IMG] dumb_audio_2.png 17-Dec-2007 12:49 3.3K [IMG] finished_internals.jpg 22-Dec-2007 19:35 1.2M [IMG] finished_internals_3..> 22-Dec-2007 19:35 11K [IMG] finished_posing.jpg 22-Dec-2007 19:35 1.3M [IMG] finished_posing_300x..> 22-Dec-2007 19:35 11K [IMG] grassroots.jpg 10-Dec-2007 12:06 35K [IMG] grassroots_300x200.jpg 10-Dec-2007 12:06 12K [IMG] h_bridge_board.jpg 22-Dec-2007 19:35 1.1M [IMG] h_bridge_board_300x2..> 22-Dec-2007 19:35 8.3K [IMG] h_bridge_schematic.jpg 22-Dec-2007 19:35 1.1M [IMG] h_bridge_schematic_3..> 22-Dec-2007 19:35 6.9K [   ] hello.H-bridge.44.cad 10-Dec-2007 12:06 57K [   ] hello.mic.45.cad 10-Dec-2007 12:06 57K [   ] hello.speaker.45.cad 10-Dec-2007 12:06 57K [   ] hello.speaker.45.wav..> 10-Dec-2007 12:06 3.4K [DIR] java/ 22-Dec-2007 19:36 - [   ] mic.cad 10-Dec-2007 12:06 56K [   ] mic_amp.b#1 17-Dec-2007 12:49 7.9K [   ] mic_amp.brd 17-Dec-2007 12:49 10K [IMG] mic_amp.jpg 22-Dec-2007 19:36 1.2M [IMG] mic_amp_300x200.jpg 22-Dec-2007 19:36 11K [IMG] microphone_board.jpg 22-Dec-2007 19:36 1.2M [IMG] microphone_board_300..> 22-Dec-2007 19:36 11K [TXT] mictest.txt 10-Dec-2007 12:06 115K [SND] mictest.txt.wav 10-Dec-2007 12:06 30K [SND] mictest1.wav 10-Dec-2007 12:06 74K [TXT] mictest2.txt 10-Dec-2007 12:06 301K [SND] mictest2.wav 10-Dec-2007 12:06 81K [SND] mictest3.wav 10-Dec-2007 12:06 81K [SND] mictest4.wav 10-Dec-2007 12:06 861K [   ] pcb.cad 10-Dec-2007 12:06 56K [   ] poster.pdf 19-Nov-2007 11:50 383K [   ] power_interconnect.cad 22-Dec-2007 19:36 56K [DIR] radio/ 17-Dec-2007 12:49 - [TXT] serialCapture.py 10-Dec-2007 12:06 307 [TXT] serialCapture.txt 10-Dec-2007 12:06 328K [SND] serialCapture.txt.wav 10-Dec-2007 12:06 86K [TXT] serialEcho.py 22-Dec-2007 19:36 580 [TXT] serialGetPutTest.py 17-Dec-2007 12:49 318 [TXT] serialReturn.py 17-Dec-2007 12:49 242 [TXT] serialSend.py 17-Dec-2007 12:49 206 [   ] serial_to_4io.cad 10-Dec-2007 12:06 56K [SND] sine.wav 10-Dec-2007 12:06 215K [   ] speaker.H-bridge.cad 10-Dec-2007 12:06 57K [   ] speaker.amp.cad 17-Dec-2007 12:49 58K [   ] speaker.amp2.cad 22-Dec-2007 19:36 58K [   ] speaker.cad 10-Dec-2007 12:06 56K [   ] speaker2.H-bridge.cad 10-Dec-2007 12:06 57K [   ] spi_bit_bang_test.asm 10-Dec-2007 12:06 11K [   ] spi_bit_bang_test.hex 10-Dec-2007 12:06 1.6K [   ] spi_bit_bang_test.lst 10-Dec-2007 12:06 17K [TXT] spi_bit_bang_test.py 10-Dec-2007 12:06 403 [TXT] status_update.html 17-Dec-2007 12:49 5.4K [   ] trunk.cad 10-Dec-2007 12:06 62K [   ] trunk.thrutrunk.asm 10-Dec-2007 12:06 3.3K [   ] trunk.thrutrunk.hex 10-Dec-2007 12:06 556 [   ] trunk.thrutrunk.lst 10-Dec-2007 12:06 5.5K [IMG] trunk_tiny.jpg 22-Dec-2007 19:36 1.2M [IMG] trunk_tiny_300x200.jpg 22-Dec-2007 19:36 10K [   ] trunkmega.cad 10-Dec-2007 12:06 64K [   ] trunkmega2.cad 17-Dec-2007 12:49 64K [   ] trunkmega3.cad 17-Dec-2007 12:49 65K [   ] trunkmega3.rml 17-Dec-2007 12:49 71K [IMG] trunkmega_sketch.jpg 22-Dec-2007 19:36 1.0M [IMG] trunkmega_sketch_300..> 22-Dec-2007 19:36 4.3K [IMG] trunkmega_v1.jpg 22-Dec-2007 19:36 1.4M [IMG] trunkmega_v1_300x200..> 22-Dec-2007 19:36 11K [   ] tssop.cad 10-Dec-2007 12:06 56K [IMG] two_finished_units.jpg 22-Dec-2007 19:36 1.3M [IMG] two_finished_units_3..> 22-Dec-2007 19:36 8.6K [IMG] video_thumb.jpg 22-Dec-2007 19:36 6.8K