- Labornetzteil AliExpress         
Ergebnis 1 bis 10 von 38

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

Hybrid-Darstellung

Vorheriger Beitrag Vorheriger Beitrag   Nächster Beitrag Nächster Beitrag
  1. #1
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.700
    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 10:31 Uhr) Grund: Interruptverschmutzung der Test-Targets
    Ciao sagt der JoeamBerg

  2. #2
    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 !

  3. #3
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.700
    ... 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

  4. #4
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.700
    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

Ähnliche Themen

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

Berechtigungen

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

LiFePO4 Speicher Test