Goldilocks Analogue – Wrap Up

This is the final item on the Goldilocks Analogue as a design and production exercise.

Thank you for pledging on the Kickstarter Project page. Closed on November 19th 2015, with 124% funding. Now that the Kickstarter Pledges have been shipped, the Goldilocks Analogue is available on Tindie.

I sell on Tindie

I’ve been updating this post with the pre-production and production experience over the past few months.

The pre-production design materials, correcting the errata noted on Prototype Version 4, have been finalised and sent to Seeed Studio.
GoldilocksAnalogue_Seeed_20151120

The interim backer report is out, and now manufacturing quantities for procuring parts ready for the February production run have been finalised.

An updated version of the Goldilocks Analogue User Manual is available, and the Production Testing Document has reached Version 2 following inclusion of Windows 10 test procedures.

Revised Arduino IDE Variant files for Goldilocks Analogue using the Arduino core are available on Github.

Also additional optional libraries to provide support for each of the advanced features of the Goldilocks Analogue are available in the Arduino IDE Library Manager.

Arduino IDE compatibility testing revealed only a few remaining issues related to support of the ATmega1284p used in the Goldilocks Analogue. Two issues have been raised and resolved as 2 pull requests on the main Arduino IDE development path.

Both these issues have been committed into the Arduino main git tree, and they have landed in Arduino IDE Release 1.6.8.

The only remaining known issue is the limitation in the configuration of the Tones() code to use only Timer 2. We would like to use Timer 2 for the RTC. There is no other option but to use this Timer for the RTC support, so it would be good if Tones() could be configured to use a different timer.

Testing

Rather than going back over old ground, I’ll just be testing the pre-production version against the Version Prototype 4, to ensure that the things that should have improved, are improved, and that nothing has become broken.

Power Supplies

In the image below, Channel 1 (yellow) is 4.47mV of noise present at the output capacitor for the power supply, and Channel 2 (blue) is the 3.47mV supply noise present on a test Vcc pin closest to the MCU.

The significant improvement in noise level for the pre-production version at the MCU is similar to that achieved for the Prototype 4 (even slightly better), and this is probably due to reduced capacitive coupling into the ground plane by removing the ground copper from directly under the main supply inductor.

GA PP Power Supply Noise

GA PP: 5V Power Supply Noise

Remembering, for context, that 4mV is still the same order of the least significant bit for a 5V 10 bit ADC sampler, as found in the ATmega1284p, and a one bit change in the LSB of the MCP4822 input generates a 1mV change in output.

Checking the other power supplies on the board, Channel 1 (yellow) is the 3.3V positive supply, provided by a linear regulator. This supply is not used for analogue components, so the 4.0mV noise level is not critical, but never the less it is slightly less than on the Version P4.

Channel 2 (blue) below shows the -3V supply for the Operational Amplifier. This shows that the supply voltage noise of 5.9mV after filtering by a first order LC filter further smooth this supply. Compared to the Version P4 with no filtering (shown below) the noise is reduced substantially. The Version P4 shows a 10mV ramp, because it is a capacitive charge switching device. The addition of this LC filter was the one substantial change from the Prototype 4, so it is good to see the positive effect on the negative supply input to the Op Amp.

GA PP 3.3V and -3V Power Supply Noise

GA PP: 3.3V and -3V Power Supply Noise

Goldilocks Analogue Prototype 4 - 3.3V & -3V Supply Noise

GA P4: 3.3V & -3V Power Supply Noise

Analogue Output

The standard test that I’ve been using throughout the development is to feed in a 43.1Hz Sine wave generated from a 1024 value 16 bit LUT. The sampling rate is 44.1kHz, which is generated by Timer 1 to get the closest match.

The spectra and oscilloscope charts below can be directly compared to the testing done with prototype Version P4 and earlier versions of the Goldilocks Analogue.

The below chart shows the sine wave generated at the output of the Op Amp. This is exactly as we would like to see, with no compression of either the 4.096V peak, or the 0V trough.

Goldilocks Analogue – 43Hz Sine Wave – Two Channels – One Channel Inverted

GA PP: 43Hz Sine Wave – Two Channels – One Channel Inverted

Looking at the spectra generated up to 953Hz it is possible to see harmonics from the Sine Wave, and other low frequency noise.

The spectrum produced by the Goldilocks Analogue shows most distortion is below -70dB, and that the noise floor lies below -100dB. The pre-production sample shows slightly higher noise carriers than the Version P4, but the difference is not substantial.

GA PP 953Hz

GA PP: 43.1Hz Sine Wave – 953Hz Spectrum

In the spectrum out to 7.6kHz we are looking at the clearly audible range, which is the main use case for the device.

The Goldilocks Analogue has noise carriers out to around 4.5kHz, but they are all below -80dB. After 4.5kHz the only noise remains below -100dB.

GA PP 7k6Hz

GA PP: 43.1Hz Sine Wave – 7k6Hz Spectrum

The spectra out to 61kHz should show a noise carrier generated by the reconstruction frequency of 44.1kHz.

The Goldilocks Analogue shows the spectrum maintains is low noise level below -90dB right out to the end of the audible range, and further out to the reconstruction carrier at 44.1kHz.

GA PP 61kHz

GA PP: 43.1Hz Sine Wave –  61kHz Spectrum

The final spectrum shows the signal out to 976kHz. We’d normally expect to simply see the noise floor, beyond the 44.1kHz reconstruction carrier noise.

The Goldilocks Analogue has a noise carrier at around 210kHz, probably generated by the -3V supply. The noise carrier at 340kHz is generated through the 5V SMPS supply, and is absent when powered by USB socket. Aside from the two carriers mentioned, there is no further noise out to 976kHz.

GA PP 976kHz

GA PP: 43.1Hz Sine Wave – 976kHz Spectrum

The Pre-production analogue output works as specified, and is essentially identical to the analogue output on the Prototype 4. It can maintain the 72dB SNR required, of which it should theoretically be capable.

Goldilocks Analogue – Testing 4

Recap

I’ve been working on the Goldilocks Analogue now for so long that its been the centerpiece of my coding evenings for the past 18 months. This is the first time that I’ve designed a piece of hardware, and I’ve managed to make many mistakes (or learnings) along the way, so I think that every step of the process has been worthwhile.

Goldilocks Analogue Prototype 4 - Rotating

Goldilocks Analogue Prototype 4 – Rotating

In this project, I’ve learned about Digital to Analogue Converters, Operational Amplifiers, Voltage translation, Switching Power Supplies, and most importantly have gained a working knowledge of the Eagle PCB design tools.

Version History

The original Goldilocks Project was specifically about getting the ATmega1284p MCU onto a format equivalent to the Arduino Uno R3. The main goal was to get more SRAM and Flash memory into the same physical footprint used by traditional Arduino (pre-R3) and latest release Uno R3 shields.

The Goldilocks project achieved that goal, but the resulting ATmega platform still lacked one function that I believe is necessary; a high quality analogue capability. The world is analogue, but having an ADC capability, without having a corresponding digital-to-analogue capability, is like having a real world recorder (the ADC capability) with no means to playback and recover these real world recordings.

A major initiative of the Goldilocks is to bring an analogue capability to the Arduino platform via a DAC, so this project was called the Goldilocks Analogue. Following a Kickstarter campaign, the Goldilocks Analogue is now available on Tindie.

I sell on Tindie

Version 1 implemented the MCP4822 DAC buffered with an expensive, very musical, Burr Brown Operational Amplifier. Although the DAC performed exactly as designed, I neglected to provide the Op Amp with a negative supply rail, so it could not approach 0V required to reproduce the full range of output available (0v to 4.096V) from the DAC. That was a mistake.

Version 1 also reverted the USB to Serial interface to use a proper FTDI FT232R device from the ATmega32u2 MCU (the solution preferred now by Arduino). Using the ATmega32u2 (or ATmega16u2) to interface with anything not running at its own 16MHz CPU clock rate is broken and doesn’t work. This is because the ATmega devices don’t produce correct serial when their CPU clock is not a clean multiple of the USART required rate. I learned this the hard way with the Goldilocks Project.

Finally Version 1 implemented a buffered microSD card interface, using devices suitable to convert from 5V to 3.3V (SCK, MOSI, CS), and 3.3V to 5V (MISO) for the SPI interface. This was a correct implementation, but later I removed it because sometimes I’m really too smart for my own good.

Updated - Goldilocks Analogue

Goldilocks Analogue – Version P1

Some significant rework of the analogue section was required for Version 2. Firstly, I decided that audio was a significant use case for the Goldilocks Analogue so it was worth while reducing the cost of the Op Amp, and sharing that expenditure with a special purpose headphone amplifier, working in parallel with the Op Amp.

The TPA6132A2 headphone amplifier was found, and implemented into the prototype. This “DirectPath” device removes the need for large output capacitors in the signal path, as it provides a zero centred output from a single supply voltage.

Version 2 also had a lesser but fully adequate TS922A Op Amp for providing DC to full rate signals, buffering the MCP4822 DAC. I had learned that Op Amps need to be provided with a negative supply rail, if they are to achieve 0V output under load.

To create a negative supply rail for the Version 2 Op Amp, I used a pair of TPS60403 voltage inverters producing -5V from the main power supply, and then fed that signal into a TPS72301 regulator configured to produce -1.186V. This design worked very well, but needed 3 devices to produce the output and also quite a lot of board space.

Finally, for Version 2, I changed the microSD voltage translation to use the TXS0104 (TXB0104) level translation products. These special purpose devices enable the bidirectional transfer of signals over voltage transitions. Normally these two device types (TXB / TXS) work very well, but somehow I couldn’t ever get either version to work properly, which caused the microSD card to never work. This exercise was a failure, and was reverted to normal buffer logic for Version 3.

Goldilocks Analogue Version 2

Goldilocks Analogue – Version P2

Version 3 was supposed to be my final prototype prior to putting this into a crowd funding project. I made some fairly simple changes, and I was pretty happy with the outcome of Version 2 as it was.

Version 3 changed the MCP4822 DAC interface to use the USART1 interface present on the ATmega1284p MCU. Using the USART1 in MSPI Mode allows the DAC to operate independently of the normal SPI bus. This frees up timing constraints on the SPI interface so that slow microSD cards can be read and streamed to the DAC, or SPI graphics interfaces can be used as in the case of the synthesiser demonstration.

As part of the testing, I found that the ATmega1284p would operate successfully at 24.576MHz. This is a magic frequency because it allows an 8 bit timer to reproduce all of the major audio sampling rates related to 48kHz. I’ve tested using this frequency and everything is working fine.

Obviously there was some feature creep over the course of experimentation, so I decided to add two SPI memory device layouts to the PCB. This would allow up to 23LC1024 256kByte of SRAM to be addressed, together with AT25M01 256kByte of EEPROM, for example. Putting these layouts on the board meant that the JTAG interface had to be moved to the back of the PCB. This was actually not a bad thing, as it would have been impossible to use the JTAG interface with a Shield in place anyway.

I was asked to beef up the 3.3V supply capability of the Goldilocks Analogue, so I added a AP1117 device capable of up to 1A supply, upgrading from 150mA.

Goldilocks Analogue Version 3

Goldilocks Analogue – Version P3

Version 4 added the feature of amplified Microphone Input. Using the MAX9814 Mic Amp electret microphones present in the normal headsets used with smart-phones can act as an audio input to the Goldilocks Analogue. The amplified signal is presented on Pin A7, which falls outside of the normal Arduino Uno R3 footprint. For completeness, I also added a level shifted non-amplified signal (for line-in) to Pin A6.

Because of the extra microphone amplifier circuitry, I needed to reduce the footprint of the negative supply rail. So I used a regulated -3V device LTC1983 to produce the negative supply rail required for the Op Amp. There are now 3 regulators on the Goldilocks Analogue, 5V at up to 2.4A, 3.3V at up to 1A, and -3V at 100mA.

Version 4 also saw the last of the through hole components gone. Both the main crystal and the 32kHz clock crystal were reformatted into surface mount technology. This reduces the flexibility of the platform, but it makes manufacturing a bit easier.

Goldilocks Analogue - Version P4

Goldilocks Analogue – Version P4

Version 4 is the end. There will be some minor adjustments to the board for the production version. But, finally, I think this is it.

Unboxing

Prototype 4 back from manufacturing

Prototype 4 back from manufacturing

Errata

There is no power supply jumper provided. Add this to the BOM.

The EEPROM is built with SOIC8 Wide Body, but it should be Narrow Body. Fix the BOM.

Labels for the recommended power supply Voltage are partially obscured by power jack. Move the labels.

The main crystal doesn’t oscillate, because the Eagle library had an incorrect footprint.
Tested to work by rotating the crystal on its existing footprint.

Respecify the main MCU crystal to the Atmel recommended type.

Change C2 and C3 to 15pF in line with Atmel recommendation.

Change C1 and C11 to 12pF in line with Atmel recommendation.

Change R18 to 100kOhm, to bias the Analogue Line in correctly.

Add a simple LC filter to the -3.3V supply, using the known inductor and 10uF capacitor.

Tie Mic Gain to AVcc with a separable link, to produce 40dB default gain. This is the setting required for most normal microphones, so will improve the “out of box” experience for most users.

Testing

Front

Version P4 – Front

Back

Version P4 – Back

Power Supplies

First, looking at power supply noise, we’ve got a slightly better result for noise at the power supply over the Prototype 1. Prototype 1 used the EUP3476 Switched Mode supply device. Problems with obtaining ready supply of this device led to changing it to the AP6503, which is pin compatible but needs slightly different voltage selection resistors. In contrast to the Arduino Uno and other devices, this is very good.

We remember that 1mV represents the Voltage change in the least significant bit of the 12 bit MCP4822. The least significant bit of the ATmega1283p 10 bit ADC is about 4mV. Sampling voltages similar to the noise level inherent on the platform will not generate any further accuracy.

Power Supply GA 4

GA P4: 5V Power Supply Noise

Channel 1 (yellow) is 4.0mV of noise present at the output capacitor for the power supply, and represents the lowest noise inherent in the supply. Channel 2 (blue) is the 5.6mV supply noise present on a test pin closest to the MCU.

The significant improvement in noise level for the GA4 version at the MCU may be due to the currently decreased system clock rate, and therefore is subject to confirmation.

Power Supply GA1

GA P1: 5V Power Supply Noise

Checking the other power supplies on the board, Channel 1 (yellow) is the 3.3V positive supply, provided by a linear regulator. This supply is not used for analogue components, so the 4.3mV noise level is not critical.

Channel 2 (blue) below shows the -3V supply for the Operational Amplifier. This shows a 10mV supply voltage ramp, generated because it is a capacitive charge switching device. This is not particularly good, and it will be worth adding an LC filter to attempt to further smooth this supply, for the production Goldilocks Analogue.

Goldilocks Analogue Prototype 4 - 3.3V & -3V Supply Noise

GA P4: 3.3V & -3V Power Supply Noise

Microphone Input

Microphone amplifier works.

Interestingly, when the amplifier is set to 60dB gain (default setting, Channel 2, blue) it oscillates at 144kHz when not connected to anything, while it doesn’t do this with the normal gain setting of 40dB (Channel 1, yellow) based on the amplification required for typical smartphone headphones. In either case, as soon as the Mic input is grounded, the Mic output reduces to less than 4mVAC on the correct bias of 1.25VDC.

Suggest to make 40dB amplification the default setting for the production Goldilocks Analogue, but allowing the connection to be segmented for increased amplification if required.

GA4 - Mic Oscillation Comparison 60dB and 40dB

GA4 – Mic Oscillation Comparison at 40dB (CH1) and 60dB (CH2) amplification.

Line-In (PA6) seems to be biased at 1.07V rather than 1.25V. Check calculation again… Doh! R18 should be 100kOhm.

Analogue Output

The standard test that I’ve been using throughout the development is to feed in a 43.1Hz Sine wave generated from a 1024 value 16 bit LUT. The sampling rate is 44.1kHz, which is generated by Timer 1 to get the closest match.

The spectra and oscilloscope charts below can be directly compared to the testing done with previous prototype versions of the Goldilocks Analogue.

The below chart shows the sine wave generated at the output of the Op Amp. This is exactly as we would like to see, with no compression of either the 4.096V peak, or the 0V trough.

Goldilocks Analogue – 43Hz Sine Wave – Two Channels – One Channel Inverted

Goldilocks Analogue P4 – 43Hz Sine Wave – Two Channels – One Channel Inverted

Looking at the spectra generated up to 953Hz it is possible to see harmonics from the Sine Wave, and other low frequency noise.

The spectrum produced by the Goldilocks Analogue shows most distortion is below -70dB, and that the noise floor lies below -100dB.

Goldilocks Analogue – 43.1Hz Sine Wave – 953Hz Spectrum

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 953Hz Spectrum

Comparing the same DAC output channel A from Op Amp (Channel 1 – Blue) with the same Headphone Amp Left (Channel 2 – Red), we see slightly more noise carriers.

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 953Hz Spectrum

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 953Hz Spectrum – Headphone in Red

In the spectrum out to 7.6kHz we are looking at the clearly audible range, which is the main use case for the device.

The Goldilocks Analogue has noise carriers out to around 4.5kHz, but they are all below -80dB. After 4.5kHz the only noise remains below -100dB.

Goldilocks Analogue – 43.1Hz Sine Wave – 7.6kHz Spectrum

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 7.6kHz Spectrum

The spectra out to 61kHz should show a noise carrier generated by the reconstruction frequency of 44.1kHz.

The Goldilocks Analogue shows the spectrum maintains is low noise level below -90dB right out to the end of the audible range, and further out to the reconstruction carrier at 44.1kHz.

Goldilocks Analogue – 43.1Hz Sine Wave – 61kHz Spectrum

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 61kHz Spectrum

The final spectrum shows the signal out to 976kHz. We’d normally expect to simply see the noise floor, beyond the 44.1kHz reconstruction carrier noise.

The Goldilocks Analogue has a noise carrier at around 210kHz. Aside from the single carrier mentioned, there is no further noise out to 976kHz.

Goldilocks Analogue – 43.1Hz Sine Wave – 976kHz Spectrum

Goldilocks Analogue P4 – 43.1Hz Sine Wave – 976kHz Spectrum

Analogue output works as specified. It can maintain the 72dB SNR required, of which it should theoretically be capable.

SPI Devices

MicroSD works.

SPI SRAM / EEPROM devices work.

Tests for REWORK

These tests are for the factory rework of the prototype boards.

Check 5V Power Supply

Plug 7-23VDC positive centre into J1.
CHECK: that there is 5VDC available on H15 DC Pin.

GAV4-5VDC

Check 3.3V and -3V Power Supply

Add a jumper to J1 from the centre pin to DC Pin.

CHECK: that 5VDC, 3.3VDC, and -3VDC is available at the test points indicated.

GA4V-Powered

Check for Internal RC Oscillator Function

Connect an AVRISP Mk2 in circuit programmer to the ICSP Socket.

Use the following command to enable the CLKO on PB1, and set other fuses correctly.

avrdude -pm1284p -cavrisp2 -Pusb -u -Ulfuse:w:0x82:m -Uhfuse:w:0xd8:m -Uefuse:w:0xfc:m

CHECK: Using an oscilloscope or counter, check that the CLKO signal on PB1 is between 7MHz and 8.1MHz (nominal value 8MHz).

GAV4-CLKO

Rework 24.576MHz Crystal & Capacitors

Identify Crystal Y2, and capacitors C2 & C3 and C1 & C11.

Screenshot from 2015-10-06 23:21:16

IMPORTANT: Y2 must be ROTATED 90 degrees (either direction) from standard footprint.

Rework Y2 to the 24.576MHz SMD Crystal Digikey 644-1053-1-ND device.

Rework C2 & C3 to 15pF.

Rework C1 & C11 to 12pF.

Check External Crystal Oscillator Function

Connect an AVRISP Mk2 in circuit programmer to the ICSP Socket.

Use the following command to enable the CLKO on PB1, and set other fuses to External Full Swing Oscillator with BOD.

avrdude	-pm1284p -cavrisp2 -Pusb -u -Ulfuse:w:0x97:m -Uhfuse:w:0xd8:m -Uefuse:w:0xfc:m

CHECK: Using an oscilloscope or counter, check that the CLKO signal on PB1 is 24.576MHz.

GAV4-CLKO

Use the following command to disable the CLKO on PB1, and set other fuses to External Full Swing Oscillator with BOD.

avrdude	-pm1284p -cavrisp2 -Pusb -u -Ulfuse:w:0xd7:m -Uhfuse:w:0xd8:m -Uefuse:w:0xfc:m

Rework R18

CHECK: DC voltage on Port A6 (ADC Input 6). Expected value 1.07VDC.

Identify resistor R18. R18 needs to be reworked to 100kOhm.

Screenshot from 2015-10-06 23:21:02

GAV4-Rework

CHECK: DC voltage on Port A6 (ADC Input 6). Confirm the expected value 1.25VDC.

Load Bootloader

Connect an AVRISP Mk2 in circuit programmer to the ICSP Socket.

Use the following command to program a bootloader using the provided HEX file.

avrdude -pm1284p -cavrisp2 -Pusb -Uflash:w:GABootMonitor.hex:a

Connect the Goldilocks Analogue to a USB port and open a serial terminal at 38400 baud to the attached FTDI USB /dev/ttyUSB0 interface.

CHECK: Enter !!! into the serial terminal, immediately following a board RESET (using the RESET button). This will enable the Boot Monitor. These are the boot monitor commands.

Bootloader>
Bootloader>H Help
0=Zero addr (for all commands)
?=CPU stats
@=EEPROM test
B=Blink LED
E=Dump EEPROM
F=Dump FLASH
H=Help
L=List I/O Ports
Q=Quit
R=Dump RAM
V=show interrupt Vectors
Y=Port blink

Bootloader>
Bootloader>? CPU stats
Goldilocks explorer stk500v2
Compiled on = Oct  7 2015
CPU Type    = ATmega1284P
__AVR_ARCH__= 51
GCC Version = 4.8.2
AVR LibC Ver= 1.8.0
CPU ID      = 1E9705
Low fuse    = D7
High fuse   = D8
Ext fuse    = FC
Lock fuse   = FF

Close the serial terminal program (disconnect from the /dev/ttyUSB0 device).

Load Test Program

With the USB interface connected to the Goldilocks Analogue, and the DTR switch in the right most position (closest to DTR text; opposite position to the pictured position).

GAV4-DTR

Use the following command to program a Test Suite using the provided HEX file.

avrdude	-pm1284p -cwiring -P/dev/ttyUSB0 -b38400 -D -v -Uflash:w:GATestSuite.hex:a

Plug a standard smartphone headset (with microphone) with a 3.5mm TRRS connector in LRGM (left, right, ground, mic) configuration into the socket.
CHECK: Sound (echo of input) should be heard from the headphones, when speaking into the microphone.

Connect the Goldilocks Analogue to a USB port and open a serial terminal at 38400 baud to the attached FTDI USB /dev/ttyUSB0 interface.
CHECK: Information on each Task’s stack “Highwater” mark should be seen on the serial terminal.

Goldilocks Analogue – Prototyping 4

Just over 6 months since the third iteration of the Goldilocks Analogue Prototyping was started, and now I’ve finished the design for a forth iteration. The Goldilocks Analogue Prototype 4 design is now finished, and I’m working out what the final bill of materials will cost to assemble into a final outcome. Testing for the Prototype 4 has begun, and everything is working as expected.

The third prototype was completely successful, and produced the improvements I was looking for. The use of the MSPI Mode on USART1 means that two SPI interfaces can be run in parallel, allowing the DAC to hold its tight timing requirements while slower SD card transactions take place (for example). This was proven through the implementation of a direct digital synthesiser, controlled by a SPI controlled touch screen.

Goldilocks Analogue - Prototype 3

Goldilocks Analogue – Prototype 3

Revision for Prototype 4

The Prototype 3 was supposed to be the final version, and it achieved everything that I set out in the original design specifications. But, then there was some feature creep.

Prototype 4 back from manufacturing

Prototype 4 back from manufacturing

In discussing the TRS 3.5mm audio socket, a better more robust TRRS version was found. The realisation that it would be possible to have a microphone input, without requiring additional board space, led me to experiment with the Adafruit breakout board for the MAX9814 Microphone amplifier, and then to build a very simple Walkie-Talkie demonstration to test the use of audio input (with the integrated ADC), simultaneously with audio output (via the DAC).

Once the use of the MAX9814 was proven, I could implement a reference circuit as an input option. The amplified microphone input is connected to Pin 7 of the Analogue Port A. Conveniently, the MAX9814 delivers the amplified signal at +1.25V with a 2V peak to peak signal. This allows the sample to fall into the range of 0V to 2.56V internal reference voltage for the ATmega ADC, providing the maximum sampling resolution with no further adjustments.

The MAX9814 also includes an integrated microphone biasing circuitry, which is designed to support normal electret microphones.

 

As an alternative input functionality, the Prototype 4 also allows for LINE level inputs. I have used a voltage divider to reference the input signal to 1.25V DC. Although a 2V peak to peak Line level input will overload the Microphone amplifier, rendering the output signal on PA7 unusable, the LINE input is routed to Pin 6 on Port A will have exactly the right range to sample using the internal ATmega ADC voltage reference.

Both Port A Pin 6 and Pin 7 are outside of the normal Arduino UNO R3 footprint, so the normal functionality of the UNO footprint is not affected by either the two input options. And if desired, the connection can be separated at a solder-jumper on the rear of the board.

The additional space required for the microphone and line level input circuitry has been created by simplifying the negative supply rail for the Op-Amp. The Op-Amp is provided to support DC to 50k sample per second analogue output. To achieve a linear output from 0v to 4.096V the Op-Amp requires a negative supply voltage. In this revision, I have used a single LTC1983 regulated supply device to provide the negative -3V supply rail. The outcome should be equivalent to the Prototype 3 solution, which used 3 devices.

Board Layout

The final board layout has been completed, and the board is now in discussion for manufacturing.

The GoldilocksAnalogueP4Schematic in PDF format.

Front of board (All Layers)

Front

This is the front of the board showing all of the layers, and the general layout of the devices. The board layout is pretty busy, but still there is sufficient prototyping capability to take all the port pins off-board, or provide on-board breakouts.

GoldilocksAnalogue_TopSilk

Top Layer

This is the Top Layer, which contains all of the devices. There are no devices on the Bottom Layer.

Route 2 (GND) Layer

The Ground Layer on Route 2 is unchanged from previous iterations, and provides a solid platform for low noise analogue circuits.

Route 15 (Vcc) Layer

The Route 15 power supply layer contains all of the supply lines, providing 5V regulated, 5V filtered for analogue AVcc, 3.3V regulated, and -3V regulated.

Bottom Layer

Back

All the pin outs are defined on the Bottom Layer. In addition to the items previously mentioned, there are two small locations where the Line and Microphone inputs can be cut, and allow the full functionality of PA6 and PA7 to be recovered.

Pin Mapping

This the map of the ATmega1284p pins to the Arduino physical platform, and their usage on the Goldilocks Analogue

Arduino
UNO R3
328p Feature 328p Pin 1284p Pin 1284p Feature Comment
Analog 0 PC0 PA0
Analog 1 PC1 PA1
Analog 2 PC2 PA2
Analog 3 PC3 PA3
Analog 4 SDA PC4 PA4 PC1 I2C -> Bridge Pads
Analog 5 SCL PC5 PA5 PC0 I2C -> Bridge Pads
Reset Reset PC6 RESET Separate Pin
Digital 0 RX PD0 PDO RX0
Digital 1 TX PD1 PD1 TX0
Digital 2 INT0 PD2 PD2 INT0 / RX1 USART1
Digital 3 INT1 / PWM2 PD3 PD3 INT1 / TX1 USART1
-> MCP4822 SPI MOSI
Digital 4 PD4 PD4 PWM1 / XCK1 16bit PWM
-> MCP4822 SPI SCK
Digital 5 PWM0 PD5 PD5 PWM1 16bit PWM
Digital 6 PWM0 PD6 PD6 PWM2
Digital 7 PD7 PD7 PWM2
Digital 8 PB0 PB2 INT2 <- _INT/SQW DS3231
Digital 9 PWM1 PB1 PB3 PWM0
Digital 10 _SS / PWM1 PB2 PB4 _SS / PWM0 SPI
Digital 11 MOSI / PWM2 PB3 PB5 MOSI SPI
Digital 12 MISO PB4 PB6 MISO SPI
Digital 13 SCK PB5 PB7 SCK SPI
 (Digital 14 PB0  T0 -> SDCard SPI _SS
 (Digital 15) PB1  T1 -> MCP4822 SPI _SS
SCL PC0 SCL I2C – Separate
SDA PC1 SDA I2C – Separate
PC2 TCK JTAG <- _CARD_DETECT
for uSD Card
PC3 TMS JTAG -> MCP4822 _LDAC
PC4 TDO JTAG -> SRAM SPI _SS
PC5 TDI JTAG -> EEPROM SPI _SS
PC6 TOSC1 <- 32768Hz Crystal
PC7 TOSC2 -> 32768Hz Crystal
XTAL1 PB6
XTAL2 PB7
 (Analog 6) PA6 -> LINE Input
 (Analog 7) PA7 -> MIC Input

Goldilocks Analogue Synthesizer

For the past year, I’ve been prototyping an Arduino clone, the Goldilocks Analogue, which incorporates advanced analogue output capabilities into the design of the original Goldilocks with ATmega1284p AVR MCU and uSD card cage. Recently the design scope crept up to include two SPI memory devices (EEPROM, SRAM, FRAM), and microphone audio input. But, before I go through another prototype cycle, I thought it would be a good idea to build some demonstration applications, showcasing the capabilities of an arduino R3 compatible platform with integrated analogue output and have some fun with audio.

Goldilocks Analogue Prototype 3

Some of the initial tests I’ve built include some 8 bit algorithmic music and, using two Goldilocks Analogue prototype devices, a digital walkie talkie using Xbee radios. They were fun, but don’t really demonstrate the full range of the audio capabilities of the platform.

It seemed appropriate to build a synthesizer using the Goldilocks Analogue as the platform, and a Gameduino 2 shield incorporating a FDTI FT800 EVE GPU, and see how close I could get to a musical outcome.

Research

Before randomly building something that made a bunch of squeaky sounds, I thought the best thing to do is to learn something about the field of analogue synthesizers and synthesizing audio.

I also obtained some simple analogue synthesizers from Korg to see exactly what they produce, so I could copy them. Some people write that this monotron analogue synthesizer family are good examples of a low cost musical instrument. I found it very interesting to examine the wave forms produced by the various settings.

Using the features of the two Korg devices, I was able to define the goal for the synthesizer that I wanted to build using the Goldilocks Analogue.

The Korg monotron DUO has two voltage controlled oscillators (VCO1 and VCO2), which produce square waves. The VCO1 has a pitch setting, which defines the basic frequency at which the ribbon keyboard operates. The ribbon keyboard can be set to have a major scale, a minor scale, a full chromatic scale, or be a ribbon with no set notes. For clarity, the pitch on the DUO is analogue, so there is no guarantee that the notes generated by the ribbon keyboard will be in tune.

The VCO2 pitch can be modified either below or above the pitch of the VCO1. In its middle section, with some care, it can be matched exactly to the VCO1 setting. The switch allows either just the VCO1 or both VCO1 and VCO2 to produce sound. A separate XMOD intensity knob allows the VCO2 to modulate the frequency of the VCO1 oscillator, producing cross-modulation.

The monotron DUO contains the famous Korg MS-20 resonant low pass filter, which can be adjusted for both cut-off frequency and intensity of the resonant frequency. Setting the filter values allows the square wave noise generated by the two oscillators to be shaped into very interesting tones.

The Korg monotron DELAY is a very different device from the DUO. It has two oscillators, but only one at audio frequencies. The audio oscillator produces a saw-tooth wave at a frequency controlled by the ribbon keyboard. On the monotron DELAY there is no capability for playing specific notes as the keyboard is only available in ribbon mode. The second oscillator of the monotron DELAY is a low frequency oscillator (LFO), which can be adjusted from 1Hz up to about 30Hz. This LFO can produce either a triangle wave or a square wave to modulate the main audio oscillator. This is used mainly to apply vibrato to musical tones, or to produce very unusual tone ramps. The intensity and pitch of the LFO are controlled by knobs.

The Korg low pass filter present in the monotron DELAY is only adjustable for its cutoff frequency, so it is less flexible and interesting than the monotron DUO implementation.

The monotron DELAY is really built to showcase the analogue space delay functionality, which can be adjusted in both length of delay, and in intensity of feedback. With about 1 second of delay and 100% or more feedback possible, very short sequences of notes can be played and then built upon.

I’m not particularly musical, but I spent some very pleasant hours playing with the two Korg synthesizers experimenting with the sounds available from their very simple platforms, and used their capabilities to guide me in what to build into my Goldilocks Analogue synthesizer.

The next piece of research was to understand how to generate analogue wave forms using direct digital synthesis, and then how to modify sound of the wave forms using convolution or modulation in the time domain.

Design Specification

Having the two Korg devices as an inspiration, and reading about the original Moog synthesizer capabilities from the 1970’s, made the specification pretty straight forward.

Goldilocks Analogue GUI

The Goldilocks Analogue synthesizer has three oscillators, two of which operate at audio frequencies, being VCO1 and VCO2, and one low frequency oscillator, being LFO. The VCO1 is tuned in octaves at correct concert pitch, so that notes played would be at the right frequency. The VCO2 is pitched relative to the VCO1 pitch, and would range minus one octave to plus one octave (or half the VCO1 frequency to double the VCO1 frequency). The LFO is adjustable over the range from 1 Hz to 40 Hz.

I had decided to let each oscillator take one of two wave forms. For VCO1 I initially chose square wave, and saw tooth wave, to be able to replicate the exact sound of the Korg devices. I’ve since decided to move the saw tooth wave to the VCO2, and replaced it with a sine wave on VCO1. It is good to have the pure tone at the correct frequency for tuning instruments. An A4 from the Goldilocks Analogue Synthesizer will, for example, always be 440Hz.

For VCO2 I selected a triangle wave and a saw tooth wave. And, for the LFO there is a sine wave and a triangle wave available. I should point out that changing the wave form available to each oscillator is no more complicated that replacing the look-up table associated with the setting, and there is space available in the ATmega1284p to store at least another 4 separate wave form tables in flash memory, even without extending to on-board SPI EEPROM, or uSD storage.

In the mixing section the intensity or volume of each of VCO1 and VCO2 can be set. It is possible to turn off either oscillator. The intensity of the LFO effect is controlled too. The LFO modulates both the VCO1 and the VCO2. The final input is the cross modulation of VCO1 by the VCO2. Very interesting tonality is created by modulating VCO1 by pitches very close to its own frequency.

Each note is put through an exponential Attack and Release envelope, to give the note some shape. The mixed signal is then be sent to the voltage controlled filter. Using the current set up, the sample rate is 16,000 samples/second, which is enough to produce 6 octaves. The upper two octaves remain implemented, but are not reconstructed accurately. I have implemented a Biquad IIR filter to enable the output to be high, low, or band pass filtered. The default set up is for low pass filtering. The filter -3dB frequency, and the ringing levels can be adjusted for different musical effect.

Following the filter stage, the signal enters the space delay stage. The space delay stage can have only about half a second of delay, because of the RAM limitations (16kByte) of the ATmega1284p. So up to 6700 16 bit samples are supported by the space delay function. Samples are recovered from the delay buffer, and mixed with the new signals, then injected back into the delay loop. This creates an infinite loop of samples, depending on the amount of feedback set by the FEEDBACK control.

The final signal output level is controlled by a MASTER volume control. Additionally, an EEPROM STO and RCL capability for the settings has been implemented. Only the most recent settings are stored, which can be recalled when power is restored.

As the keyboard notes are generated using a look up table, multiple keyboard tuning options are possible. I have implemented Concert Tuning (A4 = 440Hz) and Equal Temperament (commonly used for pianos), and Verdi or Stradivari tuning (C4 = 256Hz) with Just Intonation Equal Fifths as an alternative. There is a toggle to chose between either these two options. Any tuning can be generated, and then loaded as the note table.

GUI Implementation

The GUI of the solution depends on a Gameduino 2 screen, which is based on the FTDI Chip FT800 EVE GPU device. The FT800 was the first EVE GPU available from FTDI and it can only support single touch. This limitation makes it only partially useful as a product to support this application. The most interesting sounds are generated by bending the controls whilst playing the notes. Fortunately there are newer EVE GPU devices that support multi-touch and they would make a better platform if this synthesizer were to become more than just a demonstration.

The GUI makes extensive use of FT800 co-processor widget capabilities being dials, toggles, keys, and text. Some examples below.

// text
FT_GPU_CoCmd_Text_P(phost, 300,  8, 27, OPT_CENTER, PSTR(&amp;quot;VCF&amp;quot;));
FT_GPU_CoCmd_Text_P(phost, 300, 25, 26, OPT_CENTER, PSTR(&amp;quot;CUTOFF&amp;quot;));
FT_GPU_CoCmd_Text_P(phost, 300, 95, 26, OPT_CENTER, PSTR(&amp;quot;PEAK&amp;quot;));

// toggles
FT_API_Write_CoCmd(TAG(LFO_WAVE));
FT_GPU_CoCmd_Toggle_P(phost, 13,242,46,18, OPT_3D, synth.lfo.wave, PSTR(&amp;quot;SIN&amp;quot; &amp;quot;\xFF&amp;quot; &amp;quot;TRI&amp;quot;));

FT_API_Write_CoCmd(TAG(KBD_TOGGLE));
FT_GPU_CoCmd_Toggle_P(phost, 405,130,60,26, OPT_3D, synth.kbd_toggle, PSTR(&amp;quot;CONCRT&amp;quot; &amp;quot;\xFF&amp;quot; &amp;quot;VERDI&amp;quot;));

// dials
FT_API_Write_CoCmd(TAG(DELAY_FEEDBACK));
FT_GPU_CoCmd_Dial(phost, 365,125,20, OPT_3D, synth.delay_feedback); // DELAY FEEDBACK

FT_API_Write_CoCmd(TAG(MASTER));
FT_GPU_CoCmd_Dial(phost, 440,55,26, OPT_3D, synth.master); // MASTER

The integrated touch tracking capability makes it very easy to parse touch into specific commands.

readTag = FT_GPU_HAL_Rd8(phost, REG_TOUCH_TAG);

if (readTag &amp;gt; 0x80)// tag is greater than 0x80 and therefore is a dial.
{
	TrackRegisterVal.u32 = FT_GPU_HAL_Rd32(phost, REG_TRACKER);

	switch (TrackRegisterVal.touch.tag)
	{
	case (VCO1_PITCH):
		synth.vco1.pitch = TrackRegisterVal.touch.value &amp;amp; 0xe000;
		break;
	// continues...
	}

This integrated touch tracking capability can return which dial (slider / scroll bar) has been touched, and the relative position of the touch. This same position value can then be used in the display command to set the position of the dial (slider / scroll bar), providing direct feedback on the GUI.

The main GUI task simply calls the touch function, and if there is a touch recorded the GUI is updated, and the revised settings entered into the analogue audio control structure. Otherwise if there are no touches recorded there are no processor cycles wasted updating the display. The FT800 EVE GPU continues to display the same content until a new display list is loaded into the GPU memory.

When a keyboard touch is recorded, the tone generation information is updated, and this then directly impacts the output tone generated by the audio section.

//  setting the phase increment for VCO1 is frequency * LUT size / sample rate.
//  &amp;lt;&amp;lt; 1 in SAMPLE_RATE is residual scale to create 24.8 fixed point number.
// The LUT is already pre-scaled &amp;lt;&amp;lt; 7 in the calculation.
// The LUT can't be pre-scaled to &amp;lt;&amp;lt; 8 because this creates numbers too large for uint32_t to hold,
// and we want to allow the option to vary the SAMPLE_RATE at compilation time, so it has to stay in the calculation.
synth.vco1.phase_increment = (uint32_t)pgm_read_dword(synth.note_table_ptr + stop * NOTES + note) / (SAMPLE_RATE &amp;gt;&amp;gt; 1);

// set the VCO2 phase increment to be -1 octave to +1 octave from VCO1, with centre dial frequency identical.
if (synth.vco2.pitch &amp;amp; 0x8000) // upper half dial
	synth.vco2.phase_increment = ((synth.vco1.phase_increment &amp;gt;&amp;gt; 4) * synth.vco2.pitch ) &amp;gt;&amp;gt; 11;
else // lower half dial
	synth.vco2.phase_increment = (synth.vco1.phase_increment &amp;gt;&amp;gt; 1) + (((synth.vco1.phase_increment &amp;gt;&amp;gt; 4) * synth.vco2.pitch) &amp;gt;&amp;gt; 12);

// set the LFO phase increment to be from 0 Hz to 32 Hz.
synth.lfo.phase_increment = ((uint32_t)synth.lfo.pitch * LUT_SIZE / ((uint32_t)SAMPLE_RATE &amp;lt;&amp;lt; 4) );

The phase increment desired, respective to the relevant tone desired, is read from a look up table containing 8 octaves each of 12 notes for VCO1. VCO2 phase increment is then set as a proportion of VCO1. And LFO phase increment is set to range from 0 to around 30 Hz. With this information, and the selected wave form look up table, the audio implementation can do its thing.

Audio Implementation

The synthesizer audio section is implemented in one function, that is executed each time a new sample is generated. This means at 12,000 samples/ second sample generation frequency, we have 83 micro seconds to generate the final sample to be pushed to the Goldilocks Analogue MCP4822 12 bit dual channel DAC.

The current sample generation routine takes under 45 micro seconds to complete with 3 Oscillators running, so there is a little head room still available. With some further coding improvements it was possible to raise the sample frequency to 16,000 samples/sec as the sample generation frequency. The below logic trace shows the main SPI interface (SCK, MISO, MOSI, _SS) delivering commands to the EVE GPU, and the lower MSPI interface (MSPI SCK, MSPI MOSI, MSPI PING) providing the calculated samples, every 83 micro seconds, to the DAC.

Goldilocks Analogue Synthesizer, with 3 Oscillators operating.

Goldilocks Analogue Synthesizer, with 3 Oscillators operating.

It is clear to see that two EVE GPU transactions are being interrupted by the DAC output, but because the main SPI interface is not changing state the transaction is faultlessly resumed once the DAC interrupt is completed.

In contrast, when there are no oscillators running because no key is pressed, the sample generation routine takes just 28 micro seconds to complete. The logic trace below shows the change of state from 0 to 3 oscillators.

Goldilocks Analogue, with no Oscillators operating.

Goldilocks Analogue, with no Oscillators operating.

There is little time available to calculate sample values in real time, so all of the samples are pre-calculated and are stored in look-up tables (LUT). Each LUT contains 4096 16 bit samples, which gives 12 significant bits of accuracy for the values. I chose 4096 samples because the ATmega1284p has sufficient storage to support multiple tables of this size in its flash memory. Smaller LUTs would sacrifice accuracy, and larger LUTs would compromise on the number of available wave forms.

I have prepared LUTs for sine wave, square wave, triangle wave, and saw tooth wave options. Another advantage of the LUT approach is that better bandwidth optimised LUT values can be substituted without changing the code. Also, LUTs allow completely arbitrary waveforms could be used if desired to obtain specific timbre or nuances of sound.

The sample generation code starts with the LFO oscillator using a direct digital synthesis model. Each oscillator sample is calculated identically by stepping through the LUT with a phase increment based on the frequency of the note required, but VCO2 phase increment is modified by the LFO output and the VCO1 phase increment is modified by both VCO2 and LFO outputs.

Code shown here assumes that both LFO and VCO2 output wave forms have already been calculated.

///////////// Now do the VCO1 ////////////////////

// This will be modulated by the VCO2 value (depending on the XMOD intensity),
// and the LFO intensity.
if( synth.vco1.toggle )
{
	// Increment the phase (index into waveform LUT) by the calculated phase increment.
	// Both the phase and phase_increment are stored as 24.8 in uint32_t.
	// The fractional component of the phase and phase_increment is needed to ensure the wave
	// is tracked accurately.
	synth.vco1.phase += synth.vco1.phase_increment;

	// calculate how much the LFO affects the VCO1 phase increment
	if (synth.lfo.toggle)
	{
		// increment the phase (index into LUT) by the calculated phase increment including the LFO output.
		synth.vco1.phase += (uint32_t)outLFO; // increment on the fractional component 8.8, limiting the effect.
	}

	// calculate how much the VCO2 XMOD affects the VCO1 phase increment
	if (synth.vco2.toggle)
	{
		// increment the phase (index into LUT) by the calculated phase increment including the LFO output.
		synth.vco1.phase += (uint32_t)outXMOD; // increment on the fractional component 8.8, limiting the effect.
	}

	// if we've gone over the waveform LUT boundary -&amp;gt; loop back
	synth.vco1.phase &amp;amp;= 0x000fffff; // this is a faster way doing the table
						// wrap around, which is possible
						// because our table is a multiple of 2^n.
						// Remember the lowest byte (0xff) is fractions of LUT steps.
						// The table is 0xfff.ff bytes long.

	currentPhase = (uint16_t)(synth.vco1.phase &amp;gt;&amp;gt; 8); // remove the fractional phase component.

	// get first sample from the defined LUT for VCO1 and store it in temp1
	temp1 = pgm_read_word(synth.vco1.wave_table_ptr + currentPhase);
	++currentPhase; // go to next sample

	currentPhase &amp;amp;= 0x0fff;	// check if we've gone over the boundary.
				// we can do this because it is a multiple of 2^n.

	// get second sample from the LUT for VCO1 and put it in temp2
	temp2 = pgm_read_word(synth.vco1.wave_table_ptr + currentPhase);

	// interpolate between samples
	// multiply each sample by the fractional distance
	// to the actual location value
	frac = (uint8_t)(synth.vco1.phase &amp;amp; 0x000000ff); // fetch the lower 8bits

	// the optimised assembly code Multiply routines come from Open Music Labs.
	MultiSU16X8toH16Round(temp3, temp2, frac);

	// scaled sample 2 is now in temp3, and since we are done with
	// temp2, we can reuse it for the next result
	MultiSU16X8toH16Round(temp2, temp1, 0xff - frac);
	// temp2 now has the scaled sample 1
	temp2 += temp3; // add samples together to get an average
	// our resultant wave is now in temp2

	// set amplitude with volume
	// multiply our wave by the volume value
	MultiSU16X16toH16Round(outVCO1, temp2, synth.vco1.volume);
	// our VCO1 wave is now in outVCO1
}

The next piece of the audio process is to mix the two oscillators VCO1 and VCO2, and then calculate the space delay required. This is where the resonant low pass filter is implemented.

////////////// mix the two oscillators //////////////////
// irrespective of whether a note is playing or not.
// combine the outputs
temp1 = (outVCO1 &amp;gt;&amp;gt; 1) + (outVCO2 &amp;gt;&amp;gt; 1);

///////// Resonant Low Pass Filter here  ///////////////
IIRFilter( &amp;amp;filter, &amp;amp;temp1);

///////// Do the space delay function ///////////////////

// Get the number of buffer items we have, which is the delay.
MultiU16X16toH16Round( buffCount, (uint16_t)(sizeof(int16_t) * DELAY_BUFFER), synth.delay_time);

// Get a sample back from the delay buffer, some time later,
if( ringBuffer_GetCount(&amp;amp;delayBuffer) &amp;gt;= buffCount )
{
	temp0.u8[1] = ringBuffer_Pop(&amp;amp;delayBuffer);
	temp0.u8[0] = ringBuffer_Pop(&amp;amp;delayBuffer);
}
else // or else wait until we have samples available.
{
	temp0.i16 = 0;
}

if (synth.delay_time) // If the delay time is set to be non zero,
{
	// do the space delay function, irrespective of whether a note is playing or not,
	// and combine the output sample with the delayed sample.
	temp1 += temp0.i16;

	// multiply our sample by the feedback value
	MultiSU16X16toH16Round(temp0.i16, temp1, synth.delay_feedback);
}
else
	ringBuffer_Flush(&amp;amp;delayBuffer);	// otherwise flush the buffer if the delay is set to zero.

// and push it into the delay buffer if buffer space is available
if( ringBuffer_GetCount(&amp;amp;delayBuffer) &amp;lt;= buffCount )
{
	ringBuffer_Poke(&amp;amp;delayBuffer, temp0.u8[1]);
	ringBuffer_Poke(&amp;amp;delayBuffer, temp0.u8[0]);
}
// else drop the space delay sample (probably because the delay has been reduced).

////////////// Finally, set the output volume //////////////////
// multiply our wave by the volume value
MultiSU16X16toH16Round(temp2, temp1, synth.master);

// and output wave on both A &amp;amp; B channel, shifted to (+)ve values only because this is what the DAC needs.
*ch_A = *ch_B = temp2 + 0x8000;

This generates the required output waveforms that make the Goldilocks Analogue Synthesiser work.

The second order Biquad IIR filter code has been implemented in a general way, enabling multiple filters to be applied to the sample train. Set up for Low Pass, Band Pass, and for High Pass have been implemented. The coefficients and state variables for each filter are maintained in a structure.

//========================================================
// second order IIR -- &amp;quot;Direct Form I Transposed&amp;quot;
//  a(0)*y(n) = b(0)*x(n) + b(1)*x(n-1) +  b(2)*x(n-2)
//                   - a(1)*y(n-1) -  a(2)*y(n-2)
// assumes a(0) = IIRSCALEFACTOR = 32 (to increase calculation accuracy).

// http://en.wikipedia.org/wiki/Digital_biquad_filter
// https://www.hackster.io/bruceland/dsp-on-8-bit-microcontroller
// http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt

typedef struct {
	uint16_t sample_rate;	// sample rate in Hz
	uint16_t cutoff;	// normalised cutoff frequency, 0-65536. maximum is sample_rate/2
	uint16_t peak;		// normalised Q factor, 0-65536. maximum is Q_MAXIMUM
	int16_t b0,b1,b2,a1,a2;	// Coefficients in 8.8 format
	int16_t xn_1, xn_2;	//IIR state variables
	int16_t yn_1, yn_2;	//IIR state variables
} filter_t;

void setIIRFilterLPF( filter_t *filter ) // Low Pass Filter Setting
{
	if ( !(filter-&amp;gt;sample_rate) )
		filter-&amp;gt;sample_rate = SAMPLE_RATE;

	if ( !(filter-&amp;gt;cutoff) )
		filter-&amp;gt;cutoff = UINT16_MAX &amp;gt;&amp;gt; 1; // 1/4 of sample rate = filter-&amp;gt;sample_rate&amp;gt;&amp;gt;2

	if ( !(filter-&amp;gt;peak) )
		filter-&amp;gt;peak =  (uint16_t)(M_SQRT1_2 * UINT16_MAX / Q_MAXIMUM); // 1/sqrt(2) effectively

	double frequency = ((double)filter-&amp;gt;cutoff * (filter-&amp;gt;sample_rate&amp;gt;&amp;gt;)) / UINT16_MAX;
	double q = (double)filter-&amp;gt;peak * Q_MAXIMUM / UINT16_MAX;
	double w0 = (2.0 * M_PI * frequency) / filter-&amp;gt;sample_rate;
	double sinW0 = sin(w0);
	double cosW0 = cos(w0);
	double alpha = sinW0 / (q * 2.0f);
	double scale = IIRSCALEFACTOR / (1 + alpha); // a0 = 1 + alpha

	filter-&amp;gt;b0	= \
	filter-&amp;gt;b2	= float2int( ((1.0 - cosW0) / 2.0) * scale );
	filter-&amp;gt;b1	= float2int(  (1.0 - cosW0) * scale );

	filter-&amp;gt;a1	= float2int( (-2.0 * cosW0) * scale );
	filter-&amp;gt;a2	= float2int( (1.0 - alpha) * scale );
}

// interim values in 24.8 format
// returns y(n) in place of x(n)
void IIRFilter( filter_t *filter, int16_t * xn )
{
	int32_t yn;	// current output
	int32_t  accum;	// temporary accumulator

	// sum the 5 terms of the biquad IIR filter
	// and update the state variables
	// as soon as possible
	MultiS16X16to32(yn,filter-&amp;gt;xn_2,filter-&amp;gt;b2);
	filter-&amp;gt;xn_2 = filter-&amp;gt;xn_1;

	MultiS16X16to32(accum,filter-&amp;gt;xn_1,filter-&amp;gt;b1);
	yn += accum;
	filter-&amp;gt;xn_1 = *xn;

	MultiS16X16to32(accum,*xn,filter-&amp;gt;b0);
	yn += accum;

	MultiS16X16to32(accum,filter-&amp;gt;yn_2,filter-&amp;gt;a2);
	yn -= accum;
	filter-&amp;gt;yn_2 = filter-&amp;gt;yn_1;

	MultiS16X16to32(accum,filter-&amp;gt;yn_1,filter-&amp;gt;a1);
	yn -= accum;

	filter-&amp;gt;yn_1 = yn &amp;gt;&amp;gt; (IIRSCALEFACTORSHIFT + 8); // divide by a(0) = 32 &amp;amp; shift to 16.0 bit outcome from 24.8 interim steps

	*xn = filter-&amp;gt;yn_1; // being 16 bit yn, so that's what we return.
}

Hardware Implementation

I sell on Tindie

The Goldilocks Analogue Prototype 3 is working very well, and it has resolved some of the issues of the second prototype. Using the USART1 MSPIM mode to drive the MCP4822 DAC allows the GUI to use the SPI bus for the Gameduino 2 GUI without conflicts. This is the only way that the rigorous timing for audio output can be maintained, given the heavy SPI usage required to drive the GPU co-processor.

Goldilocks Analogue - Prototype 3

The Atmel AVR ATmega1284p in the Goldilocks Analogue Prototype 3 is running at 24.576MHz. This is significantly above the specification (20MHz at 5V), but remembering that the specification for AVR ATmega devices covers an extended temperature range (that would kill a human) and it is unlikely that the Goldilocks Analogue would be used in extreme temperature situations, I’ve had no problems with this processor frequency to date.

There are two reasons for over-clocking the ATmega1284p. The first is that it is simply not possible to make the required calculations within the time budget available at the maximum specification CPU frequency of 20MHz or even more extreme at the standard Arduino rate of 16MHz.

The second reason is related to the generation of exact audio sampling frequencies. With a CPU clock of 24.576MHz, the 8 bit timer with pre-scaling can generate EXACT audio sample timing at 8kHz, 12kHz, 16kHz, 32kHz, and 48kHz. Using a 16 bit timer, we can also generate very close approximations to 44.1kHz, if required.

The routine to transfer samples does not need to consume precious 16 bit timer resources, which are useful to produce PWM for motor control. Retaining the capability to manage two motors (using the two 16 bit timers) is fairly important outcome.

The interrupt for generating the wave forms does only two things; write the sample values to the DAC, and then calculate the new sample value for the next sample time. The samples are written to the DAC first to ensure that the output is not jittered by the possibility of variable processing time in the audio handler routine. This can happen if (for example) one of the VCO is turned off, removing the sample calculation code from the code execution path.

ISR(TIMER0_COMPA_vect) __attribute__ ((hot, flatten));
ISR(TIMER0_COMPA_vect)
{
	// MCP4822 data transfer routine
	// move data to the MCP4822 - done first for regularity (reduced jitter).
	// &amp;amp;'s are necessary on data_in variables
	DAC_out (ch_A_ptr, ch_B_ptr);

	// audio processing routine - do whatever processing on input is required - prepare output for next sample.
	// Fire the global audio handler, if set.
	if (audioHandler!=NULL)
		audioHandler(ch_A_ptr, ch_B_ptr);
}

Goldilocks Analogue – Prototyping 2

Introduction

Following my initial design article, and the testing article, I’ve put quite a lot of thought into how I can make this Goldilocks Analogue device best achieve my stated goals. Pictured is the only Goldilocks Analogue Prototype in existence.

Goldilocks Analogue - Top Left

Goldilocks Analogue Prototype – Analogue section front of image.

From the testing it was clear that the MCP4822 DAC fully achieved the goals that I had set out to achieve, but that my design for the analogue buffer stage behind it was really quite bad. Fixing it was going to take some thought.

I have decided to separate the analogue output stage into two sections. An AC section which drives the headphone socket, with a designed for purpose headphone amplifier device, and a DC section using a high current rail to rail OpAmp and a negative 1.18V supply rail to allow the OpAmp to fully reach GND or the equivalent 0x000 digital input.

I also found a better solution for the uSD level translation. There is a device designed for purpose, which I’ve now designed into the Goldilocks Analogue.

DAC – MCP4822

The selected dual DAC uses the SPI bus to write 12 bit values to each of its channels. The increments are either 1mV or 0.5mV giving full scale at DC 4.096V or 2.048V depending which scale factor is being used. The testing showed that the DAC is capable of achieving close to the 72dB of SNR that is its theoretical capability.

DAC 43Hz Sine - 7k6Hz

So from my point of view the DAC, and the AVcc filtering system employed to provide a clean analogue power rail, have achieved their design goal. Let’s not change anything.

Headphone (AC) Output – TPA6132A2

Driving a headphone socket with a nominal impedance of 32 ohm is a hard job for an OpAmp, and they are not designed specifically for this job. Therefore, I thought it would be best to separate the two outputs into two separate full-time output devices, specialised for their purposes (AC headphones, and DC PID or general pin-out).  Both Goldilocks Analogue output options are driven simultaneously, and they will not interfere with each other.

GoldilocksAnalogueDACAmplifiers

For the AC and headphone output, using a specific single ended “DirectPath” headphone amplifier device enabled me to remove the large output coupling capacitors but still achieve a good low frequency output response.

The TPA6132A2 is capable of driving 25 mW into 16 ohm headphones. Its amplifier architecture operates from a single supply voltage and uses an internal charge pump to generate a negative supply rail for the headphone amplifier. The output voltages are centred around 0 V and are capable of positive and negative voltage swings. This means that the TPA6132A2 doesn’t need output blocking capacitors, and therefore can achieve a very good low-frequency fidelity. Using the 1 uF input capacitors stops any turn-on pop or noise, and achieves a low frequency corner below 10 Hz.

As the DAC outputs a signal with up to 4 V peak to peak, I have set the gain on the TPA6132A2 to -6dB. This should result in the full range of the headphone signal being 1 V peak to peak, with approximately 25 mW being delivered into 32 ohm headphones.

The TPA6132 also has a very high power supply an RF noise rejection ratio. Although I’ve gone to a lot of effort to filter the AVcc power supply, the power supply noise generated was still significant. Having over 90 dB PSRR will help to keep the output quiet.

Analogue (DC) Output – TS922A

I originally selected a highly regarded audiophile OpAmp for use in the Goldilocks Analogue. That device was incapable of operating close to its GND rail, and caused significant distortion in the output signal. Based on that experience, I decided to use a rail-to-rail output OpAmp to provide the DC buffered signal.

Even though rail-to-rail OpAmp devices are sold as full Vcc to Vss outputs, under high current loading they all have significant output droop. The only way to avoid this is to avoid driving the (any) OpAmp close to its supply rails.

The positive rail is ok. The supply voltage is a well regulated 5 V DC, and the maximum voltage required from the OpAmp is 4.096 V which is 0xFFF input to the DAC. It is the Ground Rail, which causes the issue, as the OpAmp will be unable to deliver the analogue equivalent 0x000 under high current situations.

The only way to get an OpAmp to deliver a solid GND potential output, is to supply it with a negative supply voltage Vss.  Getting a Vss rail is described below.

The TS922A device is designed for high current rail-to-rail outputs, and is specified to work into 32 ohm headphones, 75 ohm video, and 600 ohm inputs. This DC coupled output can be used to drive PID, Triac or any other application requiring a precise analogue signal up to around 50 kHz.

OpAmp Vss (negative) rail

The TS922A can support over 50 mA per channel output, but at this current its output resistance has dropped its ability to reach both rails to greater than 300 mV. Specifically, it can only reach between 0.3 V and 4.4 V. Therefore to enable the output signal to reach GND potential, we have to generate a Vss  with greater than -0.3 V, and capable of supplying in excess of 100 mA (over OpAmp both channels).

I looked at a number of options for charge coupled devices, and decided that the cheapest and best way was to use two paralleled TPS60403 devices to each generate -5 V 60 mA from the 5V power rail. These devices don’t filter their output, but since we are not going to use the -5 V directly, this doesn’t matter.

GoldilocksAnalogueVccNegative

Following the generation of the -5 V supply, I’ve decided on a TPS72301 variable voltage 200 mA linear regulator, configured to generate its reference voltage -1.186 V, to provide a regulated Vss. Using the internal reference voltage saves a few resistors, and it still generates sufficient negative voltage to enable the OpAmp to easily reach true GND potential.

uSD Card Level Translation – TXS0104

Some further analysis of the voltage translation application revealed that the TXS0104 is designed to exactly suit the purpose of interfacing SPI bus at up to 24 MHz. As a side benefit it is a much smaller package, which recovers prototyping space back to the original Goldilocks benchmark. It is also cheaper than the general purpose OpAmps previously used.

Initially, the prototype used the TXB0104 device, but it was unsuccessful. The 4kOhm output resistance combined with less than optimal uSD card characteristics meant that the design failed. The TXB series cannot drive anything with pull-up or pull-down greater than 50kOhm. The uSD card is specified to have 10kOhm to 100kOhm integrated pull-up resistors, but in practice they all seem to be around 10kOhm. The schematic below will be updated to show TXS shortly.

GoldilocksAnalogueTranslate

The PCB Layout

The board layout has been completed, and a PCB ordered to this design.

More detail soon.

GoldilocksAnalogue

Top Signal Layer
GoldilocksAnalogueTopRatsnest

GND Signal Layer
GoldilocksAnalogueRoute2Ratsnest

5V Signal Layer
GoldilocksAnalogueRoute15Ratsnest

Bottom Signal Layer
GoldilocksAnalogueBottomRatsnest

 

 

As of June 2014, I’ve now got all the parts, and the PCB ready for a new prototype. This new version was  constructed late July 2014 and is awaiting basic testing.

Version 2 of the prototype

Version 2 of the prototype, fresh out of the oven.

 

As of August 2014, I have started testing. So far the analogue design seems to check out, with both the headphone (AC biased) circuitry and the OpAmp (DC biased) circuitry performing as intended. More testing soon, and a new post.

Goldilocks Analogue demonstrating a clean DC biased sign wave (to 0V) .

Goldilocks Analogue demonstrating a clean DC biased sign wave (to 0V) .

The spectrum at the output of the TS922A OpAmp is cleaner now than directly at the MCP4822 DAC output of the previous prototype iteration.

The nominal 12 bit DAC capabilities are able to achieve 72dB SNR. Target achieved.

Spectrum at the output of the OpAmp.

Spectrum at the output of the OpAmp.

Goldilocks Analogue – Testing

Introduction

This post follows on from the and gives some insight into the results of the first board prototype board assembled.

Updated - Goldilocks Analogue

Updated – Goldilocks Analogue

The information will develop over the next few weeks, as I add more information and test results.

I’ve built a new Goldilocks Analogue design and I have described the changes and additions.

Discussion

Well I’ve had my  Goldilocks Analogue on my desk now for a few nights, and I’m very impressed that it seems to generally meet the specification that was intended.

The code for setting the DAC levels is currently only optimised for setting two values at a time. Specifically, it is not a streaming function. Never-the-less, it is possible to achieve the stated goal for both DAC channels. The actual number achieved is 108 kSamples/second, shown below, or 18.8us to transmit 2 samples on 2 channels.

I’ve been testing the Goldilocks Analogue DAC stage and found (what I should have known) that I needed an output buffer op-amp able to do negative rail (0V) input and output to support the MCP4822 0v to 4.095V ranging DAC, so I’m going to order some soon.

Unfortunately the OPA4350 (rail to rail high current), at over $10 each, is nearly as expensive as the audiophile OPA4132 I specified previously.

There seems to be a pin compatible alternative, the TS924A, which is about $2 each, but several orders of magnitude worse in performance.

For Example: OPA4350 vs TS924A
Gain Bandwidth Product: 38MHz vs 4MHz
Slew Rate: 22V/μs vs 1.3V/μs
Total Harmonic Distortion: 0.0006% vs 0.005%

Is it worth the difference, when working with a 12 bit DAC in the presence of mV of power supply noise? I’ll revisit this with the next design notes.

How about 5V?

To build an effective DAC I’ve learned that we need to have an effective quiet 5V power supply, with as little noise as possible. To put this into context, the 12 bit MCP4822 generates a 1mV per level difference. I noticed there is quite a few mV of noise on the 5V supply of the Goldilocks Analogue. Not what I was hoping to see, so I’ve gone back to see how that compares with predecessors.

All measurements are taken with a 100MHz Rigol DS1102E, with 150MHz probes grounded onto the USB socket of each board respectively. The probes are directly on the regulator output capacitor, which should be the quietest point on the board, and then directly off Vcc on the MCU for the DIL boards, or a nearby test point for the SMD boards.

First stop is a reference design Arduino Uno R2 board. As a starting point the Uno shows 16mV on the power supply, and 35mV on the MCU. Let’s see how some other boards compare.

Arduino_Uno

Arduino Uno

The Freetronics Eleven board also uses a linear regulator, similar (if not identical to) the Arduino Uno. However the capacitor arrangement must be somewhat more effective because the noise present on the output capacitor is less than 6mV. This is significantly better than on the Arduino Uno, and even measured against the Vcc pin the supply noise remains significantly lower than the Uno.

This Freetronics Eleven board was running at 22.1184MHz rather than the standard Arduino speed, but that doesn’t seem to affect the result.

Freetronics_Eleven

Freetronics Eleven

Next up is the Seeed Studio ADK boards is an ATmega2560 board running at 16MHz, which also uses a linear regulator. The ADK board exhibits the same quiet supply found in the Freetronics Eleven, and has very similar characteristics on the Vcc test point as well.

Seeed_ADK

Seeed Studio ADK

The Goldilocks v1.1 resulting from the Pozible project is my true point of reference. I hope to be able to do slightly better than this board, by better layout of the same SMPS circuit that is used across all of the Freetronics range of products.

In measurement, the Goldilocks v1.1 sets a very high standard to surpass. Even though there is a 500kHz SMPS running in the supply, the Vcc supply capacitor shows very low noise of only 5.29mV, and the Vcc noise on the test point is only 12.0mV.

GoldilocksV1

Goldilocks V1.1

The Goldilocks Analogue Prototype 1 uses the same SMPS circuit present across the entire range of Freetronics boards, but using an optimised (for this application) layout. Shorter internal tracks should result in slightly faster smoothing, and better regulation, although the effect at normal currents would be minimal.

In comparison with the  Goldilocks v1.1, there seems to be slightly less noise at the supply capacitor with less than 5mV showing, although this effect is marginal. The noise on the Vcc line seems to be similar.

Goldilocks_Analogue

Goldilocks Analogue Prototype 1

SMPS

Having looked at the power supplies at rest, and built a baseline of what to expect, here are some screenshots of the Goldilocks SMPS under load. Port D is being switched from 0x00 to 0xFF at 30kHz. The first screenshot shows one of the Port D pins on channel 1, and the Vcc (5V) line at the supply capacitor on channel 2. Note that there is 24mV of noise on the Vcc supply capacitor, even without drawing much current.

GoldilocksAnalogue_NoLoad_Vcc

This second screenshot shows the same set up, but with 8 LEDs being driven off the Port D. Channel 2 shows the variation in supply capacitor Vcc under the increased load.

GoldilocksAnalogue_8LED_Vcc_Macro

So the big question is whether the new layout of the SMPS has achieved anything. Well, based on this simple test, it would seem to have generated a fairly significant improvement.

The below two screenshots shows the trailing edge of the 8 LED power load being switched off. Note that on the supply Vcc there is some oscillation and instability as the SMPS recovers from the load reduction.

This first screenshot shows the Goldilocks V1.1 situation, with a ripple of 832mV peak to peak.

GoldilocksV1_8LED_Vcc_Micro

With the Goldilocks Analogue, the peak to peak ripple is reduced to under 600mV, which is a 25% improvement in this situation.

GoldilocksAnalogue_8LED_Vcc

Sine Waves

I’m using my new Red Pitaya to analyse the output of the Goldilocks Analogue output state, with a 43.066Hz Sine wave (1024 samples played out at 44.1kHz) as the input to the DAC.

MCP4822 DAC

This shows the sine wave generated at the output of the low pass filter (23kHz -3dB single pole design). This is almost exactly as we would like to see.
Post Filter 43Hz Sine - Oscilloscope
Looking at the lower segment of the sine wave below and the image above, it is almost perfect to 0V and to 4.096V peak to peak.
Post Filter 43Hz Sine - Oscilloscope Segment
Looking at this sine wave on the spectrum analyser across the band up to 7.6kHz, we can see the noise floor is 70dB down from the signal exiting the DAC. It seems the DAC performs as advertised.
DAC 43Hz Sine - 7k6Hz
Looking across the band to 61kHz, we can see the peak at -70dbm from the 44.1kHz sampling noise. Unfortunately, the single pole filter doesn’t do much to suppress this noise source.
DAC 43Hz Sine - 61kHz
To get an idea of whether the 23kHz filter is working as expected, we need to look out to the 976kHz band. The next two images contract the signal before and after the Filter.
DAC 43Hz Sine - 976kHz

The lower image shows that noise peaks out to 200kHz have been properly suppressed, so the filter is working but it is too slow to hit the 41kHz noise.

Post Filter 43Hz Sine - 976kHz

Op Amps

The Op Amp selection was a mistake. Rather than thinking about the application correctly, I simply sought out the best “musical” Op Amp. The audiophile OPA4132 is absolutely not the right tool for this job. And these images show why.

Driving into a 1kOhm resistance, the output of the OPA4132 is shaved off as the op amp output amplifier saturates as it approaches the 0V rail (or Ground rail). The top of the waveform is OK, as we are still 1V from the Vcc rail. Under higher loading, such as headphones at 32Ohm, the signal is worse, much worse.

OpAmp 43Hz Sine - 1kOhm - Oscilloscope

Looking at this (initially as an open circuit) view and then with the 1kOhm loading imposed, we can see the difficulty the op amp has with the signal.

OpAmp 43Hz Sine OpenCircuit - 953Hz

The noise peaks (created by the flattening of the sine wave) are at least 10dB greater under a small load. As the load increases the situation gets worse.

OpAmp 43Hz Sine 1kOhm - 953Hz

OpAmp 43Hz Sine 1kOhm - 7k6Hz

OpAmp 43Hz Sine 1kOhm - 61kHz

To fix this issue, I will need to use a rail to rail high current op amp, and also make sure that I create a small negative rail (-o.23V using a LM7705) to allow the op amp to reach 0V effectively.

Amongst the Burr Brown range the best alternative seems to be the OPA2353, which can support almost 40mA of current, and can effectively drive 75Ohm loads. Unfortunately the OPA2353 (rail to rail high current) costs about $6 each,

There seems to be a pin compatible alternative, the TS922A, which is about $2 each, but several orders of magnitude worse in performance. However, it can supply 80mA and effectively drive 32Ohm headphones.

For Example: OPA2353 vs TS922A
Gain Bandwidth Product: 44MHz vs 4MHz
Slew Rate: 22V/μs vs 1.3V/μs
Total Harmonic Distortion: 0.0006% vs 0.005%

Errata

Reset button can be moved closer to the edge.

AVcc supply capacitors are too close together, and need to have bigger pads.

Use the DAC out header spare pin to pin-out the AVcc, for testing or use on prototyping area.

AVcc inductor is not correct footprint (device much larger).

AVcc ferrite bead is not correct footprint (device much smaller).

Remove analogue potentiometers, unnecessary as DAC is extraordinarily accurate.

Put pin-out on DC output, and headphone socket on AC output 100uF capacitors.

Replace Analogue Op Am with LM7705 and TS922A. This generates 0V to 4.096V required to properly buffer the MCP4822 DAC. LM7705 can’t sustain 80mA, but for small DC signals (up to 20mA) we will have accurate buffering of the DAC, and for headphones, it is an analogue signal anyway.

Replace uSD Op Amps with TXB0104, more suitable for the purpose.

These errata have been addressed in the new Goldilocks Analogue design and I have described the changes and additions.

Goldilocks Analogue – Prototyping

Last time I designed a Goldilocks board, it was because I was unhappy about the availability of a development platform that was within my reach; a tool to enable me to continue to learn about coding for micro-controllers.

This Goldilocks, let us call it Goldilocks Analogue, it is not about what I think is necessary, but more about what I’d like to have. The focus is not so much about the basics of SRAM and Flash, but much more on what functions I would like to have, and using my own means to get there.

Also, as the original Goldilocks is sold out, Freetronics are considering making their own version. Please add your wishes here.

Test results are in. Check out the detailed post on Goldilocks Analogue – Testing. Following the testing, I’ve redesigned the analogue output section to make it much more capable. It now support simultaneous AC and DC outputs, with an application specific headphone amplifier device to provide AC output, and high current OpAmp to provide DC output.

The Goldilocks Analogue Prototype 4 has been designed, and is now being produced.

Background

The Goldilocks Project was specifically about getting the ATmega1284p MCU onto a format equivalent to the Arduino Uno R3. The main goal was to get more SRAM and Flash memory into the same physical footprint used by traditional Arduino (pre-R3) and latest release Uno R3 shields.

Goldilocks Arduino 1284p

Original – Goldilocks Version 1.1

I also tried to optimally use the co-processor ATmega32U2, (mis)utilised by Arduino purely for the USB-Serial functionality, by breaking out its pins, and creating a cross-connect between the two MCU to enable them to communicate via the SPI bus.

Whilst the Goldilocks achieved what it set out to do, there were some problems it created for itself.

Firstly, the ATmega family of devices is really very bad a generating correct USART baud rates when their main frequency doesn’t match a multiple of the standard USART rates. Engineers in the know select one of these primary clock rates (for example 14.7456MHz, 18.432MHz, or 22.1184MHz) when they’re planning on doing any real Serial communications. Unfortunately, the 16MHz clock rate chosen by the Arduino team generates about the worst USART timing errors possible.

This means that the Arduino devices can only work at 16MHz while programming them with the Serial Bootloader, otherwise programming is bound to fail, due to losing a bit or two due to the clock rate error.

Arduino had serial programming completely solved in the old days by using a real USB-USART chip, the FTDI FT232R, but for some reason they stopped doing the right thing. This might have been the perfect solution, but they abandoned it. Who knows why…

Secondly, although having an integrated uSD card cage on the platform is a great thing, using a resistor chain to do the voltage conversion is nominally a bit problematic. The output pins (SCK, MOSI, CS) are permanently loaded by 3k2 Ohm and an input pin (MISO) high signal generates only 0.66 of Vcc, which only just clears the minimum ATmega signal high level of 0.6 Vcc. Neither of these issues prevent the uSD card from working, and the voltage divider resistor chain takes almost no space on the board. But still it is not perfect.

Thirdly, there are some minor oversights in the V1 build that I would like to correct if possible.

New Directions

I’ve been toying with the idea of building an Xmega board, in Arduino Uno R3 format, because of the significantly enhanced I/O capabilities of this MCU including true DAC capabilities, but I’ve not followed up for two reasons; the Xmega has no history of use by hobbyists as there is with the ATmega devices, and it doesn’t bring any advantage that an ARM MCU wouldn’t otherwise do better and faster.

Never the less, the ATmega platform still lacks one thing that I believe is necessary; a high quality analogue capability. The world is analogue, and having an ADC capability, without having a corresponding DAC capability, is like having a real world recorder with no means to playback these real world recordings.

A major initiative of the Goldilocks is to bring an analogue capability to the Arduino platform. So this device will be called the Goldilocks Analogue.

Updated - Goldilocks Analogue

Updated – Goldilocks Analogue

There have been music shields and audio shields built before, and the design used is closely aligned to the original Adafruit Wave Shield, but I’ve not seen dual high quality DACs with both AC and DC capability, integrated onto the main board of an Arduino previously. So that’s where I’m going.

The goal is to be able to produce a DC referenced signal, from 0Hz up to around 100kHz, that can provide a binary-linear representative voltage (with sufficient current) to enable a control system, as well as to produce the highest quality audio, with very low noise and THD buffer amplifiers, that the basic AVR platform is capable of producing.

Using Eagle

I used to look at Eagle (Kicad, etc) with healthy scepticism. Yeah, not something that I’d be able to learn, but in the process of realising the Goldilocks Analogue, I have learned that it is far easier to learn a new skill than it is to guide someone in India or Malaysia, who doesn’t even get the start of what I want. The old idiom, if you want something done right, you’ve got to do it yourself.

There is a “Fremium” version of Eagle available, which is enough to get started. I’m going to try to get a “Hobbyist” version as soon as the paperwork is through.

So all this below is my first Eagle project.

The Schematic

I’ll talk through each item in the schematic, particularly those things which are novel in the Goldilocks Analogue. The schematics for the Goldilocks V1 can be found in the User Manual.

FT232R

The FT232R is the same device used in countless earlier Arduinos, such as the Duemilanove, and in USB-Serial adapters everywhere. The drivers for all major operating systems are widespread and there is no magic required. Importantly, the FT232R chip generates a real USART baud rate, at any speed from 300 baud to 3 Mbaud.

Unlike in the Duemilanove I’m using the FT232RQ chip, which is in the QFN package. There is too much going on to take up the board space with the larger package.

FT232RQ - Goldilocks Analogue

I’ve added a switch to disable the DTR Reset functionality of the Arduino and Wiring Bootloaders. Often, I would like a running device NOT to be reset by plugging the USB cable, but then I’ll be using the Goldilocks in another thing where I do want this to happen. Having a switch, like Seeed often do, is the best answer.

Also, I’ve added a 6 pin connector replicating the standard FTDI pin-out, to enable the FT232RQ to communicate with other devices, should this be necessary. It would be a shame to lock it into the board, with no option for extension.

uSD Buffer

In designing the buffer for the uSD, I was trying to achieve two things. Firstly, isolate the uSD card entirely from the SPI bus when it was not in use. By isolate, I mean over 1MOhm resistance. This isolation ensures that the uSD card doesn’t load up the SPI pins at all, when the uSD is not being used.

Secondly, I was trying to ensure that each end of the SPI bus receives the correct voltages and currents to ensure maximum throughput.

uSD Buffer - Goldilocks Analogue

The two devices selected achieve both goals as desired.

For the MCU to uSD direction (SCK, MOSI, and CS) I’m using a 74LVC125 in quad package. This package is tolerant of inputs at 5V rising above its Vcc of 3V3. The output enable on low, is connected to the Chip Select line, which means that the uSD card will not be driven unless the CS line is low. It always presents a high impedance to the MCU.

As a quad package the 74LVC125 has one spare gate, which can be used to drive the Arduino LED. This is neat no cost result that entirely removes any loading on Arduino Pin13.

For the uSD to MCU direction the buffer has to effectively produce a 5v CMOS high when receiving a 3V3 CMOS high. The best way to do this is to use a device that is TTL signal compatible. The TTL minimum high signal is only 2V, much lower than the CMOS minimum high signal of 2/3 of Vcc, and importantly below the worst case of 2/3 of 3V3 CMOS.

The only device I could find with the required characteristic of accepting TTL inputs with a low output enable, is the MC74VHC1GT125. I’m sure there are other options though.

DAC and Buffer

This is the fun stuff. Analogue… the real world. As noted above, the goal is to produce two binary-linear signals with enough buffering that they can drive a reasonable load (such as small headphones or an audio amplifier) and produce a constant voltage under a number of power supply options.

The inspiration for the circuit came from the Adafruit Wave Shield, but there are a number of significant improvements that are worth noting, not least the use of a dual DAC, for two channels of output.

DAC and Buffer - Goldilocks Analogue

Firstly, if you want to get a very low noise output, whilst using a high current Switch Mode Power Supply, it is necessary to filter the supply voltage. I’ve utilised the dual steps of an L-C primary filter, followed by a ferrite core bead secondary filter. I’m not sure whether this is all necessary, and I’ll be testing the circuit later with various components removed to check their efficacy in the role, but if they’re not designed in now they never will be added later.

I’m using the Microchip MCP4822 DAC to produce the raw output voltage. This is an SPI device which will be selected using the other “spare” Goldilocks digital pin PB1. Using PB1 to signal the DAC means that none of the Arduino R3 pins are used for on-board Goldilocks functions, and as both CS lines (PB0 and PB1) are tied high they will ensure that all these on-board devices stay off the SPI bus during system reboot.

The MCP4822 takes 16 bits to set a signal level, this is two SPI bus transactions. The maximum SPI rate is SCK/2. Therefore, if my Goldilocks is doing nothing else, it can generate 691,200 SPI transactions per second. If both DACs are being driven we can generate a square wave of 172,800Hz. This is an unreachable figure. More likely, the best case will be around 50kHz for both channels, or 100kHz if only one DAC is being used.

Optionally, the LDAC pin-out can be used to synchronise the transfer of digital inputs to the analogue output buffers across the two DACs or to a specific clock with low jitter.

Unlike the Adafruit solution, the MCP4822 generates its own internal 4.096V reference voltage Vref. This means that irrespective of whether the Goldilocks Analogue is being powered by a battery, by USB, or by the barrel connector and the SMPS, the output voltage for a particular digital input will be constant.

The op-amp configuration with dual op-amps, in a quad package, designed to double the current capability of the output, has raised concern from all who see it. Concern was my initial thought too. However after some research, I found it to be a recommended configuration for current doubling. The only difference to the Adafruit example circuit is to add low value output resistors which allow each op-amp to find its own offset level without consuming excess current.

I have added the option to bridge the output capacitors to provide a DC output. The output capacitors are necessary for audio use, as headphones or audio amplifier inputs require an AC connection, with no DC offset.

The Layout

It takes many hours to layout even a small board the size of an Arduino Uno. Luckily, I had a completed and fully functioning example to use as a platform, thanks to Jon’s prior work on Goldilocks V1.

The final prototype board layout is now done, and the board design sent off for manufacturing.

Goldilocks Analogue BoardIn this layout, I’ve been able to retain most of what makes a Goldilocks; the ATmega1284p, the complete dual rows of header pins arranged in pin-logical order 0-7, bridging of the I2C pins to A4/A5, JTAG, and a high current power supply. Added to this now are the three items described above; the FT232RQ and Reset switch, buffers for the uSD card, and the analogue platform.

Starting in the bottom left, the SMPS has been relaid to significantly shorten the high current paths around pins 2, 3, and 4. This will reduce the circuit noise, and taken togther with the effort to create solid ground planes, and specific AVcc filtering, will help to ensure the minimum of power supply noise in the analogue platform.

On the right we can see the uSD buffers, which have eaten into the prototyping space significantly. Although the signals will be much nicer than with a resistor bridge, the cost is clearly on space. If the Goldilocks Analogue ever goes into production the SOIC package buffer chip will be replaced by a QFN package, and some space should be recoverable.

Finally, the analogue platform is implemented in the top left of the board, to the left of the pin-outs for the analogue platform and the FTDI interface. Below the pin-outs the analogue supply voltage filtering is implemented, with exception to the chip decoupling capacitors which are tied directly to their supply pins.

Keeping the analogue lines as short, as balanced, as fat, and as well shielded as possible was a key focus of my design. There are a few USART lines running under the chips, but they are unlikely to produce noise as they are under the first ground plane.

Goldilocks Analogue TopThe top layer of the board is pretty crowded. Some tricks such as bridging my lines to get a solid ground plan under the crystal, were passed to me.

Goldilocks Analogue Route2The Route2 or second layer is the ground plane of the board. As such it needs to provide a stable and solid path for currents to return to the origin. I have been able to provide almost solid copper under the entire area from MCU to power supply, and also from the analogue platform back to the central ground point.

Goldilocks Analogue Route15In the Goldilocks Analogue (as in Goldilocks V1) the Route15 layer is wholely at 5v and is a massive supply line. I’ve used this layer to transport the 3v3 supply around the lower edge of the board, to provide power to the uSD card, and its input buffer. The other thick tracks are the USB input line and the analogue AVcc supply line.

Goldilocks Analogue BottomOn the back of the board, mirrored here, things look as we expect. The previously noted bridge capability for the I2C bus to A4/A5 is there, as is the capability to bridge the DAC A and DAC B output capacitors to enable DC output.

Next Steps

The Goldilocks Analogue prototype board design has been sent to Seeed Studio for conversion into a PCB. While this is happening I’ll be sourcing components to solder to the PCB. I think the next post will be on this stage of the process.

Well I have everything finished and in the interim, until I write a new post, here’s the photos of the final assembly of the prototype at Jon’s SuperHouse.

Goldilocks Analogue - 3Here Jon is assembling the first prototype, using several faulty Goldilocks v1.1 devices as donor boards. Only two components didn’t fit correctly, and we didn’t have a uSD card cage so that was left off.

Goldilocks Analogue - 1Out of the toaster oven, and final assembly finished. Just checking that the voltages are as expected across the board.

Well I’ve had it on the desk now for two nights, and I’m very impressed that it seems to generally meet the specification that was intended. The code for setting the DAC levels is currently only optimised for setting two values at a time. Specifically, it is not a streaming function. Never-the-less, it is possible to achieve the stated goal for both DAC channels. The actual number achieved is 108 kSamples/second, shown below, or 18.8us to transmit 2 samples on 2 channels.

The trace below shows the signals for both DACs at 0x0000, then both DACs set to 0x0FFF.

Goldilocks Analogue Max DAC Rate

Therefore, we’ll be able to achieve the 44.1kHz sample rate for CD audio, but only 12 bit resolution, with some time time to spare. If there is a need to read a uSD card, or do some other processing then it is likely that this rate will be more than halved, as the data would then need to to be read over the SPI bus (the same bus the DAC is using) for example. Also, there is a single pole filter between the DACs and the OpAmp buffer, with a 3dB cut-off frequency of 23kHz, which will limit the maximum output frequency but will help to reduce sampling alias issues.

Looking at the board from the top left the MCP4822 can be seen in the SIOC8 package, with the Burr Brown OPA4132 quad op-amp in a SOIC14 package just near the POWER selection jumper. The FTDI FT232RQ USART in QFN package takes up much less space than its FT232RL peer.

Goldilocks Analogue - Top Left

Goldilocks Analogue – Top Left

Now the prototype is finished, it is easy to see what needs to be improved. Actually there’s not too much wrong. The inductors for the Analogue Vcc have the wrong footprint, so they will need to be fixed. The inductor is too large for the footprint and is snuggled up to the POWER jumper, and the ferrite bead is somewhat too small. I didn’t source the very small 15 turn potentiometers, so they are just shorted out. As is the DTR (RESET) disable switch located near the USB connector. As a final issue, the footprint for the 1/8″ jack was wrong for the supplied connectors, so I’ve just added a short set of jumpers to achieve the same outcome.

Goldilocks Analogue - Bottom Right

Goldilocks Analogue – Bottom Right

Here is a short video demonstrating a Voltage Controlled Oscillator running at 44.1kHz sampling into dual channels. It sounds a little odd, because one of the channels is inverted, generating an out of phase effect.

Results

Well, things are good, and bad.

I’ve been testing the DAC stage and found (what I should have known) that I needed an output buffer op-amp able to reach the negative rail (0V) on input and output to support the MCP4822 0v to 4.095V ranging DAC. The OPA4132 exhibits noise and instability issues around 0.3V output.

Unfortunately the OPA4350 (rail to rail high current), which looks like it will be the right pin compatible device, costs over $10 each, which is nearly as expensive as the audiophile OPA4132 I specified previously.

There seems to be a pin compatible alternative, the TS924A, which is about $2 each, but it is several orders of magnitude worse in performance.

For Example: OPA4350 vs TS924A
Gain Bandwidth Product: 38MHz vs 4MHz
Slew Rate: 22V/μs vs 1.3V/μs
Total Harmonic Distortion: 0.0006% vs 0.005%

Is it worth the difference, when working with a 12 bit DAC in the presence of mV of power supply noise?
Personally, I doubt it.

Using my new Red Pitaya to analyse the output, with a 43.066Hz Sine wave (1024 samples at 44.1kHz) the noise floor is 70dB down from the signal ex DAC. It seems the DAC performs as advertised.

GoldilocksAnalogue43HzSineZoom

43.066Hz 12bit Sine wave, 1024 samples output at 44.1kHz.

More in part two of Goldilocks Analogue – Testing.

Ends.

Making waves – Open Music Labs’ DSP Shield – Arduino – freeRTOS

There’s a great new Arduino Uno (pre-R3) Shield available from Open Music Labs. Their Audio Codec Shield is an Arduino shield that uses the Wolfson WM8731 codec. It is capable of sampling and reproducing audio up to 88kHz, 24bit stereo, but for use with the Arduino it is practically limited to 44kHz, 16bit stereo. The Audio Codec Shield has 1/8″ stereo input and headphone output jacks, a single pole analogue input aliasing filter, and 2 potentiometer for varying parameters in the program on the fly.

Open Music Labs WM8731

The Open Music Labs provides a some libraries and code examples for use with the Arduino IDE, and also with the Maple IDE. But, rather than just use the existing code, I thought it would be fun to develop some freeRTOS libraries from their basis code.

I spent quite some time understanding exactly how the WM8731 worked, and what was needed to make it perform, in a RTOS environment. It is clear, that to work at the audio rate of 44.1kHz, that the Arduino needs to be clocked by a hard interrupt, rather than by a soft timer. So, I spent some time designing and playing with different methods of driving the board.

Initially, I thought it would be good to limit the interrupt processing to constant clock in and clock out of data, that MUST happen every sample (at 44.1kHz) or the sound sampling or playback is simply broken, and allow the interrupt to semaphore a further processing task to wake it up. However, once I understood just how limited the time available is for processing, it became apparent that (at least for the 16MHz Arduino) there is no time left to muck about with a RTOS, and everything has to be kept as simple and regular as possible.

Never the less, the freeRTOS code is useful to provide serial and I2C libraries to set up the board, and possibly to do some other tasks where possible.

The resulting code consists of just one freeRTOS Task, that initialises the Shield, and then suspends itself indefinitely. The freeRTOS Scheduler keeps on running, but finding no available task will just pend itself until its next timer tick.

  AudioCodec_ADC_init();    // initialise the potentiometer sampling.
  AudioCodec_SPI_init();    // initialise the SPI bus for special purpose Audio Codec use.
  AudioCodec_init();        // initialise the Audio Codec using I2C bus.
  AudioCodec_Timer1_init(); // set up the sampling Timer1, runs at audio sampling rate.
  vTaskSuspend(NULL);       // well, we're pretty much done here...

First the Arduino ADC is initialised into free running mode, to provide inputs from the two potentiometers on the Shield. The Open Music Labs have provided an analysis of the Arduino ADC, and they show that the free running mode provides the lowest noise floor. Not that it is important to have a low noise floor for this purpose, as it is just potentiometer sampling. However, they missed the trick of using decimation to improve the sampling resolution, choosing instead to use a dead-band for the sampling. I’ve changed the ADC initialisation to do variable sample decimation, depending on the bit depth desired.

This is the example code for a single potentiometer.

static inline void AudioCodec_ADC(uint16_t* _mod0value)
{
  if (ADCSRA & (1 << ADIF))     // check if sample ready
  {
    _mod0temp += ADCW;  // fetch ADCL first to freeze sample is done by the compiler
    ADCSRA = 0xf7;      // reset the interrupt flag
    if (--_i == 0)      // check if enough samples have been collected
    {
      _mod0temp >>= DECIMATE;   // Decimate the summed samples
                                // (to get better accuracy), see AVR8003.doc
      *_mod0value = _mod0temp;  // move temp value to the output
      _mod0temp = 0x0000;       // reset temp value
      _i = _BV(2 * DECIMATE);   // reset loop counter
    }
  }
}

Then the SPI bus is configured to sample the data from the ADC on the WM8731, and to write data back to the DAC. Since we’re using the DSP interface, which is very similar to the SPI bus interface, with 16 bit transfers, the SPI mechanics can be used effectively, removing the need to bit-bang the interface. I found that although SPI Mode 0 nominally looks to be correct, it would lose the most significant bit of most transactions, being the left channel input values. I needed to use Mode 3 to get effective transactions.

The I2C bus is used on pins A4 and A5, which is pre-R3 format. I would digress to say that decision not to continue to support the SDA/SCL pins being available on A4 and A5 is a very bad one, in my opinion. There are many old, and this quite new, Shields that will simply be broken by this decision. Simply, bad for the Arduino legacy.

I have completed the register and pin definitions in the header file, to allow simple selection of the configuration, by adding the appropriate bit values into the register settings.

The initial I2C command transaction looks like this.

I2C command preamble

Here is a bit more detail on the DIGITAL_PATH_CONTROL command.

Vol I2C preamble detail

The true heart of the project lies within the use of Timer 1 to signal the 44.1kHz timing required to produce the sound samples. An interrupt driven by the Timer 1 counter signals the transfer of data, performing any audio processing required on the incoming data, and writing it to the output ready for the next transfer, and sampling the analogue potentiometers to use them as as mod inputs on the signal. The Timer 1 counter is incremented by counting the CLKOUT line coming from the Shield.

ISR(TIMER1_COMPA_vect)
{
  // WM8731 data transfer routine
  // move data from and to the WM8731 - done first for regularity (reduced jitter).
  AudioCodec_data(&left_in, &right_in, left_out, right_out);

  // audio processing routine - do processing on input - prepare output
  AudioCodec_dsp();

  // adc sampling routine
  // sampling the potentiometers (no sound here)
  AudioCodec_ADC(&mod0_value, &mod1_value);

  // end mark - check for end of interrupt - for debugging only
  PORTD |= _BV(PORTD6);   // Ping Audio Shield buffer line.
  PORTD &= ~_BV(PORTD6);
}

As I noted above, timing is everything. Based on the plots below, it takes exactly 6us for the AudioCodec_data() function to transfer the data from and to the WM8731. This doesn’t seem like very long, but to maintain a sample rate of 44.1kHz, each transaction must be completed in less than 22.7us, as shown below.

Vol 44kHz mid

The logic trace below shows the situation with the simplest AudioCodec_dsp() function available. Here the DSP processing is completed with over 15.7us to spare. The actual AudioCodec_data() function takes exactly 6us to complete (T1-T2), and can be used as a scale for other logic traces below.

inline void AudioCodec_dsp(void) // straight through connection I-O
{
  left_out  =  left_in; // put in to out on left channel
  right_out =  right_in; // put in to out on right channel
}

Simple IO Snapshot

Other more complicated routines, such as a sine-wave Voltage Controlled Oscillator (digital of course) take a little more time from our limited budget, needing 9.6us to complete.

VCO snapshot

I have used the same code on a Freetronics Eleven, an Arduino Uno clone, overclocked to 22.1184MHz, and as can be seen below, it results in the AudioCodec_data() function taking 4.33us (vs 6us standard) and the VCO code taking 6.125us (vs 9.6us standard). Whilst these savings are relatively small, by comparing the two logic traces, I think they do change the result enough to make it worthwhile for this application.

VCO Overclocked Arduino

Code is as usual on Sourceforge in avrfreeRTOS.

In further work, I will build some useful DSP programs from the examples provided, such as a reverb or flanger filter.

UPDATE

After reading this article on the MicroMonsterModular I’m going to play with adding some new sequences.

This WurstCaptures web site can help to build them quickly, and CounterComplex has a few ideas too.

output = t * (t >> (pot1>>4) | t >> (pot2>>4) )&((pot3>>3) + 16)
output = (t * (( t>>9 | t>>13 ) & 15)) & 129
output = (t * (t>>8 + t>>9)*100) + sin(t)
output = t * (((t>>12)|(t>>8))&(63&(t>>4)))