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.

As of June 2014, I’ve now got all the parts, and the PCB ready for a new prototype. Just awaiting the SD Card cage, before the next assembly and testing run.

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, but it generates sufficient negative voltage to enable the OpAmp to easily reach true GND potential.

uSD Card Level Translation – TXB0104

Some further analysis of the voltage translation application revealed that the TXB0104 is designed to exactly suit the purpose of interfacing SPI bus at up to 100 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.

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

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 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

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.

Gameduino 2 with Goldilocks and EVE

My Gameduino 2 was delivered just a few weeks ago, and I’ve spent too much time with it already. It is the latest Kickstarter project by James Bowman. James has written a Gameduino 2 Book too.

The ability to add a large touch screen, with integrated audio and accelerometer to any Arduino project is a great thing. Previously, you had to move to 32 bit processors with LVDS interfaces to work with LCD screens, but the new FT800 EVE Graphical Processing Unit (GPU) integrates all of the graphic issues and allow you to drive it with a very high level object orientated graphics language. For example it takes just one command to create an entire clock face with hour, minute, and second-hands.

The Gameduino 2, via the FT800 EVE chip, provides the following capabilities:

  • 32-bit internal color precision
  • OpenGL-style command set
  • 256 KBytes of video RAM
  • smooth sprite rotate and zoom with bilinear filtering
  • smooth circle and line drawing in hardware – 16x antialiased
  • JPEG loading in hardware
  • audio tones and WAV audio output
  • built-in rendering of gradients, text, dials, sliders, clocks and buttons
  • intelligent touch capabilities, where objects can be tagged and recognised.

The FT800 runs the 4.3 inch 480×272 TFT touch panel screen at 60 Hz and drives a mono headphone output.

EVE Block Diagram

First off, there’s a demo of some of the capabilities of the Gameduino 2. I’ll come to the drivers later, but the Arduino compatible platform used here is the Goldilocks ATmega1284P from Freetronics. The Goldilocks is in my opinion the best platform to use with the Gameduino 2. Firstly there is the extra RAM and Flash capabilities in line with the ATmega1284p MCU. But also importantly the Goldilocks holds the Pre-R3 Arduino Uno connector standard, with the SPI pins located correctly on Pins 11, 12, and 13. And the INT0 interrupt located on Pin 2. This means that it can be used with the Gameduino 2, out of the box. No hacking required.

Must be addicted to these touch screens. I’ve just received an Australian designed 4D Systems FT843 Screen. It has possibly an identical screen to the Gameduino 2, but is based on a R3 Arduino shield format (SPI on ICSP) called the ADAM (Arduino Display Adapter Module), which means that it will work on any current Arduino hardware, without hacking. The FT843 ADAM supports a RESET line, which resolves the only problem I’ve noted with the Gameduino 2. Unfortunately, audio is not supported by a 3.5mm jack but rather by a pin-out option. The FT843 uses Swizzle 0, unlike the Gameduino 2 which uses Swizzle 3, and has the Display SPI Select on either D9 or D4 rather than on D8 like the Gameduino 2. Other than these simple configuration options, it similar.

4D Systems FT843 on Goldilocks 1284p

4D Systems FT843 on Goldilocks 1284p

Demo

The screen shows 5 sets of demonstrations. These demos are provided by FTDI, and typically in an Arduino Uno you would have to choose which of the 5 sets you want to see. With the extra capabilities of the Goldilocks, it is possible to load all of them simultaneously in 110kB of flash.

Set 0 focusses on individual commands that are loaded into the Display List. The Display List is essentially a list of commands that is executed or rendered for each frame of display. A Display List will be rendered indefinitely, until it is swapped by another Display List. Two Display Lists are maintained in a double buffering arrangement. One is written, whilst the other is displayed.

Set 1 exhibits some of the co-processor command capabilities, that allow complex objects to be created with only one command. A clock, slider, dial, or a rows of buttons can be created easily in this manner.

Set 2 shows the JPEG image rendering capabilities in RGB and in 8 bit mono.

Set 3 demonstrates custom font capabilities. There are 16 fonts available in the ROM of the FT800 EVE, but you can add your own as is desired.

Set 4 shows some advanced co-processor capabilities, such as touch tag recognition, no touch (zero MCU activity) screensaver, capturing screen sketches, and inbuilt audio options.

The main screen shows an analogue clock that is drawn with one co-processor command. Real time is generated by a 32,768Hz Crystal driving the Goldilocks Timer 2 for a system clock. The accuracy of the clock is limited only by the accuracy of the watch crystal, and I’ve built mine with a 5ppm version, which should be enough to keep within a few seconds per month.

Sample Application

The FTDI provided sample application covers most of the available commands and options for the FT800 EVE GPU.

The FT_SampleApp.h file contains definitions of functions implemented for the main application. These code snippets are not really useful beyond demonstrations of capability of the GPU, but never the less demonstrate how each specific feature of the FT800 EVE GPU can be utilised.

Driver

Because the FT800 EVE GPU has a very capable object orientated graphics language, the FTDI drivers present a very capable high level interface to the user. FTDI have prepared an excellent starting point from which I could easily make customisations suitable for the AVR ATmega Arduino hardware that I prefer to use.

The FTDI driver set is separated into a Command Layer, and into a Hardware Abstraction Layer (HAL). This separation makes it easy to customise for the AVR ATmega platform, but retains the standard FTDI command language for easy implementation of their example applications, and portability of code written for their command language.

To use the FT800 EVE drivers for the Gameduino 2 it is only necessary to include the FT_Platform.h file in the main program. This file contains references to all of the other files needed.

#include "../lib_ft800/FT_DataTypes.h"
#include "../lib_ft800/FT_X11_RGB.h"
#include "../lib_ft800/FT_Gpu.h"
#include "../lib_ft800/FT_Gpu_Hal.h"
#include "../lib_ft800/FT_Hal_Utils.h"
#include "../lib_ft800/FT_CoPro_Cmds.h"
#include "../lib_ft800/FT_API.h"

The FT_DataTypes.h file contains FTDI type definitions for the specific data types needed for the FT800 EVE GPU. This is mainly used to abstract the drivers for varying MCU. For the AVR it is not absolutely necessary, but it will help when the code is used on other platforms.

The FT_X11_RGB.h file contains the standard colour set used in X11 colours and on the Web, which are stored PROGMEM. I’ve written a small macro that will insert these into commands needing 24 bit colour settings. These colours will be stored and referenced from PROGMEM when they are called from either of the X11 specific macros defined in FT_Gpu.h If they are not called from the program, they will be discarded by the linker and not waste space in the final linked program.

X11 Colours

The FT_Gpu.h file contains all the definitions for command and register setting options. I have significantly rearranged the layout and comments in this file, compared to the FTDI version. Hopefully it is arranged in a way that allows options applying to specific commands and registers to be quickly located.

By writing DL commands to the Display List which are configured by the options in the FT_Gpu.h file it is possible to control most of the low level functions in the FT800 EVE GPU. The Display List is used by the FT800 GPU to render the screen, so it is only the contents of the active Display List that appear on the screen.

In the FT_Gpu_Hal.h file the commands specific to the SPI bus (or the I2C bus if this transfer mechanism is being used) are defined.

I have simplified out some HAL options provided by FTDI for high performance MCU, that might be constrained writing to the SPI bus at only 30MHz, the maximum FT800 SPI bus rate. The Goldilocks SPI bus only runs at 11MHz, and the standard Arduino Uno SPI bus only runs at 8 MHz, so those optimisations don’t help, and they also consume RAM for streaming buffers.

But, I have integrated a multi-byte SPI transfer into the HAL, which don’t use additional RAM buffer space, as they write via a pointer. This is probably the best way to work the SPI bus in the Arduino environment. I have also implemented multi byte SPI transfer directly from the PROGMEM for Strings, and for precomputed commands.

As a preferred option, I’ve implemented PROGMEM storage of Strings for all commands. The commands utilising RAM storage of Strings are retained for compatibility, and to allow computed Strings to be used.

All of the FTDI provided commands now have optional *_P variants which take PROGMEM strings, rather than RAM strings. This saves eleven hundred bytes of RAM used for strings, just in the demonstration programs provided by FTDI and shown in the Demo!

The FT_Hal_Util.h file contains some simple utility macros.

The FT_CoPro_Cmds.h file contains definitions for all of the available co-processor commands. These command are written to the co-processor command buffer, and are used to generate low level commands that appear in the Display List and be rendered for each frame.

Many of the co-processor commands replicate functionality of setting specific registers with options via the Display List GPU commands. This is useful because it is possible to programme the co-processor to implement a task and remain at the object orientated view of the screen, even though the a individual command may be a simple GPU setting that could have been done at Display List command level. Having all the commands available at co-processor level obviates the need to switch between the two “modes” of operation and thought.

I extracted a few of the standard functions that are needed irrespective of the specific application into an API. The FT_API.h file contains these simple command sequences, for booting up the Gameduino 2, and for managing the screen brightness. It also contains precalculated simplified sin, cos, and atan functions useful when drawing circles and clocks.

The API level also contains calls on the Hardware Abstraction Layer that are simply passed through. These calls are flattened by avr-gcc to save digging ourselves into a stack wasting function call hole.

And, of course, everything is integrated into the freeRTOS v8.0.0 port that I support on Sourceforge, AVRfreeRTOS, which gives non-blocking timing, tasks, semaphores, queues, and all aspects of freeRTOS that are so great.

As an example of the power of this combination of freeRTOS and the FT800 object orientated command language we can describe the method used to create an accurate well rendered clock on the Gameduino 2 screen. Using the 3 commands below, we obtain the clock face seen in my demo video main screen.

time(&currentTime); // get a time stamp in current seconds elapsed from Midnight, Jan 1 2000 UTC (the Y2K 'epoch'), as maintained by freeRTOS.
localtime_r(&currentTime, &calendar); // converts the time stamp pointed to by currentTime into broken-down time in a calendar structure, expressed as Local time.
FT_GPU_CoCmd_Clock(phost, FT_DispWidth - (FT_DispHeight/2), FT_DispHeight/2, FT_DispHeight/2 - 20, OPT_3D, calendar.tm_hour, calendar.tm_min, calendar.tm_sec, 0); // draw a clock in 3D rendering.

I’ve updated the clock function to include a touch screen time setting interface. Using the FT800 Touch Tags, and Button generation, this process is really incredibly easy.

Hardware

I’ve taken the liberty of borrowing some of James’ pictures for this story. They can originally be found here.

Gameduino 2 Pinout

Note that because of the wrap around connector and cable for the LCD screen, it is not possible to use the Arduino R3 pin out. The SPI bus pins are located at the traditional location on Pin 11 though Pin 13. Unless you want to hack your board, you’re limited to using Arduino Uno style boards.

Gameduino 2 Shield

Unfortunately, the FTDI FT800 Reset pin has not been implemented by the Gameduino 2. Using an ISP to programme the Arduino usually “accidentally” puts the FT800 EVE GPU into an unsupported state. This means that the Gameduino 2 and Arduino usually have to be power-cycled or hard Reset following each programming iteration. It would have been good to tie the FT800 Reset pin to the Arduino Reset pin via a short (ms) delay chip, to obviate the need to remove power to generate the hard Reset for the FT800.

Hello World & other examples

I thought it might be interesting to compare the code required to achieve the demonstration outcomes that James Bowman provides on the Gameduino2 site, with the code required to achieve the same result using freeRTOS and the FTDI style driver. So I’ve implemented three simple examples, “Hello World”, “Sprites”, and “Blobs” from his library.

All of the examples have been built using an Arduino Uno ATmega328p as the MCU hardware platform.

helloworld

The Hello World application simply initialises the Gameduino2, sets the colour to which the screen shall be cleared, and then writes text with the OPT_CENTER option to center it in the X and Y axis. As there is no delay, this is written as often and as fast as the MCU can repeat the loop.

#include <SPI.h>
#include <GD2.h>

void setup()
{
  GD.begin();
}

void loop()
{
  GD.ClearColorRGB(0x103000);
  GD.Clear();
  GD.cmd_text(240, 136, 31, OPT_CENTER, "Hello world");
  GD.swap();
}

The same result can be generated in C using freeRTOS and the FTDI Drivers. I have commented extensively within the code below.

/* freeRTOS Scheduler include files. */
/* these four header files encompass the full freeRTOS real-time OS features,
   of multiple prioritised tasks each with their own stack space, queues for moving data,
   and scheduling tasks, and semaphores for controlling execution flows */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/* Gameduino 2 include file. */
#include "FT_Platform.h"

/*------Global used for HAL context management---------*/
extern FT_GPU_HAL_Context_t * phost;           // optional, just to make it clear where this variable comes from.
                                               // It is automatically included, so this line is actually unnecessary.

/*--------------Function Definitions-------------------*/

int main(void) __attribute__((OS_main));       // optional, just good practice.
                                               // Saves a few bytes of stack because the return from main() is not implemented.

static void TaskWriteLCD(void *pvParameters);  // define a single task to write to Gameduino 2 LCD.
                                               // typically multiple concurrent tasks are defined,
                                               // but in this case to replicate the Arduino environment, just one is implemented.

/*-----------------Functions---------------------------*/
/* Main program loop */
int main(void)
{
  xTaskCreate(            // create a task to write on the Gameduino 2 LCD
       TaskWriteLCD
    ,  (const portCHAR *)"WriteLCD"
    ,  128                // number of bytes for this task stack
    ,  NULL
    ,  3		  // priority of this task (1 is highest priority, 4 lowest).
    ,  NULL );

  vTaskStartScheduler();  // now freeRTOS has taken over, and the pre-emptive scheduler is running.
}
/*-----------------------------------------------------------*/
/* Tasks                                                     */
/*-----------------------------------------------------------*/

static void TaskWriteLCD(void *pvParameters) // A Task to write to Gameduino 2 LCD
{
  (void) pvParameters;

  FT_API_Boot_Config();  // initialise the Gameduino 2.

  while(1)               // a freeRTOS task should never return
  {
    FT_API_Write_CoCmd( CMD_DLSTART );                       // initialise and start a Display List
//  FT_API_Write_CoCmd( CLEAR_COLOR_RGB(0x10, 0x30, 0x00) ); // set the colour to which the screen is cleared (using RGB triplets) as in GD2 library OR
    FT_API_Write_CoCmd( CLEAR_COLOR_X11(FORESTGREEN) );      // set the colour to which the screen is cleared (using X11 colour definitions)
    FT_API_Write_CoCmd( CLEAR(1,1,1) );                      // clear the screen

    FT_GPU_CoCmd_Text_P(phost,FT_DispWidth/2, FT_DispHeight/2, 31, OPT_CENTER, PSTR("Hello world"));
      // write "Hello World" to X and Y centre of screen using OPT_CENTER  with the largest font 31
      // The string "Hello world" is stored in PROGMEM
      // Functions with *_P all use PROGMEM Strings (and don't consume RAM)
      // FT_DispWidth and FT_DispHeight are global variables set to orientate us in a flexible consistent way,
      // without hard coding the screen resolution.

    FT_API_Write_CoCmd( DISPLAY() );                         // close the Display List (DL) opened by CMD_DLSTART()
    FT_API_Write_CoCmd( CMD_SWAP );                          // swap the active Display List (double buffering), to display the new "Hello World" commands written to the Display List
  }
}

sprites

The Sprites application is similar to the original one built for the Gameduino, but here each sprite is rotating around a random point. The 2001 random points are stored in a PROGMEM array sprites. This takes 8K of flash. A second PROGMEM array circle holds the 256 XY coordinates to make the sprite move in a circle. The only RAM used is a single byte t used to keep track of the current rotation position, by counting iterations.

#include <EEPROM.h>
#include <SPI.h>
#include <GD2.h>

#include "sprites_assets.h"

void setup()
{
  GD.begin();
  GD.copy(sprites_assets, sizeof(sprites_assets));
}

static byte t;

void loop()
{
  GD.Clear();
  GD.Begin(BITMAPS);
  byte j = t;
  uint32_t v, r;

  int nspr = min(2001, max(256, 19 * t));

  PROGMEM prog_uint32_t *pv = sprites;
  for (int i = 0; i &lt; nspr; i++) {
    v = pgm_read_dword(pv++);
    r = pgm_read_dword(circle + j++);
    GD.cmd32(v + r);
  }

  GD.ColorRGB(0x000000);
  GD.ColorA(140);
  GD.LineWidth(28 * 16);
  GD.Begin(LINES);
  GD.Vertex2ii(240 - 110, 136, 0, 0);
  GD.Vertex2ii(240 + 110, 136, 0, 0);

  GD.RestoreContext();

  GD.cmd_number(215, 110, 31, OPT_RIGHTX, nspr);
  GD.cmd_text( 229, 110, 31, 0, "sprites");

  GD.swap();
  t++;
}

The code in freeRTOS is similar. I have commented within the code.

/* freeRTOS Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/* Gameduino 2 include file. */
#include "FT_Platform.h"

// The include file containing the sprite graphics, and the special command sequence
#include "sprites_assets.h

/*------Global used for HAL context management---------*/
extern FT_GPU_HAL_Context_t * phost;           // optional, just to make it clear where this variable comes from

/*--------------Function Definitions-------------------*/

int main(void) __attribute__((OS_main));       // optional, just good practice

static void TaskWriteLCD(void *pvParameters);  // define a single task to write to Gameduino 2 LCD

/*-----------------Functions---------------------------*/

/* Main program loop */
int main(void)
{
  xTaskCreate(             // create a task to write on the Gameduino 2 LCD
    TaskWriteLCD
    ,  (const portCHAR *)"WriteLCD"
    ,  128                 // number of bytes for this task stack
    ,  NULL
    ,  3                   // priority of task (1 is highest priority, 4 lowest).
    ,  NULL );

  vTaskStartScheduler();   // now freeRTOS has taken over, and the pre-emptive scheduler is running
}
/*-----------------------------------------------------------*/
/* Tasks                                                     */
/*-----------------------------------------------------------*/

static void TaskWriteLCD(void *pvParameters) // A Task to write to Gameduino 2 LCD
{
  (void) pvParameters;

  uint8_t t = 0;         // iterate over the code for 255 times, before restarting with 256 sprites where t = 0

  FT_API_Boot_Config();  // initialise the Gameduino 2.
  FT_GPU_HAL_WrCmdBuf_P(phost, sprites_assets, sizeof(sprites_assets));
    // Copy James' magic list of commands into the command buffer.
    // These co-processor commands are "compiled" into their 4 byte equivalents, and I haven't decoded them in detail.
    // But, since the FT800 is reading the same double word codes, it doesn't really matter how they're generated.

  while(1)               // a freeRTOS task should never return
  {
    FT_API_Write_CoCmd( CMD_DLSTART );       // initialise and start a Display List (DL)
    FT_API_Write_CoCmd( CLEAR(1,1,1) );      // clear the screen

    FT_API_Write_CoCmd( BEGIN(BITMAPS) );    // start to write BITMAPS into the DL
    uint8_t j = t;
    uint32_t v;
    uint32_t r;
    int16_t nspr = min(2001, max(256, 19 * t));
    ft_prog_uint32_t * pv = sprites;         //  pv is the sprite BITMAP pointer

    for (uint16_t i = 0; i < nspr; ++i) {
      v = pgm_read_dword(pv++);              // determine which sprite we're controlling
      r = pgm_read_dword(circle + j++);      // circle is the rotation control
      FT_GPU_HAL_WrCmd32(phost, v + r);      // the sprite address and the location are written here to the co-processor
    }
    FT_API_Write_CoCmd( END());              // finish writing BITMAPS into the Display List

    FT_API_Write_CoCmd( BEGIN(LINES) );      // start to write LINES into the Display List
    FT_API_Write_CoCmd( COLOR_RGB(0x00, 0x00, 0x00) );  // set the line colour to black 0x000000
    FT_API_Write_CoCmd( COLOR_A(140) );                 // set alpha channel transparency
    FT_API_Write_CoCmd( LINE_WIDTH( 28 * 16) );
    FT_API_Write_CoCmd( VERTEX2II(240 - 110, 136, 0, 0) );  // start to draw an alpha transparency background line
    FT_API_Write_CoCmd( VERTEX2II(240 + 110, 136, 0, 0) );  // finish the line
    FT_API_Write_CoCmd( END() );             // finish writing LINES into the Display List

    FT_API_Write_CoCmd( RESTORE_CONTEXT() ); // With no prior SAVE_CONTEXT() command, this restores the default colours and values.

    FT_GPU_CoCmd_Number(phost, 215, 110, 31, OPT_RIGHTX, nspr);    // write a number.
    FT_GPU_CoCmd_Text_P(phost, 229, 110, 31, 0, PSTR("sprites"));  // write using a PROGMEM stored string function, to save RAM
      //  phost is a pointer to the context for the Gameduino2.
      //  Mainly used where there may be multiple screens present, but in this case several state and semaphore items are maintained.

    FT_API_Write_CoCmd( DISPLAY() );          // close the active Display List (DL) opened by CMD_DLSTART()
    FT_API_Write_CoCmd( CMD_SWAP );           // Do a DL swap to render the just written DL

    t++;    // t will roll over and will restart the number of sprites to the minimum of 256
  }
}

main2

blobs is a sketching demonstration, as you paint on the touch screen a trail of circles follows.
The code keeps a history of the last 128 touch positions, and draws the transparent, randomly coloured circles.

#include <EEPROM.h>
#include <SPI.h>
#include <GD2.h>

#define NBLOBS      128
#define OFFSCREEN   -16384

struct xy {
  int x, y;
} blobs[NBLOBS];

void setup()
{
  GD.begin();

  for (int i = 0; i < NBLOBS; i++) {
    blobs[i].x = OFFSCREEN;
    blobs[i].y = OFFSCREEN;
  }
}

void loop()
{
  static byte blob_i;
  GD.get_inputs();
  if (GD.inputs.x != -32768) {
    blobs[blob_i].x = GD.inputs.x << 4;
    blobs[blob_i].y = GD.inputs.y << 4;
  } else {
    blobs[blob_i].x = OFFSCREEN;
    blobs[blob_i].y = OFFSCREEN;
  }
  blob_i = (blob_i + 1) & (NBLOBS - 1);

  GD.ClearColorRGB(0xe0e0e0);
  GD.Clear();

  GD.Begin(POINTS);
  for (int i = 0; i < NBLOBS; i++) {
    // Blobs fade away and swell as they age
    GD.ColorA(i << 1);
    GD.PointSize((1024 + 16) - (i << 3));

    // Random color for each blob, keyed from (blob_i + i)
    uint8_t j = (blob_i + i) & (NBLOBS - 1);
    byte r = j * 17;
    byte g = j * 23;
    byte b = j * 147;
    GD.ColorRGB(r, g, b);

    // Draw it!
    GD.Vertex2f(blobs[j].x, blobs[j].y);
  }
  GD.swap();
}

The code in freeRTOS is similar, but the touch functionality is derived directly from the FT800 register containing the most recent screen touch location. I have commented within the code.

/* freeRTOS Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/* Gameduino 2 include file. */
#include "FT_Platform.h"

#define NBLOBS       128
#define OFFSCREEN   -16384

/*----------Global used for HAL management-------------*/
extern FT_GPU_HAL_Context_t * phost;           // optional, just to make it clear where this comes from

struct xy {										// somewhere to store all the blob locations
  int16_t x, y;
} blobs[NBLOBS];

/*--------------Function Definitions-------------------*/

int main(void) __attribute__((OS_main));       // optional, just good practice

static void TaskWriteLCD(void *pvParameters);  // define a single task to write to Gameduino 2 LCD

/*-----------------Functions---------------------------*/

/* Main program loop */
int main(void)
{
  xTaskCreate(            // create a task to write on the Gameduino 2 LCD
    TaskWriteLCD
    ,  (const portCHAR *)"WriteLCD"
    ,  128                // number of bytes for the task stack
    ,  NULL
    ,  3                  // priority of task (1 is highest priority, 4 lowest).
    ,  NULL );

  vTaskStartScheduler();  // now freeRTOS has taken over, and the scheduler is running
}

/*-----------------------------------------------------------*/
/* Tasks                                                     */
/*-----------------------------------------------------------*/

static void TaskWriteLCD(void *pvParameters) // A Task to write to Gameduino 2 LCD
{
 (void) pvParameters;

  FT_API_Boot_Config();     // initialise the Gameduino 2.
  FT_API_Touch_Config();    // initialise the FT800 Touch capability.

  for (uint8_t i = 0; i < NBLOBS; ++i)
  {
    blobs[i].x = OFFSCREEN;
    blobs[i].y = OFFSCREEN;
  }

  while(1)                  // a freeRTOS task should never return
  {
    static uint8_t blob_i;  // the blob we're currently processing
    uint32_t readTouch;     // xy coordinates of a touch are stored in uint32_t

    // this is the touch interface stuff
    readTouch = FT_GPU_HAL_Rd32(phost, REG_TOUCH_SCREEN_XY);// the screen location of the last touch is stored in REG_TOUCH_SCREEN_XY
    if (readTouch != NIL_TOUCH_XY)                          // if there was a touch
    {
      blobs[blob_i].x  = (int16_t)((readTouch >> 16) & 0xffff) << 4; // read where x axis touch occurred, and scale it
      blobs[blob_i].y = (int16_t)(readTouch & 0xffff) << 4; // read where y axis touch occurred, and scale it
    } else {
      blobs[blob_i].x = OFFSCREEN;         // if there was no touch, draw the blob OFFSCREEN
      blobs[blob_i].y = OFFSCREEN;
    }
    blob_i = (blob_i + 1) & (NBLOBS - 1);  // increment to the next blob for touch interaction

    // this is the display interface stuff
    FT_API_Write_CoCmd( CMD_DLSTART );      // initialise and start a display list (DL)

    FT_API_Write_CoCmd( CLEAR_COLOR_RGB(0xe0, 0xe0, 0xe0) );// set the colour to which the screen will be cleared
    FT_API_Write_CoCmd( CLEAR(1,1,1) );     // clear the screen

    FT_API_Write_CoCmd( BEGIN(POINTS) );    // start to write POINTS into the Display List (DL)

    for (uint8_t i = 0; i < NBLOBS; ++i)
    {
      // Blobs fade away and swell as they age
      FT_API_Write_CoCmd( COLOR_A(i << 1) ); // set an alpha transparency
      FT_API_Write_CoCmd( POINT_SIZE((1024 + 16) - (i << 3)) );

      // Random colour for each blob, keyed from (blob_i + i)
      uint8_t j = (blob_i + i) & (NBLOBS - 1);
      uint8_t r = j * 17;
      uint8_t g = j * 23;
      uint8_t b = j * 147;
      FT_API_Write_CoCmd( COLOR_RGB(r, g, b) );

      // Draw it!
      FT_API_Write_CoCmd( VERTEX2F(blobs[j].x, blobs[j].y) );
    }

    FT_API_Write_CoCmd( END() );            // finish writing POINTS into the active DL

    FT_API_Write_CoCmd( DISPLAY() );        // close the active Display List (DL)
    FT_API_Write_CoCmd( CMD_SWAP );         // Do a DL swap to render the just written DL
    }
}

I intend to build a few more demonstrations of the code, and to copy some games that James has already implemented, because I’m not a game designer.

NBN Co Strategic Review – on HFC

The NBN Co has the mandate to provide high-speed broadband services for all Australians. Yet, when we walk the streets in the suburbs of our capital cities we see that in many cases there are already two existing ultra-broadband Hybrid Fibre Coaxial (HFC) networks in place. Networks that were destined, on a political whim, to be shut-down.

The NBN Strategic Review has identified these underutilised assets and proposes to use them to deliver ultra-broadband services to more Australians, faster, and cheaper than any alternative solution. This step will allow the NBN Co to focus construction activities on areas where there are currently insufficient assets.

For an alternate view, please refer to Simon Hackett’s HFC in the NBN.

UPDATE:

In May 2014 Bain & Co have released their view on HFC relative to FTTB and FTTN: “Is it too soon to declare cable the winner in the broadband wars?“.

Global References

As noted in the NBN Strategic Review, the inherent advantages of HFC over alternatives have seen the technology gain ground in the deployment of super-fast broadband networks.
The services offered by carriers using HFC are often double in speeds over alternative technologies.

For example, in the United Kingdom the Virgin Media HFC network reliably provides services at 110Mb/s (even in peak hour), competing against BT’s FTTN solution (source OFCOM).

In Spain, in October 2012, for the second consecutive year, ONO received the award for the fastest broadband operator in Spain. ONO is the leader of the high-speed broadband sector in Spain, thanks to its DOCSIS 3.0 technology, which provides high Internet access speeds using the hybrid HFC network.

And, perhaps the most relevant and clear market statistic is in the United States, where over the past twelve months HFC (Cable Operators) have added 1.8 million new customers, in the face of direct competition with AT&T FTTN and Verizon FTTH networks.

Seventeen of the largest cable and telecom companies in the U.S. added roughly 295,000 broadband subscribers in Q2 of 2013, according to Leichtman Research Group. These providers now serve 82.7 million subscribers, with cable companies providing broadband access to 47.8 million users and telephone companies working with nearly 34.9 million subscribers.

This research from the US which suggests HFC cable operators are increasing their lead on Telcos in the broadband stakes, and that FTTH fibre connections are largely converting existing ADSL customers.

Performance Roadmap

The European and American Cable Operators have worked to ensure that their HFC infrastructure has a standardised long-term performance scaling roadmap. The current DOCSIS3.0 technology can provide peak speeds of 400Mb/s to consumers, on a suitably provisioned network. Capacity can be easily scaled by “splitting” service areas, or by adding capacity by deploying additional systems onto the current network infrastructure.

The roadmap to DOCSIS3.1 standardises peak speeds of up to 10Gb/s to consumers. Whilst it may be some time before this speed is required, and the technology to support it is cost effective, the standardisation is already in place.

Matt Schmitt, Director of CableLabs DOCSIS Specifications, has this to say.

Reliability

It is recognised that HFC networks are less reliable than fully fibre networks, even though by nature a significant component of a HFC network is optical fibre. The costs to maintain and operate a HFC network have been estimated at between $15 and $25 per home passed per year. In comparison a fully fibre network is around $4 per home passed per year. However, the difference in operational cost is never sufficient to recover the capital cost of providing a full fibre network. It always remains cheaper to operate an existing HFC network, than to replace it with a full fibre network.

Scalable Performance

The current services provided over the Australian HFC networks are dimensioned to compete with ADSL based services, and are often significantly under-invested. There are no technical impediments to the NBN Co providing its own standardised service levels over the same HFC network infrastructure.

As a specific example of this capability, of the 14 ISP packages included in the most recent OFCOM Broadband Speeds Report for the United Kingdom, Virgin Media’s (HFC) ‘up to’ 120Mbit/s service achieved the fastest download speeds, an average of 112.6Mbit/s. During the peak-period average download speed on Virgin Media’s ‘up to’ 120Mbit/s was faster than 104Mbit/s.

Having achieved a performance of double BT, their nearest competitor, there is little incentive for Virgin Media to continue to increase the performance gap.

In the United States the situation is a little different, as HFC is competing directly with FTTH GPON network services provided by Verizon. Here the FCC regularly measures broadband speeds. The most recent FCC report contains a wealth of information, but specifically both Cablevision (HFC) and Verizon (FTTH) are able to achieve greater than 100% of advertised speeds during the busy hour period, and both Cablevision and Verizon are the top performers and their service levels are nearly identical during the entire day.

In Australia, the current operators of HFC networks don’t have much to compete against (only ADSL services) and further they were compelled by government policy through the NBN Co Definitive Agreements to shutter their HFC networks, and migrate their customers off. Hardly a scenario for further investment in capacity, and this created the basis for the current complaints about the “HFC networks” locally.

There is an example of this situation in the United States, as evidenced by the same FCC Broadband America reports. In 2011 and 2012 the situation for Cablevision’s customers was roughly similar to the situation facing Optus’ customers. Cablevision was the worst of the worst in 2011 and 2012, but by appropriate upgrades to their infrastructure and implementation of “best practice” capacity management they are now amongst the best broadband providers in the United States.

HFC technology is unique in that it enables the NBN Co to scale and manage its investment in network capacity in line with the take-up of and demand for its services. This flexibility and scalable performance characteristic is quite unlike some network technologies, which require all of the investment in customer access ports to be made in advance.

Multi-Dwelling Units

Significant numbers of homes in MDUs are not currently addressed within the HFC areas. The NBN Strategic Review addresses the issue of serving Multi-Dwelling Units, and notes that agreements would need to be made with the Bodies Corporate and utilities suppliers, and that the NBN Co would need powers to compel access to MDUs in line with its service obligations.

In the United States the FCC has created rules to regulate the in-building HFC wiring of MDUs to facilitate standardisation, and competition.

There is no technical impediment to the NBN Co servicing MDU premises with HFC based services.

Optus and Telstra do not service MCUs currently, because of the difficulty these two operators experienced in reaching agreements with the Bodies Corporate for provision of an optional cable-TV service.

The situation for the NBN Co, as a utility provider, would be quite different. The NBN Co would have no impediment in providing broadband services to MDUs, as it would have similar arrangements to those enjoyed by the electricity, gas, and water utilities currently.

Faster and Cheaper

In comparison with other network technology, HFC networks can be upgraded to provide NBN Services at a fraction of the cost. The NBN Co Strategic Review has determined that the existing HFC networks can be upgraded at around $100 per premises, based on overseas experience.

The NBN Co HFC services can be provided faster to Australians than any other network technology. The technology to provide greater than 100Mb/s services already exists and has been proven around the world. The NBN Co will use this existing experience to deliver services to more Australians more quickly.

In millions of cases, a HFC network is already connected to customers’ homes, allowing the NBN Co services to be provided without any physical changes for the home owner. As soon as the contractual negotiations and regulatory changes are completed, and the network upgrades are completed, the NBN Co will be able to begin offering services.

Currently, the largest HFC network passes ~2.7 million premises (in metropolitan areas across Adelaide, Brisbane, Gold Coast, Melbourne, Perth and Sydney). Using the HFC networks enables the NBN Co to provide services across all of these homes in the shortest possible timeframe, and to allocate its resources into building new networks where there is no current viable network option.

The Right Scenario is 2 + 4, not 6

The Strategic Review describes a number of Scenarios for implementing the NBN. I think that the obvious Scenario was omitted. In my opinion, the right path for the NBN Co is to build a hybrid of Scenario 2 – a radically redesigned cost optimised FTTP solution, and Scenario 4 – using HFC in locations where it already exists.

Also, given the high cost of FTTP for longer country lead-in and rate of advance of LTE technology, extending the fixed wireless LTE solution from 4% of the country to around 15% of the country (being to locations where FTTP is not economic) is a real alternative in terms of speed, capacity and time to deliver services to country Australians.

Additionally, there has been little discussion of increasing the amount of fibre being buried to enable a true “home run” direct fibre solution in the future. I think that we should look closely at the cost/benefit for providing sufficient dark fibre for a 1-fibre-per-customer Layer-1 wholesale option. Direct fibre is the long-run solution for the whole country, so we should look at starting early if we can.

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.

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.

SATA on UDOO

My SSD and eSATA caddy have arrived. So now we plug it all in and off we go.

Some testing on my amd64 Ubuntu Linux Machine, for comparison with the uSD cards used for the UDOO currently.

The SanDisk Black uSD card behaves in the amd64 machine, just as it did in the UDOO previously.
SanDisk_BlackSD_4GB

Now we test the SanDisk Extreme ii SSD, connected via USB3.0.
SanDisk_Extreme2_USB3

Quite a difference.
If we can get close to this performance in the UDOO, then it will be worth the money spent.

UDOO and SSD Preparation

The guide available on elinux describes all of the steps required for booting the UDOO from the SATA drive.

First prepare a small uSD card to be the boot drive. Format it with one ext3 partition, and install the u-boot bootloader as usual.

sudo dd if=u-boot-q.imx of=/dev/<MICROSD_DEVICE> bs=512 seek=2

This is sufficient to get the UDOO to boot.

Now prepare the SSD, by formatting it in the same way you formatted the uSD previously. I’m now adding an additional linux-swap partition about 2GB in size. Although there are warnings about using SSD for swap, if you’re using a full desktop on your UDOO, your browser won’t respect the memory limitation and you’ll create worse problems.

Although the 8MB free space is not currently used in the SATA SSD, because u-boot is contained on the uSD. My guess is that at some time soon the UDOO team will get the u-boot loadable on the SATA drive, and then this space will be needed.

Once the SSD is prepared, then the fastest way to replicate your already created environment is to copy disk to disk.

cd /media
sudo cp -rp UDOO_SDroot/* UDOO_SSDroot
sudo cp -rp UDOO_SDhome/* UDOO_SSDhome
sync; sync

One final thing is to change the references in the /etc/fstab from

/dev/mmcblk0p1 to /dev/sda1 for /
/dev/mmcblk0p2 to /dev/sda2 for /home
/dev/mmcblk0p3 to /dev/sda3 for swap

Now, plug the SSD caddy into the UDOO, and put the uSD in its slot.

First boot

When first booting the UDOO, interrupt the auto boot process and enter the commands noted in the elinux instructions.
Open a serial terminal to your PC with a baud of 115200 8n1. Reset the UDOO and press any key over serial terminal when prompted to cancel the autoboot. If you miss the prompt, you can press reset on the UDOO.

setenv bootdev "sata init; sata dev 0; ext2load sata 0"
setenv root root=/dev/sda1
saveenv
boot

And the UDOO should boot as normal, but from the eSATA drive.

Note that there can be errors with eSATA / USB3.0 casings. I initially chose one which uses the Prolific PL2773, which implements the attachment as a USB Bulk-Only Mass Storage Class. Unfortunately this storage class doesn’t have the capability to pass TRIM commands.

But, although the attachment for the SSD doesn’t have TRIM capability, the SSD reports that it does have this capability, via eSATA, and this confuses the Kernel.

Errors are caused by the Kernel calling for TRIM on the swap space during the boot process.

How to fix this? Well the simplest way is to throw away the disk casing and connect the SSD drive directly. So, this is what I did. The disk performance also increases markedly too!

UDOO SSD speed testing

The UDOO SATA port doesn’t achieve quite the same throughput as the amd64 desktop does over USB3. But the speed increase over the uSD card is significant, and is very noticeable in use. Worth doing, in any case.
SanDisk_Extreme2_eSATA

After removing the SSD drive from the housing, and driving it directly, the performance increase can be seen. The average read rate has doubled to over 110MB/s and the access time has decreased by a third making it about the same speed as on the amd64 desktop.

In practice the desktop feels even smoother. Great result!
Screenshot from 2013-11-18 23:08:14