Ding:Schrittmotor Controller TMC222micro

Aus FabLab Region Nürnberg
Foto
TMC222microt.png
flattr.png
Basisdaten
Status unbenutzbar
Schöpfer Udo (Diskussion)


Diese Seite befindet sich im Aufbau (BETA Status)


Für dieses Projekt benötigt

  • 1x Adruino
  • 2x 10K Widerstände
  • 1x TMC222micro oder andere Platine mit TMC222
  • 1x Schrittmotor BiPolar (4-Kabel)
  • 1x Stromversorgung für Arduino (kann auch von USB erfolgen)
  • 1x Netzteil min. 8V 800mA (empf. 12V/1A) für den TMC
  • 5x Verbindungskabel vom TMC22micro zum Arduino
  • -- Kabel zum anschließen der beiden Widerstände

Der TMC222 ist ein Schrittmotor Controller für Positionierungsaufgaben

Die Position kann hierbei mit einem 16-Bit breiten Wert (0 - 65535) bestimmt werden. Im Idealfall wird dem Chip nur die Position angegeben an welche er den Motor steuern soll, der Rest wie Beschleunigung, Verzögerung, Geschwindigkeit, StepMode, Strombegrenzung usw. usf. wird vom Chip gesteuert, dies muss im IC natürlich vorher einmalig eingestellt sein.

Anwendungen

Mir fallen für diesen Einsatzzweck folgende Anwendungen ein:

  • Modellbahn: Drehscheibensteuerung, Schrankensteuerung, Hebebrückensteuerung
  • Regalsystem: Regalroboter fü z.B. CD-Sammlung ;-)
  • Zeigersteuerung: Zeiger für Analog Uhr, Anzeigeistrumente (Amaturenbrett im KFZ)
  • Lüftung: Schiebersteuerung für Luftverteiler
Außerdem ist im TMC222 eine Wegoptimierung eingebaut

Ist die angegebene Position von der aktuellen Position z.B. links herum kürzer als rechts herum wird dieser Weg eingeschlagen. Beispiel: akt. Pos = 250, Zielpos = 65530 (links herum wären nur -250 & -5 also -255 Schritte nötig) Dies kann durch abfragen der aktuellen Position und geschickter Programmierung der Zielposition umgangen werden. Auch kann die aktuelle Position jederzeit genullt oder auf einen beliebigen Wert gesetzt werden.

Genau aus diesem Grund ist dieses IC auch NICHT für z.B. CNC Steuerungen geeignet. Vielmehr eignet sich dieses IC um bestimmte Positionen mit definierten Parametern zu "anzufahren".

Dieses Sketch wird diskret ohne TMC Library (GitHub) aufgebaut
  • Beachte: Die I2C Leitungen, SCL und SDA benötigen einmalig einen 10kR Pull Up Widerstand zu +5V des Arduino
  • Beachte: Die Versorgungsspannung des TMC222 darf nicht unter 8V liegen
  • Beachte: Es muss ein Schrittmotor am TMC222 angeschlossen sein
  • Beachte: Die Pins HW und SWI haben keinen Logic Level!
HW löst den zweiten Adressbereich aus mehr dazu im Datenblatt
SWI ist ein Eingang für einen Refernzschalter mehr dazu im Datenblatt
Um diese Eingange auszulösen reicht ein Schalten auf (+UB)/GND im anderen Fall sind diese offen zu halten.
Im Layout wurde ein Schalten gegen GND vorgesehen
Important Hint: The SWI is not a logic level input as usual;
it needs to be connected via 1K resistor either to (+VBAT) or GND;

ansonsten kann der TMC keine sinnvollen Daten generieren

Datenblatt zum TMC222: http://www.trinamic.com/_articles/products/integrated-circuits/tmc222/_datasheet/TMC222_datasheet.pdf

Adressierung und OTP Memory

Der TMC222 wird über I2C (TWI) Bus angesprochen, dazu ist es erforderlich dass bei Verwendung mehrerer dieser ICs jeder seine eigene Adresse erhält, da sonst auf dem BUS Konflikte auftreten.

Hierzu hat der TMC22 einen sog. OPT Speicher (frei übersetzt Einmalig programmiererbarer Speicher) Die Speicherzellen in diesem Speicher können ähnlich wie in einem EPROM gesetzt aber nie wieder zurückgesetzt werden. d.h. der Speicher inhalt kann jederzeit verändert werden aber nur nach oben. Es ist also Vorsicht beim beschreiben dieser Speicherzellen gegeben. Es muss also dem IC einmalig eine eindeutige Adresse gegeben werden. Hilfreich kann hier der HW Eingang sein, dieser Schaltet zwischen zwei Adressbereichen um.

      HW = offen : 16 verfügbare Adressen ab 0xC0 (DEZ=192) jede 4. Adresse, jede 2. Adresse bestimmt schreiben/lesen
      HW = GND   : 16 verfügbare Adressen ab 0xC2 (DEZ=194) jede 4. Adresse, jede 2. Adresse bestimmt schreiben/lesen

Siehe auch im Datenblatt Abschnitt "6.3 Physical Address of the circuit"

Es ist somit möglich bis zu maximal 32 Motoren an einem einzigen Arduino I2C-Bus unabhängig voneinander anzusteuern Wenn das nicht reichen sollte kann man ja einen anderen Controller mit einbeziehen, welcher dann entweder über LAN oder Seriell (RS485) mit anderen Controllern Synchronisiert werden kann.

Werden alle 32 Treiber mit voller Leistung gefahren, dann hat man in Summe fast 26 Ampere an Stromaufnahme, also schon eine ordentliche Hausnummer für ein oder mehrere passende Netzteile. So ein 'normales' Kabel wie für die Breadboard's Verwendung findet kann da natürlich auch nicht mehr verwendet werden, das wird ganz schnell zum leuchten anfangen (BSQ)


Aufbau / Berechnung der I2C Adressierung (1 Byte)
       Im Datenblatt wird AD0 auf Bit1 genannt, da Bit0 IMMER die Richtung (schreiben/lesen) definiert.
          Bit7  Bit6  Bit5  Bit4  Bit3  Bit2  Bit1  Bit0
          ^     ^     ^     ^     ^     ^     ^     ^
          |     |     |     |     |     |     |     |
          |     |     |     |     |     |     |     Schreiben/Lesen
          |     |     |     |     |     |     HW-Pin Status
          |     |     |     |     |     programmierbares Adress-Bit
          |     |     |     |     programmierbares Adress-Bit 
          |     |     |     programmierbares Adress-Bit      
          |     |     programmierbares Adress-Bit      
          |     Immer 1 (HIGH) fest eigebrannt
          Immer 1 (HIGH) fest eigebrannt      
    

Auch die Motorparameter können in diesem OTP Speicher abgelegt werden, diese sind allerdings auch in einem flüchtigen RAM konfigurierbar und müssen dann eben bei jedem Neustart/Reset neu parametriert werden.

Die Steuerung geschieht immer mit einem sog. Daten-Telegramm, in welchen die einzelnen Paramerter eingetragen sind. Je nach Befehl an den TMC222 sind diese Telegramme anders aber ähnlich aufgebaut. Hierzu habe ich eingenen Funtionen im Nachfolgenden Sketch geschrieben.

Damit das ganze nicht zu sehr Theorie wird

baue ich in den kommenden Tagen so nach und nach ein Arduino Sketch auf, welches entsprechend dokumentiert den Einstieg in die Ansteuerung des TC222 erleichtern soll.


Aufbau des Sketches Schritt für Schritt

Als erstes definieren wir die TMC222 Befehle

Diese definieren wir als Konstanten mit sprechenden Bezeichnungen, damit wir uns nicht den Wert merken müssen

 // TMC222 Befehlssatz
 const byte _TMC222GetFullStatus1     = 0x81;
 const byte _TMC222GetFullStatus2     = 0xFC;
 const byte _TMC222GetOTPParam        = 0x82;
 const byte _TMC222GotoSecurePosition = 0x84;
 const byte _TMC222HardStop           = 0x85;
 const byte _TMC222ResetPosition      = 0x86;
 const byte _TMC222ResetToDefault     = 0x87;
 const byte _TMC222RunInit            = 0x88;
 const byte _TMC222SetMotorParam      = 0x89;
 const byte _TMC222SetOTPParam        = 0x90;
 const byte _TMC222SetPosition        = 0x8B;
 const byte _TMC222SoftStop           = 0x8F;

Nun noch ein paar Arrays zum arbeiten

       byte _TMC222dump[9];                      // Ein Array zum arbeiten mit den TMC222 Daten
       byte _TMC222adr[32];                      // Ein Array mit allen erlaubten Adressen der TMC222 IC's
       int  _TMC222current[16];                  // Ein Array mit den Motorstromdaten des TMC222 IC's
include <Wire.h>                                 // Bibliothek damit wir Daten über I2C Senden/Empfangen können

Der Setup Teil

  void setup() {
  // put your setup code here, to run once:
  // Nach einem Reset MUSS immer ein _TMC222GetFullStatus1 ausgeführt werden!
     Serial.begin(9600);        // open the serial port at 9600 bps:
     // Vordefinition aller erlaubten Adressen für die TMC222 IC's (nur der Übersicht wegen)
     _TMC222adr[0] = 0xC0;      // Eingang HW = offen = 0 // Dies ist auch die Adresse eines fabrikneuen IC's wenn HW=offen
     _TMC222adr[1] = 0xC4;      // Eingang HW = offen = 0 //
     _TMC222adr[2] = 0xC8;      // Eingang HW = offen = 0 //
     _TMC222adr[3] = 0xCC;      // Eingang HW = offen = 0 //
     _TMC222adr[4] = 0xD0;      // Eingang HW = offen = 0 //
     _TMC222adr[5] = 0xD4;      // Eingang HW = offen = 0 //
     _TMC222adr[6] = 0xD8;      // Eingang HW = offen = 0 //
     _TMC222adr[7] = 0xDC;      // Eingang HW = offen = 0 //
     _TMC222adr[8] = 0xE0;      // Eingang HW = offen = 0 //
     _TMC222adr[9] = 0xE4;      // Eingang HW = offen = 0 //
     _TMC222adr[10] = 0xE8;     // Eingang HW = offen = 0 //
     _TMC222adr[11] = 0xEC;     // Eingang HW = offen = 0 //
     _TMC222adr[12] = 0xF0;     // Eingang HW = offen = 0 //
     _TMC222adr[13] = 0xF4;     // Eingang HW = offen = 0 //
     _TMC222adr[14] = 0xF8;     // Eingang HW = offen = 0 //
     _TMC222adr[15] = 0xFC;     // Eingang HW = offen = 0 //
     _TMC222adr[16] = 0xC2;     // Eingang HW = GND   = 1 // Dies ist auch die Adresse eines fabrikneuen IC's wenn HW=GND
     _TMC222adr[17] = 0xC3;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[18] = 0xCA;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[19] = 0xCE;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[20] = 0xD2;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[21] = 0xD3;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[22] = 0xDA;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[23] = 0xDE;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[24] = 0xE2;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[25] = 0xE5;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[26] = 0xEA;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[27] = 0xEE;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[28] = 0xF2;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[29] = 0xF6;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[30] = 0xFA;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist
     _TMC222adr[31] = 0xFE;     // Eingang HW = GND   = 1 // !!!  GND=1 gilt nur in diesem Fall da dies kein Logic Level ist


     // Vordefinition der Motor Stromstärken, leider lassen sie die Werte nicht mittels MAP-Befehl errechnen.
     _TMC222current[0]  =  59;  // Irun oder Ihold =  59mA
     _TMC222current[1]  =  71;  // Irun oder Ihold =  71mA
     _TMC222current[2]  =  84;  // Irun oder Ihold =  84mA
     _TMC222current[3]  = 100;  // Irun oder Ihold = 100mA
     _TMC222current[4]  = 119;  // Irun oder Ihold = 119mA
     _TMC222current[5]  = 141;  // Irun oder Ihold = 141mA
     _TMC222current[6]  = 168;  // Irun oder Ihold = 168mA
     _TMC222current[7]  = 200;  // Irun oder Ihold = 200mA
     _TMC222current[8]  = 238;  // Irun oder Ihold = 238mA
     _TMC222current[9]  = 283;  // Irun oder Ihold = 283mA
     _TMC222current[10] = 336;  // Irun oder Ihold = 336mA
     _TMC222current[11] = 400;  // Irun oder Ihold = 400mA
     _TMC222current[12] = 476;  // Irun oder Ihold = 476mA
     _TMC222current[13] = 566;  // Irun oder Ihold = 566mA
     _TMC222current[14] = 673;  // Irun oder Ihold = 673mA
     _TMC222current[15] = 800;  // Irun oder Ihold = 800mA
}

Der loop Teil

 void loop() {
   // put your main code here, to run repeatedly:
  cleardump();
  TMC222GetFullStatus1(_TMC222adr[0]);     // Prozedur zum auslesen des TMC als Parameter wird die Adresse des IC's übegeben
  printdump();
  delay(10000);
 }

Nach dem Loop Teil können wir eigene Prozeduren schreiben

welche wir dann vom Hauprogramm (loop-Teil) aus aufrufen werden

Satzaufbau zur Abfrage des TMC222 GetFullStatus1

TMC222GetFullStatus1.png

  void TMC222GetFullStatus1(byte Adresse) {
     _TMC222dump[0] = Adresse;                                // I2C Adresse eines TMC222
     _TMC222dump[1] = _TMC222GetFullStatus1;                  // Den Befehl GetFullStatus1 in das Array schreiben
  }

Dieses Array wird an den TMC222 gesendet und anschließend werden die Empfangenen Daten darin abgelegt um diese dann anschließend entsprechend auszuwerten

Die Zeilen 0 bis 8 aus der Grafik entsprechen exakt dem Array Index 0 bis 8

Allerdings ist es etwas aufwändig die Daten sinngemäß aus dem Array zu lesen, bzw. in dass Array zu schreiben. Ich werde dies absichtlich etwas umständlicher schreiben in der Hoffnung dass es dadurch verständlicher wird. Die "Hacker" unter Euch mögen es mir nachsehen ;-)

Ausgabe des Zwischenspeichers

Darin werden die Befehle und Daten abgelegt welche wir zum TMC22 senden oder von diesem empfangen werden

 void printdump() {
    // ein einfaches darstellen des Array's _TMC222dump[]
    for (int i=0;  i<9; i++){
       Serial.print("Dump Data (");
       Serial.print(i);
       Serial.print(")   : ");
       Serial.println(_TMC222dump[i], BIN);
    }
    Serial.println();
 }
Leeren des Zwischenspeichers
  void cleardump() {
     // ein einfaches nullen des Array's _TMC222dump[]
     for (int i=0;  i<9; i++){
        _TMC222dump[i]=0;
     }
  }


Wichtige Tipps

Ich kann es nicht oft genug wiederholen:

  • Die I2C Leitungen, SCL und SDA benötigen einmalig einen 10kR Pull Up Widerstand zu +5V des Arduino
  • Die Versorgungsspannung des TMC222 darf nicht unter 8V liegen
  • Es muss ein Schrittmotor am TMC222 angeschlossen sein
  • Die Pins HW und SWI haben keinen Logic Level!
HW löst den zweiten Adressbereich aus mehr dazu im Datenblatt (am besten beim ersten Test unbeschaltet lassen)
SWI ist ein Eingang für einen Referenzschalter mehr dazu im Datenblatt (am besten beim ersten Test unbeschaltet lassen)


Nützliche Werkzeuge

I2cScanner

Sollte es in irgendeiner Weise Problme mit der I2C Kommunikation geben? Ich habe Im Playground einen I2C Scanner gefunden:

Dieses Programm soll die Komplette I2C Adress-Range nach kompatiblen Devices absuchen. Ich habe dieses Programm (noch) nicht getestet.


     // --------------------------------------
     // i2c_scanner
     //
     // Version 1
     //    This program (or code that looks like it)
     //    can be found in many places.
     //    For example on the Arduino.cc forum.
     //    The original author is not know.
     // Version 2, Juni 2012, Using Arduino 1.0.1
     //     Adapted to be as simple as possible by Arduino.cc user Krodal
     // Version 3, Feb 26  2013
     //    V3 by louarnold
     // Version 4, March 3, 2013, Using Arduino 1.0.3
     //    by Arduino.cc user Krodal.
     //    Changes by louarnold removed.
     //    Scanning addresses changed from 0...127 to 1...119,
     //    according to the i2c scanner by Nick Gammon
     //    http://www.gammon.com.au/forum/?id=10896
     // Version 5, March 28, 2013
     //    As version 4, but address scans now to 127.
     //    A sensor seems to use address 120.
     // Version 6, November 27, 2015.
     //    Added waiting for the Leonardo serial communication.
     // 
     //
     // This sketch tests the standard 7-bit addresses
     // Devices with higher bit address might not be seen properly.
     //
      #include <Wire.h>
      void setup()
     {
       Wire.begin();
     
       Serial.begin(9600);
       while (!Serial);             // Leonardo: wait for serial monitor
       Serial.println("\nI2C Scanner");
     }
     void loop()
     {
       byte error, address;
       int nDevices;
       Serial.println("Scanning...");
       nDevices = 0;
       for(address = 1; address < 127; address++ ) 
       {
         // The i2c_scanner uses the return value of
         // the Write.endTransmisstion to see if
         // a device did acknowledge to the address.
         Wire.beginTransmission(address);
         error = Wire.endTransmission();
         if (error == 0)
         {
           Serial.print("I2C device found at address 0x");
           if (address<16) 
             Serial.print("0");
           Serial.print(address,HEX);
           Serial.println("  !");
           nDevices++;
         }
         else if (error==4) 
         {
           Serial.print("Unknow error at address 0x");
           if (address<16) 
             Serial.print("0");
           Serial.println(address,HEX);
         }    
       }
       if (nDevices == 0)
         Serial.println("No I2C devices found\n");
       else
         Serial.println("done\n");
       delay(5000);           // wait 5 seconds for next scan
     }

Abkürzungen

OTP = One Time Programmable
BSQ = Beißend Schwarzer Qualm