Close

#2 - The Modules - IOAPEX

A project log for MAD - Modular Audio Devices

A set of Eurorack modules to control synths, make custom MIDI-compatible interfaces and USB audio, powered by Teensy 3.6

michele-perlaMichele Perla 04/30/2017 at 17:120 Comments

The IOAPEX module is a port expander that provides control of up to 256 digital inputs (e.g. buttons), 256 digital outputs (e.g. LEDs), 256 analog inputs (e.g. potentiometers, FSRs), and maybe 16 CV/gate signals.

One CPLD to rule them all

IOAPEX is an acronym for Input Output and Analog Port EXpander. It uses a CPLD as a SPI interface between a microcontroller and a parallel interface, to control 16 bit multiplexers. The CPLD code will fit a XC9572XL-5-VQ64.

The multiplexers will be soldered on the submodules that the user will connect to the IOAPEX. One mux can be used to control one of the following types of sensors: inputs, outputs, analog.

So for example, if on one submodule I would like to have 16 buttons, with 1 LED near each button, and 16 potentiometers, I would need 3 muxes on my submodule.

The SPI interface of the IOAPEX accepts 16 bits words, and produces 16 bits words as well.

The IOAPEX is designed to send and receive streams of 16x16 bits words. Each bit in a word represents the state of one digital IO, and for every word the IOAPEX changes the selected digital IO through the parallel mux interface. The IOAPEX counts the words it receives to control the state of the submodules muxes. The IOAPEX presents a RESET pin to reset that counter. So, in a case of initialization the first word sent to the IOAPEX will contain the data to present on the 1st digital output of every module, while the first word received will contain the state of the 1st digital input of every module.

In a digital IO only use-case, a theoretical update frequency limit for all 256 IOs is around 104KHz, or 1 uS delay.

The software controlling the IOAPEX will make use of the Teensy 3.6 hardware CS SPI module to tune the performance, as well as DMA access.

Analog muxing

The CPLD is also connecterd to an external analog multiplexer controlled by the same digital IO interface, that is used to make again a 16x16 mux in front of one Teensy 3.6 ADC pin.

The use of the ADC is different. Every 16 bit word transfered through the SPI interface activates the next input on the currently selected analog module. This means that after 256 words, that is after 16 full updates of the digital IO section, we will have sampled all 256 analog inputs.

The minimum time to send/receive 16 bits through the Teensy 3.6 SPI is 18 SPI clock cycles (max 30 MHz), that is 600 ns. The minimum time to read one 8 bit sample from the ADC is 5 us + 5 bus clock cycles (60 MHz) + 24 ADCK clock cycles. Setting the ADC clock to 60 MHz takes 5.48 uS of sample time. Summing the two sampling periods and multiplying that by 16 gives us the actual time to update one analog module and all digital IO modules: (5.483 uS + 0.6 uS) * 16 = 6.083 uS * 16 = 97.328 uS, that makes around 10 KHz (10.274535 KHz) of update frequency for all digital IO. For all 256 analog inputs it would require 16 times that again, that means we could have an analog sampling frequency of 642.1584 Hz; Nyquist says that we can sample signals as much as half of that, so around 321.0792 Hz; this means that there would be a 3.11496 ms delay between every sample on the analog inputs, or a 6.229 ms delay if an average of two samples is done. This should be a reasonable value for controls such as potentiometers, force sensing resistors.

If we reduce the number of analog input (192, 128, or 64 max. analog inputs) we could have 2.3658 ms delay for 192 inputs, 1.5572 ms delay for 128 inputs and 0.778624 mS for 64 max. analog inputs. I should consider an option to set this through some pins on the CPLD, in fact I should have at least three pins available.

64 analog inputs sampled at 2568.633 Hz are still plenty of sensors at a decent frequency for human interfaces: for example, a 4x4 FSR matrix, a 37 keys keyboard ( 3 octaves + one key), and there would still be 11 left, like 3 for a pitch bend and modulation control, and 8 generic pots, assignable to filters or whatever.

Using less inputs also allows to spend less on connectors :D I could easily fab the board without the connectors and provide an option to buy the needed amount of connectors (in multiple of fours for example).

CV/Gate OUT? No CV IN?

The same controls to select for 64, 128, 192 and 256 analog inputs could also be used to select between 4, 8, 12 or 16 cv/gate signals by multiplexing the DAC pin. Two DACs could be used in parallel and linked thru the DMA, right after the ADC read. This Teensy forum post says that the DAC bandwidth is way higher than reported in the specs, because it depends on how fast you can write to the DAC registers. Using the DAC will surely add a delay but let's not keep it in count for now, hoping that it will be as small as possible. I would like to use a smaller amount of CV/gate signals to have a better bandwidth out of them: if I can update the DACs once every full analog module is read, with 64 analog inputs we could have 4 (or 2x4 if two DACs are used) output channels sampled at 10.274 KHz. Adding a low pass filter near the Nyquist frequency would yield around up to 4 KHz signal. 8 CVs (or 2x8) scale to 5.137 KHz fs, 2.568 KHz fN, around 2 KHz filter; 12 (or 2x12) CVs scale to 3.424 KHz, 1.71 KHz fN, aroujnd 1 KHz filter, and finally 16 (or 2x1 CVs) scale to 2.568 KHz fs, 1284.25 KHz fN, maybe I can still get around 1 KHz of clean signal.

The CV looks really promising only if used in a 4 channel config, or 2x2 channel in case of a teensy 3.6 for double bandwidth. My plan to include the +/- 15V supplies on the IOAPEX is in the event of using the CV/Gate. A nice gain stage could be implemented in front of a Teensy DAC pin to convert its signal from the Teensy's voltage reference level to more professional level, like +/5 V, +/-10 V, or +5V, +10 V, etc. The DAC's resolution is 12 bit so there should be enough digital headroom for precision. Maybe the best option would be to have one buffer in front of each CV/gate signal. I would like the output to work well for both DC and AC. In case of DC signals I need the buffer to keep the same value it received from the DAC on its output jack, long enough for the IOAPEX to finish its CV update cycle and send the next sample out.

A CV in could be implemented in the same way on the analog input modules. A buffer circuit could be put on the module's output to decrease the expected cg/gate input signal (again around +/5 V or +/10 V, or 5 V, etc) to the Teensy ADC voltage range. The sampling frequencies restrictions explained before would still apply.

Connectors connectors

There will be 16 connectors on the IOAPEX for each type of submodule, that makes 3 rows of 16 connectors. Each connector will have these pins (not in this order): GND, 5V, 3.3V, 4 pins for the mux control pins, 1 pin for the mux common pin. I could add+15 V, -15 V (for analog io?). This would either need either 8 or 10 pins connectors.

LED driving

I am thinking of implementing a constant current LED driver directly on the IOAPEX for each output module, with its current modifiable by a resistor (to drive more or less current in different types of LEDs). Maybe the whole system will be fast enough for a decent software PWM. This would also keep the design easier.

The math given some paragraphs before shows a full digital IO update frequency of 10.274 KHz. This gives a PWM frequency of max 5.137 KHz. Consider that for every update, only one LED per module is on. So if we turn one output ON and OFF every sample the output will be ON for 6.0833 uS, OFF for 1/5137 KHz *2 - 6.0833 uS = 383.2489 uS time. That is, the duty cycle of a software PWM would be 1/32 -> 3.125% duty cycle. Maybe there's a way to buffer this kinda like in the CV case to let this output stay on long enough before the next sample arrives. Using LEDs in this way should reduce power consumption since not all LEDs can be on at the same time.

Discussions