Hallo, ich hab ein kleines Problem bei der Programmierung des SPI. Die Forumssuchfunktion half mir leider auch nicht weiter. Ich habe einen ATmega8515 und möchte damit Daten an einen ATmega16 per SPI senden. Das funktioniert im Prinzip auch zu 90%. Bei 10% kommt Datenmüll im Mega8 an. Mein Problem ist, das ich nicht weis wann ich wieder Daten in das Senderegister des Mega8515 schreiben darf. Laut Datenblatt wird das Flag SPIF im SPSR sofort gelöscht, sobald der Interrupt auslöst oder ich einmal das SPSR lese. Da ich mit Interrupts arbeite, kriege ich ein Problem. Ich kann ja nicht sagen if (SPSR & _BV(SPIF)) SPDR = x; // Pseudocode :-) Das SPIF wird ja schon bei meinem letzten Interrupt gelöscht. Bin ich nun im Transfer oder Nicht ?! Ein Bit wie beim UART "TrasmitRegister Empty" habe ich nicht gefunden. Wie löst Ihr so ein Problem ?! Danke Juergen
Die SPI-Schnittstelle ist doch eine synchrone Schnittstelle, d.h. bei Auslösen des Interruptes ist die Datenübertragung komplett. Also hat an dieser Stelle der Slave die Daten vom Master übernommen. Durch das Ring-Schieberegister-Prinzip könntest du dir doch vom Slave ein Bestätigungs-Byte (0xAA oder so) schicken lassen. So weißt du eventuell, wieso bei 10% Mist übertragen/empfangen wird. Wenn du einen SPI-Interrupt bekommst, liest du zuerst das SPI-Datenregister (MISO-Byte vom ATmega16) und schreibst dann die MOSI-Daten (zum ATmega16) in das SPI-Datenregister. Mfg
>Da ich mit Interrupts arbeite, kriege ich ein Problem. Ich kann ja nicht >sagen if (SPSR & _BV(SPIF)) SPDR = x; // Pseudocode :-) Du vermischt da irgendwie zwei Sachen: Der Interrupt wird ausgeführt, wenn das SPIF gesetzt wird und das entsprechende Enable-Bit gesetzt ist. Dann springt der Controller in die SPI-Interruptservice routine. Wenn man in der ISR dann noch mal das SPIF abfragt, ist das die gleiche Abfrage, die der Controller durch den Sprung in die ISR schon erledigt hat. Die Daten kann man also einfach in der ISR ins SPDR schreiben. Oder wie machst du das? Etwas Code würde helfen...
Anbei ist mal der code für die SPI. Das ganze Projekt wäre zu umfangreich. Beim Start rufe ich "spiInitMaster()" auf. Danach immer wenn ich was senden will ------ spibuffer.add("Dies ist ein test"); spiStartSend(); ------ In spiStartSend() komme ich dann an mein Problem. Darf ich nun schon das erste Byte in das SPDR schreiben ? Läuft mein Interrupt ? Das File ist nur mit Mega CPUs getestet. Also ich schreibe Daten in den Sendepuffer. starte das Senden und den Interrupt per Interrupt sende ich die weiterne Bytes bis der Puffer leer ist und Stoppe den Interrupt. Ich vermute das ich hier Timingprobleme bekomme, das ich SPDR überschreibe während einer Übertragung :-( Im Slave mache ich alles per Polling, da er nix anderes macht wie SPI Daten zu Sammeln und per UARt an den PC zu senden. if ((SPSR & _BV(SPIF))) // neue Daten Da ! { register char c; c = SPDR; serbuffer.add(c); // Add Data to buffer PORTD ^= _BV(PD5); } Wieso gibt es da auch keine Möglichkeit eine laufende Übertragung festzustellen ? Gruss Juergen
> serbuffer.add(c); // Add Data to buffer Diese Funktion steht nirgends. Was macht sie, wie lange dauert sie (worst case) ? Wie lange dauern sämtliche Interrupts im Programm ? AVR-SPI-Slave möchte man nicht wirklich benutzen. Wenn das Empfangsbyte nicht garantiert innerhalb des nächsten Bytes abgeholt wird, ist Sense. Und Senden wird überhaupt nicht gepuffert, ohne Handshake oder lange Wartezeiten geht da überhaupt nichts. Als SPI-Slave würde ich nur den AT89LP4051 nehmen. Der hat auch nen Sendepuffer und Interuptprioritäten, d.h. er kann sämtliche anderen Interrupts unterbrechen, sobald die SPI-Kacke am Dampfen ist. Peter
Die Funktion "serbuffer.add()" steht an anderen Stellen im Programm, wo ich eben Debugausgaben haben will. Wird von mir vielfach genutzt. Ist nichts anderes wie ein Puffer Objekt. Die Routine ist aber getestet. Habe im Slave in Mainline einfach "serbuffer.add(x);" laufen lassen...... Alles wurde fehlerfrei zum PC übertragen. Natürlich hat die Funktion die meisten Daten verworfen, da der Puffer die Daten nicht alle aufnehmen konnte. Aber das war ja nur ein Test um zu sehen ob ich hier schon Daten Müll produziere. Uff, mir gehts nur darum zum Debuggen eine Schnittstelle zu haben. Mit dem USART der Mega8515 bearbeite ich einen RS485 Bus, das läuft auch Prima. Anfangs hatte ich auch eine Softuart Schnittstelle, Das Problem ist nur, das durch die anderen Interrupts, das Timing nicht mehr stimmt und ich auch Übertragungsfehler bekomme, das Bittiming ist einfach zu kritisch. War schon am Überlegen mir einfach einen Externen Hardware UART zu besorgen. Ich dachte so kann ich mir das Hardware kaufen sparen und bekomme etwas Übung mit dem SPI. Aber das Problem müsste doch handhabbar sein. Wenn beim Empfang etwas verloren geht, würde ja ein komplettes Byte fehlen. Bei mir sind die Daten aber Müll. Kein Bitkipper sondern richitg Müll bei 10%. Juergen
- Master-SCK < Slave-XTAL / 4 - kurze Leitungen < 20cm - dicke GND-Verbindung - lange Pausen (>10ms) zwischen dem Senden oder Handshakeleitung, wenn der Slave das Byte ausgelesen hat. Peter
Hmm, so wie ich das sehe wäre es wohl sinnvoller auf I2C umzusteigen.... Da hab ich die Probleme nicht und brauch nur halb so viele Leitungen ;-) Danke für die Tips soweit. Gruss Juergen
>Da hab ich die Probleme nicht und brauch nur halb so viele Leitungen ;-) Sicher? TWI ist auch nicht ganz ohne. Die einfachste (und bei AVRs vermutlich auch am besten realisierte) Schnittstelle ist immer noch das USART...
Ja, I²C ist besser geeignet, einen Controller als Slave anzusteuern. SPI ist wirklich weiter nichts als ein Hardwareschieberegister und kann folglich von einem solchen am besten implementiert werden. Aber zurück zu deiner eigentlichen Frage: wenn du mit Interrupts arbeitest, musst du dir den Status einfach in der ISR merken: wenn der Interrupt getriggert hat, war das SPIF irgendwann mal gesetzt. Ansonsten gar nicht erst mit Interrupts arbeiten und gleich pollen. Wenn dein SPI-Slave vorbeugend auf sein slave select pollen kann, weil er weiß, wann der Master ihm was in Auftrag geben wird, hast du den ersten Teil erschlagen. Aber der zweite Hammer kommt gleich hinterher: typischerweise sendet man bei SPI sowas wie ein Kommando als erstes, an Hand dessen der Slave dann entscheidet, was zu tun ist. Diese Entscheidung ist auch total zeitkritisch, zumindest, falls du den Master nicht irgendwo per ,,Aktennotiz'' dazu bewegen kannst, nach dem Kommandobyte eine Pause einzulegen.
Naja, Bei mir ist die Aufgabe einfach für den Slave: Nimm alle Daten die du per SPI bekommst. kopiere sie in einen Zwischenpuffer, und Übertrage Sie bei Gelegenheit zum PC per UART. Nunja, versuche ich eben mal mit I2C. Hab gestern mit viel Probieren es so hinbekommen, das keine Daten mehr verstümmelt wurden. Dafür gehen jetzt Zeichen verloren. Ich hab ein Fach zwischen jedem Byte per SPI die SS Leitung mit Verzögerung kurz High und wieder Low gesetzt um den SPI zu Syncronisieren. Naja die Wartezeiten die ich brauche das es Fehlerfrei läuft sind zu lange und stören schon das restliche Timing mehr als mir lieb ist. Aber ich werde mir Morgen mal den I2C per Hardware ansehen. Den in SW zu machen ist mir etwas Rechenverschwendung :-) Gruss und Danke für die Tips Juergen
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.