The device at the moment is built around the ATTiny861 microcontroller which is closely related to the rather common ATTiny85. There exists ports of this firmware to the ATTiny85 and also a port that runs on a PC using libao. (By extension, should work on Linux-based single-board computers too.)
A third candidate in the AVR world would be the ATMega32U4 which is available as a through-hole module in the form of the Arduino Leonardo. This code should also work on ARM, TI MSP430 and Microchip PIC32 microcontrollers and anything else that gcc works on.
The plan is to have 8 peripheral ports (probably using DIN-8 connectors) which expose:
- Power rails: +12V and 0V
- A general purpose I/O line … 12V tolerant (so smoke won't be released if +12V and GPIO get crossed)
- N-MOSFET drain output for driving lights up to ~1A
- Microcontroller control signals for I²C networking/peripherals and ICSP programming (MOSI/MISO/SCK/nRESET)
This allows some flexibility: through the use of pull-resistors, it is possible for the microcontroller to sense what is connected on a given port by looking at the analogue voltage seen at power-up, and thus auto-detection of buttons, lights and light+button combos is possible.
Future expansion ideas:
- Networking multiple units using an I²C "network"
- Control from an I²C master such as a WIFI module (e.g. ESP8266) or single-board computer (Beagle Bone, Raspberry Pi, etc)
- Reading from I²C slaves such as EEPROMs, GPIO expanders.
The idea here is a toy that can grow with the person using it. It can be used by a child (disabled or otherwise) as a toy for them to play with… then reprogrammed to create new games as they develop. The device can also be used in other projects to provide sound and light control.
To provide +12V tolerance, each channel will use a module like the following:
The design here is based on this article by Digikey on input protection. The aim here is to tolerate +12V, over-current and ESD. 8 of these, plus some tweaked ones for the I²C, MOSI and nRESET lines comprise the front line that connects the external sockets to the internal controller.
My controller has this schematic:
The microcontroller pin assignments are as follows:
- Pin 1 (PB0, SDA/MOSI/DI): I²C SDA / ICSP MOSI
- Pin 2 (PB1, MISO/DO): Common GPIO / ICSP MISO
- Pin 3 (PB2, SCL/SCK): I²C SCL / ICSP SCK
- Pin 4 (PB3, OC1B): Audio PWM output
- Pin 7 (PB4): Audio enable
- Pin 8 (PB5, OC1D): Light PWM output (inverted)
- Pin 9 (PB6): GPIO Enable
- Pin 10 (PB7, nRESET): ICSP nRESET
- Pins 11…20 (PA0…PA7): Channel GPIOs/MOSFET control
The Port A pins connect to the inputs on two 74HC4066s and a 74HC574 edge-triggered D-latch. The light PWM connects to the output enable on the 74HC574. The GPIO Enable line controls the 74HC4066s and the 74HC574.
- When GPIO_EN is high: the 74HC4066s connect the GPIO pins on each channel to the microcontroller so it can sense the voltage on that pin.
- When GPIO_EN is low: the 74HC4066s go high-impedance, disconnecting the external GPIOs. The MCU is then free to assert one of the PAx lines to choose a MOSFET to turn on.
- Once PAx has been asserted, the MCU raises GPIO_EN and sets OC1D's duty cycle, which causes the '574 to latch the selected MOSFET and to PWM it at the desired duty cycle. The '4066s connect Port A to the outside world again.
I haven't yet tested the above control scheme, but that's the theory anyway. :-)
The audio passes through a simple RC low-pass filter then is amplified by a NJR NJM2113D amplifier IC. The RC filter component values were roughly picked… I started with nominal values (1k and 100nF) with the intention of optimising later, then found that optimisation was not necessary as the performance was considered "acceptable" (there was no visible 250kHz carrier):
The synthesizer code itself is loosely modelled on the rather well regarded Commodore SID chip. I don't support the analogue filtering features of this chip, but...Read more »