- Labornetzteil AliExpress         
Seite 4 von 4 ErsteErste ... 234
Ergebnis 31 bis 38 von 38

Thema: I²C mit Bitrate > 100 kHz - nur mit Treiber ?

  1. #31
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Anzeige

    Praxistest und DIY Projekte
    ... I2C mit maximaler Geschwindigkeit ... TWBR = 10 ...
    So, nun ist meine Stimmung doch deutlich gestiegen. Ich habe endlich einen halbwegs realistischen Testaufbau - drei Controller. Dazu ein fast zweieinhalb Meter langes 10fach-Flachkabel. Und I2C läuft mit TWBR = 5. Master wie vor mit 20 MHz. Da machts einfach gute Laune, wenn der Master bei einem Rundruf in seine - hier noch unbekannte I²C-Welt (...for ( uint8_t look=0x00; look <= 0xFC; look = look + 2 )...) auch die tatsächlich vorhandenen Controller erkennt , siehe Dump vom Terminal :

    Code:
     C501 R5M_x15-16 m1284p/20MHz 28Nov2012 16:46
     I2C >>400kHz [t05], I2C mit Taste [gelb], dann [OK] zu MoCo328
     Motoren rauf+runter mit Taste [P100]
     Gute Funktion mit extINT2 für RC-5
     Initialisierung ADC auf ADC5/PA5=Poti
     UbattADC5 Min = 2 , Mess = 678
    
     Es folgt Aufruf i2clook
     Suche vorhandene I²C-Devices von 0x00 bis 0xFE
    -----------------------------------------------------------------
     Slave erkannt auf 130 dez = 0x82
     Slave erkannt auf 132 dez = 0x84
    ------------------------------------------------------------
     Rückkehr von i2clook
    
     Beginn Schleife/RC-5-lesen in ~r1n15~
     Aktiv :  Taste [MIX], [P100], [9] und [gelb]
     Bitte um Aktion _
    Ach so - jedes Minus oben im Slave-Suchabschnitt ist eine nicht-antwortende Adresse.
    Ciao sagt der JoeamBerg

  2. #32
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo oberallgeier.

    Gratulation zum Erfolg bei diesem Teil-Problem.


    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  3. #33
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Das Thema ist erfolgreich abgeschlossen, im ersten Posting (klick) ist ein Inhaltsverzeichnis der relevanten Beiträge.
    Ciao sagt der JoeamBerg

  4. #34
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Viel Unverständnis zu diesem Zustand (passt halt nur so ungefähr in diesen Thread):

    I2C-Lesen braucht ne Pause.

    Vorgeschichte: Bei meinem Archie hängen an einem I²C-Master (mega1284/20MHz) mehrere Slaves, einer davon eine Motor-Steuerplatine (mega328/20MHz) mit Treiberplatine für zwei Motoren je max 60W. Die Befehle für die Motoransteuerung der beiden Motoren gehen vom Master zur Motor-Steuerplatine per I²C, das läuft prächtig. Lesen des Slavepuffers - z.B. Encoderstand oder Ist-Speed - ging oft, meist, führte bisher stehts nach 1 bis etwa 20 (evtl. mehr?) Lesevorgängen zum Blackout des Masters. Blackout: TWI-Übertragung stoppte (z.B. belegt durch testweise Ausgabe per UART), aber ISR (TIMER2_COMPA_vect) lief weiter mit 20kHz-Interrupt, erkennbar am Toggeln der 1-sec-Heartbeat-LED.

    Sonstige Angaben: 2 UARTkanäle laufen per Interrupt - 1x 115,2 kBd fürs Terminal und 1x 57,6 kBd für die PingPong-LED-Anzeigetafel, ISR (TIMER2_COMPA_vect) mit 20 kHz, ADC im free running mit rund 15 kHz, External Interrupt 20 für RC5, I2C nach PFleury mit 100 kHz.

    Fazit bisher: Telegramme werden an die Slaves per I²C nur gesendet, es wird nichts zurückgelesen. Ein ziemlich unbefriedigender Zustand (aber Archie lief ziemlich gut).

    Versuch einer Nachbesserung heute, dazu zuerst Versuch einer Identifizierung der Abbruchstelle. Um die Absturzstelle des Codes zu identifizieren wurden zuerst kurze UART-Telegramme in die I²C-Lesesequenz eingefügt. Die erste im Master gleich nach dem Schreiben der Adresse des ersten zu lesenden Pufferbytes. Und schon läufts klaglos. Ein einziges Millisekundenwait tat den gleichen Nutzen, mittlerweile tuts ein wait von 100 Mikrosekunden. Kontrolle: ohne Wait bekomme ich den Master nach 1 bis 15 Lesevorgängen ins Koma.

    Derzeit wurde als Testsequenz tausend Mal auf den Puffer zugegriffen und stets jeweils die gleichen fünf Bytes der Motorplatine ausgelesen, Slaveadresse 130 dez = 0x82, Startbyte zum Lesen = 23. No Problem, mit UART-Ausgabe und einem Wait von 50 ms in der Leseschleife eine Sache von gut 60 sec (die ersten fünf brauche ich um den Befehl per RC5 an den Master zu senden). Das sieht zum Schluss am Terminal so aus, die Sekunden ist die aktuelle Boardzeit mit Start beim Power on:

    PHP-Code:
        I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    985    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    986    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    987    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    988    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    989    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    990    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    991    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    992    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    993    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    994    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    995    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    996    Zeit  65 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    997    Zeit  66 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    998    Zeit  66 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    999    Zeit  66 sec
        
    I2CMrid # 131/23    O-AL 23    O-AH 24    O-BL 25    O-BH 26    1000    Zeit  66 sec
        
    Ende test841 
    Fazit: diese tausend Lesevorgänge lassen vermuten, dass zuküftig keine Störungen mehr auftauchen.

    Hier zur Erläuterung der Leseabschnitt der Funktion void I2CMrid ( void ) // I2C, Motordaten auslesen über I²C
    Code:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Lesen vom Slave     
      if(!(i2c_start(SLAVE_MoCo+I2C_WRITE))) //Slave bereit zum schreiben/lesen?
      {                                     //
            i2c_stop();     // Dies scheint notwendig, um den Lesepointer korrekt
                            //      zu positionieren
        i2c_start(SLAVE_MoCo+I2C_WRITE);    // Slave bereit zum schreiben/lesen?
    //  i2cdmy = i2c_write( 0x15 );         // Bufferadresse 15hex/21dez zum Lesen
    //  i2cdmy = i2c_write( 0x04 );         // Bufferadresse 04hex/04dez zum Lesen
        i2cdmy = i2c_write( laddr );        // Lese Buffer ab Adresse laddr
            i2c_stop();                     //
    //uputs0 ("\r\tLabel nach Start ");     // Nach Einfügen dieser Zeile lief es gut!
    //  wms  (    1);                       //  daher statt der UART-Ausgabe das wait
        wmus (  100);                       //  kurzes Wait, ca. 0,1 ms
        i2cdmy  = i2c_start(SLAVE_MoCo+I2C_READ); // <<<### Lesen beginnen
        ipwm12  = i2c_read (ACK);           // Bytes lesen...
        soll12  = i2c_read (ACK);           //
        ipwm34  = i2c_read (ACK);           // 
        soll34  = i2c_read (ACK);           //
        i2cdmy  = i2c_read (NAK);           // letztes Byte lesen, NAK
            i2c_stop();                     // Zugriff beenden
      }                                     //
      else                                  // Wenn Fehler, dann nelde jetzt:
      {                                     //    Lesefehler, dazu Fehlerblinken
        uputs0("\r\n\t### Kein Lesen möglich.\r\n");     //
        i2cerr      = 0b00000001;           // Fehlercode zu i2c-read nicht möglich
      }                     // Ende if(!(i2c_start(SLAVE_MoCo+I2C_WRITE)))
    Frage/Bitte:
    Kann mir jemand bitte erklären wo ungefähr die Leseroutine sich durch eine zu knappe zeitliche Bemessung aufhängen könnte? Ich dachte, dass das
    Ciao sagt der JoeamBerg

  5. #35
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Das Problem ist offensichtlich gelöst - nach der Methode "Auch ein blindes Huhn ...". Eine Erklärung, warum die Verzögerung nötig ist habe ich nämlich nicht. Vielleicht werde ich mit einem DSO noch Messungen am I²C-Bus machen, aber das hat erstmal Zeit.

    Was geschah?
    Die kritische Stelle der I²C-Leserei hatte ich im obigen Posting wohl recht gut getroffen. Da die konstanten wait-Vorgaben doch unbefriedigend sind, hatte ich mal versucht die Stati des Busses abzufragen. Das klappte nicht wirklich, ist auch eine etwas seltsame Lösung.

    Mittlerweile habe ich den Code geändert, der Befehl "..rep_start.." steht in einer while-Schleife. Und nun tuckerts klaglos, aktuell mit 800 kHz, das ist ein TWBR von 4 (eigentlich 4,5), PFleury nennt ein Minumum von 10 für stabilen I²C-Lauf.
    Anmerkung: der "..rep_start.." in der PFleury-Bibliothek ist nur ein 1:1 umgeleiteter "... i2c_start ...", der ja mit dem Ergebnis einer Bus-Statusprüfung zurückkommt ;.-.)
    Anmerkung2: Das Datenblatt des m1284 nennt als TWI-Frequenz eine obere Grenze von Slavetakt / 16. Diesen kann ich nicht erreichen. Mit TWBR 2 gehts nämlich schon nicht mehr ! . . .

    Code:
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Lesen (read back) vom Slave   ... mit der Routine aus fleury´s lib
      i2c_start_wait(SLAVE_MoCo+I2C_WRITE); // set device address and write mode
      i2c_write( laddr );           // write address = laddr, das angepeilte Byte
            i2c_stop();             //
    
      while ((i2c_rep_start(SLAVE_MoCo+I2C_READ))) {}// Slave bereit zum Lesen?
    //i2c_rep_start(SLAVE_MoCo+I2C_READ);   // set device address and read mode
      ipwm12  = i2c_readAck();      // Bytes lesen... ab laddr = 0x33/51
      soll12  = i2c_readAck();      //
      ipwm34  = i2c_readAck();      // 
      soll34  = i2c_readNak();      // letztes Byte lesen, NAK
            i2c_stop();             //
    Ärgerlich für mich ist nur, dass diese Änderung wieder mal ne experimentelle Softwareentwicklung ist, weil mir der tatsächliche Grund für die Notwendigkeit dieser Verzögerung nicht klar ist.

    Getestet wurde in diesem Zusammenhang in meinem aktuellen Archie-Aufbau mit Master (m1284/20MHz), drei Slaves: 2x1284/20MHz und 1x328/20MHz und einer rund 1,5 m langen I²C-Leitung mit zwei Zwischensteckern. Master und Slaves sind durch mehrere Interrupts "verseucht", der Motorcontroller z.B. durch Regelungsroutine ( > 2 x 100 Hz ), Encoder (2 Stk, bis > 500 Hz), Heartbeat+Boardtimer 20 kHz und UART-115kBd. Ähnlich auch der Master durch Heartbeat+Boardtimer, RC-5-Decoder, UART 1 x mit 115kBd und 1 x mit 57kBd. . .
    Geändert von oberallgeier (13.07.2014 um 11:31 Uhr) Grund: Interruptverschmutzung der Test-Targets
    Ciao sagt der JoeamBerg

  6. #36
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    07.03.2011
    Beiträge
    1.899
    @oberallgeier
    Eine Erklärung, warum die Verzögerung nötig ist habe ich nämlich nicht.
    Eigentlich schon. Manche Slaves, z.B.EEPROMS, zeigen an, daß sie nicht zum Lesen bereit sind, indem sie ihre Adresse nicht mit ACK bestätigen. Das nennt man glaube ich ACK-Polling. Ob dein Slave so reagiert, kann ich jetzt nicht sagen

    Ich verwende "Repeated Start" nicht (Repeated Start braucht man nur bei Multimaster-Betrieb), sondern mache einen Stop und fange dann mit Start neu an. Und ich werte bei jedem Byte das ACK aus. Kommt das ACK nicht wie erwartet, breche ich den Vorgang mit Stop ab. Wenn danach der Bus nicht Idle wird, was vor dem Anlegen der nächsten Start-Condition geprüft wird, versuche ich den Slave mit bis zu 8 Pulsen auf der SCL-Leitungen zu resetten, d.h. den Bus in den Idle-Zustand zu bringen. Wenn das nicht klappt, ist die Hardware kaput (oder ich habe den Slave selbst programmiert )

    Wie das irgendwelche Libraries machen, weiß ich nicht. Wenn man I2C Hardware benutzt, kann man die paar Registerzugriffe auch selber programmieren. Und selbst SW-I2C ist nicht wirklich kompliziert.

    MfG Klebwax
    Strom fließt auch durch krumme Drähte !

  7. #37
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    ... Manche Slaves, z.B.EEPROMS, zeigen an, daß sie nicht zum Lesen bereit sind, indem sie ihre Adresse nicht mit ACK bestätigen ...
    Danke für diese Beschreibung. Ich sehe das hier bei mir auch so. Mittlerweile habe ich ja auch die Bibliothek einigermassen durchgehechelt - denn selbst diese Hardware-I²C braucht ja ein bisschen Software - und diese paar Zeilen stehen ja eigentlich fast identisch im Datenblatt. So blicke ich allmählich durch und verstehe was da abläuft. Und offensichtlich ging da bei mir einiges fehl, weil ich beim I²C-Start nicht immer prüfte, ob ich auch Antwort bekomme.

    ... was vor dem Anlegen der nächsten Start-Condition geprüft wird ...
    Da scheint bei einigen Beispielen der Hase im Pfeffer zu liegen. Und meine Probleme traten sicher dadurch auf, dass ich die Beispiele ohne Verständnis abgekupfert hatte. Egal - wie erwähnt geht mir langsam ein Licht auf. Und danke für den Trick mit den acht Pulsen (hatte ich wohl schon irgenwo mal gelesen - aber wenn man nicht weiß was da geht . . . ).

    Den Repeated Start hatte ich ja schon identifiziert (siehe oben) als das identische Teil wie der "normale" Start (neee, eigentlich kein Teil sondern ein drübergestülptes "Mehr"), nur dass damit die "..rep_start.."-Routine aufgerufen wird - die mit demselben Parameter die "... i2c_start ..."-Routine aufruft. Also einfach nur Routinen-Overhead-Verplemperei.
    Ciao sagt der JoeamBerg

  8. #38
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Gut, wer viel misst misst Mist. Kenne ich. Trotzdem hatte ich nach Einführung der Bereitschaftsprüfung beim I²C-lesen (danke Klebwax für den Ausdruck "ACK-Polling") mal die benötigten Zeiten wissen wollen. Hier sind diese Werte, bei denen vier (4) Bytes aus dem I²C-Puffer des Slaves gelesen wurden, natürlich mit den Zeiten für den zugehörigen Overhead :

    Code:
    I²C                   Δt1                 Δt2
    kHz                tupsi              tupsi ( 1 tupsi sind 50 µs)
     
    100                 22..26             14..17
    400                 13..15             4..6    
    800                 11..13             2..4
    Δt1 ist Messung EINSCHLIEßLICH UART-Ausgabe, Δt2 ist das wirklich interessierende Ding – NUR I²C-Übertragung, siehe Code im Kasten unten. Die Zeitangabe ist in tupsi, meiner Board-Zeiteinheit von 50 µs. Die angegebene I²C-Rate ist der Wert aus "#define SCL_CLOCK" in meiner twima_hze.c, real sind also z.B. 800 kHz; wegen der Rundung beim Berechnen von TWBR = ((F_CPU/SCL_CLOCK)-16)/2; sind das schon 833 kHz. Hier ist dann TWBR 4 -- und damit deutlich unter der verbreiteten Grenzangabe in den Libraries von 10. Trotzdem läuft die Chose bei mir klaglos.

    Woher dieser Grenzwert stammt weiß ich noch nicht. Ebenso ist (mir, noch) unklar das Timing der I²C-Lese-Hardware der 8bittigen ATMEL Megas. Aber - abwarten.

    Code:
    // ============================================================================= =
    //      Lesen Daten von der Motorplatine, Slaveadresse 0x82/130dez;
    //        Ausgabe auf UART0
    // - - - - - - - - - - - - - - - -
      void I2CMrid ( void )                 // I2C, Motordaten auslesen über I²C
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     {                              //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      u8        ipwm12  =  99;      // Read-back-Byte vom Slave
      u8        soll12  =  98;
      u8        ipwm34  =  97;
      u8        soll34  =  96;
      u8        laddr   = 0x33;     // Leseaddresse = 51dez
      u8        i2cttt  =   0;      // Lokal gemessene Zeit
     
      i2ctim        =       0;      // Sendedauer - siehe ~com~.h
     
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //      Lesen (read back) vom Slave   ... mit der Routine aus fleury´s lib
      i2c_start_wait(SLAVE_MoCo+I2C_WRITE); // set device address and write mode
      i2c_write( laddr );           // write address = laddr, das angepeilte Byte
            i2c_stop();             //
     
      while ((i2c_start(SLAVE_MoCo+I2C_READ))) {}   // Slave bereit zum Lesen?
    //while ((i2c_rep_start(SLAVE_MoCo+I2C_READ))) {}// Slave bereit zum Lesen?
    //i2c_rep_start(SLAVE_MoCo+I2C_READ);   // set device address and read mode
      ipwm12  = i2c_readAck();      // Bytes lesen... ab laddr = 0x33/51
      soll12  = i2c_readAck();      //
      ipwm34  = i2c_readAck();      // 
      soll34  = i2c_readNak();      // letztes Byte lesen, NAK
            i2c_stop();             //
     
      i2cttt        = i2ctim;       // Timerwert übernehmen
      if ( ipwm12 <= 1 ) i2cRct++;  // Wenn Lesebyte fehlerhaft scheint
                                    // I2C-ERRorcounter hochzählen
    // - - - - - - - - - - - - - - - - - - - -
    //      Ausgabe der Daten über UART - Fortsetzung der Startsequenz
      uputs0 ("\r\tI²Crd # ");    // Kennung dieser Routine
      uputs0i(SLAVE_MoCo+I2C_READ); uputs0("/"); uputs0i ( laddr );
      uputs0("\tP12 ");  uputs0u(ipwm12);
      uputs0("\tsp1 ");  uputs0u(soll12);
      uputs0("\tP34 ");  uputs0u(ipwm34);
      uputs0("\tsp4 ");  uputs0u(soll34);
    //uputs0("\ttmr ");  uputs0u(i2ctim);   // Timerwert ausgeben MIT UART
      uputs0("\tttt ");  uputs0u(i2cttt);   // Gestoppte Zeit NUR I2C
                                            //
    // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    //  uputs0("\tEnde I2CMrid");
      return;               //
     }                       
    // ===  Ende void I2CMrid ( void ) 
    // ============================================================================= =
    Overhead rausmessen, sprich: NUR die reine Datenübertragung zu messen, wäre möglich. Aber wozu? Immerhin geben diese Werte einen Anhalt über den tatsächlichen Zeitaufwand bei mittelschnellem I²C.
    Ciao sagt der JoeamBerg

Seite 4 von 4 ErsteErste ... 234

Ähnliche Themen

  1. ADU und Treiber
    Von manhunt im Forum AVR Hardwarethemen
    Antworten: 2
    Letzter Beitrag: 15.06.2009, 19:27
  2. CAN-BUS: Wie könnte man die Bitrate messen?
    Von Kaiser-F im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 29.09.2006, 10:38
  3. Treiber IC
    Von jonas im Forum Elektronik
    Antworten: 10
    Letzter Beitrag: 27.04.2005, 17:58
  4. FET-Treiber
    Von FelixR im Forum Elektronik
    Antworten: 0
    Letzter Beitrag: 20.02.2005, 15:15
  5. Treiber Ic
    Von Robbigay im Forum Motoren
    Antworten: 10
    Letzter Beitrag: 05.05.2004, 21:00

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •  

Labornetzteil AliExpress