Question: Teensy 3.6 Analog Pins 39-33
milan3000 opened this issue · comments
First off: the Mozzi Library is amazing and I am very grateful to everyone involved in the creation and the port to the Teensy 3.6, which I am using.
My problem in short:
when using the Mozzi Library, I am unable to read the analog input values of pins 39-33.
Project: I am trying to create a monophonic 4 oscilator (+1 Sub) synthesizer with variable volume and detune per oscilator, an LFO for modulating the pitch and filter cutoff, LowPassFilter, ADSR-Envelope, Midi-Capabilities and some analog audio effects.
Problem: The oscilator section and Midi work fine, so does the LFO. However, while implementing the filter, I ran into the issue. I tried to modulate the filter cutoff frequency with a potentiometer connected to pin 39 (also sometimes called A20). But it didn't work.
I tested the potentiometer before coding, and tested it again in a clean sketch. It seemed to be connected, but testing it in a sketch, which implements the Mozzi Library, it suddenly didn't work. (Testing by Serial.pintln(mozziAnalogRead(pin))). The other analog pins I used so far (pin14-13, A0-A9) work fine and were tested in the same manner.
Question: Is anyone else having the same issue? What could I do?
I don't have a teensy, myself, so my answer is guesswork to a degree. But looking at the code, mozzi uses only ADC_0, and as far as I am aware, not all analog pins are accessible by both ADC units. Likely, this is what you are running into.
Fortunately, it seems rather straight-forward to set up non-synchronous ADC on teensy (and the ADC library is already required; https://github.com/pedvide/ADC). You should be able to use ADC_1, freely.
Thank you both for your help!
I looked through the analog.c and mozzi_analog.h channel mappings and quite frankly didn't understand too much at first. After realizing that the code differentiates the channel mapping based on the chip the Teensy is using, for instance
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
for the Teensy 3.6, I tried copying this whole chunk of code into the mozzi_analog.h file, which didn't work. As suggested by tfry-git, I looked into the ADC library and found this pin scheme:
https://forum.pjrc.com/attachment.php?attachmentid=11811&d=1508341808
which shows that the "problematic" pins are in fact connected to ADC1.
So by using the ADC Library
#include <ADC.h>
Creating an object of it
ADC *adc1 = new ADC();
And using the corresponding reading function
adc1->analogRead(pin)
instead of mozziAnalogRead(pin)
the program works.
I am unsure, if this method of reading has disadvantages over the mozziAnalogRead(), since it says in the doc:
"mozziAnalogRead() reads the analog input of a chosen channel, without blocking other operations from running."
However I am calling the ADC reading in updateControl() at 64 Hz without problems so far.
So the issue is resolved and I can keep building the synth of my dreams.
Thank you very much again!
adc->analogRead() waits for the conversion to complete before returning. I don't know how long that takes on teensy (by default). On the classic AVRs, it simply introduces too long delays. It might be quite ok on teensy, but if you're experiencing buffer underruns, that will be one of the first things to look into.
Alternatively, you can use non-blocking API:
adc->startSingleRead(..., ADC_1);
[...]
if (adc->isComplete(ADC_1)) {
x = adc->readSingle(ADC_1);
} else {
// keep using the previous value of x until the next iteration
}
It may be a bit cumbersome when reading multiple pins, but it should cause virtually no overhead.