Problem with multiple slave SPI

Status
Not open for further replies.

akym

Member
Hey guys, I am using Teensy 3.6 and compiling it for 180Mhz. I have an OLED display connected with HW_SPI and 3 TMC2130 stepper motor drivers to teensy and I am configuring them over SoftwareSPI(bit-banging), the implemented library is from teemuatlut (link). There is a peculiar problem that I am facing, after each hard reset of the power supply to both teensy and drivers, I am unable to send commands over to drivers. Interestingly enough when I upload the code again it doesnt work straight out of the box, I need to upload stripped down version of same code (where I only initialize one driver) and after that the main program, and then it starts working. I researched a bit and found numerous solution for similar problems. But sadly none worked for me, so now I am confused what is the issue. Any help will be appreciated.

OLED used: https://www.adafruit.com/product/2674
TMC2130 used: https://www.watterott.com/en/SilentStepStick

Main code:
Code:
#include <SPI.h>
#include <ADC.h>
#include <Bounce2.h>          // Software Debouncing Library
#include <TMC2130Stepper.h>   // Stepper Motor Driver library
#include <Adafruit_GFX.h>     // OLED graphics library
#include <Adafruit_SSD1325.h> // OLED driver library


//SM3 Pin definations
#define EN_PIN    46
#define DIR_PIN   41
#define STEP_PIN  42
#define CS_PIN    43
#define MOSI_PIN  45
#define MISO_PIN 19
#define SCK_PIN  44

#define lsmot3 4
#define rsmot3 3

//SM1 Pin definations
#define EN_PIN1 10
#define DIR_PIN1 5
#define STEP_PIN1 6
#define CS_PIN1 7
#define MOSI_PIN1 9
#define MISO_PIN1 47
#define SCK_PIN1 8

#define lsmot1 32
#define rsmot1 31

//SM2 Pin definations
#define EN_PIN2    28
#define DIR_PIN2  40
#define STEP_PIN2  24
#define CS_PIN2    25
#define MOSI_PIN2  27
#define MISO_PIN2 48   //1/ori48
#define SCK_PIN2  26

#define lsmot2 30
#define rsmot2 29

//motor homing sanity check
bool sm3homed = false;
bool tblocked = false;
bool calibhomed = false;

//oled pin definations
#define OLED_CS 23
#define OLED_RESET 21
#define OLED_DC 22

//UX Pin definations
#define switch1p 51         // switch 1 NC pin  //NC - Normal Closed
#define switch1led 37      // switch 1 led pin
#define switch2p 49         // switch 2 NC pin 
#define switch2led 38      // switch 2 led pin
#define switch3p 50         // switch 2 NC pin 
#define switch3led 39      // switch 2 led pin
#define switch4p 54         // switch 2 NC pin 
#define switch4led 34      // switch 2 led pin
#define switch5p 53         // switch 2 NC pin 
#define switch5led 35      // switch 2 led pin
#define switch6p 52         // switch 2 NC pin 
#define switch6led 36      // switch 2 led pin

int fsreadPin = A2;
ADC *adc = new ADC();;

//debouncing limit switches
Bounce calibupswitch = Bounce(rsmot3, 5);
Bounce calibdownswitch = Bounce(lsmot3, 5);

Bounce fsclswitch = Bounce(rsmot1, 5);
Bounce fsfarswitch = Bounce(lsmot1, 5);

Bounce dsclswitch = Bounce(rsmot2, 5);
Bounce dsfarswitch = Bounce(lsmot2, 5);

//debouncing UX switches
Bounce switch1 = Bounce( switch1p, 5 );
Bounce switch2 = Bounce( switch2p, 5 );
Bounce switch3 = Bounce( switch3p, 5 );
Bounce switch4 = Bounce( switch4p, 5 );
Bounce switch5 = Bounce( switch5p, 5 );
Bounce switch6 = Bounce( switch6p, 5 );


TMC2130Stepper SM3 = TMC2130Stepper(EN_PIN, DIR_PIN, STEP_PIN, CS_PIN, MOSI_PIN, MISO_PIN, SCK_PIN);
TMC2130Stepper SMfs = TMC2130Stepper(EN_PIN1, DIR_PIN1, STEP_PIN1, CS_PIN1, MOSI_PIN1, MISO_PIN1, SCK_PIN1);
TMC2130Stepper SM2 = TMC2130Stepper(EN_PIN2, DIR_PIN2, STEP_PIN2, CS_PIN2, MOSI_PIN2, MISO_PIN2, SCK_PIN2);

Adafruit_SSD1325 oled(OLED_DC, OLED_RESET, OLED_CS);

void setup() {
  SPI.begin();
  //OLED Stuff
  oled.begin();
  oled.clearDisplay();
  oled.setRotation(2);
  oled.setTextSize(3);
  oled.setTextColor(WHITE);
  oled.setCursor(10, 15);
  oled.println("AF-MPD");
  oled.setCursor(30, 48);
  oled.setTextSize(1);
  oled.println("CALIBRATION");
  oled.display();
  delay(1000);
  oled.clearDisplay();
  oled.setTextSize(1);
  oled.setCursor(7, 24);
  oled.println("Initializing...");
  oled.display();
  delay(200);

  digitalWrite(EN_PIN, LOW);
  delay(50);
  digitalWrite(EN_PIN1, LOW);
  delay(50);
  digitalWrite(EN_PIN2, LOW);
  delay(50);

  pinMode(rsmot2, INPUT_PULLUP);
  pinMode(lsmot2, INPUT_PULLUP);

  pinMode(rsmot3, INPUT_PULLUP);
  pinMode(lsmot3, INPUT_PULLUP);

  pinMode(rsmot1, INPUT_PULLUP);
  pinMode(lsmot1, INPUT_PULLUP);

  pinMode(A0, INPUT);
  pinMode(A14, INPUT);

  pinMode(switch1p, INPUT);
  pinMode(switch2p, INPUT);
  pinMode(switch3p, INPUT);
  pinMode(switch4p, INPUT);
  pinMode(switch5p, INPUT);
  pinMode(switch6p, INPUT);

  pinMode(switch1led, OUTPUT);
  pinMode(switch2led, OUTPUT);
  pinMode(switch3led, OUTPUT);
  pinMode(switch4led, OUTPUT);
  pinMode(switch5led, OUTPUT);
  pinMode(switch6led, OUTPUT);

  delay(2000);
  SPI.begin();
  pinMode(MISO_PIN, INPUT_PULLUP);
  pinMode(MISO_PIN1, INPUT_PULLUP);
  pinMode(MISO_PIN2, INPUT_PULLUP);

  SM3.begin();
  delay(3000);
  SM3.rms_current(900);
  SM3.stealthChop(1);
  SM3.microsteps(4);
  digitalWrite(EN_PIN, HIGH);
  digitalWrite(DIR_PIN, HIGH);
  delay(300);

  SMfs.begin();
  delay(3000);
  SMfs.rms_current(1000);
  SMfs.stealthChop(0);
  SMfs.microsteps(1);
  digitalWrite(EN_PIN1, HIGH);
  delay(300);

  SM2.begin();
  delay(3000);
  SM2.rms_current(900);
  SM2.stealthChop(1);
  SM2.microsteps(1);
  digitalWrite(EN_PIN2, HIGH);
  delay(300);

}

void loop() {
  calibupswitch.update();
  calibdownswitch.update();
  fsclswitch.update() ;
  fsfarswitch.update() ;
  dsclswitch.update() ;
  dsfarswitch.update() ;

  switch1.update();
  switch2.update();
  switch3.update();
  switch4.update();
  switch5.update();
  switch6.update();

  int sw4 = switch4.read();
  int sw5 = switch5.read();

  if (switch1.fell()) {
    digitalWrite(switch1led, HIGH);
    lockTB();
    delay(2000);
    digitalWrite(switch1led, LOW);
  }
  if (switch2.fell()) {
    digitalWrite(switch2led, HIGH);
    decoupleTB();
    delay(1000);
    delay(1000);
    digitalWrite(switch2led, LOW);
  }
  if (switch3.fell()) {
    digitalWrite(switch3led, HIGH);
    delay(1000);
    calibrate();
    delay(1000);
    digitalWrite(switch3led, LOW);
  }

 
  if (switch4.fell()) {
    digitalWrite(switch4led, HIGH);
    // dshome();
    fsload();
    digitalWrite(switch4led, LOW);
  }
  if (switch5.fell()) {
    //dsengage();
    digitalWrite(switch5led, HIGH);
    fsdeload();
    digitalWrite(switch5led, LOW);
  }


  oledtext("Waiting for command", 1);
}

int fsread = 0;

void fsload() {
  digitalWrite(EN_PIN1, LOW);
  digitalWrite(DIR_PIN1, LOW);
  do {
    digitalWrite(STEP_PIN1, HIGH);
    delayMicroseconds(200); //DO NOT CHANGE KEEP 200 for switch
    digitalWrite(STEP_PIN1, LOW);
    delayMicroseconds(200); //DO NOT CHANGE KEEP 200
    switch6.update();
  } while (switch6.read()); //analogRead(A14) < 735 735 is valid only for
  //preset position of the distance sensor, if its position
  //is changed the value here needs to be calibrated for
  //desired position. //switch6.read()
  digitalWrite(EN_PIN1, HIGH);

}
void fsdeload() {
  // turning on the driver
  digitalWrite(EN_PIN1, LOW);
  digitalWrite(DIR_PIN1, HIGH);
  do {
    digitalWrite(STEP_PIN1, HIGH);
    delayMicroseconds(200); //DO NOT CHANGE KEEP 200
    digitalWrite(STEP_PIN1, LOW);
    delayMicroseconds(200); //DO NOT CHANGE KEEP 200
    switch6.update();
  } while (switch6.read());   //homesense(fsfarswitch) switch6.read()
  for (int i = 0; i < 2000; i++) {
    digitalWrite(STEP_PIN1, HIGH);
    delayMicroseconds(200);
    digitalWrite(STEP_PIN1, LOW);
    delayMicroseconds(200);
  }
  // turning off the driver again
  digitalWrite(EN_PIN1, HIGH);

}
void preload() {
  digitalWrite(EN_PIN1, LOW);
  digitalWrite(DIR_PIN1, LOW);

  do {
    digitalWrite(STEP_PIN1, HIGH);
    delayMicroseconds(1);
    digitalWrite(STEP_PIN1, LOW);
    delayMicroseconds(1);
  } while (analogRead(A0) < 550);
  delay(2000);
  digitalWrite(EN_PIN1, HIGH);

}
void lockTB() {
  digitalWrite(EN_PIN, LOW);
  SM3home();
  tblocked = true;
}

void fshome() {
  digitalWrite(EN_PIN1, LOW);
  digitalWrite(DIR_PIN1, HIGH);
  do {
    fsfarswitch.update();
    digitalWrite(STEP_PIN1, HIGH);
    delayMicroseconds(120);
    digitalWrite(STEP_PIN1, LOW);
    delayMicroseconds(120);
  } while (homesense(fsfarswitch));
  digitalWrite(EN_PIN1, HIGH);
}

void dsengage() {
  digitalWrite(EN_PIN2, LOW);
  digitalWrite(DIR_PIN2, HIGH);

  do {
    digitalWrite(STEP_PIN2, HIGH);
    delayMicroseconds(8); //DO NOT CHANGE KEEP 200 for switch
    digitalWrite(STEP_PIN2, LOW);
    delayMicroseconds(8); //DO NOT CHANGE KEEP 200
    switch6.update();
  } while (switch6.read());
  //
  //  for (int i = 0; i < 1420000; i++) {
  //    digitalWrite(STEP_PIN2, HIGH);
  //    delayMicroseconds(8);
  //    digitalWrite(STEP_PIN2, LOW);
  //    delayMicroseconds(8);
  //  }

  digitalWrite(EN_PIN2, HIGH);
}
void dshome() {
  digitalWrite(EN_PIN2, LOW);
  digitalWrite(DIR_PIN2, LOW);
  do {
    dsfarswitch.update();
    digitalWrite(STEP_PIN2, HIGH);
    delayMicroseconds(8);
    digitalWrite(STEP_PIN2, LOW);
    delayMicroseconds(8);
  } while (homesense(dsfarswitch));
  digitalWrite(DIR_PIN2, HIGH);
  for (int i = 0; i < 10000; i++) {
    digitalWrite(STEP_PIN2, HIGH);
    delayMicroseconds(20);
    digitalWrite(STEP_PIN2, LOW);
    delayMicroseconds(20);
  }
  digitalWrite(EN_PIN2, HIGH);
}

void calibrate() {
  if (calibhomed) {
    delay(500);
    digitalWrite(EN_PIN, LOW);
    SM3move(HIGH, 29000); //7000 before for 3 mass calibration
    digitalWrite(EN_PIN, HIGH);
    delay(90000);
    //    digitalWrite(EN_PIN, LOW);
    //    SM3move(HIGH, 10000);
    //    digitalWrite(EN_PIN, HIGH);
    //    delay(70000);
    //    digitalWrite(EN_PIN, LOW);
    //    SM3move(HIGH, 12000);
    //    digitalWrite(EN_PIN, HIGH);
    //    delay(70000);

    digitalWrite(EN_PIN, LOW);
    digitalWrite(DIR_PIN, LOW);
    do {
      calibupswitch.update();
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(120);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(120);
    } while (homesense(calibupswitch));
    digitalWrite(DIR_PIN, HIGH);
    for (int i = 0; i < 1500; i++) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(200);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(200);
    }
    calibhomed = true;
    digitalWrite(EN_PIN1, HIGH);
  }
  else {
    delay(1500);
  }


}
void decoupleTB() {
  if (tblocked) {
    digitalWrite(EN_PIN, LOW);
    digitalWrite(DIR_PIN, LOW);
    for (int i = 0; i < 3500; i++) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(4000);        //4000 for roundhead
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(4000);
    }
    delay(1800); // 1200 for roundhead
    do {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(200);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(200);
      calibupswitch.update();
    } while (homesense(calibupswitch));

    digitalWrite(DIR_PIN, HIGH);
    for (int i = 0; i < 1500; i++) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(200);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(200);
    }
    tblocked = false;
    sm3homed = false;
    calibhomed = true;
    digitalWrite(EN_PIN, HIGH);
  }
  else {
    delay(1000);
  }

}

void SM3move(bool dir, int steps) {
  digitalWrite(EN_PIN, LOW);
  digitalWrite(DIR_PIN, dir); //setting direction to move
  for (int i = 0; i < steps; i++) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(400);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(400);
  }
  sm3homed = false;
  calibhomed = false;
  digitalWrite(EN_PIN, HIGH);
}

void SM3home() {
  if (!sm3homed) {
    digitalWrite(EN_PIN, LOW);
    digitalWrite(DIR_PIN, HIGH);
    do {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(220);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(220);
      calibdownswitch.update();
    } while (homesense(calibdownswitch));

    //move preset number of steps in the opposite
    //direction to have a homing reference
    digitalWrite(DIR_PIN, LOW);

    for (int i = 0; i < 500; i++) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(200);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(200);
    }
    sm3homed = true;
    digitalWrite(EN_PIN, HIGH);
    delay(500);
  }
  else {
    delay(1000);
  }
}

char * oledtext(String txt, int size) {
  oled.clearDisplay();
  oled.setRotation(2);
  oled.setTextSize(1);
  oled.setTextColor(WHITE);
  oled.setCursor(7, 24);
  oled.println(txt);
  oled.display();
}

bool homesense(Bounce db) {
  // Senses the limit switch press and returns false
  if (db.rose()) {
    return false;
  } else {
    return true;
  }
}

Stripped down code
Code:
#include <Bounce2.h>          // Software Debouncing Library
#include <TMC2130Stepper.h>   // Stepper Motor Driver library
#include <Adafruit_GFX.h>     // OLED graphics library
#include <Adafruit_SSD1325.h> // OLED driver library


//SM3 Pin definations
#define EN_PIN    46
#define DIR_PIN   41
#define STEP_PIN  42
#define CS_PIN    43
#define MOSI_PIN  45
#define MISO_PIN 1
#define SCK_PIN  44

#define lsmot3 4
#define rsmot3 3

//motor homing sanity check
bool sm3homed = false;

//oled pin definations
#define OLED_CS 23
#define OLED_RESET 21
#define OLED_DC 22

//UX Pin definations
#define switch1p 52         // switch 1 NC pin  //NC - Normal Closed
#define switch1led 36      // switch 1 led pin
#define switch2p 53         // switch 2 NC pin 
#define switch2led 35      // switch 2 led pin

//debouncing limit switches
Bounce calibupswitch = Bounce(rsmot3, 5);
Bounce calibdownswitch = Bounce(lsmot3, 5);
//debouncing UX switches
Bounce switch1 = Bounce( switch1p, 5 );
Bounce switch2 = Bounce( switch2p, 5 );
TMC2130Stepper SM3 = TMC2130Stepper(EN_PIN, DIR_PIN, STEP_PIN, CS_PIN, MOSI_PIN, MISO_PIN, SCK_PIN);
Adafruit_SSD1325 oled(OLED_DC, OLED_RESET, OLED_CS);

void setup() {
  pinMode(rsmot3, INPUT_PULLUP);
  pinMode(lsmot3, INPUT_PULLUP);

  pinMode(switch1p, INPUT);
  pinMode(switch2p, INPUT);
  
  SM3.begin();
  SM3.rms_current(900);
  SM3.stealthChop(1);
  SM3.microsteps(4);
  digitalWrite(EN_PIN, LOW);
  digitalWrite(DIR_PIN, HIGH);
}

void loop() {
//  calibupswitch.update();
//  calibdownswitch.update();
//  switch1.update();
//  switch2.update();
////  if (switch1.fell()) {
////    SM3home();
////  }
//  if (switch2.fell()) {
//    SM3home();
//  }
//  oledtext("Waiting for command", 2);
//      

}


void SM3move(bool dir, int steps) {
  digitalWrite(DIR_PIN, dir); //setting direction to move
  for (int i = 0; i < steps; i++) {
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(400);
    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(400);
  }
  sm3homed = false;
}

void SM3home() {
  if (!sm3homed) {
    digitalWrite(DIR_PIN, HIGH);
    do {
      calibdownswitch.update();
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(1500);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(1500);
    } while (homesense(calibdownswitch));

    //move preset number of steps in the opposite
    //direction to have a homing reference
    digitalWrite(DIR_PIN, LOW);

    for (int i = 0; i < 200; i++) {
      digitalWrite(STEP_PIN, HIGH);
      delayMicroseconds(1500);
      digitalWrite(STEP_PIN, LOW);
      delayMicroseconds(1500);
    }
    sm3homed = true;
    delay(500);
  }
  else {
    delay(1000);
  }
}

char * oledtext(String txt, int size) {[URL="https://drive.google.com/open?id=1FZg5xVejizheG5QSlIUX6WKXLZtzo4v9"]https://drive.google.com/open?id=1FZg5xVejizheG5QSlIUX6WKXLZtzo4v9[/URL]
  oled.clearDisplay();
  oled.setRotation(2);
  oled.setTextSize(size);
  oled.setTextColor(WHITE);
  oled.setCursor(5, 5);
  oled.println(txt);
  oled.display();
}

bool homesense(Bounce db) {
  // Senses the limit switch press and returns false
  if (db.rose()) {
    return false;
  } else {
    return true;
  }
}

P.S Sometimes I've to upload another stripped down program for another driver and then final big program and it works. Its quite weired!!

Also schematics are attached if it helps, they are terrible resolution in the attachment. Visit https://drive.google.com/open?id=1FZg5xVejizheG5QSlIUX6WKXLZtzo4v9 for high-res PDF, there are few manual jumper cables used which are not in the schema, but overall no major changes.
 

Attachments

  • mot_driver_schem.jpg
    mot_driver_schem.jpg
    58.3 KB · Views: 92
  • Controller Board_schem_small.jpg
    Controller Board_schem_small.jpg
    78.1 KB · Views: 108
Last edited:
Sorry, I have not used any of these products so it is sometimes hard to know exactly what is going on...

You might do a search on the forum for others using this controller board. I found a few hits like: https://forum.pjrc.com/threads/49312-Teensy-3-6-SPI-controlled-TMC2130-driver?highlight=TMC2130

Things I would do include maybe rearrange the order things get initialized. Example maybe the display goes last.

Also I would try things like add Serial.print(...) statements at different points in the code, like maybe several of them in Setup, such that you can hopefully verify that the code makes it through (i.e.) try to detect if and where the code hangs.

Good luck
 
Thanks for the reply.
I tried rearranging the order without any luck. I will definitely try to debug it with Serial.print() statements more. But reuploading(2 file method) the code retains all the functionality so I don't think there is any problem with the code, at least on the surface. I thought maybe multiple SPI peripherals connected with Software SPI might be the issue. I even added delays while initializing the drivers, still no luck.
 
hardware spi slave support for any of the 3 hardware SPI ports on 3.6 is supported and on the forums
 
The problem using hardware SPI for these chips is I wanted it to be backward compatible with other drivers and they do not support SPI. That's why the main logic board was only provisioned with non-SPI specific pins. It is the same reason why I am using software SPI for TMC2130.
 
The real issue is that it works with the Software SPI as well, But the only thing is I need to upload the other files first. Thats what i find strange, I must be missing something with code or initialization or it just might be the issue with SoftwareSPI. As I dont know much about bitbanging, I thought people on this forum might know.
I can try porting everything to Hardware SPI permanently but that will remove the backward compatibility of the system.
 
The solution was to remove the backwards compatiblity for other motor drivers and share the SPI lines, now it works fine.
 
Status
Not open for further replies.
Back
Top