Hallo Hardwaremässig kommunizieren (vorerst) ein Master und ein Slave via LIN-Topologie miteinander. Protokollmässig weiche ich vom LIN-Standard ab (bei mir: Break, Sync (0x55), 10 Bytes Nutzdaten vom Master, dann 15 Bytes Antwort vom Slave). Das Ganze läuft reibungslos ....bis der Slave das Senden nicht terminiert und den Bus ständig auf 'low' zieht. ps: Der Master sendet noch andere Pakete, welche aber vom Slave ignoriert werden. Der Master versucht auch dann weiter zu senden, wenn der Bus permanent auf 'low' ist (TX-Pin am Master-uC toggelt). Im obigen Fall, wenn der Slave die Leitung permanent auf 'low' zieht, ist das Registerbit TXSTA->TRMT auf '0', was soviel bedeutet, wie dass das UART-Modul das TSR-Byte noch am "raus-shiften" ist. BAUDCON->RCIDL ist dann auch auf '0', was soviel heisst, wie dass das UART-Modul am Daten empfangen ist. TXSTA->TRMT und BAUDCON->RCIDL können nicht beschrieben werden (read-only). Andere Register ändern ihre Werte nicht. Das Baudraten-Register hat immer gültige (die richtigen) Werte. Wenn ich im "nicht-funktionierenden" Betrieb TXSTA->TXEN mit dem Debugger auf '0' setze (UART-Transmitter disable), setzt der uC das TXSTA->TRMT auf '1' (UART-Modul sendet nicht mehr). Wenn ich dann TXSTA->TXEN wieder aktiviere, funktioniert meistens die Verbindung wieder, und wenn nicht, haben die Register wieder obige Werte. Datenblatt PIC16F1509 (Seite 240 oben und Seite 246) http://ww1.microchip.com/downloads/en/DeviceDoc/41609A.pdf (4.0MB) Meine Frage: Wie kann es dazu kommen, dass das Senden beim UART nicht abgeschlossen wird? Im Datenblatt bin ich nicht fündig geworden (und das Errata enthält auch nichts dazu). Oder was könnte sonst die Ursache sein? Vielen Dank für jegliche Hilfe edit: Bei einem SW-Reset beim Slave, funktioniert die Verbindung wieder.
Ja was sendet er denn da? Normalerweise hört das Senden auf, wenn der gesamte TX leergelaufen ist. Wenn aber eine Interrupt-Routine auf jeden Interrupt vom TX damit reagiert, daß ein neues Byte in den Sender geschoben wird, dann geht das eben ewig. Also: Wenn das letzte Byte in den TX geschoben worden ist und es nix mehr zu senden gibt, dann mußt du eben das zugehörige ..IE Bit rücksetzen. Beim nächsten anfallenden Byte setzt du es dann pauschal wieder auf 1 Benutzest du irgendwelche Fremdquellen, die du noch nicht gelesen und verstanden hast? W.S.
Danke für die schnelle Antwort. > Ja was sendet er denn da? Nichts: Bus ist permanent auf 'low'. Ich werde aber noch verifizieren ob der TX-pin auch immer 'low' ist. [ edit: Ja, der ist immer auf 'low' ] > ..dann mußt du eben das zugehörige ..IE Bit rücksetzen. Sollte so sein (letzte Zeile des ersten Codes). Meine Funktion, die im Interrupt aufgerufen wird:
1 | inline void ISRTransceiveLin() { |
2 | unsigned char c, x; |
3 | if (PIR1bits.RCIF) { |
4 | /*** Interrupt Receive ****/
|
5 | c = RCREG; |
6 | if ((PIE1bits.RCIE) && (BAUDCONbits.ABDEN == 0)) { |
7 | LinRxBuff[LinRxBuffPos++] = c; |
8 | if (LinRxBuffPos == 1) { // reset 16ms-counter (Timer 0) |
9 | TMR0 = 0; |
10 | LinIdleCounter = 0; |
11 | }
|
12 | else if (LinRxBuffPos > (ReceiveLength + ReceiveOffstet)) { // receiving finished |
13 | PIE1bits.RCIE = 0; |
14 | c = 0; |
15 | for (x = 1; x < (ReceiveLength + ReceiveOffstet); x++) // calculate dummy "CRC" |
16 | c += LinRxBuff[x]; |
17 | if (c == LinRxBuff[ReceiveLength + ReceiveOffstet]) { // if "CRC" matches |
18 | LED_Orange = 1; |
19 | LinReceptionCorrect = 1; |
20 | TXREG = LinTxBuff[0]; |
21 | LinTxBuffPos = 1; |
22 | PIE1bits.TXIE = 1; |
23 | ParseLinReception(); |
24 | }
|
25 | }
|
26 | }
|
27 | }
|
28 | /*** Interrupt Transmit ****/
|
29 | else if ((PIR1bits.TXIF) && (LinTxBuffPos < TransmitLength)) |
30 | TXREG = LinTxBuff[LinTxBuffPos++]; |
31 | else { |
32 | PIE1bits.TXIE = 0; |
33 | }
|
34 | }
|
16ms nach einer Break/Sync-Übertragung wird folgender Code aufgerufen, um für das Empfangen einer neuen Übertragung bereit zu sein (Master sendet alle 20ms eine neue Übertragung und eine ganze Übertragung geht max. 10ms).
1 | LinReceptionCorrect = 0; |
2 | LED_Orange = 0; |
3 | for (tmp8a = 0; tmp8a < (ReceiveLength + ReceiveOffstet + 1); tmp8a++) |
4 | LinRxBuff[tmp8a] = 0xFF; |
5 | PIE1bits.TXIE = 0; |
6 | LinRxBuffPos = 0; |
7 | tmp8a = RCREG; // clear RCIF |
8 | BAUDCONbits.WUE = 1; |
9 | BAUDCONbits.ABDEN = 1; |
10 | PIE1bits.RCIE = 1; |
> Benutzest du irgendwelche Fremdquellen, die du noch nicht gelesen > und verstanden hast? nein.
Das PIR1bits.RCIF wird nirgends wieder gelöscht...
"The RCIF interrupt flag bit is read-only, it cannot be set or cleared by software. [...] The RCIF interrupt flag bit will be set when there is an unread character in the FIFO, regardless of the state of interrupt enable bits" hmm, müsste ich zuerst das RCIE deaktivieren (auch den RCSTA->SPEN (Rx enable), und dann sicherstellen, dass der Rx-Buffer leer ist? Wäre ja echt mühsahm. edit: Ich sehe gerade, dass ich 'SPEN' nicht abschalten darf, da dies auch den Tx-Pin deaktiviert. Aber genügt denn das Abschalten des Receivers nicht? c = RCREG; PIE1bits.RCIE = 0;
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.