Ich habe zwei PIC18F4620 über SPI + Slave Select + zusätzliche IRQ-Leitung verbunden. Beide Controller werden von demselben Quarzoszillator mit denselben Takteinstellungen angesteuert. Der Master sendet ein Byte und wartet dann, bis der Slave diese zusätzliche IRQ-Leitung umschaltet. Die Dauer des Umschaltens beträgt 4 Befehlszyklen. Alle Kanten sehen auf dem Oszilloskop gut aus und die SPI-Kommunikation funktioniert ordnungsgemäß, mit Ausnahme der Erkennung des Umschaltens ( while(!PORTBbits.RB1);
).
Dies ist mein SPI-Sendecode:
while (spi_out_msg_buffer.write_cursor > spi_out_msg_buffer.read_cursor)
{
DisableInterrupts;
SSPBUF = spi_out_msg_buffer.data[spi_out_msg_buffer.read_cursor];
LATBbits.LATB0 = 1;
while(!PORTBbits.RB1); // wait for toggle on IRQ line
LATBbits.LATB0 = 0;
EnableInterrupts;
spi_out_msg_buffer.read_cursor++;
}
Das while(!PORTBbits.RB1);
wird in zwei Anweisungen übersetzt:
BTFSS PORTB, 1, ACCESS
BRA 0x188
Ich habe diese B0
Zeile zu Debugging-Zwecken eingefügt, Sie können sie ganz unten in diesem Zeitdiagramm sehen:
Sie können das Umschalten der IRQ-Leitung (zweite von unten) sehen und wie es unentdeckt bleibt, weil die B0
Debugging-Leitung hoch bleibt. Wenn ich die Ausführung über ICD stoppe, hängt es in der while
. Es ist erwähnenswert, dass es normalerweise für ein paar Bytes funktioniert und dann stoppt, wie Sie hier sehen können:
Ich habe gemessen, dass der Impuls tatsächlich 4 Befehlszyklen (= 16 PLL-Zyklen = 4 Taktzyklen) lang ist:
Ich denke, das sollte ausreichen, um den Puls zu erkennen. Selbst wenn das erste BTFSS es vermisst, weil der Port zu Beginn des Befehlszyklus abgetastet wird, sollte es das zweite bekommen:
10 MHz -> PLL -> 40 MHz -> 10 M Befehle pro Sekunde -> 100 ns pro Befehl.
Sollte das nicht lang genug sein, um das zu verlassen while
?
Sie verwenden einen Compiler, daher haben Sie keine Ahnung, wie viele Zyklen diese Abfrageschleife benötigt. In Assembler konnten Sie es auf 3 Zyklen reduzieren, aber Sie haben das Recht aufgegeben, Zyklen zu zählen, als Sie den Code in einer Hochsprache geschrieben haben.
Das eigentliche Problem ist jedoch der Gesamtansatz. Es ist keine gute Idee, den Code zu bitten, einen kurzen Fehler abzufangen. Selbst wenn Sie garantieren könnten, dass die Schleifenzeit kleiner als die Glitch-Zeit ist, können Sie jetzt während des Wartens keine Interrupts einschalten. Dies kann später zu architektonischen Problemen führen.
Eine viel bessere Idee ist es, die Hardware zu verwenden, die Sie bereits haben, um den Fehler zu erkennen, und dann die Firmware diese Hardware überprüfen zu lassen. Am einfachsten wäre es, den Glitch mit einer der INTx-Leitungen zu verbinden und dann nach dem INTxIF-Flag zu suchen. Änderungserkennungsstifte würden auch funktionieren, aber denken Sie daran, dass das Flag an beiden Rändern gesetzt wird und Sie die Nichtübereinstimmung beseitigen müssen, um die Bedingung zu beseitigen.
Die letzte Anweisung ist eine unbedingte Verzweigung, richtig? Normalerweise benötigen Verzweigungen und Speicherzugriffe (bei der ersten Anweisung durchgeführt, richtig?) etwa 2-3x mehr Zeit für die Ausführung. In Ihrem Fall könnten diese Anweisungen also etwa 16 Zyklen dauern, was 400 ns entspricht (im besten Fall). ).
while(!SSPSTATbits.BF);
.Der eigentliche Grund war, dass ich ein Idiot war. Mein DisableInterrupts
Makro hat es getan INTCONbits.GIE=1
.
Ich habe das gefunden, indem ich während des geschäftigen Wartens eine Stecknadel umgeschaltet habe:
while(!PORTBbits.RB1)
{
LATBbits.LATB0 = 0;
LATBbits.LATB0 = 1;
}
Mir ist aufgefallen, dass das Toggeln in regelmäßigen Abständen aufhört und wenn der Benachrichtigungsimpuls in eines dieser Fenster fällt, bleibt es unbemerkt.
Kortuk
Majenko