- fchao-Sinus-Wechselrichter AliExpress         
Seite 4 von 7 ErsteErste ... 23456 ... LetzteLetzte
Ergebnis 31 bis 40 von 66

Thema: Dicker Fehler in der RP6I2CmasterTWI.h der RP6Lib + Bugfix

  1. #31
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    Anzeige

    Praxistest und DIY Projekte
    Zitat Zitat von SlyD
    Der Schreibpointer wie auch der Lesepointer MUSS vom Master kontrolliert werden damit der Slave weis welches Register gemeint ist.
    Lötzinn :P
    Noch mal...
    Würde ich (bzw. Du damals) die Daten nicht sofort in die Slaveregister schreiben, wäre ein Ringbuffer natürlich das Mittel der Wahl... keine Frage, und dann stimmt natürlich alles was Du gesagt hast. Wir reden aber beim TWI immer noch über Registeraccess und NICHT über UART/ISO-OSI

    Zitat Zitat von SlyD
    Schau Dir erstmal an wie ein Ringbuffer funktioniert (google).
    Du das weis ich aber ich bleibe dabei das wir uns missverstehen Und ich hoffe die Aussage da klärt es nun. Ich gebe dir vollkommen recht wenn man keine Register sondern eine Pipe verwenden würde... aber schau dir vielleicht einfach den geänderten Code mal an... ich ändere nichts am Prinzip was Du mal vorgegeben hast, ich mache ihn nur gängig. Alle Daten landen sofort im RAM, und zwar in den Slave Registern. Ein Ringbuffer ist unnötig und hilft nicht, das Receiverpüroblem zu lösen. Es wäre nur weitere RAM verbraucht.. für nix. Ob ich ein N-Dimensionales Array als Ringbuffer verwende oder die Daten direkt ins RAM auf die Registerplätze schreibe, ist Pott wie Deckel. Für die ISR ebenso wie für verlorene Zeichen.

    I2CTWI_writeRegisters[current_register++] = TWDR;

    sagt doch alles, oder?
    Mit der Aussage bezüglich Read/Write Register oben lag ich übrigends daneben wie ich jetzt sehe... tut aber nichts zur Sache.

    LG RolfD

  2. #32
    Erfahrener Benutzer Roboter Genie Avatar von SlyD
    Registriert seit
    27.11.2003
    Ort
    Paderborn
    Alter
    39
    Beiträge
    1.516
    OK gut - wie ich schon geschrieben hatte hattest du glaube ich deinen Beitrag da oben auch nochmal editiert das hatte ich nicht gesehen - oder meine Augen lassen nach

    Dennoch: Der Ringbuffer ist notwendig wenn Du tatsächlich wie in dem Testcode von Dirk nahezu komplett ohne Pause Daten in Richtung Slave ballerst
    Sonst kann da natürlich mal was überschrieben werden bevor der Slave überhaupt mitbekommt das sich da was geändert hatte (läuft ja asynchron zum Hauptprogramm).

    Mit der bisherigen Methode ist eine kleine Pause nach jeder Übertragung notwendig sonst kann das in die Hose gehen auch wenn der Rest vom Code 100% korrekt arbeitet.
    Man kann in der Zeit natürlich irgendwas anderes machen - auch auf dem I2C Bus aber mit anderen Slaves.

    So nun aber genug geschrieben für heute

    MfG,
    SlyD

  3. #33
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    Zitat Zitat von SlyD
    OK gut - wie ich schon geschrieben hatte hattest du glaube ich deinen Beitrag da oben auch nochmal editiert das hatte ich nicht gesehen - oder meine Augen lassen nach
    *grins ... sollich dir meine Lesebrille leihen

    Zitat Zitat von SlyD
    Dennoch: Der Ringbuffer ist notwendig wenn Du tatsächlich wie in dem Testcode von Dirk nahezu komplett ohne Pause Daten in Richtung Slave ballerst

    Sonst kann da natürlich mal was überschrieben werden bevor der Slave überhaupt mitbekommt das sich da was geändert hatte (läuft ja asynchron zum Hauptprogramm).
    Genau das ist das hüpfende Komma.... und das wäre zu prüfen. Wenn es so ist... ok. Wenn es doch echte verlorene Zeichen sind, gehts weiter mit der Fehlersuche... Aber der Hinweis ist wichtig, man muss dem Slave natürlich Zeit lassen um Daten zu verarbeiten... man kann den nicht mit Daten bombardieren und erwarten das er immer sofort reagiert.

    (@Fabian, da ist auch dein Delay mit 50 ms aus dem Beispiel zwischen schreiben der LEDs und lesen von Zustand zu kurz gesetzt - das TWI ist einfach zu schnell dafür. Du stresst hier die Base und nicht das TWI. Für die Base würde sich ein Busy Flag im Statusregister anbieten was anzeigt ob die Base schon aktiv war.. das der Master dann abfragt und erst liest wenn das Bit getoggelt ist. Macht mit mehreren Mastern z.B. bei eienr M128 aber auch Probleme, ist als wenn, dann nur ein Notpflaster. Ihr müsst euch glaub ich erst an das schnellere TWI gewöhnen Übrigends kann man das was ich der M32 beibringe auch mit der M128 machen... "kann das nicht" gibts nicht! Ich hab ne M128 hier liegen.. also irgendwann.... )

    Das kann so wirklich nur eine Pipe mit Ringbuffer. Ich halte es für realistisch, sich auf 3 bis 5 Updates/sec eines kompletten Registersatzes zu beschränken, aber die umgebaute Lib zeigt mit Dirks Programm zumindest was nun auf dem TWI möglich wäre. Da ist 1% Fehlerquote ohne Terminalausgabe schon ganz gut. Vielleicht kann man da tatsächlich einen Ringbuffer einbauen aber zuerst muss alles andere laufen. Ein Ringbuffer für Registeraccess ist mässig sinnvoll (man müsste ein Ringbuffer in der Breite der Register bauen, also 16 byte x z.B. 8 Byte Tiefe, was min. 128 Byte fürs Schreibregister an kostbarem RAM verballert - und auch 8 byte Buffer kriegt man bei 100Kbit/sec schnell platt geschrieben.) und direkte Kommunikation via Pipe zwischen Prozessoren eher ne Aufgabe für linux oder so . Aber vielleicht findet sich mal jemand der sowas umsetzt wenn die Grundlagen funktionieren.
    Die generic Adresse 00 würde sich für so Spielchen anbieten. Eine Pipe wäre dann sozusagen ein Broadcast und das Protokoll muss sicherstellen das der richtige Prozessor sich angesprochen fühlt. Von mir aus dann auch mit crc und so Schnickschnack Dann noch 8 M32er auf die Base und man hat den kleinsten Clusterbot der Welt

    Zitat Zitat von SlyD
    So nun aber genug geschrieben für heute
    Dir ein schönen Feierabend Mein RP6 ist aufgeladen, kann weiter gehen mit testen
    LG Rolf

  4. #34
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    @Dirk, ich kann dich beruhigen.. bzw. uns
    Ich habe dein Testprogramm nun so umgebaut, das es exakt 1000 Pakete sendet... und auf der Base nachgeschaut wieviel IRQs reinkommen bzw. wie oft die ISR aufgerufen wird. Bei 1000 sind es exakt 6000 Aufrufe - je 4 für 4 Datenbytes und 1 für start, 1 für stop ... macht 6000. nicht ein mal mehr oder weniger. Die Sorge, das der Prozessor also was nicht mitbekommt war zum Glück unbegründet, die Errors haben nur mit dem Laufzeitverhalten der ansyncronen Datenübertragung zu tun. Das relativiert auch Aussagen zum Slavemode oben... er ist wohl stabil. Allerdings gibts doch einiges zu beachten was das Timing zwischen Base und M32 angeht - wie unsere Diskussion heute zeigte. Ich bin froh das sich das so aufgelöst hat. Aber weiter gehts, die Kuh ist noch nicht vom Eis.
    LG Rolf

    Das noch als Anhang:
    Code:
    //     if (I2CTWI_writeRegisters[0] && !I2CTWI_writeBusy) {
    //I2CTWI_writeBusy ist eine Statusvariable der ISR die so nicht mehr nötig ist
    //und unterstützt wird. Statt dessen bitte wie im Master I2CTWI_isBusy() nutzen.
    //ret=0 isr frei, 1= isr belegt
           if (I2CTWI_writeRegisters[0] && !I2CTWI_isBusy()) {
    EDIT:
    Nach reiflicher Überlegung und überschlafen des Problems mit Dirks Programm überlege ich nun, ob ich das verhalten der TWI dahingehend ändern soll, das nach einem Schreibvorgang auf den Slave das TWI NACKs senden soll bis der Slavecode quasi signalisiert das die Daten verarbeitet wurden. Das Entspricht auch dem Verhalten von EEPROMS und ähnlichen Bausteinen und würde das überschreiben unverarbeiteter Register im Slave nachhaltig verhindern. Jedoch muss der Slave dann zusätzlich über ein bitset eines Flags das Empfangen/Verarbeiten quitieren. Ggf muss auch der Mastercode verändert werden, so das er ein retransmit versucht bis keine NACKs mehr kommen (was ich aber komplett in der Lib regeln kann) Das bedeutet natürlich weitere kleine Änderungen an vorhandenen Programmen im Slavemode, macht aber die Synconisation zwischen Master und Slave absolut sicher, laufzeitunkritisch und conform zu anderen Bauteilen. Es würde aber auch die Prüfung im Slave erleichtern, ob er was zu tun hat - er braucht nur eben dieses Flag zu befragen.
    Meinungen?

    EDIT: Je länger ich drüber nachdenke, um so mehr frag ich mich warum ich das noch nicht umgesetzt hab...

    EDIT: Oh Ohhh.... @Fabian, deine 2400 Fehler erklären sich grade noch aus einem Punkt, der mir beim mergen der Dateien unterlaufen ist. Es ist nicht nur dein timing... Ich denke, heute Abend gibts ne neue Beta Version zum testen für alle. Dann aber schon mit der Funktion aus edit 1. Dazu sag ich aber dann noch mehr.

    EDIT: hat jemand vielleicht ne schließende Klammer übrig, ich hab eine in der ISR verbummelt *seufz
    Noch'n EDIT: ich hab sie... www.prettyprinter.de sei dank

    Und der letzte EDIT für heute....
    Leider wird das wohl nichts mit der Beta für heute Abend. Das System reagiert auf NACKs nicht richtig (harmlos ausgedrückt...) , weder in der ISR noch im Mastercode (Fehlerbehandlung, Retransmit usw.) Das wird dauern bis ich das laufen hab. Sorry.

  5. #35
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    21.04.2009
    Beiträge
    523
    Mach dir keinen Stress
    Also das Verhalten was ich erwarten würde. bzw. am Besten finde, sieht so aus:
    Ich kann vom Master einen Slave so schnell ich will mit Daten beschießen ohne dass irgendwas schief geht.
    Das dann natürlich irgendwo gewartet werden muss versteht sich von selbst.
    Das Warten sollte allerdings die Lib übernehmen und außerdem sollte das Warten so kurz wie möglich sein.

    Das entspricht ja quasi dem, was du in deinem ersten Edit geschrieben hast.
    Wenn du das so hinbekommst, dann wäre die Lib schneller und stabiler als die alte.
    Und das sie Multimaster kann wäre dann der ultimative Bonus

  6. #36
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    Irgendwie muss die I2C Hardware der Mega32 CPUs ne Macke haben...
    Ich zeig euch mal nen Protokoll, vielleicht hat ja einer eine Idee dazu:
    Es geht um den Buserror da... wir sind Receiver Slave.

    die Syntax des Protokls ist ca.
    Datenregister x Statusregister x STATUSREGISTERALSTEXT meineANTWORT (Grund) Flags (bit2=SlaveBusy bit1=IsrBusy bit0=ohne Bedeutung)
    Die Flags spielen eigentlich keine Rolle, erklären aber warum die ISR nackt (was auch vom Prinzip her so richtig ist). Die Datenverarbeitung ist asyncron, im Prinzip nackt die isr bis das Programm SlaveBusy auf 0 setzt.
    Start der Datenübertragung

    got DATA a and STATUS 60 mean / SRX_ADR_ACK ACK (Start) Flags 1
    got DATA 0 and STATUS 80 mean <- SRX_ADR|data)_ACK -> ACK (Adress) Flags 11
    got DATA 63 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 11
    got DATA 1 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 111
    got DATA 0 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 111
    got DATA a and STATUS 60 mean / SRX_STOP_RESTART (eot) Flags 101

    Datenübertragung abgeschlossen, nächstes Datagram (wird abgebrochen)

    got DATA a and STATUS 60 mean / SRX_ADR_ACK ACK (Start) Flags 101
    got DATA 0 and STATUS 80 mean / SRX_(ADR|DATA)_ACK NACK (Slave busy) Flags 111

    Die isr nackt weil der Client die Daten noch nicht bearbeitet hat
    Clent sagt aber nun "Received: 1"

    got DATA 63 and STATUS 88 mean / SRX_ADR_DATA_NACK ACK (eof) Flags 1

    Wir antworten noch auf das Nack, der Versuch ist abgebrochen. Der Master versucht ein Neustart. Wir sahen bis hier ein sauber ünbertragenes Byte und einen abgebrochenen Versuch, beides gut abgewickelt.
    Also weiter...

    got DATA a and STATUS 60 mean / SRX_ADR_ACK ACK (Start) Flags 1
    got DATA 0 and STATUS 80 mean <- SRX_ADR|data)_ACK -> ACK (Adress) Flags 11
    got DATA 63 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 11
    got DATA 2 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 111
    got DATA 0 and STATUS 80 mean <- SRX_(adr|DATA)_ACK -> ACK (Data) Flags 111
    got DATA a and STATUS 60 mean / SRX_STOP_RESTART (eot) Flags 101

    Wieder ein Datagram übertragen...

    got DATA a and STATUS 60 mean / SRX_ADR_ACK ACK (Start) Flags 101
    got DATA 0 and STATUS 80 mean / SRX_(ADR|DATA)_ACK NACK (Slave busy) Flags 111

    isr nackt weil Daten unbearbeitet
    Clent sagt aber nun Received: 2

    erwartet wird ein SRX_ADR_DATA_NACK vom Master wie in den ersten beiden Durchläufen damit die ISR ein ACK senden kann, bekommen tue ich das:

    got DATA 1 and STATUS 0 mean BUSERROR Flags 1

    In der Folge verschluckt sich das System weil der Master den Buserror nicht mitbekommen hat, ist hier aber nicht mehr relevant...

    Warum bekomme ich erst im 3 Datensatz nach immerhin 6 übertragenen Byte Daten einen Buserror auf einen Ablauf, der genau so vorher 2 mal geklappt hat? Der Master macht in beiden duchläufen exakt das gleiche, der Slave auch. Was ist am 3. bzw. ende vom 2 anders? Andere Master sind nicht am Bus. Das Ganze bei langsamen 100khz.
    Achja, das Ganze ist aus Dirks Programm, senden von 3 Byte auf Register 0,1 und 2

    Die Vorgeschriebene Reaktion auf SRX_ADR_DATA_NACK (0x8 laut Datenblatt ist [Switched to the not addressed Slave mode; own SLA will be recognized; GCA will be recognized if TWGCE = “1”] -> (1<<TWINT)|(1<<TWEA) ... also ACK

    Buserrors findet man im allgemeinen nur bei ungültigen Start/Stop Folgen, es kann sein das der Master das letzte Datenbyte mit einem NACK senden muss als Vorbereitung auf Datenende und Stop, das muss ich noch rausfinden aber es erklärt nicht warum es mal geht und mal nicht!

    Ideen, Ratschläge,Meinungen?

    PS: SlyD hat es sich übrigends einfach gemacht ... er ACKt einfach alles was reinkommt *grins

    LG Rolf


    EDIT:
    So... das Problem ist behoben... und in Dirks Programm gehen keine Daten mehr flöten... keine Buserrors... und das Ganze mit ca. 4000 Zeichen/Sek. UND Textausgabe... Leider bleibt ab und zu der Transport komplett hängen, wo ich noch nicht raus hab warum. Vielleicht hab ich mir irgendwo nen deadlock gebaut. Und ich hab jetzt noch nicht alle anderen Funktionen geprüft. Und noch was... wenn ich gewusst hätte wieviel besch.... schlechte Doku es zu dem Thema gibt, hätte ich NIEMALSNICHT damit angefangen... aber es wird langsam.

  7. #37
    Erfahrener Benutzer Roboter Genie Avatar von SlyD
    Registriert seit
    27.11.2003
    Ort
    Paderborn
    Alter
    39
    Beiträge
    1.516
    So... das Problem ist behoben... und in Dirks Programm gehen
    keine Daten mehr flöten... keine Buserrors... und das Ganze mit ca. 4000 Zeichen/Sek. UND Textausgabe...


    Tipp: In die ISR könntest Du zumindest LED Ausgaben reinmachen um zu schauen an welcher Stelle er sich aufhängt.


    schlechte Doku es zu dem Thema gibt
    Sei froh DAS es überhaupt Doku gibt :P
    Ich kenne Bauteile wo nur die RegisterNAMEN im Datenblatt stehen und nix weiter erläutert wird was die genau machen - und der Hersteller ist da auch keine große Hilfe


    MfG,
    SlyD

  8. #38
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    @SlyD oh.. auch nicht schlecht... da bin ich mit dem Prozessordatenblatt und den vielen halb implementierten Sources die im Web rumgeistern (incl. Atmels Sourcecode) ja noch gut dran Im Web zu googlen lohnt sich für mich nicht mehr.. da finde ich inzwischen meine eigenen Beiträge hier Interssanter Weise finden sich die besten Infos immer noch hier im RN-Wissen.

    Hallo,
    damit euch nicht langweilig wird, hab ich für die Betatester was.
    Die Geschichte ist noch nicht stabil aber zumindest sollten sich Master und Slave unterhalten können. (bei mir tuen sie das )

    Zunächst das modifizierte Testprogramm von Dirk:
    Die Base/Slave, ich poste nur die main

    Code:
    int main(void)
    {
       initRobotBase();
       setLEDs(0b111111);
       mSleep(500);      
       setLEDs(0b000000);
       I2CTWI_initSlave(RP6BASE_I2C_SLAVE_ADR);
    
       while (true)
       {   
    /*		asks TWI for waiting Jobs, textblock may be a "task_slave" in rp6 c notation?
    **
    */		if (I2CTWI_needAction()) {
    /*
    **		yessssss ... doit!
    */
    		// get data from slave receiver mode register
            controlbyte = I2CTWI_writeRegisters[0];      // Read control byte
            I2CTWI_writeRegisters[0] = 0;            //  and reset it (!!!)
            lowbyte = I2CTWI_writeRegisters[1];         // Read lowbyte
            highbyte = I2CTWI_writeRegisters[2];      // Read highbyte
    
    		// copy data to slave sender mode register
    		I2CTWI_readableRegisters[0] = controlbyte;		//copy controlbyte
    		I2CTWI_readableRegisters[1] = lowbyte;         // copy lowbyte 
            I2CTWI_readableRegisters[2] = highbyte;      // copy highbyte		 
    		 
    //	this is controlled by I2CTWI_needAction()
    //        if (controlbyte == CMD_SHOW_DATA) { //
                cnt = ((highbyte << 8) | lowbyte);      // Restore 16-bit value
    #ifdef TEXT_OUTPUT
                writeString_P("Received: ");         //  and show it
                writeInteger(cnt, DEC);
    #endif
                if (!cnt) error_cnt = 0;            // Reset error counter
                else error_cnt++;                  // Error counter + 1
                if (cnt != error_cnt) {
                   writeString_P(" ERROR!\n");
                   error_cnt = cnt;
                }
    #ifdef TEXT_OUTPUT
                else writeChar('\n');
    #endif
                controlbyte = 0;
    //         }
    
    /*		signals Job as "done" and free the receiver for next Data
    **
    */		I2CTWI_doneAction();
    /*
    **		done!
    */
          }
    /*
    ** blink like fireworks, attract girls by danci'n circles or lying around an drink ... gear oil
    */
       }
       return 0;
    }
    Dann der Master auf der M32

    Code:
    int main(void)
    {
       initRP6Control();
    
       initLCD();
    
       I2CTWI_initSlave(12); // Initialize the TWI Module for Master operation
                         // with 100kHz SCL Frequency
       
       // Register the event handlers:
       I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);
    
       setLEDs(0b1111);
       mSleep(500);      
       setLEDs(0b0000);
       
       while(true) 
       {
            if (!I2CTWI_isBusy()) {
    			cnt++;                           // TEST: COUNTER!!!
    			if (cnt > 255) cnt = 0;
    			buffer[0] = 0;
    			buffer[1] = CMD_SHOW_DATA;
    			buffer[2] = cnt;
    			buffer[3] = (cnt >> 8);
    			I2CTWI_transmitBytes(RP6BASE_I2C_SLAVE_ADR, buffer, 4);
    			
    			mSleep(1000); //the slave works...
    			
    			buffer[0] = 0; //reset buffer
    			buffer[1] = 0;
    			buffer[2] = 0;
    			buffer[3] = 0;
    
    			I2CTWI_readRegisters(RP6BASE_I2C_SLAVE_ADR, 0, buffer, 4);
    			
    			if (cnt == ((buffer[2] << 8) | buffer[1])) {
    #ifdef TEXT_OUTPUT
    				setCursorPosLCD(0, 0);
    				writeStringLCD_P("I2C has moved:");      // What was sent?
    				setCursorPosLCD(1, 0);
    				writeIntegerLCD(cnt, DEC);
    #endif
    			} else {
    				setCursorPosLCD(0, 0);
    				writeStringLCD_P("Error!");      // What was sent?
    			}
    //if (cnt==3) while(true); //countertrap
    		}
    	}
       return 0;
    }
    Es hat sich in soweit etwas verändert, das der Master die Daten auf den Slave schreibt, dieser kopiert die Daten vom Schreib- ins Leseregister und prüft, eine Zeit lang später (hier 1 Sek. weil ich am debuggen bin) liest der Master die Daten zurück um sie mit dem Original zu vergleichen. Sinnvoll wäre hier ein Statusbyte einzuplanen das der Master abfragen kann. Dafür müsste der Master aber ins Leseregister schreiben da der slave nicht mitbekommt ob der Master liest. Ließe sich aber irgendwie anders einbauen. Ich vermute aber das man in Dirks Programm locker auf 1ms runter gehen kann, der Slave copiert ja nur bissel in der Gegend rum bis die Daten bereit sind. Hier wie in der Schreibfunktion zu nacken macht aber keinen Sinn da es den Master lesend blockiert. Das ist mit einem Statusbyte besser gelöst

    Es sind also alle 4 Modi mit Slave Receive/Transmit und Master Receive/Transmit beteiligt. Die ISR sperrt nach einem schreibenden Durchgang auf den Slave weitere Schreibversuche durch NACKen. Erst wenn der Slave fertig ist schaltet er die ISR frei. I2CTWI_needAction() und insbesondere I2CTWI_doneAction() erledigen das.

    Eine Abfrage von Statusbytes in den Registern erledigt sich damit, allerdings muss damit jede Schreibaktion vom Slave quitiert werden sonst wartet sich der Master einen Wolf.

    Die aktuelle twi_target.h sieht bei mir so aus (hier von der Base):
    Code:
    /**/
    
    #ifndef TARGET_H //Include once
    #define TARGET_H
    
    
    /* this define Hardware to selecting the right includes
    ** use one of them, never both
    */
    #define M32
    //#define BASE
    
    /* this define TWI Modus to stip obsolete Slave code in Mastermode
    ** use one of them, never both
    */
    //#define TWIMASTER
    #define TWISLAVE
    
    /* 
    ** use LOWLEVEL I2C Functions without interupts too
    */
    //#define TWILOW
    
    /* this TWI define Speedsetup at 100 or 400 KHz Standart
    ** use one of them
    */
    #define TWISPEED 100
    
    /* 
    ** use Generic calls, not supported yet 
    */
    //#define GENADR
    
    
    /* 
    ** if set, Base can use I2CLCD like LCD on M32
    */
    //#define I2C_LCD
    
    
    
    
    /* 
    ** internal use, hide warnings
    */
    #define UNUSED(x) ((void)(x)) //help optimizing
    #define DEBUG
    
    #include "RP6I2CTWI.h"
    
    #ifdef BASE
    	#include <RP6RobotBase.h>
    	#ifdef DEBUG
    		#include <RP6RobotBaseLib.h>
    	#endif
    	#ifdef I2C_LCD
    		#include <RP6RobotBaseLib.h>
    		#include <lcd.h>
    		#define writeLCDCommand writeI2CLCDCommand
    		#define initLCD initI2CLCD
    		#define clearLCD clearI2CLCD
    		#define clearPosLCD clearPosI2CLCD
    		#define writeCharLCD writeCharI2CLCD
    		#define writeStringLCD_P writeStringI2CLCD_P
    		#define writeStringLengthLCD writeStringLengthI2CLCD
    		#define writeStringLCD writeStringI2CLCD
    		#define writeNStringLCD_P writeNStringI2CLCD_P
    		#define _showScreenLCD_P _showScreenI2CLCD_P
    		#define writeIntegerLCD writeIntegerI2CLCD
    		#define writeIntegerLengthLCD writeIntegerLengthI2CLCD
    		#define setCursorPosLCD setCursorPosI2CLCD
    		#define setlightLCD setlightI2CLCD
    	#endif
    #else
    #ifdef M32
    	#include <RP6Control.h>
    	#ifdef DEBUG
    		#include <RP6ControlLib.h>
    	#endif
    	#ifdef I2C_LCD
    		#include <RP6ControlLib.h>
    		#include <lcd.h>	
    	#endif
    #endif
    #endif
    #endif
    Ihr werdet nicht alles brauchen, allerdings sind die Optionen im oberen Bereich schon interessant da sie ggf. Code einsparen helfen. Achtung, DEBUG ist Aktiv... unten stricke ich mir u.a. das i2c-lcd für die Base als normals M32 Display zurecht.... macht sich gut wenn man die gleichen Programme auf der Base UND der M32 testen will.

    In der TWI hat sich viel getan, u.a. habe ich einige Variablen abgeschaltet, die versuchten die ISR zu monitoren. Sowas z.B.

    /* don't use, obsolte, try I2CTWI_isBusy() instead
    volatile uint8_t I2CTWI_genCallCMD;
    volatile uint8_t I2CTWI_dataWasRead = 1;
    volatile uint8_t I2CTWI_dataReadFromReg = 1;
    volatile uint8_t I2CTWI_readBusy = 0;
    volatile uint8_t I2CTWI_writeBusy = 0;
    */

    Die Funktionalität (war eigentlich keine) ist mit den Action Befehlen und isBusy besser gelöst, der C Preprozessor hilft hier beim anpassen älterer Projekte ungemein ohne das man viel umschreiben muss. Allerdings funktioniert das jetzt so nicht mehr so einfach mit dem Slave Programm für die Base. Aber zum testen reicht Dirks Programm und Fabian wird den Slave sicher anpassen können. Sonst mach ich das irgendwann. Ich sehe jedenfalls nicht ein, Code zu pflegen der obsolet ist, nur weil er da ist. So viel Ram und Flash hat der RP6 auch nicht...
    Evtl. mache ich das NACKen nach schreiben auf den Slave optional, derzeit kann man sich gut mit dem bedingungslosen Befehl I2CTWI_doneAction(); in der äusseren While Loop helfen wenn der Slave möglichst nicht nacken soll - allerdings werden dann halt die Register überschrieben. Die gencall Geschichte ist z.Z. komplett abgeschaltet, da konnte bisher eh nur ein Byte mit empfangen werden. Da hab ich noch was in der Todo stehen für irgendwann mal...

    Das ganze System hat immer noch viele Macken, es ist noch nicht auf Multimaster umgestellt aber man kann aus dem Slavemode herraus zumindest Masterfunktionen ansprechen. Ein paar Macken sind leider systembedingt - z.B. werden zusammenhängende Befehlsketten wie Setzen einer Registeradresse und anschließendes Register lesen in 2 Zyklen ausgeführt was nicht nötig wäre, was aber z.B. dazu führt, das die ISR für kurze Zeiten "frei" ist obwohl sie eigentlich mitten in einer Transaktion steckt. Ein folgender Befehl kann hier die noch arbeitende ISR stören. Das scheint auch für Buserrors zu sorgen. Sowas ist unschön! Ob ich das beheben kann, weis ich noch nicht. Es stört mich auch, das in einer ansich Interruotgesteuerten Umgebung blockende Befehle stecken, das mindert den Sinn einer ISR doch gewaltig. Vermutlich stimmen auch einige Reaktionen auf die TWI-State Engine noch nicht, was wohl auch zu Buserrors führt, da bin ich aber dran... alles in allem also noch sehr Beta. Aber wieder mal ein Stück weiter hoffe ich.

    Mein nächstes Ziel ist zum einen die Geschichte stabiler zu machen, aus irgendeinem Grund bleibt der Transport hängen, zum anderen möchte ich die Programme von Dirk zusammen legen, zu einem "Masterslave" so das sich Master und Slave des jeweiligen Boards abwechseln und gegenseitig Daten zuwerfen und prüfen. Also bidirektionaler/intermitierender Master/Slave Betrieb auf Base und M32.
    Mir erschließt sich noch nicht, welch tieferer Sinn sich dahinter verbirgt, das man z.B. mit Readregisters nur Speicherplätze ab 1 im Buffer lesen, aber mit anderen Funktionen ab 0 beschreiben kann. Sowas werde ich wohl auch ändern wenns keine großen Einsprüche gibt.

    Benutzt man die Geschichte nur im Mastermode mit nur einem Prozessor (per twi_target einstellen), kann man den Slavecode komplett einsparen, benutzt man auch den Slave, hat man beide Modi zur Auswahl. Die default Werte für
    #define I2CTWI_SLAVE_WRITE_REGISTERS 16
    #define I2CTWI_SLAVE_READ_REGISTERS 48
    sind etwas zu hoch gewählt, hier würden im normalen Slaveprogramm auch 8/32 reichen wenn man ein paar Byte sparen will. Ich habs aber mal so gelassen.

    EDIT:
    Und wieder eine kleine Änderung in der RP6I2CTWI.c
    Um die Buffer gehören Präprozessorabfragen zum TWISLAVE, keine funktionelle Änderung aber es spart Platz im Mastermode. In der nächsten Fassung ist das mit drin. In der .h war es schon eingetragen.

    #ifdef TWISLAVE
    uint8_t I2CTWI_readableRegisters[I2CTWI_SLAVE_READ_REGISTERS];
    volatile uint8_t I2CTWI_writeRegisters[I2CTWI_SLAVE_WRITE_REGISTERS];
    #endif

    Dann noch was zum NACKen und Buffergrenzen überfahren, es wäre z.Z. wohl denkbar, das der Master hinter die Buffergrenze liest was der Slave nacken müsste worauf hin der Master abbrechen soll. Ob das klappt weis ich nicht, muss ich noch testen. Ich überlege sowieso, alternativ 1 R+W oder 2 R/W Registersets per twi_target.h anzubieten, das macht den Slave universeller. Und demnächst wirds zusätzlich ein Satz ISR-lose Funktionen geben, ähnlich der von Peter Fleury oder der AVR-LIBC aber angepasst an die Abläufe und Vorgaben der aktuellen TWI Steuerung.

    EDIT: Hm.. ich glaube da stimmt was noch nicht... der Master hängt sich auf laut LEDs.. aber morgen wirds wieder ne Beta Version geben denk ich mal. NACK als Option ist drin, die Lowlevelfunktionen sind schon drin, jede Menge Code cleanup über #ifdef...

    LG Rolf
    Angehängte Dateien Angehängte Dateien

  9. #39
    Erfahrener Benutzer Robotik Einstein Avatar von Dirk
    Registriert seit
    30.04.2004
    Ort
    NRW
    Beiträge
    3.803
    @Rolf:
    Du bleibst ja energisch am Ball. Komplement! =D>

    Kurze Frage als Beta-Tester:
    Warum wird der M32 Master mit I2CTWI_initSlave(12) initialisiert?
    Muss ich ihn in der twi_target.h auch als Slave (#define TWISLAVE) definieren, weil als Master das I2CTWI_initSlave(12) zum Fehler führt?

    Kurze Anregung als "normaler User":
    Du bist ja da an einem dynamischen Prozeß dran, d.h. versuchst, in mehreren Schritten möglichst gute Lösungen zu finden. Dabei verändert sich auch die "Makrosprache" und der Funktionsumfang, der dem RP6 zur Nutzung des I2C-Bus mitgegeben wurde.
    Wenn die entstehende Lib (ich bin da guter Hoffnung!) problemlos für alle zu nutzen sein soll, gibt es bei der Entwicklung eines neuen TWI-"Treibers" aus meiner Sicht auf der Makroebene nur 3 Möglichkeiten:
    1. Man nutzt NUR die vorgegebenen Befehle und Makros, so dass vorhandene Programme mit der neuen Version kompiliert werden können.
    2. Man ergänzt alle vorgegebenen Befehle und Makros durch neue Funktionen und Makros. Damit ist ebenfalls Abwärtskompatibilität möglich, es können dann aber neue Funktionalitäten zusätzlich genutzt werden.
    3. Man verzichtet auf Kompatibilität und beschreibt einen neuen "Befehlssatz" für die TWI-Funktion.
    Mir persönlich liegt die Option 2. am Herzen, weil ich faul bin, und meine Programme nicht ändern möchte. Trotzdem würde ich gern von "Fortschritten" durch eine neue Lib profitieren (egoistisch wie ich bin ...).

    Also: Bitte nicht als Kritik, sondern nur als Anregung verstehen.

    Ich teste weiter ...

    Gruß Dirk

  10. #40
    Erfahrener Benutzer Roboter-Spezialist Avatar von RolfD
    Registriert seit
    07.02.2011
    Beiträge
    414
    Zitat Zitat von Dirk
    @Rolf:
    Du bleibst ja energisch am Ball. Komplement! =D>
    Naja ich will das es funktioniert... ich kauf mir keine Zusatzboards wenn die am TWI nur so vor sich hin stottern... alles Eigennutz

    Zitat Zitat von Dirk
    Kurze Frage als Beta-Tester:
    Warum wird der M32 Master mit I2CTWI_initSlave(12) initialisiert?
    Muss ich ihn in der twi_target.h auch als Slave (#define TWISLAVE) definieren, weil als Master das I2CTWI_initSlave(12) zum Fehler führt?
    Nein.. ja.. das auch.. aber es hat andere Gründe. Technisch gesehen gibts zwischen der Master und Slave Init ganze 3 Unterschiede. Der Master kann ohne eigene Adresse leben funktioniert aber auch mit dieser, der Slave ohne Geschwindigkeitsangabe und funktioniert mit dieser und letztlich macht der Master im Init ein NACK und der Slave ein ACK.
    Dazu braucht es keine 2 separaten Funktionen, es reicht wenn diese Daten da sind, zur Not eben Defaultwerte. Daher habe ich in der aktuellen Codefassung nicht mal mehr ein Unterschied sondern gleich alles in eine Funktion gesetzt.
    Code:
    void I2CTWI_init(uint8_t dummy)
    {
    	UNUSED(dummy); // reserved, set up speed and OWN address in twi_target.h
    
    	TWI_operation = I2CTWI_NO_OPERATION; //Setup defaults
    	bitset(TWI_statusReg,STR_lastTransOK);
    	bitclr(TWI_statusReg,STR_needAction); // we start clean
     	bitclr(TWI_statusReg,STR_isr); // don't talk if isr is busy
    	bitset(TWI_statusReg,STR_NACKonAction);//we NACK, Master must wait to rewrite dirty Regs
    	cli();
    #ifdef TWISLAVE
    	TWAR = TWIADDR;                  // Set own TWI slave address.
    #endif
    	TWDR = 0xFF;                     // Default content = SDA released.
    	TWSR = 0x00;                    // DO NOT USE PRESCALER! Otherwise you need to mask the
    	TWBR = I2CTWI_SPEED(TWISPEED);		// default Speed @ KHz in master mode, 100 and 400 are well known
    #ifdef TWISLAVE
    	TWACK();
    #else
    	TWNACK();
    #endif
    	sei();
    }
    So schaut die Init in der kommenden Version aus...

    Wer möchte, kann sich dann ein:
    #define I2CTWI_initMaster I2CTWI_init
    und
    #define I2CTWI_initSlave I2CTWI_init
    in die twi_target setzen und man muss nicht mal groß was an alten Programmen umschreiben. Ich glaube das setz ich sogar so ins .h File.
    Weitere Krücken wären ebenfalls denkbar. Zu irgendwas muss so'n Compiler ja taugen...
    #define I2CTWI_delay nop // microwaiting
    der is auch schön

    Noch mal zum Verständnis, es gibt keinen wirklichen Unterschied zwischen Master und Slave AUSSER das der Slave Code enthält, den der Master allein so nicht braucht und der Master Code enthält, den der Slave allein so nicht braucht. Das würde immer zu einer Codegröße von Master+Slave führen und man müsste sich um Code kümmern den man vielleicht nie nutzt. Das versuche ich mit der twi_target.h etwas einzugrenzen wenn man z.B. den Slave nicht braucht weil man nur ein RP6 ohne Zusatz und vielleicht ein SRF-Sensor hat. Mit der Lib wird man aber auch von 2 CPUs gemeinsam auf Targets wie i2c-LCDs zugreifen können und da müssen dann beide Programmteile zusammen wirken wenn die Prozessoren noch untereinander quatschen sollen. Ich betone "zusammen" ... also nicht Master oder Slave. Der alleinige Mastermode ist quasi nur eine reine Ersparnis um ein paar codebytes + etwas ram für Register aber oft sinnvoll wenn man eben kein Slave braucht. Es ist aber nicht als sich "gegenseitig ausschließender Modus" zu verstehen... Hier in der Lib ist vorgesehen: Slave+Master und Master sowie eine Lowlevel Master Geschichte die aber davon eigentlich unbetroffen und z.Z. noch unveröffentlicht ist.

    Das ist das Gleiche wie bei der Multimastergeschichte.... jede ATMEL-cpu mit I2C Bus hat eine eingebaute Busarbitierung und daher sind sie alle MM-Fähig. Allerdings muss die Software die Situation erkennen - tut sie es nicht, ist sie eben nicht MM-fähig... die Hardware.. ist es aber, und die sorgt z.B. auch dafür wenn sich die Software nicht kümmert, das es auf dem Bus eigentlich nicht zu Schäden/Datenverlust kommt - im Gegensatz zu selbstgeschriebenen Softwarelösungen an irgendwelchen Portpins. Wenn man aber jegliches Handshake abschaltet, ist klar das Daten verloren gehen. Es käme auch keiner auf die Idee ein UART mit wilden Baudraten zu betreiben bzw. da weiss jeder das sowas in die Buxe geht. Wir nutzen mit dem alten Treiber quasi nur max. 30% dessen was möglich wäre - und selbst das nur wackelig. Das ist der Punkt. Was ich hier mache hat absolut nix mit "Magic" zu tun... das TWI in der MEGA32 ist mit 400KHz stabil vorgesehen, es gibt nichts was daran hindert das auch zu nutzen... ausser suboptimale Software. Das versuch ich mit meinen bescheidenen Mitteln zu beheben. Wirklich ärgerlich ist nur, das selbst die Codebeispiele von ATMEL selbst unvollständig sind. Scheinbar will man bei ATMEL die Lust aufs unbekannte wecken indem man nur ja nicht konkret wird. Und die TWI-State Engine von ATMEL wird bei Philips/NPX nun mal nicht genauer beschrieben... Das Problem ist nicht i2c, das Problem ist TWI. (Oder ich hab noch nicht die richtigen Stellen im Mega32-Datenblatt gefunden... will ich nicht ausschließen.) Sorry für's ausschweifen

    Der Grund warum man in der twi_target einstellen soll was man möchte, ist schlicht und einfach das ich daran erkennen kann welcher Code Teil nicht gebraucht wird - und der wird dann entfernt. Entfernt wurde dabei eben auch der überflüssige Initaufruf für den Master da ja in der target Slave angegeben war. Also bei mir.. bei euch war es noch TWIMASTER was natürlich zu fehlendem Code führt. Sorry dafür. Hätte ich besser kommunizieren sollen.

    Zitat Zitat von Dirk
    Kurze Anregung als "normaler User":

    Du bist ja da an einem dynamischen Prozeß dran, d.h. versuchst, in mehreren Schritten möglichst gute Lösungen zu finden. Dabei verändert sich auch die "Makrosprache" und der Funktionsumfang, der dem RP6 zur Nutzung des I2C-Bus mitgegeben wurde.
    Wenn die entstehende Lib (ich bin da guter Hoffnung!) problemlos für alle zu nutzen sein soll, gibt es bei der Entwicklung eines neuen TWI-"Treibers" aus meiner Sicht auf der Makroebene nur 3 Möglichkeiten:
    1. Man nutzt NUR die vorgegebenen Befehle und Makros, so dass vorhandene Programme mit der neuen Version kompiliert werden können.
    2. Man ergänzt alle vorgegebenen Befehle und Makros durch neue Funktionen und Makros. Damit ist ebenfalls Abwärtskompatibilität möglich, es können dann aber neue Funktionalitäten zusätzlich genutzt werden.
    3. Man verzichtet auf Kompatibilität und beschreibt einen neuen "Befehlssatz" für die TWI-Funktion.
    Absolut richtig.
    Weg 1 funktioniert nicht.
    Weg 2 ist der goldene Mittelweg aber leider nicht immer möglich.
    Weg 3 hört sich theoretisch gut an aber auch ich koche nur mit Wasser und habe nicht vor das Rad neu zu erfinden.

    Zitat Zitat von Dirk
    Mir persönlich liegt die Option 2. am Herzen, weil ich faul bin, und meine Programme nicht ändern möchte. Trotzdem würde ich gern von "Fortschritten" durch eine neue Lib profitieren (egoistisch wie ich bin ...).
    Das sehe ich zu 100% wie Du. Siehe oben die defines. Letztlich wird es eine Mischung aus allen 3 Wegen wobei ich Weg 2 anvisiere. Es ist auch immer eine Frage der Abwägung von Aufwand und Nutzen. Ich sitze zwar jeden Tag lange hier dran aber es mus eben auch zum Prozessor und zum Rest der Libs passen.
    Ich versuche jedenfalls die Änderungen klein zu halten und ändere nur da wo es wirklich Sinn macht oder Notwendig ist. Grundsätzliche Änderungen wären nur möglich wenn man die ganze RP6 Lib auf den Kopf stellt und dazu braucht man a. mehrere Leute um das in einem zeitlich sinnvollen Rahmen zu schaffen und es besteht b. glaube ich kaum eine echte Notwendigkeit da es nur ein (schönes!) Spielzeug und Experimentierplattform ist. Wenn auch eine sehr Interssante. Aber so lange mir die ESA kein Gehalt zahlt, tue ich auch nicht so als sei das hier ein Marsrover...

    Zitat Zitat von Dirk
    Also: Bitte nicht als Kritik, sondern nur als Anregung verstehen.
    Ich teste weiter ...
    Das ist schön.
    Nein ich verstehe das nicht als Kritik, nur meine Zeiten als Codewarrior sind schon etwas länger her und ich hab den RP6 erst seid 3 Wochen. AVR-Prozesoren sind mir auch fremd, ich komme eigentlich von 68000er CPUs (asm) die heute kaum einer noch kennt... und Linux von da her ists ne gewaltige Umstellung. Aber keine Sorge, ich werd euch keinen Linux Kernel schreiben auch wenns mich in den Fingern juckt Ich versuche euch an den Veränderungen Teil haben zu lassen und zu begründen und ihr habt natürlich die Möglichkeit darauf zu reagieren. Eine richtige Docu dazu fehlt ja auch noch aber das meiste ist im Programm zu erkennen.

    Vielleicht erklärt das auch die RTOS Frage von mir an anderer Stelle des Forums etwas besser. Ich bin es gewohnt, in den Source zu schauen und nehme nicht alles als gegeben hin. (Was ich auch nicht als Kritik verstanden haben möchte) Na jedenfalls hab ich Hoffnung das es noch was wird mit dem TWI hier Es geht ja jetzt schon mehr als mit dem alten Treiber ohne das es riesengroß wird.
    Ich bin übrigends dabei einen weiteren Fehler einzukreisen, welcher sich hier in meinem Hardwareaufbau eingeschlichen hat - der evtl. auch die Buserrors BEI MIR verursacht. Wäre möglich das ihr weniger bis keine habt... Hängt evtl. mit der Nutzung von E_INT1 zusammen. Der Lötkolben ist schon warm.... Ansonsten läuft die Lib schon ganz gut hab ich das Gefühl.

    PS: mich wundert schon etwas, das sich noch niemand rangetraut hat um dem RP6 bzw. die Libs zu verbessern, schließlich sagt SlyD selbst das nicht alles optimal ist. Die TWI ist da nur ein, aber bestimmt nicht das einzige Beispiel. Und ich hab jetzt nicht den Eindruck, das sich SlyD guten Ideen und Umsetzungen gegenüber sperren würde. Ich rege mich jedenfalls mehr über ein störanfälliges TWI auf, als über laute Zahnräder ...

    LG Rolf

Seite 4 von 7 ErsteErste ... 23456 ... LetzteLetzte

Berechtigungen

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

MultiPlus Wechselrichter Insel und Nulleinspeisung Conrad