- 3D-Druck Einstieg und Tipps         
Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 11

Thema: m168 - als I²C-Receiver-Sklave, NUR 7Bit Daten möglich!?!

  1. #1
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30

    m168 - als I²C-Receiver-Sklave, NUR 7Bit Daten möglich!?!

    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hi, hab wieder einmal ein Problem mit meinem ATmega168..

    verwendetes Zeugs:
    - m168 @8Mhz
    - AVRSTudio mit GCC
    - Ponyprog
    - JTAG ICE MK2
    - nen Oszi
    - ein VB2005 I²C Terminalprogramm
    - I²C-Serial Adapter von robotikhardware.de


    Es geht um den I²C Sklave im Receiver Modus.


    Der Chip bekommt über den Bus das Adresspaket und 2 Datenpakete, mittels des hier im Shop erhältlichen I²C-Seriell Übersetzers und einem (von mir geschriebenen) VisualBasic2005 I²C Terminalprogramm.
    (welches frei nach dem, dem I²C-Seriell Übersetzer beiligenden Programms (war für VB6 oder so) geschrieben wurde)

    In folgendem Bild sieht man, was das Terminalprogramm für Signale auf SCL/SDA erzeugt, wenn man eine bestimmte Befehlsfolge startet.
    Alles sauber, auch die Antworten vom m168 - meiner Meinung nach.
    Er müsste eigentlich alles haben...

    "W255;" bedeutet im übrigen - schreibe 255 an Sklave


    Bild hier  


    In den nachfolgenden Bildern hab ich an dieser Befehlsfolge jeweils nur beim 3. Byte den zu übertragenden Wert geändert - Fehler bleibt gleich.

    Beachtet bitte die Zustände im Datenregister TWDR, welche ich rot markiert hab.
    Es sieht so aus, als ob die empfangenen Daten (des letzen Bytes) nach links geschiftet werden - aber WIESO?




    Bild hier  

    Bild hier  



    Und bei folgendem Bild hab ich die übertragenen Signale (nebst Antworten vom m16 nochmal mit reingepackt.



    Bild hier  



    .. und zugeuter Letzt noch den Code-Schnipsel, mit der TWI-Interrupt-Sequenz (glaub nach der Anleitung im GCC-Tutorial oder wars ein dem GCC beiligendes Beispiel?..


    Code:
    ISR (TWI_vect) // I²C Interrupt - 8Bit Solltemperatur einlesen (ohne Fehlercheck!!!)
    {
    	TWSTATUS++;  // Schalter um eins erhöhen
    	switch (TWSTATUS)
    	{
    		case 1:  // erster Durchlauf
    		{	
    			if (TW_STATUS != TW_SR_SLA_ACK) { TWSTATUS = 0;} // wenn erkannt weiter, ansonsten Reset
    		}
    		case 2:
    		{
    			// I²C Temperaturvorgabe gültig oder Analoge Temperaturvorgabe nutzen?
    			if (TWDR > 0) { I2C_TEMPSOLL = 1;} // der I²C Temp-Vorgabewert gilt
    			else { I2C_TEMPSOLL = 0;} // Analoger Temp-Vorgabewert gilt, I²C gibt Steuerung ab
    		}
    		case 3:
    		{
    			if (I2C_TEMPSOLL == 1) // I²C Temp-Vorgabe ist möglich, also los..
    			{
    				temp_soll = TWDR; // Soll-Temperatur übernehmen
    			}
    /*			else // I²C gibt Temp NICHT mehr vor!!
    			{
    				__asm__ __volatile__ (" nop \n" :: ); // nichts tun...
    			}
    */			TWSTATUS = 0; // Reset des Schalters, Ende erreicht	
    		}
    	}
    	// TWI wieder empfangsbereit machen (TWINT-Bit setzen)
    	// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
    	TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
    }
    
    int main (void)
    {
    	// Pin11(D7)<-I_Anteil ON/OFF, Pin10(D6)<-D_Anteil ON/OFF
    	// Pin9(D5)->T0_PWM, Pin2(D4)<-T0_CLK, Pin1(D3)->ALIVE-Signal, Pin32(D2)<-INT0,
    	// Pin31(D1)->Heizen/Kühlen, Pin30(D0)<-Laserdiode oder nicht
    	DDRD = (0<<DDD7)|(0<<DDD6)|(1<<DDD5)|(0<<DDD4)|(1<<DDD3)|(0<<DDD2)|(1<<DDD1)|(1<<DDD0);
    
    	// Pin27(C4)/28(C5)<-SDA/SCL für I²C,
    	DDRC = (0<<DDC6)|(0<<DDC5)|(0<<DDC4)|(0<<DDC3)|(0<<DDC2)|(0<<DDC1)|(0<<DDC0);
    
    	// Pin7,8 & 16,17(B4-B7) für I²C Adresse, Pin15(B3)->T0_CLK, Pin12(B0)<-ICP1, 
    	DDRB = (0<<DDB7)|(0<<DDB6)|(0<<DDB5)|(0<<DDB4)|(1<<DDB3)|(0<<DDB2)|(0<<DDB1)|(0<<DDB0);
    
    ...
    
    	// I²C: Sklave, TWI-Enable, TWI-Interrupt-Enable (Pin27 = SDA & Pin28 = SCL)
    	TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWWC)|(1<<TWEN)|(1<<TWIE);
    
    	// ***********************************************************************************************
    	// nur in der folgenden Zeile Änderungen an der I²C-Adresse vornehmen!!!
    	TWAR |= (0<<TWA6)|(0<<TWA5)|(1<<TWA4)|(0<<TWGCE); // Setzen der ersten 3 (TWA) Bits der I²C-Adresse
    TWAR = 254;
    	// in diesem Fall werden die Chips mit den Adressen: [xxx]0000 bis [xxx]1111 erreicht!!!
    	// die letzten 4 Bits werden durch die hardwareseitige Beschaltung der Pins 7,8, 16 & 17 bestimmt!
    	// ***********************************************************************************************
    
    ...
    
    	}
        return (0);
    }

    Also nochmal: Wieso bekomm ich per Interrupt aus dem Datenregister des TWI nur 7Bit - anstatt der 'üblichen' 8Bit?

    Das LSB in TWDR ist immer Zero, außer nach dem einschalten des m168.
    "LSB" heißt least significant Bit, "MSB" entsprechend most .. (für Neulinge)

    Grüße und besten Dank
    0tes_Gesetz

    PS: wenn noch irgendwelche Angaben fehlen.. bitte schreibts, ich liefere gerne nach, wenn nur irgendjemand einen Rat hat..

  2. #2
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.842
    Ich bin erschlagen *pfuuu*

    Zwischenfrage von einem Doofen: du willst vom PC was an den Slave senden ? Ich seh da oben eine Slave ID von "127" . Das heißt aber doch vom Slave Lesen ?
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  3. #3
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30
    Sorry, dass das gleich so viel war... wenn das so gehen würde wie gedacht hätt ich niemanden "genervt"

    zu deinen Fragen:

    1) Ja, ich sende via Serieller Com Port -> I²C Umetzer über die SCL/SDA Leitungen Daten an den Atmel Prozessor (hier mega 16.
    Allerdings derzeit nur mit dem PC, weil ich da "spielen" kann und sich auch mal schnell was ändern lässt

    2) Das I²C-Adressierungsformat lautet folgendermassen (8Bit):

    - die ersten 7 Bit sind die Adresse des Chips, also von 0-127
    - das letzte Bit (8tes) ist die Schreib(0)/Lese(1) Info

    Damit wird 's127w'="Sklave mit ID 127, BEschreiben" zu: 1111.1110

    - das ganze wirde gefolgt von einem SCL-Impuls des Masters, bei dem der Sklave die SDA-Leitung auf Masse ziehen muss -> ACKnowledged.

    An den Oszi-Aufnahmen sieht man sehr schön, wie der Sklave gleich nach dem 8. SCL-Impuls die SDA-Leitung runterzieht und so lange GÜLTIG hält, wie der Master den 9. SCL-Impuls anliegen hat, damit der das ACK auch sicher empfangen kann (das Read Data Feld im Terminal-Prog zeigt dann ja auch das ACK jeweils an ).
    Dann lässt der Sklave die SDA-Leitung wieder los und der Master macht entweder mit Daten weiter oder aber zum Schluss das STOP.

    Ich hab mir die Zeitverläufe auch genauer angesehen (hatte Verdacht, dass der Sklave es nicht richtig macht und ungültige SDA-Werte verursacht ), aber dem ist nicht so.. ist halt nur recht fix der Kerl.
    Daran sollte es jedenfalls nicht liegen, dass bei der Datenübertragung in TWDR nur die letzten 7Bit vom gewünschten vollen Byte stehen.

    Irgendwie sieht das so aus, als ob mit dem 9. SCL-Impuls die Bits in TWDR noch eins weiter geschoben werden...

    Muss morgen mal nen Test mit Nicht-ACK machen, vielleicht steht dann zufällig eine 1 an der letzten Stelle in TWDR.. hm..

    Grüße
    0tes_Gesetz

  4. #4
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo,

    ich weiss jetzt nicht, ob ich hier alles gelesen hab,
    aber das mit dem das TWDR ein Bit zu weit nach links geschoben ist, liegt meistens daran, das man erst nach dem Stopbit da rein schaut.
    Das Stopbit kommt auch über den Bus, und wird wie alle anderen Daten ins TWDR geschoben, nur das danach schluss ist, und somit das Byte das zuletzt in TWDR stand dann eins nach links geschoben ist.
    Deswegen muss das Byte aus TWDR immer schon ausgelesen werden, bevor man das ACK oder NACK zurückgibt, und es am Bus weitergeht mit der Übertragung.

  5. #5
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30
    Das mit dem STOP-Bit könnte ich ja gleich morgen ausprobieren, indem ich meine Befehlszeile ohne 'STOP;' ausführen lasse, Danke.

    Muss ich dann wohl aber doch noch ein wenig tiefer in die Materie rein, da ich bis jetzt erst in den Interrupt komme, NACHDEM das ACK vom Sklaven gesendet wurde - automatisch...
    Ich seh schon, das wird noch ne lustige Angelegenheit, bis ich das im Kasten hab.

    Grüße
    0tes_Gesetz

  6. #6
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.842
    @linux , leichter Widerspruch: Wenn du den HW-TWI aktivierst, dann mit ack-enable oder -disable. Zwischen Daten und ack kommst du da nicht hin, das macht er intern elektrisch. Oder umgekehrt, du kriegst gesendet+Ack empfangen oder gesendet+Nicht Ack
    Ich mißtrau' aus dem Bauch eher dem PC Programm.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    28.06.2006
    Beiträge
    7
    Hab leider mein PW nicht dabei.. deswegen mit anderem Login


    Ich weiß jetzt woran es liegt: an der Stop-Sequenz!

    Hier das "Beweisfoto"


    Bild hier  


    Es ist also so, wie linux_80 gesagt hat, die TWI-Unit des m168 interpretiert das STOP als den Beginn einer weiteren Übertragung und beginnt schon wieder mitzuschreiben und versaut dadurch die Daten im TWDR (Schieberegister)...

    vermutliche Lösung: Abschalten der TWI-Unit des m168, gleich nachdem er das ACK gesendet hat.. weiß der Geier wie das gehen soll

    Vielen Dank bis hierher - falls jemand ne Idee haben sollte, wie ich der TWI-Unit ins Getriebe greifen kann?!? Bin für alles offen

    Grüße
    0tes-Gesetz

    PS: ich meld mich wieder, wenn ich ne Lösung hab..

  8. #8
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Hallo miteinander,

    schaut mal hier im Wiki vorbei -> https://www.roboternetz.de/wissen/index.php/TWI_Praxis
    für jeden Fall ein kleines Beispiel.
    Hatte selber schon ein paar Experimente gemacht, und rausgefunden das es an dem Stopbit liegt.

    Und man kann natürlich auf das TWDR zugreifen bevor man das ACK/NACK abgibt, denn es muss erst das richtige Flag in TWCR gesetzt werden, damits überhaupt weiter geht, automatisch gehts auf jeden Fall nicht.

    Das TWI-Modul deaktivieren ist schon mal die schlechteste Idee, weil die Ports des AVR wieder für normale IO umgeschaltet werden, wer weiss was da auf dem Bus los ist, kennt sich kein Slave mehr aus was läuft.

    Hat da einer das DB nicht im Kopf

    Edit:
    noch vergessen,
    Guter Satz:

    Zitat Zitat von PicNick
    ... das macht er intern elektrisch...
    hab mir schon sowas gedacht, weil ich noch nie damit an der Takstelle war und meine AVRs trotzdem laufen

  9. #9
    Benutzer Stammmitglied
    Registriert seit
    22.09.2005
    Beiträge
    30
    Zitat Zitat von linux_80
    ...schaut mal hier im Wiki vorbei -> https://www.roboternetz.de/wissen/index.php/TWI_Praxis
    für jeden Fall ein kleines Beispiel.
    Hatte selber schon ein paar Experimente gemacht, und rausgefunden das es an dem Stopbit liegt.
    Es liegt nicht _nur_ am Stopbit bzw. ist das Stopbit im letzten Byte nur ein Symptom..
    Ich bekomm das TWDR auch nicht zwischendurch mit dem richtigen Byte ausgelesen, sondern immer nur das nachfolgende, weil das ACK eben schon gesendet wurde und der Master (berechtigterweise) fröhlich weiter macht...

    Zitat Zitat von linux_80
    Und man kann natürlich auf das TWDR zugreifen bevor man das ACK/NACK abgibt, denn es muss erst das richtige Flag in TWCR gesetzt werden, damits überhaupt weiter geht, automatisch gehts auf jeden Fall nicht.
    Was ebend so nicht richtig sein kann, denn sonst würde ja auch das Stop-Bit zum Schluss nicht stören

    Ich werd mal meine derzeitige Auffassung der Dinge geben:

    Das, was der TWI machen soll, wenn Daten/Adressen kommen sagt man ihm mit dem TWCR.
    In dem Basom-Beispiel hat man nichts anderes gemacht als ich auch, nur dass ich zusätzlich noch 'nen Interrupt aufrufen lasse, in dem ich dann eigentlich das TWDR auslesen wollte..

    Bascom-Bsp:
    Twcr = &B01000100 ' TWI aktivieren, ACK einschalten
    ich:
    TWCR = (1<<TWINT)|(1<<TWEA)|(0<<TWSTA)|(0<<TWSTO)|(0<<TWW C)|(1<<TWEN)|(1<<TWIE);
    // Flag gelöscht (TWI gestartet), ACK senden anstatt No-ACK nach Empfang, Pins an TWI angeschlossen und TWI-Interruptvektor
    *) ob ich nun TWINT beschreibe oder nicht, dürfte null Auswirkung haben..

    Interessant wäre nun die Diskussion um das TWEA-Bit..
    Das Datenblatt des m168 sagt dazu folgendes:
    • Bit 6 – TWEA: TWI Enable Acknowledge Bit
    The TWEA bit controls the generation of the acknowledge pulse. [highlight=orange:5ea0e0b877]If the TWEA bit is written to
    one, the ACK pulse is generated on the TWI bus if the following conditions are met:[/highlight:5ea0e0b877]
    1. The device’s own slave address has been received.
    2. A general call has been received, while the TWGCE bit in the TWAR is set.
    [highlight=orange:5ea0e0b877]3. A data byte has been received in Master Receiver or Slave Receiver mode.[/highlight:5ea0e0b877]
    By writing the TWEA bit to zero, the device can be virtually disconnected from the 2-wire Serial
    Bus temporarily. Address recognition can then be resumed by writing the TWEA bit to one
    again.
    Meiner Auffassung und meinem Erleben nach passiert folgendes (in vollkommener Übereinstimmung mit dem hervorgehobenen):
    Die TWI Unit empfängt ein Byte und quitiert den Empfang dann während des 9ten SCL Impulses vom Master entweder mit einem ACK oder einem No-ACK und dann kommt schon wieder das nächste Bit, weil der Master ja zurecht annimmt, dass der Sklave weiter machen will. Dazwischen kann man nix machen, das läuft AUTOMATISCH so ab!
    Was ich eigentlich bräuchte, wäre das der Sklave die SCL-Leitung gegen Masse zieht und somit dem Master mittteilt, dass der noch auf das ACK oder No-ACK warten muss...

    Nur wie mache ich das, wenn ich doch mit dem TWCR Register nur sagen kann, dass er nach dem Empfang eines Bytes ACK oder No-ACK machen soll, aber nicht, dass er die SCL-Leitung auf LOW ziehen soll?
    Ich sehe diese Möglichkeit nirgends!!


    Ich hab gestern und heut schon 2 Chips gegrillt, weil mein Aufbau mit dem JTAG ICE MK2 und dem Seriell-I²C-Übersetzer irgend wie Mist bauen - zusammen mit dem Notebook und dem Netzteil..
    Und das I²C-Terminal-Progg ist auch irgendwie instabil geworden seit neuestem..


    Morgen werd ich, um meine 2 verbliebenen m168 zu schonen, erstmal tiny2313 nehmen müssen und versuch dann mal nen reines I²C Prog zum testen, weil mein Code von oben bisher in nem etwas größeren Temperatursteuerungsproggie steckt..

    Ihr hört von mir..

    Grüße
    0tes_Gesetz


    PS: vielleicht sollte ich meine Daten lesen, sobald ich Case 1: erreicht hab, also die Adresse erkannt wurde, ACK gesendet wurde und schon die richtigen Daten im TWDR stehen, nur eben eine Runde zu früh (nach meiner Auffassung)..
    Hm.. das macht auf eine ganz verrückte Art sogar irgendwie einen verdrehten Sinn.. oder?

    Master sagt:
    SklaveXXX, ich beschreibe dich!

    SklaveXXX:
    oh, ich bin gemeint, Geht klar Master!

    Master schreibt Datenbyte:
    Blablabla..bla..

    SklaveXXX:
    alle Daten in den TWDR und Flagge setzen wenn fertig, Bing!

    Das Interrupt im SklavenXXX findet daraufhin in TWDR das erste Datenbyte und im Statusregister TWSR steht drin, dass sich der SklaveXXX erkannt hat und alles bestens ist (Auslöser des Interrupts war die Adresserkennung!!)

    Nun kann der Interrupt in TWCR die Flagge zurücksetzen & löst damit ein "Geht klar Master!" als Meldung an den Master aus, so dass dieser das nächste Datenbyte raufschiebt...

    Hm..
    Hoffentlich geht das so..
    Die Kausalität die dahintersteckt ist mir zwar irgendwie noch suspekt, aber eine andere Möglichkeit seh ich ehrlich gesagt nicht mehr..

    Man liest die Daten aus, obwohl man sie eigentlich noch gar nicht erwartet (das im Hinblick auf TWSR, welches ja den "eigentlich" vorherigen Status enthält).. das macht Kopfschmerzen, hoffentlich gewöhnt man sich daran..

  10. #10
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    22.05.2005
    Ort
    12°29´ O, 48°38´ N
    Beiträge
    2.731
    Zitat Zitat von 0tes_Gesetz
    Nur wie mache ich das, wenn ich doch mit dem TWCR Register nur sagen kann, dass er nach dem Empfang eines Bytes ACK oder No-ACK machen soll, aber nicht, dass er die SCL-Leitung auf LOW ziehen soll?
    Ich sehe diese Möglichkeit nirgends!!
    Lese mal ein paarmal durch, was bei der Beschreibung von TWINT steht, bei mir auf Seite 213 unten (beim M16.
    Nur immer diesen Absatz lesen, und erst zum lesen aufhören wenns Klick gemacht hat !!

    Evtl. mit meinem Beispiel, auf der von mir oben genannten Seite, vergleichen.


    Zum schluss hört sich das schon gut an was Du in kursiv geschrieben hast, jetzt nur noch in Software umsetzen.

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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

fchao-Sinus-Wechselrichter AliExpress