Control-Surface icon indicating copy to clipboard operation
Control-Surface copied to clipboard

Potentiometer reading is unstable on Teensy 4.1

Open stonepreston opened this issue 2 years ago • 7 comments

Describe the bug First off, thanks for this library. It is by far the most well documented arduino library I have ever come across.

Potentiometer reading is unstable on Teensy 4.1 Using a Teensy 2 ++, the same potentiometer and same code is read just fine. However, on teensy 4.1, the read value is very unstable, constantly changing +- 5 or so. I have tried changing the clock speed to 16MHz, but the problem persists. Any help would be greatly appreciated

To Reproduce Read a potentiometer using a teensy 4.1

Expected behavior The value read should be stable, and not constantly changing by a small amount.

Code

#include <Arduino.h>
#include <Control_Surface.h>

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

PBPotentiometer pitchBendPotentiometer = {
        A4,        // Analog pin connected to potentiometer
        CHANNEL_1, // MIDI Channel 1
};

void setup() {
    Control_Surface.begin(); // Initialize Control Surface
}

void loop() {
    Control_Surface.loop(); // Update the Control Surface
}

stonepreston avatar Mar 28 '22 22:03 stonepreston

I have added a full platformio basedd example here. This is the weirdest thing. I have added the ResponsiveAnalogRead to try and denoise the reading. The serial example works perfectly, but as soon as a try doing anything midi related, things stop working as expected. If you have a teensy 4.1, I would greatly appreciate you trying to reproduce. I am at a complete loss as to what is going on : (. Even with the denoising applied, its still super noisy when sending midi, despite things working perfectly fine when sending the serial data. Simply calling Control_Surface.begin(); is enough. That throws everything off kilter. I cant explain it :(. If I dont initiailize control surface, the serial messages work just as expected. If I call the begin() method, the input is super noisy (despite being read using ResponsiveAnlogRead())

Ive tried with 2 different teensy 4.1s. Both exhibit the same issue. Ive also tried 2 different pots (well, the same model of the pot, but different physical devices). Im banging my head against the wall here. It seems its either related to the teensy 4.1 hardware itself and however its sending midi, or the library isnt working as expected.

Ive tried different analog pins on the teensy as well, to no effect.

It must have something to do with the way the ADC is initialized or something, but i dont know enough about this too really begin to dig in to debug it

stonepreston avatar Mar 29 '22 02:03 stonepreston

Alright I figured out the issue causing the weird behavior with the denoised values. Control surface was using a different ADC precision than I thought (12 bit not 10 bit). Once I set that in the ResponsiveAnalogRead object it worked. However Id like to be able to use the library without denoising the read myself. It seems there is some filtering present in the control surface library, but it does not seem to be doing its job in this case. I have updated the platformio example above to print the raw read value along with the filtered value. You can see how noisy the unfiltered signal is. Is there a way to prevent this?

stonepreston avatar Mar 29 '22 03:03 stonepreston

I did a quick test and was unable to reproduce what you're describing. I'm using a Teensy 4.1 with a 5kΩ potentiometer, using Teensyduino v1.56 and the Arduino IDE v1.8.15.

The raw value is quite noisy, as expected, but Control Surface's filter does a good job at filtering out the noise: Screenshot from 2022-04-02 20-03-31

#include <Arduino.h>
#include <Control_Surface.h>

// define the pin you want to use
const int ANALOG_PIN = A0;

USBDebugMIDI_Interface midi {115200};
FilteredAnalog<> analog {ANALOG_PIN};

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

void loop() {
  if (analog.update() || true) {
    Serial.print(analog.getRawValue() / 16.f);
    Serial.print("\t");
    Serial.print(analog.getValue());
    Serial.println();
    delay(10);
  }
}

Now since the T4.1 is so incredibly fast, it might make sense to change the filter's cut-off frequency. You can easily go to a factor of 2⁻⁸ while still keeping it responsive enough. You can configure this using the second template argument to the FilteredAnalog class. For large shifts, you have to use a 32-bit integer type, by setting the third argument. See https://tttapa.github.io/Control-Surface-doc/Doxygen/d1/d08/1_8FilteredAnalog-Advanced_8ino-example.html for more details.

#include <Arduino.h>
#include <Control_Surface.h>

FilteredAnalog<10, 8, uint32_t> analog {A0};

void setup() {
  analog.setupADC();
  Serial.begin(115200);
}

void loop() {
  if (analog.update() || true) {
    Serial.print(analog.getRawValue() * 1023.f / analog.getMaxRawValue());
    Serial.print("\t");
    Serial.print(analog.getValue());
    Serial.println();
  }
}

You can experiment with different settings in a sketch like this, and once you've found a good setting, you can update Control Surface's config file so it applies to all MIDI classes as well:

https://github.com/tttapa/Control-Surface/blob/f50cee7a75a8ffc6828c5fc4f1d308f066959354/src/AH/Settings/Settings.hpp#L57-L73

If you want to prevent Control Surface from changing the ADC resolution to 12 bits, you can define ADC_RESOLUTION=10 or edit the config file:

https://github.com/tttapa/Control-Surface/blob/f50cee7a75a8ffc6828c5fc4f1d308f066959354/src/AH/Hardware/ADCConfig.hpp#L49-L51

tttapa avatar Apr 02 '22 18:04 tttapa

Hey thanks for the response. I tried your test sketch and it indeed did work fine using a FilteredAnalog. However I still cant get it to work using PBPotentiometer. Using a plain FilteredAnalog works perfectly. But if instead I use a PBPotentiometer, its noisy. Which does not make sense to me as I can see that PBPotentiometer is inheriting from MIDIFilteredAnalog which has a filtered analog member variable that its using to do the reading :/.

Can you try using this simple sketch and inspecting the midi output?

#include <Arduino.h>
#include <Control_Surface.h>

// Instantiate a MIDI over USB interface.
USBMIDI_Interface midi;

PBPotentiometer pb = {
        A17,        // Analog pin connected to potentiometer
        CHANNEL_1, // MIDI Channel 1
};

void setup() {
    Control_Surface.begin(); // Initialize Control Surface
}

void loop() {
    Control_Surface.loop();
    Serial.print(pb.getRawValue());
    Serial.print("\t");
    Serial.print(pb.getValue());
    Serial.println();;
}

The getValue() is fluctuating by a small amount, 1 or 2. But I guess when this gets remapped to the pitchbend range of values a fluctation of 1 or 2 in the 0-1024 range translates to a lot more when its 0-16000 or whatever the pb value is.

stonepreston avatar Apr 03 '22 16:04 stonepreston

Folllwing... I've got the same issue here. Logarithmic PBpotentiometer connected to A0. First half of the run seems safe whilst the second half gets very imprecise.

EmanuelINO avatar Feb 09 '23 10:02 EmanuelINO

Logarithmic PBpotentiometer connected to A0. First half of the run seems safe whilst the second half gets very imprecise.

Are you using a mapping function?

tttapa avatar Feb 11 '23 11:02 tttapa

I'm not, but I thought it's due to the logarithmic nature of the potentiometer. However, I managed to apply the filter to one of the analog inputs. Do you think it would be possible to apply it to all the analog inputs? Thanks!

EmanuelINO avatar Feb 13 '23 23:02 EmanuelINO