Forum Rule: Always post complete source code & details to reproduce any issue!
Page 2 of 2 FirstFirst 1 2
Results 26 to 35 of 35

Thread: Teensy LC + CD74HC4051 multiplex Midi problem...

  1. #26
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,052
    Here is a version retaining the array of ResponsiveAnalogRead (RAR) objects (thanks to Christoph for sorting me out on this!).
    It's now very similar to the analog section of my example code and was very easy to implement the other changes once I had my head straight on how to get an RAR array when the pin is always the same.

    Code:
    //************LIBRARIES USED**************
    // include the ResponsiveAnalogRead library for analog smoothing
    #include <ResponsiveAnalogRead.h>
    //usbMIDI.h library is added automatically when code is compiled as a MIDI device
    
    // ******CONSTANT VALUES******** 
    // customize code behaviour here!
    const int muxTimeMin = 500; // minimum micro-seconds between MUX reads 
    const int channel = 1; // MIDI channel
    const int MUX_PINS = 16; // number of MUX Channnels
    
    // define the CC ID numbers on which to send them..
    
    const int CCID[MUX_PINS] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36};
    
    
    //******VARIABLES***********
    // a data array and a lagged copy to tell when MIDI changes are required
    byte data[MUX_PINS];
    byte dataLag[MUX_PINS]; // when lag and new are not the same then update MIDI CC value
    byte i=0; // global index for MUX channel reads
    
    //mapping of mux to teensy digital pins
    int pin_Out_S0 = 0;
    int pin_Out_S1 = 1;
    int pin_Out_S2 = 2;
    int pin_Out_S3 = 3;
    int pin_In_Mux1 = A1;
    
    
    //****** TIMER VARIABLE *** change scale here!
    elapsedMicros mux1Updated; // switch to micros to run at speed and tune with muxTimeMin setting above
    //elapsedMillis mux1Updated; // switch to millis to troubleshoot 
    
    //************INITIALIZE LIBRARY OBJECTS**************
    // initialize the ReponsiveAnalogRead objects
    ResponsiveAnalogRead analog[]{
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true},
      {pin_In_Mux1 ,true}
    }; 
    
    
    
    //************SETUP**************
    void setup() {
      //! don't forget to set for output!
      pinMode(pin_Out_S0, OUTPUT);
      pinMode(pin_Out_S1, OUTPUT);
      pinMode(pin_Out_S2, OUTPUT);
      pinMode(pin_Out_S3, OUTPUT);
    }
    
    //************LOOP**************
    void loop() {
      nextMUXpin();
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    
    //************MUX SECTION**************
    void nextMUXpin(){  
      if (mux1Updated>muxTimeMin) {  
        // update the ResponsiveAnalogRead object every loop
        analog[i].update(); 
        // if the repsonsive value has change, print out 'changed'
        if(analog[i].hasChanged()) {
          data[i] = analog[i].getValue()>>3;
          if (data[i] != dataLag[i]){
            dataLag[i] = data[i];
            usbMIDI.sendControlChange(CCID[i], data[i], channel);
            serialPringMIDIdata(); // use to troublshoot
          }
        }  
    
        //reset timer
        mux1Updated = 0; 
        //increment index
        i++;
        if (i>15)   {i=0;}      
        // set mux control pins for next pass
        digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
        digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
        digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
        digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
      }
    }
    
    // **useful for debugging, comment out function call to run full speed
    void serialPringMIDIdata(){
      Serial.print(i,DEC);
      Serial.print(" :");
      Serial.print(HIGH && (i & B00000001),BIN);
      Serial.print(HIGH && (i & B00000010),BIN);
      Serial.print(HIGH && (i & B00000100),BIN);
      Serial.print(HIGH && (i & B00001000),BIN);
      Serial.print(" MUX_PIN: ");
      Serial.print(i,DEC); 
      Serial.print(" CC: ");
      Serial.print(CCID[i],DEC); 
      Serial.print(" DATA HEX: ");
      Serial.println(data[i],HEX); 
    }

    As an added benefit you can leave your MUX pins float if you point their initialization at a grounded Teensy pin... RAR will read that (stable) value and you won't see 'noise' messages flying everywhere.

    It also allows me to test a bit more... By having only 1 RAR object point at the pin where I have a control and the rest at a grounded pin I can get a better idea of how it's working because I only see messages generated for that MUX CC.

    So I think I've tested everything except the MUX logic and timing which require the hardware.

    And the timing is everything... With RAR and three-bits of reduction stability should be very easy to achieve and hardware filtering never seems to really be needed at seven bits.

    That is if you can live with whatever trade-off between responsiveness and stability that the additional processing and timing issues with controlling a MUX entail. Of hardware changes lower resistance on your pots (if you can afford the current and not really below 10KOhm) and better quality pots likely have the best payoff. That and some care with signal paths.
    Last edited by oddson; 09-30-2017 at 07:09 PM.

  2. #27
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,052
    I was at my local electronics shop and picked up a CD74HC4067 MUX breakout.

    So I was able to try my code (RAR version) and, ...well I had it pretty close....

    Biggest problem was I forget to setup for output for digital write (which I often do) so it took me a while to figure why the MUX would only read Ch1.

    Other than that the only change is I was writing to the pins before the the index is incremented which seems clearly wrong to me today.
    (Changes are made in the code posted above but not yet in the roll-your-own-hysteresis version.)

    I haven't tested extensively but it appears solid even when I allow MUX reads as close a 5 microsecond apart. (Since found one setup where 5 uS left one channel bouncing between adjacent MIDI outputs but 25 uS seems to be very stable with my electrical setup.)

    So far I'm using a single pot with the rest of the pins held LOW except one other which is held HIGH...

    I used a header with a wire soldering 14 terminals together to make holding the MUX pins stable at some voltage easier.
    Click image for larger version. 

Name:	headerBar.jpg 
Views:	50 
Size:	57.0 KB 
ID:	11664
    This way I can tie 14 HIGH, LOW or to a divider with one wire instead of having ground them all separately.
    Last edited by oddson; 09-30-2017 at 07:30 PM.

  3. #28
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    You could always slow down the ADC Clock(ADCK) also. I think by default in Analog.c the minimum is 12Mhz(@48Mhz), you can drop it all the way down to 3Mhz I believe.
    Would probably help with charging the ADC if you gave it a little more time each read.

  4. #29
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,052
    Quote Originally Posted by Donziboy2 View Post
    You could always slow down the ADC Clock(ADCK) also. I think by default in Analog.c the minimum is 12Mhz(@48Mhz), you can drop it all the way down to 3Mhz I believe...
    Good to know but both the RAR version and my deadband version are very stable with very quick polling intervals.

    Here's my corrected dead-band hysteresis version which appears to be stable even if muxTimeMin is set to zero.
    Code:
    // ******CONSTANT VALUES******** 
    // customize code behaviour here!
    const int muxTimeMin = 5; // minimum micro-seconds between MUX reads
    const int channel = 1; // MIDI channel
    const int A_PINS = 16; // number of Analog PINS (these are now MUX pins)
    const int D_PINS = 3; // number of Digital PINS
    const int ON_VELOCITY = 99; // note-one velocity sent from buttons (should be 65 to  127)
    
    // define the CC ID numbers on which to send them..
    const int CCID[A_PINS] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36}; // set your own CC values for the 16 MUX pins
    
    const int dbt = 8; // a threshold value for how big the dead-band is before recalc
    
    //******VARIABLES***********
    //mapping of mux to teensy digital pins
    int pin_Out_S0 = 0;
    int pin_Out_S1 = 1;
    int pin_Out_S2 = 2;
    int pin_Out_S3 = 3;
    int pin_In_Mux1 = A0;
    //the state of the mux channels(initialized to zero)
    int Mux1_State[16] = {0};
    int Mux1_State_Lagged[16] = {0};
    elapsedMicros mux1Updated;
    //elapsedMillis mux1Updated; // switch to millis to troubleshoot 
    byte i = 0; // index for mux loop
    
    
    void setup() {
      //! don't forget to set for output!
      pinMode(pin_Out_S0, OUTPUT);
      pinMode(pin_Out_S1, OUTPUT);
      pinMode(pin_Out_S2, OUTPUT);
      pinMode(pin_Out_S3, OUTPUT);
    }
    
    //************LOOP**************
    void loop() {
      getMUX1Data();
      // other work here... mux is called once in each loop rather than updating all in every loop
      while (usbMIDI.read()) {
         // controllers must call .read() to keep the queue clear even if they are not responding to MIDI
      }
    }
    
    
    //************MUX1 SECTION**************
    void getMUX1Data(){  
      if (mux1Updated>muxTimeMin) {
    
         Mux1_State[i] = analogRead(pin_In_Mux1);
    
        if(abs(Mux1_State[i] - Mux1_State_Lagged[i]) > dbt ) {
          Mux1_State_Lagged[i] = Mux1_State[i];
          
    
            usbMIDI.sendControlChange(CCID[i], Mux1_State[i]>>3, channel);
            serialPringMIDIdata(); // use to troublshoot
    
    
        }
    
        //reset timer
        mux1Updated = 0; 
        //increment index
        i++;
        if (i>15)   {i=0;}
        // set mux control pins for next pass
        digitalWrite(pin_Out_S0, HIGH && (i & B00000001));
        digitalWrite(pin_Out_S1, HIGH && (i & B00000010));
        digitalWrite(pin_Out_S2, HIGH && (i & B00000100));
        digitalWrite(pin_Out_S3, HIGH && (i & B00001000));
      }
    }
    
    // ****useful for debugging, comment out function call to run full speed
    void serialPringMIDIdata(){
      Serial.print(i,DEC);
      Serial.print(" :");
      Serial.print(HIGH && (i & B00000001),BIN);
      Serial.print(HIGH && (i & B00000010),BIN);
      Serial.print(HIGH && (i & B00000100),BIN);
      Serial.print(HIGH && (i & B00001000),BIN);
      Serial.print(" MUX_PIN: ");
      Serial.print(i,DEC); 
      Serial.print(" CC: ");
      Serial.print(CCID[i],DEC); 
      Serial.print(" DATA HEX: ");
      Serial.println(Mux1_State[i]>>3,HEX); 
    }

  5. #30
    heyo! Sorry I've been busy lately!
    Dealing with a super painful hiatial hernia I got when my lung collapsed a few months ago...hernia started feeling way worse recently and the painkillers are making it difficult to juggle projects (i have waaay too many on the go right now and its really difficult to focus )

    Ill check back in later but its looking like I'll need surgery again so I'm not really sure when Ill have the time...gad dangit.

  6. #31
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,052
    sorry to hear that... when you are feeling better I hope you're able to make use of this.

  7. #32
    Heyo! I got a chance to try it out and your code worked! Multiple analog inputs works perfectly through the mux! annnd the cc values didnt seem to jitter at all. You're a gad dang wizard!
    related: any idea how to output this midi info from the teensy to 5 pin midi? Usb is awesome but the thing I'm using this for requires 5 pin apparently.

    Im gunna start drafting up a vid on how to wire this thing and plop it on youtube this week. It turns out that I needed to ground my EE pin to get everything to work so Ill be damn sure to include that in the schematic......Im obviously inexperienced with multiplexers so It kinda makes sense that Id miss something like that lol

    You kick ass! Thanks so much, this solves like 10000 problems at once for me !!!

  8. #33
    Senior Member oddson's Avatar
    Join Date
    Feb 2013
    Location
    Isle in the Salish Sea
    Posts
    1,052
    I hope you're feeling better!

    Quote Originally Posted by andrewslobford View Post
    Heyo! I got a chance to try it out and your code worked! Multiple analog inputs works perfectly through the mux! annnd the cc values didnt seem to jitter at all.
    Have you tried both versions? The RAR version might me more usable in noisier electrical situations but I believe the noise you were getting was mostly from the mux channel change being sent too close to the analog read. (The dead-zone can be expanded in the other version to stabilize very noisy signals but this can limit responsiveness and make finding specific CC values with a control difficult or even impossible if the threshold it too broad.)

    Quote Originally Posted by andrewslobford View Post
    ...related: any idea how to output this midi info from the teensy to 5 pin midi? Usb is awesome but the thing I'm using this for requires 5 pin apparently.
    Here's where to start: https://www.pjrc.com/teensy/td_libs_MIDI.html

    If you are only doing MIDI-out then the hardware is pretty simple except you need to lower the values on the current-limiting resistors to run at 3.3 volts but still conduct sufficient current to operate the optocoupler in the receiving unit.

    Some schematics for 3.3v omit any resistor on the Tx line, assuming the 220 ohm on the receiving end will do that job but this is dangerous if the line gets shorted.

    Paul recommends 47 ohm for both pull-up and Tx lines. While there is no word of these values not working with any receiver; the MIDI 1.0 Electrical Specification Update gives 10 Ohms for the Tx line (enough to limit current if shorted) and 33 Ohm as a pull-up.

    The MIDI library calls are nearly identical to usbMIDI and you should be able to use them instead of, or in addition to sending usbMIDI.
    For control change messages the code is identical, just change usbMIDI.sendControlChange() to MIDI.sendControlChange().


    The other missing update in the documentation above is you now need to initialize each MIDI object before talking to it in your script in the MIDI library that is loaded with the current Teensyduino; but if you're using Tx to send normally you just need to add this before setup():
    MIDI_CREATE_DEFAULT_INSTANCE()

    Use the sample test code with this line added to test your hardware before trying anything more complex.
    Code:
    #include <MIDI.h>
    const int channel = 1;
    MIDI_CREATE_DEFAULT_INSTANCE() 
    
    void setup() {
      MIDI.begin();
    }
    
    void loop() {
      int note;
      for (note=10; note <= 127; note++) {
        MIDI.sendNoteOn(note, 100, channel);
        delay(200);
        MIDI.sendNoteOff(note, 100, channel);
      }
      delay(2000);
    }
    Quote Originally Posted by andrewslobford View Post
    It turns out that I needed to ground my EE pin to get everything to work so Ill be damn sure to include that in the schematic......Im obviously inexperienced with multiplexers so It kinda makes sense that Id miss something like that lol ...
    Hey... I wasted an hour trying to figure why the MUX wasn't responding before I remembered you have to set pins to OUTPUT mode. And that was in my very first Teensy lesson.

  9. #34
    HUGE REPLY!
    I think I have a couple 47 ohm resistors laying around here. Ill give er' a go later on (hopefully tonight)

    Once again, thanks for your time. I can't wait to make a video on how to do this for others. There's a lot of people who will be tripping balls once they see how quickly this project can be completed!

    edit: gunna try out the rar version too, if it works half as well as the other did it'll be gold.

  10. #35
    Junior Member
    Join Date
    Jan 2019
    Posts
    1
    Quote Originally Posted by andrewslobford View Post
    I can't wait to make a video on how to do this for others.
    Hi Andrew, did you ever get around to this? Did your controller work out?

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •