Things have changed since I wrote original post because in addition to the keyboard (48 analog Hall sensors) I have expended the multiplexer infrastructure to read 48 analog pots. So I have 96 analog inputs right now. Pots are more troublesome than Hall sensors because Pots have much higher impedance (10kohm). Hall sensor output impedance is low because it has emitter follower output stage and something like <500 ohm so it is easier to drive capactive load from Hall sensor than pot.
Why I am mentioning this? Because higher impedance means more settling time required after switching analog multiplexer and that makes reading pots is more problematic and bumps up timing requirements (you need to specifically add extra "wait" time after analog multiplexer channel switch to make sure that voltage stabilised at new level).
Data sheet of 4067 16-to-1 analog switch says that it's "ON" resistance is 70ohm, so it is way less than pots 5k (10k/2) impedance, input capacitance is 10pF, OFF-ON propagation delay is about 60 ns. Now assuming that wire connecting pot to multiplexer is less than 1meter (worst case for me) it would add another 21pF (
https://www.emisoftware.com/calculator/wire-pair-capacitance/)
So overall I have 5kohm source charging 30pF capacitance. Time constant for this RC circuit would be R * C (5 * 10^3 * 30 * 10^-12 ) = 150 * 10^-12 = 150 ns. Settling time to 99.8% is 6 time constants = 900ns. I don't need more than that for pots because I would encode pots to 7 bit MIDI anyway.
The above calculations say that to get correct measurement I need to wait at least 1 μs after changing analog switch address lines for output voltage to stabilize within 99.8% of actual value.
With 16-input multiplexer it means that 16 μs per one read cycle (all 16 inputs per mux) is just spent **waiting** for mux output to stabilize. This also means that proper timing is crucial.
My goal was to read the analog values 1000 times per second. With 96 analog inputs it means that I need to read at about 100kHZ sampling rate, which means 10μs total sampling time, including time required to wait for analog mux, so effectively it is below 9 μs.
With twice as many analog inputs as you are planning, it would mean half of that (4.5μs), unless you dropped scanning frequency below 1000 times per second.
General workflow would be (in Arduino speak):
C++:
void setup()
{
// D0..D3 to the mux address pins
pinMode( PIN_D0, OUTPUT ); // configure pings
pinMode( PIN_D1, OUTPUT );
pinMode( PIN_D2, OUTPUT );
pinMode( PIN_D3, OUTPUT );
// we want 12 bit resolution
analogReadResolution(12);
// and NO averaging because it is VERY slow with averaging
// this setting allows to go down to 6usec per analogRead()
analogReadAveraging(1);
}
void setMux( int addr )
{
digitalWriteFast( PIN_D0, ( addr & 1 ) ? HIGH : LOW );
digitalWriteFast( PIN_D1, ( addr & 2 ) ? HIGH : LOW );
digitalWriteFast( PIN_D2, ( addr & 4 ) ? HIGH : LOW );
digitalWriteFast( PIN_D3, ( addr & 8 ) ? HIGH : LOW );
}
#define HOW_MANY_MUXES 6
#define MUX_CHANNELS 16
int anReadData[ HOW_MANY_MUXES * MUX_CHANNELS ];
// the code below assumes that you have muxes connected to
// consecutive analog inputs PIN_A0, A1, A2 and so on.
void loop()
{
// this reads ALL data from ALL muxes
for( int i = 0; i < MUX_CHANNELS; i++ )
{
setMux( i );
delayMicroseconds( 1 ); // settling time required for mux output to stabilize
for( int j = 0; j < HOW_MANY_MUXES; j++ )
{
anReadData[ i + j * MUX_CHANNELS ] = analogRead( PIN_A0 + j );
}
}
}
Problem is that Teensy's 4.0 analogRead is too slow to handle that as by default (out of the box, without tweaking) it takes 20μs.
There are tweaks to make it faster (down to approx 6μs ) by switching OFF averaging and thus decreasing signal-to-noise ratio
You could also use some third party libs like this:
https://github.com/pedvide/ADC
that promise to get extra speed but at the expense of lowering resolution. As it turned out Teensy 4 ADC subsystem is not as good as all the other parts of this microcontroller.
After doing some more research, I came to conclusion that I would need to sacrifice entire Teensy 4 to do nothing but data acquisition and whenever I could achieve desired speed would be questionable, so I decided to move data acquisition to separate microcontroller, so Teensy is free to do what it is good at (ie, heavy number crunching). Since I was familiar with STM32 family (from previous projects) I decided to use cheapest thing available (so called "Blue Pill", STM32F103) that has support for hardware based DMA scan mode reading so instead of wasting Teensy just to wait for the hardware, I would use dirt cheap micro that has hardware that does most of the work by itself (STM32 has DMA scan mode that automatically does inner loop completely in hardware -> i.e. read ADC from analog input pin, store to RAM, switch analog channel to the next pin and repeat the whose scan, without using CPU at all). And now I have Teensy 4 free to do actual audio processing.
In your use case, with twice as many analog inputs, if you wanted to continue to use Teensy 4 for that task, you would either use above code and lower scan rate to 500-700 per second (which I believe would be perfectly fine), or dig into iMXRT 1060 Manual
https://www.pjrc.com/teensy/IMXRT1060RM_rev3_annotations.pdf and figure out how to talk directly to hardware to make the most out of it .
On paper Teensy 4 processor can reach 1M sps (1μs) conversion time with effective number of bits = 10.
If you wanted to go hardware route (that frees your CPU to do other work) on Teensy 4 (as opposed to software-driven data acqustition), you would need to program timer (PIT), then use ADC_ETC (ADC external trigger control) to switch channels and do the AD conversion and use eDMA controller to transfer AD data to RAM. Unfortunately Arduino library won't do that for you and you need to talk to hardware directly. I did not choose that route because doing the same on BluePill was just cheaper with slightly less noise, as Teensy is high-frequency part and AD converters don't like HF around them.