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/1RzpDqx0uk7i45H-KwqzlbZ8_fo2bvtM1/view?usp=sharing
gerrit controller project:
https://forum.pjrc.com/threads/42477-Teensy-3-6-controlled-motorfader-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)
the way i tryd to run it
gerrit code for the slave i used
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
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/1RzpDqx0uk7i45H-KwqzlbZ8_fo2bvtM1/view?usp=sharing
gerrit controller project:
https://forum.pjrc.com/threads/42477-Teensy-3-6-controlled-motorfader-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: