potentiometer controller for Teensy (D&D)

Status
Not open for further replies.

acbc

Member
Hi
I've been working on a little controller PCB with some extra pads for experimenting/hacking.

https://hackaday.io/project/174682-dd-teensy
https://github.com/bjc01/D-D_Teensy

I was working with teensy 3.2 + audio shield (Rev B).
I got it fabricated by ALLpcb.

When I have it connected, each of the 8 potentiometers work, but it's not quite behaving as expected.
There should be three oscillator channels and a noise channel.


The oscillators seem to warble and drift in unpredictable ways.
In v6_3 the oscillator frequencies don't stay still and the volume can't be adjusted. The noise and filter pots don't respond.
Code:
//DRONEs - not chromatic - roaming quite a bit - creates modulations
//three sine oscillators - some frequency control audible / 
//three OSC - amplitude/volume control subtle not working - doesn't change volume - seems to change OSC FREQ!
// PINK NOISE + FILTER - no audible control over filter cutoff nor amplitude

//add Bounce.h - does it help with stability? not yet

#include <Bounce.h>

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>


// GUItool: begin automatically generated code
AudioSynthNoisePink      pink1;          //xy=128,277
AudioSynthWaveform       waveform2;      //xy=170,161
AudioSynthWaveform       waveform3;      //xy=173,214
AudioSynthWaveform       waveform1;      //xy=179,87
AudioFilterStateVariable filter1;        //xy=262,312
AudioEffectBitcrusher    bitcrusher1;    //xy=425,291
AudioMixer4              mixer1;         //xy=523,143
AudioOutputI2S           i2s1;           //xy=674,144
AudioConnection          patchCord1(pink1, 0, filter1, 0);
AudioConnection          patchCord2(pink1, 0, filter1, 1);
AudioConnection          patchCord3(waveform2, 0, mixer1, 1);
AudioConnection          patchCord4(waveform3, 0, mixer1, 2);
AudioConnection          patchCord5(waveform1, 0, mixer1, 0);
AudioConnection          patchCord6(filter1, 0, bitcrusher1, 0);
AudioConnection          patchCord7(bitcrusher1, 0, mixer1, 3);
AudioConnection          patchCord8(mixer1, 0, i2s1, 0);
AudioConnection          patchCord9(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=501,357
// GUItool: end automatically generated code

// Bounce objects to read pushbuttons - cutnpaste from part_2_07_Filters
//not needed for D&D yet
/*
Bounce button0 = Bounce(0, 15);
Bounce button1 = Bounce(1, 15);  // 15 ms debounce time
Bounce button2 = Bounce(2, 15);
 */
 
void setup() {
  
  // put your setup code here, to run once:
Serial.begin(9600);
  AudioMemory(20);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  waveform1.begin(WAVEFORM_SINE);
  waveform1.amplitude(0.75);
  waveform1.frequency(330);

  waveform2.begin(WAVEFORM_SINE);
  waveform2.amplitude(0.75);
  waveform2.frequency(220);

  waveform3.begin(WAVEFORM_SINE);
  waveform3.amplitude(0.75);
  waveform3.frequency(100);

  pink1.amplitude(0.7);

  mixer1.gain(0, 0.7);
  mixer1.gain(1, 0.7);
  mixer1.gain(2, 0.7);
  mixer1.gain(3, 0.7);
  delay(100);

  filter1.frequency(6);
  filter1.resonance(9); 
  //Q ranges from 0.7 to 5.0. Resonance greater than 0.707 will amplify the signal near the corner frequency. 
  //You must attenuate the signal before input to this filter, to prevent clipping.

  bitcrusher1.bits(6); 
  bitcrusher1.sampleRate(516);
  /*xcrushBits sets the bitdepth, from 1 to 16. 
   * A Value of 16 does not crush the bitdepth, and is effectively a passthru for this part of the function. 
   * xsampleRate sets the frequency, from 1 to 44100Hz, 
   * however it works in integer steps so you will only really get a handful of results from the many samplerates you can pass. 44100 is passthru.
   * set xbitDepth to 16 and xsampleRate to 44100 to pass audio through without any Bitcrush effect.
 */
  }

void loop() { 
  // put your main code here, to run repeatedly:
  // Read the knobs, scale knobs to 0-1.0 - WaveformsModulated
  
  float knob_A0 = (float)analogRead(A0);
  float knob_A1 = (float)analogRead(A1);
  float knob_A2 = (float)analogRead(A2);
  float knob_A3 = (float)analogRead(A3);
  float knob_A4 = (float)analogRead(A4) / 1023;
  float knob_A5 = (float)analogRead(A5) / 1023;
  float knob_A6 = (float)analogRead(A6) / 1023;
  float knob_A7 = (float)analogRead(A7) / 1023;

  // use Knobs to adjust the waveform frequency
  waveform1.frequency(knob_A0);
  waveform2.frequency(knob_A1);
  waveform3.frequency(knob_A2);
  filter1.frequency(knob_A3);
  
  // pink1.(knob_A3); - some DRAMA filter cutoff effect parameter
    // use Knobs to adjust the amount of waveform amplitude
  waveform1.amplitude(knob_A4);
  waveform2.amplitude(knob_A5);
  waveform2.amplitude(knob_A6);
  pink1.amplitude(knob_A7);
  
  // read the knob and adjust the filter frequency DRAMA
  int knob = analogRead(A3);
  // quick and dirty equation for exp scale frequency adjust
  float freq =  expf((float)knob / 150.0) * 10.0 + 80.0;
  filter1.frequency(freq);
  Serial.print("frequency = ");
  Serial.println(freq);
  delay(100);
  
 }


In v6_5 it seems as if all pots influence noise and filter.
Code:
//odd behaviour - distort crunch - some pulses of hiss
//3x SINE waves - none audible
//filter on pink noise channel 4 - 
//all knobs adjust some noise / filter element - none act as planned

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthWaveformSine   sine3;          //xy=53,158
AudioSynthWaveformSine   sine2;          //xy=54,111
AudioSynthWaveformSine   sine1;          //xy=66,60
AudioSynthNoisePink      pink1;          //xy=119,242
AudioFilterStateVariable filter1;        //xy=390,212
AudioMixer4              mixer1;         //xy=514,108
AudioOutputI2S           i2s1;           //xy=769,86
AudioConnection          patchCord1(sine3, 0, mixer1, 2);
AudioConnection          patchCord2(sine2, 0, mixer1, 1);
AudioConnection          patchCord3(sine1, 0, mixer1, 0);
AudioConnection          patchCord4(pink1, 0, filter1, 0);
AudioConnection          patchCord5(pink1, 0, filter1, 1);
AudioConnection          patchCord6(filter1, 0, mixer1, 3);
AudioConnection          patchCord7(mixer1, 0, i2s1, 0);
AudioConnection          patchCord8(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=492,322
// GUItool: end automatically generated code

void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
  AudioMemory(20);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.7);
 
  sine1.amplitude(0.8);
  sine1.frequency(220);
  sine1.phase(90);
  
  sine2.amplitude(0.8);
  sine2.frequency(440);
  sine2.phase(95);

  sine3.amplitude(0.8);
  sine3.frequency(880);
  sine3.phase(100);

  pink1.amplitude(0.8);

  mixer1.gain(0, 0.7);
  mixer1.gain(1, 0.7);
  mixer1.gain(2, 0.7);
  mixer1.gain(3, 0.7);
  delay(100);

  filter1.frequency(9);
  filter1.resonance(9); 
  //Q ranges from 0.7 to 5.0. Resonance greater than 0.707 will amplify the signal near the corner frequency. 
  //You must attenuate the signal before input to this filter, to prevent clipping.

}

void loop() {
  // put your main code here, to run repeatedly:
  float knob_A0 = (float)analogRead(A0) / 1023;
  float knob_A1 = (float)analogRead(A1) / 1023;
  float knob_A2 = (float)analogRead(A2) / 1023;
  float knob_A3 = (float)analogRead(A3) / 1023;
  float knob_A4 = (float)analogRead(A4) / 1023;
  float knob_A5 = (float)analogRead(A5) / 1023;
  float knob_A6 = (float)analogRead(A6) / 1023;
  float knob_A7 = (float)analogRead(A7) / 1023;

  // use Knobs to adjust the waveform frequency
  sine1.frequency(knob_A0);
  sine2.frequency(knob_A1);
  sine3.frequency(knob_A2);
  filter1.frequency(knob_A3);
    // pink1.(knob_A3); - some DRAMA filter cutoff effect parameter
  

    // use Knobs to adjust the amount of waveform amplitude
  sine1.amplitude(knob_A4);
  sine2.amplitude(knob_A5);
  sine3.amplitude(knob_A6);
  pink1.amplitude(knob_A7);
  
  // read the knob and adjust the filter frequency DRAMA
  int knob = analogRead(A3);
  // quick and dirty equation for exp scale frequency adjust
  float freq =  expf((float)knob / 150.0) * 10.0 + 80.0;
  filter1.frequency(freq);
  Serial.print("frequency = ");
  Serial.println(freq);
  delay(100);
}

View attachment 22636
D&D_Teensy_v4_2 pot pcb col.png

Is it likely the hardware is wrong or is it more likely to be a code issue?
Any advice on getting the oscillators to produce steady tones and the knobs to produce consistent behavior?
D&D Teensy v2.jpg

Is the audio shield potentiometer causing a bad influence?

Thanks for your time and support.
 
100k is rather high for a pot, which increases sensitivity to noise pickup and may allow some crosstalk in
the ADC. 10k linear is the go-to value for control pots, and often less than this for critical controls (most
motor controllers use 5k for instance).

However you may simply need to do some averaging of analog reads(*), and add extra supply decoupling to keep
the voltage going to the pots more stable. The Teensy 3.3V is noisy because of all the digital noise injected into
it by the processor. Adding 100uF or more across the supply may tame this. Alternatively adding 100nF caps
to ground on each wiper line would be another approach.

Its usual (though not important here) for power and ground traces on a PCB to be significantly wider than signal traces,
in order to keep inductance and IR voltages low.

(*) For each pin:
discard one reading.
sum N more readings and divide by N.
Try N = 4, 8, 16 or so and see if this helps
 
Many thanks for your feedback MarkT -
I'll try changing pot values for a start and then try adding capacitors.
I think making the traces wider is easy to do on eagle.

Do you have a link to more information on averaging of analogue reads?
 
"Adding 100uF or more across the supply may tame this".
Would this be an electrolytic capacitor between + / - ; the negative leg of the capacitor to ground and positive to 3.3v?
The device should be powered from USB.
Does this image seem right? Thanks for suggestions.


D&D_Teensy_v4_3 cap pcb.png
 
I tried using 5k pots and the tones are a lot more stable - thanks MarkT.

There is still a little wobble, and some audible clicking - like a clock in the background.
Is that likely a programme error or is can it be resolved by adding the 100uF capacitor?

ANyone got any suggestions to try?
 
Hi rolf, thanks for that.
I can order a MCP3204 to test
I was hoping that using the teensy audio shield (4+ rev D / 3.2 + rev c) would be able to deliver usable output.
 
Hi luni - thanks for the link - I tried it but I am still experiencing issues.

I think the best thing for me to do is make my project more simple to try to identify the issues.

It seems that control knob 7 (connected to pin A6) is acting as a kind of 'master'.
The other pots can make adjustments, but for some reason 7 (A6) as a gain/volume control can make everything go from silence to noise.

Could this be because I got cheap pots?

I wanted to be able to control 3 x sine wave channels (pitch/frequency & volume) and one noise channel (filter frequency & volume).
I am surprised at how difficult this is for me!
 
Here is the design:

D_D_teensy_v6_bc 2021-01-12 at 16.24.04.jpg

Here is the code:

Code:
//DRONE 
//three sine oscillators - very close - creates modulations in amplitude
// PINK NOISE + FILTER 
//v6 - remove waveshaper - ADD BITCRUSHER
//waveshape
//add Bounce.h

#include <Bounce.h>

// GUItool: begin automatically generated code
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// GUItool: begin automatically generated code
AudioSynthNoisePink      pink1;          //xy=128,277
AudioSynthWaveform       waveform2;      //xy=170,161
AudioSynthWaveform       waveform3;      //xy=173,214
AudioSynthWaveform       waveform1;      //xy=179,87
AudioFilterStateVariable filter1;        //xy=262,312
AudioEffectBitcrusher    bitcrusher1;    //xy=425,291
AudioMixer4              mixer1;         //xy=523,143
AudioOutputI2S           i2s1;           //xy=674,144
AudioConnection          patchCord1(pink1, 0, filter1, 0);
AudioConnection          patchCord2(pink1, 0, filter1, 1);
AudioConnection          patchCord3(waveform2, 0, mixer1, 1);
AudioConnection          patchCord4(waveform3, 0, mixer1, 2);
AudioConnection          patchCord5(waveform1, 0, mixer1, 0);
AudioConnection          patchCord6(filter1, 0, bitcrusher1, 0);
AudioConnection          patchCord7(bitcrusher1, 0, mixer1, 3);
AudioConnection          patchCord8(mixer1, 0, i2s1, 0);
AudioConnection          patchCord9(mixer1, 0, i2s1, 1);
AudioControlSGTL5000     sgtl5000_1;     //xy=501,357
// GUItool: end automatically generated code

// GUItool: end automatically generated code

// Bounce objects to read pushbuttons - cutnpaste from part_2_07_Filters
//not needed for D&D yet
/*
Bounce button0 = Bounce(0, 15);
Bounce button1 = Bounce(1, 15);  // 15 ms debounce time
Bounce button2 = Bounce(2, 15);
 */
 
void setup() {
  // put your setup code here, to run once:
Serial.begin(9600);
  AudioMemory(20);
  sgtl5000_1.enable();
  sgtl5000_1.volume(0.5);
  waveform1.begin(WAVEFORM_SINE);
  waveform1.amplitude(0.75);
  waveform1.frequency(55);

  waveform2.begin(WAVEFORM_SINE);
  waveform2.amplitude(0.75);
  waveform2.frequency(110);

  waveform3.begin(WAVEFORM_SINE);
  waveform3.amplitude(0.75);
  waveform3.frequency(220);

  pink1.amplitude(1.0);

  mixer1.gain(0, 0.7);
  mixer1.gain(1, 0.7);
  mixer1.gain(2, 0.7);
  mixer1.gain(3, 0.6);
  delay(1000);

  filter1.frequency(65);
  filter1.resonance(4.9); 
  //Q ranges from 0.7 to 5.0. Resonance greater than 0.707 will amplify the signal near the corner frequency. 
  //You must attenuate the signal before input to this filter, to prevent clipping.

  bitcrusher1.bits(8); 
  bitcrusher1.sampleRate(22050);
  /*xcrushBits sets the bitdepth, from 1 to 16. 
   * A Value of 16 does not crush the bitdepth, and is effectively a passthru for this part of the function.
   * 
   * xsampleRate sets the frequency, from 1 to 44100Hz, 
   * however it works in integer steps so you will only really get a handful of results from the many samplerates you can pass. 44100 is passthru.
   * 
   * set xbitDepth to 16 and xsampleRate to 44100 to pass audio through without any Bitcrush effect.

/*set xbitDepth to 16 and xsampleRate to 44100 to pass audio through without any Bitcrush effect.
 * 
 */
  }

void loop() {
  // put your main code here, to run repeatedly:
{
 }

  // Read the knobs, scale knobs to 0-1.0 - WaveformsModulated
  
  float knob_A0 = (float)analogRead(A0);
  float knob_A1 = (float)analogRead(A1);
  float knob_A2 = (float)analogRead(A2);
  float knob_A3 = (float)analogRead(A3);
  float knob_A4 = (float)analogRead(A4) / 1023.0;
  float knob_A5 = (float)analogRead(A5) / 1023.0;
  float knob_A6 = (float)analogRead(A6) / 1023.0;
  float knob_A7 = (float)analogRead(A7) / 1023.0;

  // use Knobs to adjust the waveform frequency
  waveform1.frequency(knob_A0);
  waveform2.frequency(knob_A1);
  waveform3.frequency(knob_A2);
  filter1.frequency(knob_A3);
  
  // pink1.(knob_A3); - some DRAMA filter cutoff effect parameter
    // use Knobs to adjust the amount of waveform amplitude
  waveform1.amplitude(knob_A4);
  waveform2.amplitude(knob_A5);
  waveform2.amplitude(knob_A6);
  pink1.amplitude(knob_A7);
  
  // read the knob and adjust the filter frequency DRAMA
  int knob = analogRead(A3);
  // quick and dirty equation for exp scale frequency adjust
  float freq =  expf((float)knob / 150.0) * 10.0 + 80.0;
  filter1.frequency(freq);
  Serial.print("frequency = ");
  Serial.println(freq);
  delay(100);
  
 }

Is there anything in the code that is clearly wrong?
Are my issues all in hardware?

Thanks for your time and input!
 
Status
Not open for further replies.
Back
Top