Forum Rule: Always post complete source code & details to reproduce any issue!
Page 1 of 3 1 2 3 LastLast
Results 1 to 25 of 63

Thread: motorized fader controller teensy 3.6 issue

  1. #1

    motorized fader controller teensy 3.6 issue

    hi
    im working on a motorized midi controler with 8 motor faders.
    i start develop my project with 1 teensy trying to use it for all functions.
    first after few weeks since i connect the first teensy the teensy just die one day (i did not make any changes or touch any thing just power it up as usual.
    so i thout that bay be my connection or wires soldering so i order another teensy and i solder everything from start to be sure its not my mistake. after few weeks of development i decided thats i should add 1 more teensy as a slave coz 1 teensy starts act weird when i used all the functions i need in the code. so i buy another teensy and connected it as a master in i2c with pullup resistors.
    it work for few days of code development untill today. i must say that again i didnt touch any thing or make any changes. the only change i made was in the master code trying to send movement data to gerrit slave code to move the faders and i did it they move to the place i send them. so i know the system work and also the codes work until the teensy dies.

    first i must say im new in the code field and im not programer.
    my goal is to send usb midi from pc to the master process the data and send it to faders.
    i have already did this process in serial rx tx connection test and its work fine also sending data from the fader to the pc was ok
    but only when i tryd to read and write from both sides its got stack. so i move to gerrit slave code that i know is build for this goal.
    but after 2 or 3 times i change the slave code and send the data to master the master stop responed and just die.
    i tryd all the recovery methods from press reset button and plug the cable also tryd to look in verbos info and even i lookd under- about this mac / usb/
    and nothing.... the chip is dead.

    ther is any chance the master can kill the slave chip with overflow data? coz if so that the only think i can think of.

    im waitng now for the pcb i develop and orderd. and im waiting for new teensy to come to build this project again in the best way but im realy afraid that this is gonna heppend again from no where.
    so if u gays can halp me to understend what im doing wrong ill be very grateful.
    also ill be glad to get any help with the code.

    this is the PCB schematic i made of the project its the same as gerrit project.(i have one mistake over ther coz the pcb ready for Serial RX TX 33,34 and im gonna use I2C. so ill solder 2 new lines in the back of the pcb with pull ups resistors from 33,34 in the slave to new free pin that il choos in the master)

    https://drive.google.com/file/d/1Rzp...ew?usp=sharing


    gerrit controller project:
    https://forum.pjrc.com/threads/42477...torfader-panel.


    i used the same parts in my project:

    220 ac to 12 dc 4A psu
    2X dc to dc step down (for 5v and 10v)
    2X teensy 3.6
    4X l9110s H briges
    8X ALPS motorized faders 100mm
    AD70 cricut for AREF

    gerrit code for the slave i used (i tryd put this code to run in the loop for test that the code that moves my faders in the last time)
    Code:
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
      for (int i=0;i<8;i++){
        // split Target integers over two bytes in array
        faderTargetData[(i*2)]=(faderTarget[i] >> 8) & 0xFF;
        faderTargetData[(i*2)+1]=faderTarget[i] & 0xFF;
        // fill last byte in array with faderMove boolean array
        faderTargetData[16] |= faderMove[i] << i;
      }
      // Transmit to Slave
      Wire.beginTransmission(PANEL_ADDR);   // Slave address
      // Send mode
      Wire.write(mode);
      // Send target data
      for(idx = 0; idx <= MESSAGE_LEN; idx++) // Write data to I2C Tx buffer
          Wire.write(faderTargetData[idx]);
      Wire.endTransmission();           // Transmit to Slave
    }
    the way i tryd to run it
    Code:
    // -------------------------------------------------------------------------------------------
    // Basic Master
    // -------------------------------------------------------------------------------------------
    //
    // This creates a simple I2C Master device which when triggered will send/receive a text 
    // string to/from a Slave device.  It is intended to pair with a Slave device running the 
    // basic_slave sketch.
    //
    // Pull pin12 input low to send.
    // Pull pin11 input low to receive.
    //
    // This example code is in the public domain.
    //
    // -------------------------------------------------------------------------------------------
    
    #include <i2c_t3.h>
    
    // Memory
    #define MESSAGE_LEN 17
    uint8_t PANEL_ADDR = 0x66; 
    char databuf[MESSAGE_LEN];
    
    int count;
    int     faderTargetData[8]={500,500,500,500,500,500,500,500}; 
    boolean faderMove[8];
    int     faderTarget[8];
    
    
    void setup()
    {
        pinMode(LED_BUILTIN,OUTPUT);    // LED
        digitalWrite(LED_BUILTIN,LOW);  // LED off
        pinMode(12,INPUT_PULLUP);       // Control for Send
        pinMode(11,INPUT_PULLUP);       // Control for Receive
    
        // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
        Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
        Wire.setDefaultTimeout(200000); // 200ms
    
        // Data init
        memset(databuf, 0, sizeof(databuf));
        count = 0;
    
        Serial.begin(115200);
    }
    
    void loop()
    {
    sendFaderCommand(MESSAGE_LEN);
    //    if(digitalRead(11) == LOW)
    //    {
    //        digitalWrite(LED_BUILTIN,HIGH);   // LED on
    //
    //        // Print message
    //        Serial.print("Reading from Slave: ");
    //        
    //        // Read from Slave
    //        Wire.requestFrom(PANEL_ADDR, (size_t)MESSAGE_LEN); // Read from Slave (string len unknown, request full buffer)
    //
    //        // Check if error occured
    //        if(Wire.getError())
    //            Serial.print("FAIL\n");
    //        else
    //        {
    //            // If no error then read Rx data into buffer and print
    //            Wire.read(databuf, Wire.available());
    //            Serial.printf("'%s' OK\n",databuf);
    //        }
    //
    //        digitalWrite(LED_BUILTIN,LOW);    // LED off
    //        delay(100);                       // Delay to space out tests
    //    }
    }
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
      for (int i=0;i<8;i++){
        // split Target integers over two bytes in array
        faderTargetData[(i*2)]=(faderTarget[i] >> 8) & 0xFF;
        faderTargetData[(i*2)+1]=faderTarget[i] & 0xFF;
        // fill last byte in array with faderMove boolean array
        faderTargetData[16] |= faderMove[i] << i;
      }
      // Transmit to Slave
      Wire.beginTransmission(PANEL_ADDR);   // Slave address
      // Send mode
      Wire.write(mode);
      // Send target data
      for(idx = 0; idx <= MESSAGE_LEN; idx++) // Write data to I2C Tx buffer
          Wire.write(faderTargetData[idx]);
      Wire.endTransmission();           // Transmit to Slave
    }
    gerrit code for the slave i used

    Code:
    /* 
      Zeus Commander Controller Series
      I2C controlled motorfader octet
    
      Full PID motor control supporting two operating modes:
      TARGET  for fast preset recall
      FOLLOW  for slow to fast following of values 
    
      This code expands on the examples provided with the i2c_t3 library for the I2Ccommunication
      
      This code is in the public domain.
    */
    #include <i2c_t3.h>
    #include <ResponsiveAnalogRead.h>
    
    // PID arrays
    float dState[8];
    float iState[8];
    float iMin[8];
    float iMax[8];
    float pGain[8];
    float iGain[8];
    float dGain[8];
    float plantDrive[8];
    float maxD=0.00;       // maximum derivative value for debugging purposes
    
    void UpdatePID(int faderIndex, float faderError, float faderPosition)
    {
      float pTerm, dTerm, iTerm, plantDriveInput;
      // calculate the proportional term
      pTerm = pGain[faderIndex] * faderError;   
      // calculate the integral state with appropriate limiting
      iState[faderIndex] += faderError;
      if (iState[faderIndex] > iMax[faderIndex]){
        iState[faderIndex] = iMax[faderIndex];
        }
      else if (iState[faderIndex] < iMin[faderIndex]){
        iState[faderIndex] = iMin[faderIndex];
      }
      iTerm = iGain[faderIndex] * iState[faderIndex];  // calculate the integral term
      dTerm = dGain[faderIndex] * (faderPosition - dState[faderIndex]);
      if (abs(faderPosition - dState[faderIndex]) > maxD){
        maxD=abs(faderPosition - dState[faderIndex]);
      }
      dState[faderIndex] = faderPosition;
    
      plantDriveInput = pTerm + iTerm - dTerm;
      if (plantDriveInput > 4096) {
        plantDriveInput=4096;
      }
        if (plantDriveInput < -4096) {
        plantDriveInput=-4096;
      }
      plantDrive[faderIndex]=plantDriveInput;
    }
    
    elapsedMicros sinceFaderRead;                         // timer for fader check
    unsigned int  faderReadInterval=1000;                 // interval in microseconds for checking fader position(update)
    elapsedMicros sinceTouchRead;                         // timer for touch read
    unsigned int  touchReadInterval=5000;                 // interval in microseconds for reading fader touch
    elapsedMillis sinceLastCommand;                       // timer for time-out of PIF after last command
    unsigned int  commandTimeOutInterval=500;             // interval for PID time-out in milliseconds
    int     faderWiperPin[8]={32,31,39,20,21,15,65,64};   // analog in pin for fader wipers
    int     faderTouchPin[8]={1,0,16,17,18,19,22,23};     // touchRead pins for fader touch
    int     faderMotorUpPin[8]={29,9,7,5,3,14,36,38};     // motor up PWM pin
    int     faderMotorDownPin[8]={30,10,8,6,4,2,35,37};   // motor down PWM pin
    int     faderValue[8];                                // fader value ranging 0 to 1023
    int     faderTarget[8];                               // fader target value ranging 0 to 1023
    int     faderTouch[8];                                // fader touch reading
    boolean faderPidOn[8];                                // status of PID
    int     faderTouchThreshold=3000;                     // threshold value for touchRead
    boolean faderTouched[8];                              // boolean indicating if fader is touched
    
    ResponsiveAnalogRead analog[8]{ResponsiveAnalogRead(32, true),ResponsiveAnalogRead(31, true),
                                   ResponsiveAnalogRead(39, true),ResponsiveAnalogRead(20, true),
                                   ResponsiveAnalogRead(21, true),ResponsiveAnalogRead(15, true),
                                   ResponsiveAnalogRead(65, true),ResponsiveAnalogRead(64, true)};
    
    // I2C communication
    // Command definitions
    #define TARGET    0x10              // All faders to target value as fast as possible. PID state is cleared with each command.
    #define FOLLOW    0x20              // Faders follow value, last byte in message is used to determine which motors should move.
                                        // PIDs will time-out after last command.
    
    // Function prototypes
    void receiveEvent(size_t count);
    void requestEvent(void);
    #define PANEL_ADDR 0x66              // I2C address, should be selectable by jumper using leftover pins.
    #define MESSAGE_LEN 17
    byte faderValueData[MESSAGE_LEN];    // 16 bytes for values, 1 byte for touch
    byte faderTargetData[MESSAGE_LEN];   // 16 for target values, 1 byte for indicating which faders should be moved.
    volatile uint8_t received;
    volatile uint8_t cmd;
    byte operatingMode = TARGET;
    
    
    void setup()
    {  
      
      //initialize faders and analog reference 
      analogReference(EXTERNAL);
      analogWriteResolution(12);
      for (int i=0; i<8; i++){
        pinMode(faderMotorUpPin[i], OUTPUT);
        pinMode(faderMotorDownPin[i], OUTPUT);
        analogWriteFrequency(faderMotorUpPin[i],14648.437);  // 14648.437 ideal frequency for 180MHz 12bit PWM
        analogWriteFrequency(faderMotorDownPin[i],14648.437);  //14648.437 ideal frequency for 180MHz 12bit PWM
        faderTouched[i]=false;
        faderValueData[i]=0;
        faderTarget[i]=500;
        faderPidOn[i]=false;
      }    
           
      readFaders();
      // set PID tuning parameters
      for (int i=0;i<8;i++){
        pGain[i]=10;
        iGain[i]=1;
        dGain[i]=50.00;
        iMin[i]=-1500;
        iMax[i]=1500;
      }
      
      // Setup for Slave mode pins 33/34, external pullups, 400kHz
      Wire.begin(I2C_SLAVE, PANEL_ADDR, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);
      // register events
      Wire.onReceive(receiveEvent);
      Wire.onRequest(requestEvent);
      cmd = 0;    // incoming command operating mode
    }
    
    void loop()                     
    {
      // check elapsedMicros and millis timers
      // faders
      if (sinceFaderRead >=faderReadInterval) {
        sinceFaderRead = sinceFaderRead-faderReadInterval;
        readFaders();
        
        // always update PID for timing consistency
        for (int i=0;i<8;i++){
            UpdatePID(i,faderTarget[i]-faderValue[i],faderValue[i]);
          }
          
        // loop through faders and move where necessary
        for (int i=0;i<8;i++){
          if (!faderTouched[i] && faderPidOn[i]){
            if(plantDrive[i]>0 && faderValue[i] <=1022){
              analogWrite(faderMotorDownPin[i],0);
              analogWrite(faderMotorUpPin[i],plantDrive[i]);
            } else if (plantDrive[i] <=0 && faderValue[i] >=1){
              analogWrite(faderMotorUpPin[i],0);
              analogWrite(faderMotorDownPin[i],-plantDrive[i]);
            }
          } 
          else if(!faderPidOn[i]){
              analogWrite(faderMotorDownPin[i],0);
              analogWrite(faderMotorUpPin[i],0);
            }
        }
      }
      
      //  separate touchRead timer 
      if (sinceTouchRead >= touchReadInterval){
        sinceTouchRead = sinceTouchRead - touchReadInterval;
        readTouch();
      }
      
      // command time-out  
      if (sinceLastCommand >= commandTimeOutInterval){
        for (int i=0;i<8;i++){
          faderPidOn[i]=false;
        }
        sinceLastCommand = 0;
      }
      
    }
    
    // read fader analog values and update faderValue array
    void readFaders() {
      for (int i=0; i<8; i++) {
        analog[i].update();
        faderValue[i] = analog[i].getValue();
      } 
    }
    
    // read fader touch
    void readTouch() {
      for (int i=0; i<8; i++) {
        faderTouch[i]= touchRead(faderTouchPin[i]);
        if (faderTouch[i]>faderTouchThreshold){
          faderTouched[i]=true;
        } else if (faderTouch[i]<=faderTouchThreshold){
          faderTouched[i]=false;
        }
      } 
    }
    
    // handle Rx Event (incoming I2C data)
    void receiveEvent(size_t count) {
      size_t idx;
      int incomingTargetValue[8];
      boolean incomingFaderMove[8];
      if(count)
      {
        // grab command
        cmd = Wire.readByte();
        switch(cmd)
        {
        case TARGET:
          if (operatingMode==FOLLOW){
            // set PID tuning parameters
    //        for (int i=0;i<8;i++){
    //          pGain[i]=20.00;
    //          iGain[i]=0.5;
    //          dGain[i]=40.00;
    //        }
            operatingMode=TARGET;
          }
          break;
        case FOLLOW:
          if (operatingMode==TARGET){
            // set PID tuning parameters
    //        for (int i=0;i<8;i++){
    //          pGain[i]=20.00;
    //          iGain[i]=0.5;
    //          dGain[i]=40.00;
    //        }
            operatingMode=FOLLOW;
          }
          break;
        }
        idx = 0;
        while(Wire.available()) faderTargetData[idx++] = Wire.readByte();
              
        // Process data
        for (int i=0;i<8;i++){
          // combine bytes back to integers and put in temporary array
          incomingTargetValue[i]= faderTargetData[(i*2)];
          incomingTargetValue[i]= incomingTargetValue[i] << 8 | faderTargetData[(i*2)+1];
          // fill faderPidOn boolean array with last byte
          incomingFaderMove[i] = 1 & faderTargetData[16] >> i;
          // clear PID states if PID is switched on or if mode is TARGET
          if ((incomingFaderMove[i] && faderPidOn[i]!=incomingFaderMove[i]) || operatingMode==TARGET){
            dState[i]=faderValue[i]; 
            iState[i]=0; 
          }
          faderPidOn[i]=  incomingFaderMove[i];
          // update fader target
          faderTarget[i]=incomingTargetValue[i];
        }
        // reset timer
        sinceLastCommand=0;
      }
    }
    
    // handle Tx Event (outgoing I2C data)
    void requestEvent(void)
    {
      faderValueData[16]=0;
      for (int i=0;i<8;i++){
        // split value integers over two bytes in array
        faderValueData[(i*2)]=(faderValue[i] >> 8) & 0xFF;
        faderValueData[(i*2)+1]=faderValue[i] & 0xFF;
        // fill last byte in array with touch boolean array
        faderValueData[16] |= faderTouched[i] << i;
      }
      Wire.write(faderValueData, MESSAGE_LEN); // fill Tx buffer (send full mem)
    }
    my final goal is send PROTOOLS faders data to motor faders thru usbmidi and receive data from motor faders to PROTOOLS with faders touch sens press / release command in the highest speed response i can get and best stability.
    soon ill upload the assembled pcb and ill up load the codes im gonna use to get ur opinion before i run it again,

    thank u all
    Rota
    Last edited by rotabox; 01-28-2019 at 12:55 PM.

  2. #2
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    An actual schematic would be required to comment on this, not just the PCB layout. My first guess would be that you connected the I2C pull up resistors to 5V in stead of 3.3V because there's no way sending data can destroy a Teensy.

  3. #3
    Quote Originally Posted by Gerrit View Post
    An actual schematic would be required to comment on this, not just the PCB layout. My first guess would be that you connected the I2C pull up resistors to 5V in stead of 3.3V because there's no way sending data can destroy a Teensy.
    thank you gerrit for your fast replay
    i connected the pullup resistor to the 3V inthe master teensy.
    just for mention master teensy got the 5v power from the usb cable and the slave got the power from psu after i cut the usb power trace as wirte on the teensy manual and all works ok.

    here is my schematic:
    https://drive.google.com/file/d/1sjN...ew?usp=sharing
    Last edited by rotabox; 01-28-2019 at 02:21 PM.

  4. #4
    in time im waiting for parts
    im trying to think how the master code should be handle usb midi i guess its need to be somthing like this:

    Code:
    // -------------------------------------------------------------------------------------------
    // Basic Master
    // -------------------------------------------------------------------------------------------
    //
    // This creates a simple I2C Master device which when triggered will send/receive a text
    // string to/from a Slave device.  It is intended to pair with a Slave device running the
    // basic_slave sketch.
    //
    // Pull pin12 input low to send.
    // Pull pin11 input low to receive.
    //
    // This example code is in the public domain.
    //
    // -------------------------------------------------------------------------------------------
    #include <MIDIUSB.h>
    #include <i2c_t3.h>
    
    // Memory
    #define MESSAGE_LEN 17
    uint8_t PANEL_ADDR = 0x66;
    char databuf[MESSAGE_LEN];
    
    int count;
    int     faderTargetData[8];
    boolean faderMove[8];
    int     faderTarget[8];
    byte lo[8];
    byte hi[8];
    byte Gain[8];
    
    void setup()
    {
    
      // Setup for Master mode, pins 18/19, external pullups, 400kHz, 200ms default timeout
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 400000);
      Wire.setDefaultTimeout(200000); // 200ms
    
      // Data init
      memset(databuf, 0, sizeof(databuf));
      count = 0;
    
      Serial.begin(115200);
    }
    
    void loop()
    {
      sendFaderCommand(MESSAGE_LEN);
      //    if(digitalRead(11) == LOW)
      //    {
      //        digitalWrite(LED_BUILTIN,HIGH);   // LED on
      //
      //        // Print message
      //        Serial.print("Reading from Slave: ");
      //
      //        // Read from Slave
      //        Wire.requestFrom(PANEL_ADDR, (size_t)MESSAGE_LEN); // Read from Slave (string len unknown, request full buffer)
      //
      //        // Check if error occured
      //        if(Wire.getError())
      //            Serial.print("FAIL\n");
      //        else
      //        {
      //            // If no error then read Rx data into buffer and print
      //            Wire.read(databuf, Wire.available());
      //            Serial.printf("'%s' OK\n",databuf);
      //        }
      //
      //        digitalWrite(LED_BUILTIN,LOW);    // LED off
      //        delay(100);                       // Delay to space out tests
      //    }
    }
    void sendFaderCommand(byte mode) {
      size_t idx;
      faderTargetData[16] = 0;
      for (int i = 0; i < 8; i++) {
        // split Target integers over two bytes in array
        faderTargetData[(i * 2)] = (faderTarget[i] >> 8) & 0xFF;
        faderTargetData[(i * 2) + 1] = faderTarget[i] & 0xFF;
        // fill last byte in array with faderMove boolean array
        faderTargetData[16] |= faderMove[i] << i;
      }
      // Transmit to Slave
      Wire.beginTransmission(PANEL_ADDR);   // Slave address
      // Send mode
      Wire.write(mode);
      // Send target data
      for (idx = 0; idx <= MESSAGE_LEN; idx++) // Write data to I2C Tx buffer
        Wire.write(faderTargetData[idx]);
      Wire.endTransmission();           // Transmit to Slave
    }
    void myControlChange(byte channel, byte control, byte value) {               // blink the LED a number of times
      value = map(value, 0, 127, 127, 0);
      //INT FADERS GAINS
      if (control == 32) {
        hi[0] = value;
      }
      if (control == 0) {
        lo[0] = value;
        Gain[0] = (hi[0] >> 7) + lo[0];
        faderTargetData[0] = Gain[0];
      }
    
      if (control == 33) {
        hi[1] = value;
      }
      if (control == 1) {
        lo[1] = value;
        Gain[1] = (hi[1] >> 7) + lo[1];
        faderTargetData[1] = Gain[1];
      }
      if (control == 34) {
        hi[2] = value;
      }
      if (control == 2) {
        lo[2] = value;
        Gain[2] = (hi[2] >> 7) + lo[2];
        faderTargetData[2] = Gain[2];
      }
    
      if (control == 35) {
        hi[3] = value;
      }
      if (control == 3) {
        lo[3] = value;
        Gain[3] = (hi[3] >> 7) + lo[3];
        faderTargetData[3] = Gain[3];
      }
    
      if (control == 36) {
        hi[4] = value;
      }
      if (control == 4) {
        lo[4] = value;
        Gain[4] = (hi[4] >> 7) + lo[4];
        faderTargetData[4] = Gain[4];
      }
    
      if (control == 37) {
        hi[5] = value;
      }
      if (control == 5) {
        lo[5] = value;
        Gain[5] = (hi[5] >> 7) + lo[5];
        faderTargetData[5] = Gain[5];
      }
    
      if (control == 38) {
        hi[6] = value;
      }
      if (control == 6) {
        lo[6] = value;
        Gain[6] = (hi[6] >> 7) + lo[6];
        faderTargetData[6] = Gain[6];
      }
    
      if (control == 39) {
        hi[7] = value;
      }
      if (control == 7) {
        lo[7] = value;
        Gain[7] = (hi[7] >> 7) + lo[7];
        faderTargetData[7] = Gain[7];
      }
    }

  5. #5
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    Quote Originally Posted by rotabox View Post
    thank you gerrit for your fast replay
    i connected the pullup resistor to the 3V inthe master teensy.
    just for mention master teensy got the 5v power from the usb cable and the slave got the power from psu after i cut the usb power trace as wirte on the teensy manual and all works ok.

    here is my schematic:
    https://drive.google.com/file/d/1sjN...ew?usp=sharing
    You really should use labels in your schematic in stead of hooking everything up with lines because it's not very readable like this.
    It's not clear to me what the status is, does it all work now? No more issues with dead chips?

    With regards to Protools, I don't know how (and how fast) Protools sends the fader data so I can't comment on that yet.
    Please keep in mind that the panel was developed for fast preset recall for use with a MIDI step sequencer and not for slowly following fades, the PID control would probably need to be adapted for that purpose (tuning parameters).

  6. #6
    Quote Originally Posted by Gerrit View Post
    You really should use labels in your schematic in stead of hooking everything up with lines because it's not very readable like this.
    It's not clear to me what the status is, does it all work now? No more issues with dead chips?

    With regards to Protools, I don't know how (and how fast) Protools sends the fader data so I can't comment on that yet.
    Please keep in mind that the panel was developed for fast preset recall for use with a MIDI step sequencer and not for slowly following fades, the PID control would probably need to be adapted for that purpose (tuning parameters).
    you right about the labels . sorrry its the first time i try to do schem on EASY EDA.
    now after the last chip is dead i take all apart and im witing now for the pcb.
    and im waitng for new teensy to arrive from ebay and im gonna build everything again.
    so nothing work now.
    about protools movment ill take care for that tuning part at the end after communication will work good both side.
    thanks to you its gonna be less hard to do it coz the pid for 8 motors its allredy in your code.

  7. #7
    about protools hui midi protocol.
    I know the protocol works and how he send the data like in my example under control change void
    I test this void in all of my test and it works and send data to faders as aspected.
    I also test send wiper value to protocols and it works and move the fader in the DAW.
    Like I said before when I was trying to combine the send receive void's in my test Its always stack's the slave or the master teensy I did so many test in midi USB to faders
    and midi USB to serial to slave to fader.
    But I didn't figure out how to get smooth send receive for for read and wirte faders.
    Should I use the regular master sketch example for this use or advanced master example or maybe loopback?
    Should I send receive 17 bytes all the time non stop? If yes how can I do it in the right way?

  8. #8

  9. #9
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    This is the code I currently have in the master:

    Code:
    // get fader values and touch status
    void getFaderData() {
      size_t idx;
      int incomingFaderValue[16];    // 
      int touchCount=0;
      ZeusPattern *currentPattern=&sequencerChannel[selectedChannel].pattern[sequencerChannel[selectedChannel].selectedPattern];
      // Read from Slave
      for (int j=0;j<2;j++){
        Wire.requestFrom(panelAddress[j], (size_t)MESSAGE_LEN); // Read from Slave
        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
        {
          // If no error then read Rx data into buffer
          idx = 0;
          while(Wire.available()) faderValueData[idx++] = Wire.readByte();
          // Process data in buffer
          for (int i=0;i<8;i++){
          // combine bytes back to integers and put in temporary array
          incomingFaderValue[i]= faderValueData[(i*2)];
          incomingFaderValue[i]= incomingFaderValue[i] << 8 | faderValueData[(i*2)+1];
          // fill touch boolean array with last byte
          faderTouched[i+j*8] = 1 & faderValueData[16] >> i;
          if (faderTouched[i+j*8]) touchCount++;
          // check if faderValue needs to be updated
          if (incomingFaderValue[i]!=faderValue[i+j*8] and faderTouched[i+j*8]){
            faderValue[i+j*8]=incomingFaderValue[i];
            currentPattern->step[i+j*8].value[selectedParameter]=map(faderValue[i+j*8],0,1023,parameterLimit[selectedParameter][0],parameterLimit[selectedParameter][1]);
            updateDisplayData=true;
    //        Serial.print("Fader ");
    //        Serial.print(i+j*8);
    //        Serial.print("\t");
    //        Serial.println(faderValue[i+j*8]);
          }
        }
      }
      faderTouchCount=touchCount;
      }
    }
    
    // Send command with faderTarget array values to fader, TARGET or FOLLOW mode
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
      for (int j=0;j<2;j++){
        for (int i=0;i<8;i++){
          faderTargetData[(i*2)]=(faderTarget[i+j*8] >> 8) & 0xFF;                // split Target integers over two bytes in array
          faderTargetData[(i*2)+1]=faderTarget[i+j*8] & 0xFF;
          faderTargetData[16] |= faderMove[i+j*8] << i;                           // fill last byte in array with faderMove boolean array
        }
        Wire.beginTransmission(panelAddress[j]);                                  // Transmit to Slave
        Wire.write(mode);                                                         // Send mode (TARGET or FOLLOW)
        for(idx = 0; idx < MESSAGE_LEN; idx++) Wire.write(faderTargetData[idx]);  // Write data to I2C Tx buffer
        Wire.endTransmission();                                                   // Transmit to Slave
      }
    }
    There're two panels connected to the master getFaderData() is called from within the main loop:
    Code:
      //  substract interval to maintain schedule
      // faders
      if (sinceFaderRead >=faderReadInterval) {
        sinceFaderRead = sinceFaderRead - faderReadInterval;
        getFaderData();
        if (linkMode!=LINK_OFF) handleLinkMode();
      }
    The fader read interval is set at 5ms. The I2C communication is setup for 1Mhz:
    Code:
      //**** I2C *****
      // Setup for Master mode, pins 18/19, external pullups, 1MHz, 200ms default timeout
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 1000000);
      Wire.setDefaultTimeout(200000); // 200ms
    The getFaderData() function takes just under 0.5ms for sending requests to two panels and storing the responses. You should be able to just call sendFaderCommand() from your MIDI event handler function.

    Sometimes I get I2C communication errors on startup, I haven't figured out yet what the cause is but it only happens on startup. Once started everything works just fine.

  10. #10
    Quote Originally Posted by Gerrit View Post
    This is the code I currently have in the master:

    Code:
    // get fader values and touch status
    void getFaderData() {
      size_t idx;
      int incomingFaderValue[16];    // 
      int touchCount=0;
      ZeusPattern *currentPattern=&sequencerChannel[selectedChannel].pattern[sequencerChannel[selectedChannel].selectedPattern];
      // Read from Slave
      for (int j=0;j<2;j++){
        Wire.requestFrom(panelAddress[j], (size_t)MESSAGE_LEN); // Read from Slave
        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
        {
          // If no error then read Rx data into buffer
          idx = 0;
          while(Wire.available()) faderValueData[idx++] = Wire.readByte();
          // Process data in buffer
          for (int i=0;i<8;i++){
          // combine bytes back to integers and put in temporary array
          incomingFaderValue[i]= faderValueData[(i*2)];
          incomingFaderValue[i]= incomingFaderValue[i] << 8 | faderValueData[(i*2)+1];
          // fill touch boolean array with last byte
          faderTouched[i+j*8] = 1 & faderValueData[16] >> i;
          if (faderTouched[i+j*8]) touchCount++;
          // check if faderValue needs to be updated
          if (incomingFaderValue[i]!=faderValue[i+j*8] and faderTouched[i+j*8]){
            faderValue[i+j*8]=incomingFaderValue[i];
            currentPattern->step[i+j*8].value[selectedParameter]=map(faderValue[i+j*8],0,1023,parameterLimit[selectedParameter][0],parameterLimit[selectedParameter][1]);
            updateDisplayData=true;
    //        Serial.print("Fader ");
    //        Serial.print(i+j*8);
    //        Serial.print("\t");
    //        Serial.println(faderValue[i+j*8]);
          }
        }
      }
      faderTouchCount=touchCount;
      }
    }
    
    // Send command with faderTarget array values to fader, TARGET or FOLLOW mode
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
      for (int j=0;j<2;j++){
        for (int i=0;i<8;i++){
          faderTargetData[(i*2)]=(faderTarget[i+j*8] >> 8) & 0xFF;                // split Target integers over two bytes in array
          faderTargetData[(i*2)+1]=faderTarget[i+j*8] & 0xFF;
          faderTargetData[16] |= faderMove[i+j*8] << i;                           // fill last byte in array with faderMove boolean array
        }
        Wire.beginTransmission(panelAddress[j]);                                  // Transmit to Slave
        Wire.write(mode);                                                         // Send mode (TARGET or FOLLOW)
        for(idx = 0; idx < MESSAGE_LEN; idx++) Wire.write(faderTargetData[idx]);  // Write data to I2C Tx buffer
        Wire.endTransmission();                                                   // Transmit to Slave
      }
    }
    There're two panels connected to the master getFaderData() is called from within the main loop:
    Code:
      //  substract interval to maintain schedule
      // faders
      if (sinceFaderRead >=faderReadInterval) {
        sinceFaderRead = sinceFaderRead - faderReadInterval;
        getFaderData();
        if (linkMode!=LINK_OFF) handleLinkMode();
      }
    The fader read interval is set at 5ms. The I2C communication is setup for 1Mhz:
    Code:
      //**** I2C *****
      // Setup for Master mode, pins 18/19, external pullups, 1MHz, 200ms default timeout
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 1000000);
      Wire.setDefaultTimeout(200000); // 200ms
    The getFaderData() function takes just under 0.5ms for sending requests to two panels and storing the responses. You should be able to just call sendFaderCommand() from your MIDI event handler function.

    Sometimes I get I2C communication errors on startup, I haven't figured out yet what the cause is but it only happens on startup. Once started everything works just fine.
    amazing. thank you very much gerrit
    thats for sure gonna help me. ill dig it and ill try to understand how should i write my code .
    soon when all the new parts will arrive ill post some new photos with the new pcb and the system and ill post the sketch im gonna test first.

  11. #11
    so...
    i got the pcb and i started to solder the mount pins and the pullups 4.6K resistors on the back side from pins 18 19 to 3V pin.
    like i said here before i i have mistake on this bord so i solder 2 lines from pins 18 19 in the master to pins 33 34 on the slave to use i2c connection.
    here is the Back side Pic of PCB:
    https://drive.google.com/file/d/1l4O...ew?usp=sharing

  12. #12
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    Quote Originally Posted by rotabox View Post
    so...
    i got the pcb and i started to solder the mount pins and the pullups 4.6K resistors on the back side from pins 18 19 to 3V pin.
    like i said here before i i have mistake on this bord so i solder 2 lines from pins 18 19 in the master to pins 33 34 on the slave to use i2c connection.
    here is the Back side Pic of PCB:
    https://drive.google.com/file/d/1l4O...ew?usp=sharing
    4k6 seems a bit high to me, master and slave are on the same board but still why not use a something like 2k2 or 1k8? Do you have (access to) an oscilloscope so you can check the I2C signal to verify that the rise time is sufficiently low (120 ns for 1MHz)?

  13. #13
    Quote Originally Posted by Gerrit View Post
    4k6 seems a bit high to me, master and slave are on the same board but still why not use a something like 2k2 or 1k8? Do you have (access to) an oscilloscope so you can check the I2C signal to verify that the rise time is sufficiently low (120 ns for 1MHz)?
    i used info from here:
    https://www.pjrc.com/teensy/td_libs_Wire.html

    Teensy LC & 3.0-3.6 requires pullup resistors to +3.3V. The on-chip pullups are not used. 4.7K resistors are recommended for most applications.

    that could make any damage to use 4.7K? what resistor size u use for pullup resistors?

  14. #14
    Quote Originally Posted by Gerrit View Post
    4k6 seems a bit high to me, master and slave are on the same board but still why not use a something like 2k2 or 1k8? Do you have (access to) an oscilloscope so you can check the I2C signal to verify that the rise time is sufficiently low (120 ns for 1MHz)?
    i search on web and i also find paul stoffregen recommendation to use 1K to 2k2 resistors for SDA SCL .
    but why the pjrc site recommends for 4k7?
    i must say that in my last test it works with the 4k7. im a bit confused.
    i find some 2k2 value in my stock and also 10K value.
    now i wonder what is the best way... to connect the 2k2 to 3.3v from the teensy. or 10K to 5V from the PSU?
    Last edited by rotabox; 02-16-2019 at 06:08 AM.

  15. #15
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    8,838
    Quote Originally Posted by rotabox View Post
    i search on web and i also find paul stoffregen recommendation to use 1K to 2k2 resistors for SDA SCL .
    but why the pjrc site recommends for 4k7?
    The ideal resistance a factor of bus speed and voltage. Possibly the PJRC pages not linked was in reference to 5V T_2's? The 3.3V power of the T_LC and 3.x's are different and a lower value can allow faster bus speed transitions.

  16. #16
    Quote Originally Posted by defragster View Post
    The ideal resistance a factor of bus speed and voltage. Possibly the PJRC pages not linked was in reference to 5V T_2's? The 3.3V power of the T_LC and 3.x's are different and a lower value can allow faster bus speed transitions.
    i change my resistors to 2K2 connected to 3.3v pin of the master teensy. i hope that will be ok.

    the PJRC page talk about reference to 3.3V

  17. #17
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    Quote Originally Posted by rotabox View Post
    i search on web and i also find paul stoffregen recommendation to use 1K to 2k2 resistors for SDA SCL .
    but why the pjrc site recommends for 4k7?
    i must say that in my last test it works with the 4k7. im a bit confused.
    i find some 2k2 value in my stock and also 10K value.
    now i wonder what is the best way... to connect the 2k2 to 3.3v from the teensy. or 10K to 5V from the PSU?
    First, always connect the pull up resistors to 3.3V when using a Teensy 3.6! Second, a too high value of the pull up resistors cannot damage a Teensy (a much too low value could).

    The best way is to use an oscilloscope to check the shape of the pulses, that's why I asked if you have (access to) one. The value of the pull up resistors depends on the operating voltage and the I2C speed. My guess would be that the 4k7 recommendation refers to 5V operation and 100kHz clock (normal I2C speed). If it works in your case and you have reliable communication there's no need to lower the value. The thing is that without using an oscilloscope to check the pulse shape you do not know if you're close to the edge of what is required which might lead to intermittent errors, hence my suggestion to use 2k2 or 1k8 just to be on the safe side.

    My case is very different from yours because I have two slaves connected via a cable to the master and I wanted to use the highest speed possible, this requires very low values for the pull ups because of the high(er) capacitance of the cables.
    Here's a comparison of three different values for the pull up resistors:

    Click image for larger version. 

Name:	I2C_PullUp_Compare.jpg 
Views:	18 
Size:	45.4 KB 
ID:	15922

    The I2C speed was 2.5MHz (notice that the pulse frequency is actually just over 1MHz). The 1k8 resistors cannot pull up the voltage fast enough and even the minimum I2C spec value of 980Ω (approximate, for 3mA sink current) is not sufficient so I ended up increasing the sink current to about 5mA by using 640Ω as there are no other I2C devices on the bus, just three Teensies. Even with 640Ω the communication was not reliable at 2.5MHz so I reduced the speed to 1MHz and now everything is working fine.
    Note that this is for my specific case with two slaves and long cables, for your case 2k2 should be fine, it's just to show how the pull up resistor values affect the pulse shape.

  18. #18
    Quote Originally Posted by Gerrit View Post
    First, always connect the pull up resistors to 3.3V when using a Teensy 3.6! Second, a too high value of the pull up resistors cannot damage a Teensy (a much too low value could).

    The best way is to use an oscilloscope to check the shape of the pulses, that's why I asked if you have (access to) one. The value of the pull up resistors depends on the operating voltage and the I2C speed. My guess would be that the 4k7 recommendation refers to 5V operation and 100kHz clock (normal I2C speed). If it works in your case and you have reliable communication there's no need to lower the value. The thing is that without using an oscilloscope to check the pulse shape you do not know if you're close to the edge of what is required which might lead to intermittent errors, hence my suggestion to use 2k2 or 1k8 just to be on the safe side.

    My case is very different from yours because I have two slaves connected via a cable to the master and I wanted to use the highest speed possible, this requires very low values for the pull ups because of the high(er) capacitance of the cables.
    Here's a comparison of three different values for the pull up resistors:

    Click image for larger version. 

Name:	I2C_PullUp_Compare.jpg 
Views:	18 
Size:	45.4 KB 
ID:	15922

    The I2C speed was 2.5MHz (notice that the pulse frequency is actually just over 1MHz). The 1k8 resistors cannot pull up the voltage fast enough and even the minimum I2C spec value of 980Ω (approximate, for 3mA sink current) is not sufficient so I ended up increasing the sink current to about 5mA by using 640Ω as there are no other I2C devices on the bus, just three Teensies. Even with 640Ω the communication was not reliable at 2.5MHz so I reduced the speed to 1MHz and now everything is working fine.
    Note that this is for my specific case with two slaves and long cables, for your case 2k2 should be fine, it's just to show how the pull up resistor values affect the pulse shape.
    thank for your deep replay gerrit ill dig it as allways
    i have an old oscilloscope i m not realy sure how to mesure it but ill try to do it when all the board will be soldered and working.
    for now im going with the 2K2 ilke you said. soon ill upload some pics of the panel with the screens and the internal view.
    many thanks

  19. #19
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    20,176
    If you're buying I2C displays, they may also have pullup resistors.

    Usually you would want to combined (parallel) resistance to be between 1K to 5K.

  20. #20
    Quote Originally Posted by PaulStoffregen View Post
    If you're buying I2C displays, they may also have pullup resistors.

    Usually you would want to combined (parallel) resistance to be between 1K to 5K.
    thanks for your replay Paul
    im gonna use TCA9548A for 8 screens.

    here is some pics from my project:
    https://drive.google.com/file/d/1FC4...ew?usp=sharing
    https://drive.google.com/file/d/1XK6...ew?usp=sharing
    https://drive.google.com/file/d/1JDF...ew?usp=sharing
    https://drive.google.com/file/d/139B...ew?usp=sharing
    https://drive.google.com/file/d/1a1F...ew?usp=sharing
    https://drive.google.com/file/d/1XK6...ew?usp=sharing
    Last edited by rotabox; 02-16-2019 at 11:01 AM.

  21. #21

  22. #22
    Quote Originally Posted by Gerrit View Post
    This is the code I currently have in the master:

    Code:
    // get fader values and touch status
    void getFaderData() {
      size_t idx;
      int incomingFaderValue[16];    // 
      int touchCount=0;
      ZeusPattern *currentPattern=&sequencerChannel[selectedChannel].pattern[sequencerChannel[selectedChannel].selectedPattern];
      // Read from Slave
      for (int j=0;j<2;j++){
        Wire.requestFrom(panelAddress[j], (size_t)MESSAGE_LEN); // Read from Slave
        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
        {
          // If no error then read Rx data into buffer
          idx = 0;
          while(Wire.available()) faderValueData[idx++] = Wire.readByte();
          // Process data in buffer
          for (int i=0;i<8;i++){
          // combine bytes back to integers and put in temporary array
          incomingFaderValue[i]= faderValueData[(i*2)];
          incomingFaderValue[i]= incomingFaderValue[i] << 8 | faderValueData[(i*2)+1];
          // fill touch boolean array with last byte
          faderTouched[i+j*8] = 1 & faderValueData[16] >> i;
          if (faderTouched[i+j*8]) touchCount++;
          // check if faderValue needs to be updated
          if (incomingFaderValue[i]!=faderValue[i+j*8] and faderTouched[i+j*8]){
            faderValue[i+j*8]=incomingFaderValue[i];
            currentPattern->step[i+j*8].value[selectedParameter]=map(faderValue[i+j*8],0,1023,parameterLimit[selectedParameter][0],parameterLimit[selectedParameter][1]);
            updateDisplayData=true;
    //        Serial.print("Fader ");
    //        Serial.print(i+j*8);
    //        Serial.print("\t");
    //        Serial.println(faderValue[i+j*8]);
          }
        }
      }
      faderTouchCount=touchCount;
      }
    }
    
    // Send command with faderTarget array values to fader, TARGET or FOLLOW mode
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
      for (int j=0;j<2;j++){
        for (int i=0;i<8;i++){
          faderTargetData[(i*2)]=(faderTarget[i+j*8] >> 8) & 0xFF;                // split Target integers over two bytes in array
          faderTargetData[(i*2)+1]=faderTarget[i+j*8] & 0xFF;
          faderTargetData[16] |= faderMove[i+j*8] << i;                           // fill last byte in array with faderMove boolean array
        }
        Wire.beginTransmission(panelAddress[j]);                                  // Transmit to Slave
        Wire.write(mode);                                                         // Send mode (TARGET or FOLLOW)
        for(idx = 0; idx < MESSAGE_LEN; idx++) Wire.write(faderTargetData[idx]);  // Write data to I2C Tx buffer
        Wire.endTransmission();                                                   // Transmit to Slave
      }
    }
    There're two panels connected to the master getFaderData() is called from within the main loop:
    Code:
      //  substract interval to maintain schedule
      // faders
      if (sinceFaderRead >=faderReadInterval) {
        sinceFaderRead = sinceFaderRead - faderReadInterval;
        getFaderData();
        if (linkMode!=LINK_OFF) handleLinkMode();
      }
    The fader read interval is set at 5ms. The I2C communication is setup for 1Mhz:
    Code:
      //**** I2C *****
      // Setup for Master mode, pins 18/19, external pullups, 1MHz, 200ms default timeout
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 1000000);
      Wire.setDefaultTimeout(200000); // 200ms
    The getFaderData() function takes just under 0.5ms for sending requests to two panels and storing the responses. You should be able to just call sendFaderCommand() from your MIDI event handler function.

    Sometimes I get I2C communication errors on startup, I haven't figured out yet what the cause is but it only happens on startup. Once started everything works just fine.
    hi gerrit

    i see in your master code that u use:

    Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 1000000);
    Wire.setDefaultTimeout(200000); // 200ms

    and the slave is:

    Wire.begin(I2C_SLAVE, PANEL_ADDR, I2C_PINS_33_34, I2C_PULLUP_EXT, 400000);

    that is ok to use it like that? or should i change the speed in the slave to 1000000?
    i looked in the master slave exemples and its the same speed in master and slave codes.

    tnx
    rota

  23. #23
    Senior Member
    Join Date
    Jan 2017
    Location
    Maastricht
    Posts
    168
    You should change it to 1000000, that's how it's configured now, the 400000 is from the earlier version with the test panel.

  24. #24
    like i thought so just wanna be sure
    tnx for your replay

  25. #25
    i tryed to write the master code but im not sure about few things
    first under "void sendFaderCommand" its use "faderTarget" and the "faderMove"

    thats my master code:

    Code:
    #include <i2c_t3.h>
    #include <MIDIUSB.h>
    
    #define TARGET    0x10              // All faders to target value as fast as possible. PID state is cleared with each command.
    #define FOLLOW    0x20
    #define MESSAGE_LEN 17
    
    elapsedMicros sinceFaderRead;                         // timer for fader check
    unsigned int  faderReadInterval = 1000;
    elapsedMicros faderTouchCount;
    
    uint8_t panelAddress = 0x66;
    
    byte faderValueData[MESSAGE_LEN];    // 16 bytes for values, 1 byte for touch
    byte faderTargetData[MESSAGE_LEN];   // 16 for target values, 1 byte for indicating which faders should be moved.
    
    boolean faderTouched[8];                              // boolean indicating if fader is touched
    int     faderValue[8];                                // fader value ranging 0 to 1023
    int     faderTarget[8];                               // fader target value ranging 0 to 1023
    int     faderMove[8];                               // fader target value ranging 0 to 1023
    
    
    int hi[8];
    int lo[8];
    int Gain[8];
    
    
    void setup() {
    //**** I2C *****
      // Setup for Master mode, pins 18/19, external pullups, 1MHz, 200ms default timeout
      Wire.begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, 1000000);
      Wire.setDefaultTimeout(200000); // 200ms
      usbMIDI.setHandleControlChange(myControlChange);
    
    }
    
    void loop() {
      usbMIDI.read();
      //  substract interval to maintain schedule
      // faders
      if (sinceFaderRead >=faderReadInterval) {
        sinceFaderRead = sinceFaderRead - faderReadInterval;
        getFaderData();
        //if (linkMode!=LINK_OFF) handleLinkMode();
       
      }
    }
    // get fader values and touch status
    void getFaderData() {
      size_t idx;
      int incomingFaderValue[16];    // 
      int touchCount=0;
      //ZeusPattern *currentPattern=&sequencerChannel[selectedChannel].pattern[sequencerChannel[selectedChannel].selectedPattern];
      // Read from Slave
      
        Wire.requestFrom(panelAddress, (size_t)MESSAGE_LEN); // Read from Slave
        // Check if error occured
        if(Wire.getError())
            Serial.print("FAIL\n");
        else
        {
          // If no error then read Rx data into buffer
          idx = 0;
          while(Wire.available()) faderValueData[idx++] = Wire.readByte();
          // Process data in buffer
          for (int i=0;i<8;i++){
          // combine bytes back to integers and put in temporary array
          incomingFaderValue[i]= faderValueData[(i*2)];
          incomingFaderValue[i]= incomingFaderValue[i] << 8 | faderValueData[(i*2)+1];
          // fill touch boolean array with last byte
          faderTouched[i*8] = 1 & faderValueData[16] >> i;
          if (faderTouched[i*8]) touchCount++;
          // check if faderValue needs to be updated
          if (incomingFaderValue[i]!=faderValue[i*8] and faderTouched[i*8]){
            faderValue[i*8]=incomingFaderValue[i];
    //        currentPattern->step[i+j*8].value[selectedParameter]=map(faderValue[i+j*8],0,1023,parameterLimit[selectedParameter][0],parameterLimit[selectedParameter][1]);
    //        updateDisplayData=true;
    //        Serial.print("Fader ");
    //        Serial.print(i+j*8);
    //        Serial.print("\t");
    //        Serial.println(faderValue[i+j*8]);     
        }
      }
      faderTouchCount=touchCount;
      }
    }
    
    // Send command with faderTarget array values to fader, TARGET or FOLLOW mode
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
        for (int i=0;i<8;i++){
          faderTargetData[(i*2)]=(faderTarget[i*8] >> 8) & 0xFF;                // split Target integers over two bytes in array
          faderTargetData[(i*2)+1]=faderTarget[i*8] & 0xFF;
          faderTargetData[16] |= faderMove[i*8] << i;                           // fill last byte in array with faderMove boolean array
        }
        Wire.beginTransmission(panelAddress);                                  // Transmit to Slave
        Wire.write(mode);                                                         // Send mode (TARGET or FOLLOW)
        for(idx = 0; idx < MESSAGE_LEN; idx++) Wire.write(faderTargetData[idx]);  // Write data to I2C Tx buffer
        Wire.endTransmission();                                                   // Transmit to Slave
    }
    void myControlChange(byte channel, byte control, byte value) {               // blink the LED a number of times
    
      value = map(value, 0, 127, 127, 0);
      //INT FADERS GAINS
      if (control == 32) {
        hi[0] = value;
      }
      if (control == 0) {
        lo[0] = value;
        Gain[0] = (hi[0] >> 7) + lo[0];
      }
    
      if (control == 33) {
        hi[1] = value;
      }
      if (control == 1) {
        lo[1] = value;
        Gain[1] = (hi[1] >> 7) + lo[1];
      }
      if (control == 34) {
        hi[2] = value;
      }
      if (control == 2) {
        lo[2] = value;
        Gain[2] = (hi[2] >> 7) + lo[2];
      }
    
      if (control == 35) {
        hi[3] = value;
      }
      if (control == 3) {
        lo[3] = value;
        Gain[3] = (hi[3] >> 7) + lo[3];
      }
    
      if (control == 36) {
        hi[4] = value;
      }
      if (control == 4) {
        lo[4] = value;
        Gain[4] = (hi[4] >> 7) + lo[4];
      }
    
      if (control == 37) {
        hi[5] = value;
      }
      if (control == 5) {
        lo[5] = value;
        Gain[5] = (hi[5] >> 7) + lo[5];
      }
    
      if (control == 38) {
        hi[6] = value;
      }
      if (control == 6) {
        lo[6] = value;
        Gain[6] = (hi[6] >> 7) + lo[6];
      }
    
      if (control == 39) {
        hi[7] = value;
      }
      if (control == 7) {
        lo[7] = value;
        Gain[7] = (hi[7] >> 7) + lo[7];
      }
      sendFaderCommand(FOLLOW);
    }
    my midi fader value is the "int Gain" so should it be like this ? :
    Code:
    void sendFaderCommand(byte mode){
      size_t idx;
      faderTargetData[16]=0;
        for (int i=0;i<8;i++){
          faderTargetData[(i*2)]=(Gain[i*8] >> 8) & 0xFF;                // split Target integers over two bytes in array
          faderTargetData[(i*2)+1]=Gain[i*8] & 0xFF;
          faderTargetData[16] |= Gain[i*8] << i;                           // fill last byte in array with faderMove boolean array
        }
        Wire.beginTransmission(panelAddress);                                  // Transmit to Slave
        Wire.write(mode);                                                         // Send mode (TARGET or FOLLOW)
        for(idx = 0; idx < MESSAGE_LEN; idx++) Wire.write(faderTargetData[idx]);  // Write data to I2C Tx buffer
        Wire.endTransmission();                                                   // Transmit to Slave
    }
    and about the "sendFaderCommand(FOLLOW);" i puted under the "void myControlChange"
    did i use it right? it should be FOLLOW in there?
    can u guys please look at it and tell me if im doing ok?



    here is the slave code the only change i have made is in (I2C_PULLUP_EXT, 1000000) :
    Code:
    /*
      Zeus Commander Controller Series
      I2C controlled motorfader octet
    
      Full PID motor control supporting two operating modes:
      TARGET  for fast preset recall
      FOLLOW  for slow to fast following of values
    
      This code expands on the examples provided with the i2c_t3 library for the I2Ccommunication
    
      This code is in the public domain.
    */
    #include <i2c_t3.h>
    #include <ResponsiveAnalogRead.h>
    
    // PID arrays
    float dState[8];
    float iState[8];
    float iMin[8];
    float iMax[8];
    float pGain[8];
    float iGain[8];
    float dGain[8];
    float plantDrive[8];
    float maxD = 0.00;     // maximum derivative value for debugging purposes
    
    void UpdatePID(int faderIndex, float faderError, float faderPosition)
    {
      float pTerm, dTerm, iTerm, plantDriveInput;
      // calculate the proportional term
      pTerm = pGain[faderIndex] * faderError;
      // calculate the integral state with appropriate limiting
      iState[faderIndex] += faderError;
      if (iState[faderIndex] > iMax[faderIndex]) {
        iState[faderIndex] = iMax[faderIndex];
      }
      else if (iState[faderIndex] < iMin[faderIndex]) {
        iState[faderIndex] = iMin[faderIndex];
      }
      iTerm = iGain[faderIndex] * iState[faderIndex];  // calculate the integral term
      dTerm = dGain[faderIndex] * (faderPosition - dState[faderIndex]);
      if (abs(faderPosition - dState[faderIndex]) > maxD) {
        maxD = abs(faderPosition - dState[faderIndex]);
      }
      dState[faderIndex] = faderPosition;
    
      plantDriveInput = pTerm + iTerm - dTerm;
      if (plantDriveInput > 4096) {
        plantDriveInput = 4096;
      }
      if (plantDriveInput < -4096) {
        plantDriveInput = -4096;
      }
      plantDrive[faderIndex] = plantDriveInput;
    }
    
    elapsedMicros sinceFaderRead;                         // timer for fader check
    unsigned int  faderReadInterval = 1000;               // interval in microseconds for checking fader position(update)
    elapsedMicros sinceTouchRead;                         // timer for touch read
    unsigned int  touchReadInterval = 5000;               // interval in microseconds for reading fader touch
    elapsedMillis sinceLastCommand;                       // timer for time-out of PIF after last command
    unsigned int  commandTimeOutInterval = 500;           // interval for PID time-out in milliseconds
    int     faderWiperPin[8] = {32, 31, 39, 20, 21, 15, A11, A10}; // analog in pin for fader wipers
    int     faderTouchPin[8] = {1, 0, 16, 17, 18, 19, 22, 23};   // touchRead pins for fader touch
    int     faderMotorUpPin[8] = {9, 29, 5, 7, 4, 2, 35, 37};    // motor up PWM pin
    int     faderMotorDownPin[8] = {10, 30, 6, 8, 3, 14, 36, 38}; // motor down PWM pin
    int     faderValue[8];                                // fader value ranging 0 to 1023
    int     faderTarget[8];                               // fader target value ranging 0 to 1023
    int     faderTouch[8];                                // fader touch reading
    boolean faderPidOn[8];                                // status of PID
    int     faderTouchThreshold = 4800;                   // threshold value for touchRead
    boolean faderTouched[8];                              // boolean indicating if fader is touched
    
    ResponsiveAnalogRead analog[8] {ResponsiveAnalogRead(32, true), ResponsiveAnalogRead(31, true),
                           ResponsiveAnalogRead(39, true), ResponsiveAnalogRead(20, true),
                           ResponsiveAnalogRead(21, true), ResponsiveAnalogRead(15, true),
                           ResponsiveAnalogRead(A11, true), ResponsiveAnalogRead(A10, true)
    };
    
    // I2C communication
    // Command definitions
    #define TARGET    0x10              // All faders to target value as fast as possible. PID state is cleared with each command.
    #define FOLLOW    0x20              // Faders follow value, last byte in message is used to determine which motors should move.
    // PIDs will time-out after last command.
    
    // Function prototypes
    void receiveEvent(size_t count);
    void requestEvent(void);
    #define PANEL_ADDR 0x66              // I2C address, should be selectable by jumper using leftover pins.
    #define MESSAGE_LEN 17
    byte faderValueData[MESSAGE_LEN];    // 16 bytes for values, 1 byte for touch
    byte faderTargetData[MESSAGE_LEN];   // 16 for target values, 1 byte for indicating which faders should be moved.
    volatile uint8_t received;
    volatile uint8_t cmd;
    byte operatingMode = TARGET;
    
    // DEBUG
    //elapsedMillis sinceSerialDebug; // timer for serial debug output
    
    void setup()
    {
      //Serial.begin(250000);
    
      //initialize faders and analog reference
      analogReference(EXTERNAL);
      analogWriteResolution(12);
      for (int i = 0; i < 8; i++) {
        pinMode(faderMotorUpPin[i], OUTPUT);
        pinMode(faderMotorDownPin[i], OUTPUT);
        analogWriteFrequency(faderMotorUpPin[i], 14648.437); // 14648.437 ideal frequency for 180MHz 12bit PWM
        analogWriteFrequency(faderMotorDownPin[i], 14648.437); //14648.437 ideal frequency for 180MHz 12bit PWM
        faderTouched[i] = false;
        faderValueData[i] = 0;
        faderTarget[i] = 500;
        faderPidOn[i] = false;
      }
    
      readFaders();
      // set PID tuning parameters
      for (int i = 0; i < 8; i++) {
        pGain[i] = 10;
        iGain[i] = 1;
        dGain[i] = 50.00;
        iMin[i] = -1500;
        iMax[i] = 1500;
      }
    
      // Setup for Slave mode pins 33/34, external pullups, 1MHz
      Wire.begin(I2C_SLAVE, PANEL_ADDR, I2C_PINS_33_34, I2C_PULLUP_EXT, 1000000);
      // register events
      Wire.onReceive(receiveEvent);
      Wire.onRequest(requestEvent);
      cmd = 0;    // incoming command operating mode
    }
    
    void loop()
    {
      // check elapsedMicros and millis timers
      // faders
      if (sinceFaderRead >= faderReadInterval) {
        sinceFaderRead = sinceFaderRead - faderReadInterval;
        readFaders();
    
        // always update PID for timing consistency
        for (int i = 0; i < 8; i++) {
          UpdatePID(i, faderTarget[i] - faderValue[i], faderValue[i]);
        }
    
        // loop through faders and move where necessary
        for (int i = 0; i < 8; i++) {
          if (!faderTouched[i] && faderPidOn[i]) {
            if (plantDrive[i] > 0 && faderValue[i] <= 1022) {
              analogWrite(faderMotorDownPin[i], 0);
              analogWrite(faderMotorUpPin[i], plantDrive[i]);
            } else if (plantDrive[i] <= 0 && faderValue[i] >= 1) {
              analogWrite(faderMotorUpPin[i], 0);
              analogWrite(faderMotorDownPin[i], -plantDrive[i]);
            }
          }
          else if (!faderPidOn[i]) {
            analogWrite(faderMotorDownPin[i], 0);
            analogWrite(faderMotorUpPin[i], 0);
          }
        }
      }
    
      //  separate touchRead timer
      if (sinceTouchRead >= touchReadInterval) {
        sinceTouchRead = sinceTouchRead - touchReadInterval;
        readTouch();
      }
    
      // command time-out
      if (sinceLastCommand >= commandTimeOutInterval) {
        for (int i = 0; i < 8; i++) {
          faderPidOn[i] = false;
        }
        sinceLastCommand = 0;
      }
    
      // DEBUG serial
      //  if (sinceSerialDebug >= 100){
      //    sinceSerialDebug = sinceSerialDebug - 100;
      //    for (int i=0;i<8;i++){
      //      Serial.print(faderTarget[i]);
      //      Serial.print("\t");
      //    }
      //    Serial.print("\t");
      //    Serial.println();
      //  }
    }
    
    // read fader analog values and update faderValue array
    void readFaders() {
      for (int i = 0; i < 8; i++) {
        analog[i].update();
        faderValue[i] = analog[i].getValue();
      }
    }
    
    // read fader touch
    void readTouch() {
      for (int i = 0; i < 8; i++) {
        faderTouch[i] = touchRead(faderTouchPin[i]);
        if (faderTouch[i] > faderTouchThreshold) {
          faderTouched[i] = true;
        } else if (faderTouch[i] <= faderTouchThreshold) {
          faderTouched[i] = false;
        }
      }
    }
    
    // handle Rx Event (incoming I2C data)
    void receiveEvent(size_t count) {
      size_t idx;
      int incomingTargetValue[8];
      boolean incomingFaderMove[8];
      Serial.println(incomingTargetValue[1]);
      if (count)
      {
        // grab command
        cmd = Wire.readByte();
        switch (cmd)
        {
          case TARGET:
            if (operatingMode == FOLLOW) {
              // set PID tuning parameters
              //        for (int i=0;i<8;i++){
              //          pGain[i]=20.00;
              //          iGain[i]=0.5;
              //          dGain[i]=40.00;
              //        }
              operatingMode = TARGET;
            }
            break;
          case FOLLOW:
            if (operatingMode == TARGET) {
              // set PID tuning parameters
              //        for (int i=0;i<8;i++){
              //          pGain[i]=20.00;
              //          iGain[i]=0.5;
              //          dGain[i]=40.00;
              //        }
              operatingMode = FOLLOW;
            }
            break;
        }
        idx = 0;
        while (Wire.available()) faderTargetData[idx++] = Wire.readByte();
    
        // Process data
        for (int i = 0; i < 8; i++) {
          // combine bytes back to integers and put in temporary array
          incomingTargetValue[i] = faderTargetData[(i * 2)];
          incomingTargetValue[i] = incomingTargetValue[i] << 8 | faderTargetData[(i * 2) + 1];
          // fill faderPidOn boolean array with last byte
          incomingFaderMove[i] = 1 & faderTargetData[16] >> i;
          // clear PID states if PID is switched on or if mode is TARGET
          if ((incomingFaderMove[i] && faderPidOn[i] != incomingFaderMove[i]) || operatingMode == TARGET) {
            dState[i] = faderValue[i];
            iState[i] = 0;
          }
          faderPidOn[i] =  incomingFaderMove[i];
          // update fader target
          faderTarget[i] = incomingTargetValue[i];
        }
        // reset timer
        sinceLastCommand = 0;
      }
    }
    
    // handle Tx Event (outgoing I2C data)
    void requestEvent(void)
    {
      faderValueData[16] = 0;
      for (int i = 0; i < 8; i++) {
        // split value integers over two bytes in array
        faderValueData[(i * 2)] = (faderValue[i] >> 8) & 0xFF;
        faderValueData[(i * 2) + 1] = faderValue[i] & 0xFF;
        // fill last byte in array with touch boolean array
        faderValueData[16] |= faderTouched[i] << i;
      }
      Wire.write(faderValueData, MESSAGE_LEN); // fill Tx buffer (send full mem)
    }

Posting Permissions

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