dsPIC33, SPI-Slave und Timer1-Interrupts. Was geschieht?

Ich habe ein interessantes Problem mit dem dsPIC33FJ128GP802 .

Ich habe es als Slave-SPI-Gerät konfiguriert, das mit einem Arduino verbunden ist, der als Master fungiert.

Timer1 ist so eingerichtet, dass er zu bestimmten Zeiten in einer bestimmten Reihenfolge einen Interrupt auslöst.

Eine der Unterbrechungssequenzen benötigt etwa 50 µs zur Ausführung. Ja, ich weiß, es ist keine "gute Praxis", eine Interrupt-Routine so lange zu haben, aber es gibt nur einen Interrupt, der im System verwendet wird, und Zeitbeschränkungen bedeuten, dass es so lange dauern muss.

Jetzt funktioniert alles - das SPI läuft und empfängt Befehle vom Arduino. Der Timer1 löst den Interrupt genau zu den richtigen Zeiten aus, und alles sieht gut aus.

Außer, ich sehe Korruption auf dem SPI. Ich kann nur vermuten, dass es am Interrupt für das Auslösen von Timer1 während der SPI-Übertragung liegt. Wenn ich den Timer und seinen Interrupt deaktiviere, bekomme ich überhaupt keine Probleme mit der SPI-Übertragung.

Soweit ich Interrupts verstehe, sollten sich alle Register usw. in genau demselben Zustand befinden, wenn die ISR zurückkehrt, wie sie waren, als der Interrupt ausgelöst wurde. Das behauptet jedenfalls die C30-Bedienungsanleitung.

Ich habe versucht, meinen C-Code für den SPI-Empfang in Assembly neu zu schreiben, aber das Problem besteht weiterhin.

Hier ist ein Ausschnitt meines C-Codes:

while(PORTAbits.RA3==1);     // Wait for a transfer to be requested     
SPI1STATbits.SPIEN=1;        // Enable the SPI module     
SPI1BUF=0x0;                 // Prime the buffer to start a transfer     
LATAbits.LATA1=0;            // Signal to the master it may transfer     
while(PORTAbits.RA3==0);     // Wait for the master to signal it has transferred   
in = SPI1BUF;                // Store the resultant word     
SPI1STATbits.SPIEN=0;        // Turn off the SPI module     
               ... perform operations depending on SPI command received ...     
LATAbits.LATA1=1;            // Signal to the master the command has finished and it may transfer again.
  • RA3 ist der Slave-Select-Pin für den SPI
  • LATA4 ist Reverse-Handshaking zurück vom Slave zum Master

Beide sind low-aktiv.

Wie Sie sehen können, verwende ich mehr Handshaking als normales SPI, da ich vom Slave an den Master zurückmelden muss, wenn es sicher ist, mit der Übertragung eines anderen SPI-Befehls zu beginnen.

Mein ISR ist definiert als:

void __attribute__((__interrupt__,no_auto_psv)) _T1Interrupt(void)   

Ich habe versucht, das __shadow__Attribut hinzuzufügen, um die Schattenregister zu verwenden, aber es hatte keine Wirkung.

Was passiert also eigentlich mit dem SPI in diesem Chip, wenn ein Timer-Interrupt ausgelöst wird? Da es unabhängig von der Haupt-CPU getaktet wird und nur Bits in ein Schieberegister hinein- und herausschiebt, sollte es sicherlich nicht von Interrupts betroffen sein.

Es macht meine Nuss, also wären alle Hinweise sehr willkommen.

Antworten (1)

Normalerweise würden Sie das SPI-Peripheriegerät einmal einrichten und dann eingeschaltet lassen. Das zusätzliche Handshaking, das Sie durchführen, hindert Sie daran, die Hardware voll auszunutzen. Es ist auch eine schlechte Idee, geschäftig darauf zu warten, dass der Master die Slave-Auswahl bestätigt, wenn Sie jemals möchten, dass der Prozessor etwas anderes tut.

Da Sie 16 Bit weniger pro Nachricht übertragen, würde ich es einfach der Hardware überlassen. Dann können Sie das SPI-Interrupt-Flag überwachen, um festzustellen, wann neue Daten vom Master empfangen wurden. Wenn Sie den Master aus Gründen der Flusskontrolle verlangsamen müssen, würde ich das außerhalb der SPI-Nachricht tun. Ich vermute, dass der Interrupt Ihrem selbst entwickelten Handshaking-Schema Latenz hinzufügt, und irgendetwas stimmt nicht ganz und kann diese Latenz nicht tolerieren. Das setzt natürlich voraus, dass der Interrupt nicht versucht, die SPI-Hardware oder eine ihrer I/O-Leitungen zu berühren.

Leider ist es mir nicht möglich, das SS-Handling der Hardware zu nutzen. Auf diesem Chip wird es mit einem der PORTB-Pins geteilt, und das Datenblatt besagt, dass "Driving the pin high die Übertragung abbricht", und ich muss das gesamte PORTB für dieses System verwenden (es fungiert als Schieberegister). Also muss ich manuell einen PORTA-Pin als SS-Signal verwenden. Der Prozessor wird während der geschäftigen Wartezeiten nie etwas anderes tun wollen. Es gibt 2 grundlegende Operationen. Die SPI-Lesung und der Timer-Interrupt. Das ist alles, was vor sich geht, und alles, was jemals vor sich gehen wird.
Der Interrupt manipuliert PORTB, und die SPI-Funktionalität wird mit einigen der PORTB-Pins geteilt. Die Neuzuordnungsfunktion des dsPIC deaktiviert jedoch die PORT-Funktionalität dieser Pins, wenn der SPI auf ihnen aktiviert ist. Der Interrupt manipuliert SPI in keiner Weise.
Ich habe alles so umgeschrieben, dass es zu 100 % unterbrechungsgesteuert ist. Indem ich mit den Unterbrechungspegeln auf diesem Chip herumgespielt habe, habe ich es geschafft, dass es tatsächlich richtig funktioniert. Danke für die Hinweise.