UART Interrupt erhält nicht mehr als ein Zeichen - PIC32MX110F106B

Ich habe wirklich Probleme mit einer UART-Kommunikation mit meinem PIC32MX110F016 . Es ist das erste Mal, dass ich versuche, eine UART-Kommunikation mit der PIC32MX-Familie zu implementieren, aber ich finde es schwierig und ich weiß nicht, warum es nicht richtig funktioniert. Also habe ich beschlossen, meinen gesamten Code in Form eines Tutorials (Schritt für Schritt) zu veröffentlichen, um etwas Hilfe von euch zu bekommen. Ich hoffe, es hilft in Zukunft anderen Menschen, die mit dem gleichen Problem konfrontiert sind.

Also habe ich zuerst die Bibliotheken importiert und diese Mikrocontroller-Konfigurationen deklariert:

#pragma config   FNOSC       = FRCPLL
#pragma config   FPLLIDIV    = DIV_2
#pragma config   FPLLMUL     = MUL_20
#pragma config   FPLLODIV    = DIV_2
#pragma config   FPBDIV      = DIV_1
#pragma config   ICESEL      = ICS_PGx2
#pragma config   WDTPS       = PS16384

#define GetSystemClock()        (40000000ul)
#define GetPeripheralClock()    (GetSystemClock())
#define BaudRate   115200

Dann habe ich meine Funktion uartconfig() implementiert:

void uartconfig(void){
PPSUnLock;                        // Allow PIN Mapping for BLE
  PPSOutput(1, RPA0, U1TX);     // MAP Tx to RA0 set to digital out
  PPSInput (3, U1RX, RPA2);     // MAP Rx to RA2 set to digital in
  PPSOutput(4, RPA3, U1RTS);
  PPSInput (2, U1CTS,RPA1);
PPSLock;                         // Prevent Accidental Mapping

#define UART1TX TRISAbits.TRISA0
#define UART1RX TRISAbits.TRISA2

#define CMD TRISBbits.TRISB5

UART1TX = 0;//output
UART1RX = 1;//input

DDPCONbits.JTAGEN = 0;

UARTConfigure(UART1, UART_ENABLE_PINS_CTS_RTS);
UARTSetFifoMode(UART1, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY);
UARTSetLineControl(UART1, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1);
UARTSetDataRate(UART1, GetPeripheralClock(), BaudRate);
UARTEnable(UART1, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX));

INTEnable(INT_SOURCE_UART_RX(UART1), INT_ENABLED);
INTSetVectorPriority(INT_VECTOR_UART(UART1), INT_PRIORITY_LEVEL_2);
INTSetVectorSubPriority(INT_VECTOR_UART(UART1), INT_SUB_PRIORITY_LEVEL_0);

// configure for multi-vectored mode
INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR);
INTEnableInterrupts();
}

command_printDann habe ich mich entschieden, eine Funktion zum Senden von Daten über UART zu erstellen :

void command_print(char *buffer){ 
while(*buffer != (char)0)
{
  while(!UARTTransmitterIsReady(UART1));
  UARTSendDataByte(UART1, *buffer++);
}
UARTSendDataByte(UART1, '\r');
while(!UARTTransmissionHasCompleted(UART1));
}

Ich habe mich entschieden, eine Struktur zu erstellen, um einen Puffer für den TX/RX-Pin zu erstellen (ab jetzt verwende ich nur noch den inputBuffer):

typedef volatile struct UARTBuffer {
char outputBuffer[ UART_INPUT_BUFFER_SIZE ];
char inputBuffer[ UART_OUTPUT_BUFFER_SIZE ];
unsigned short int inputReaderPos;
unsigned short int inputWriterPos;
unsigned short int outputReaderPos;
unsigned short int outputWriterPos;
} UARTBuffer;

UARTBuffer UARTBuffer1;

In meiner Interrupt-Service-Routine ISRhabe ich beschlossen, den Teil zu ignorieren U1TXund das Flag immer zu löschen. Für die U1RXdefinierte ich die als:

void __ISR(_UART_1_VECTOR, ipl2)UART1HANDLER(void){
char c;
if ( INTGetFlag(INT_U1TX) )
 {
    INTClearFlag(INT_SOURCE_UART_TX(UART1));
}

if ( INTGetFlag(INT_U1RX) )
 {

if( (U1STAbits.OERR == 1) || (U1STAbits.PERR == 1) || (U1STAbits.FERR == 1) ){
    // Ignore
    U1STAbits.OERR = 0;//clears if the Receive buffer has overflowed
    U1STAbits.PERR = 0;//parity error
    U1STAbits.FERR = 0;//framing error
    U1RXREG;
}
else {
    // Check if the buffer is all readed. If so, clear the buffer;
    if( UARTBuffer1.inputWriterPos == UARTBuffer1.inputReaderPos ) {
        UARTBuffer1.inputWriterPos = 0;
        UARTBuffer1.inputReaderPos = 0;
    }
    if (UARTBuffer1.inputWriterPos >= UART_INPUT_BUFFER_SIZE){
        // Buffer overflow
        UARTBuffer1.inputWriterPos = 0;
        UARTBuffer1.inputReaderPos = 0;
    }
    c = U1RXREG;
    UARTBuffer1.inputBuffer[ UARTBuffer1.inputWriterPos++ ] = c;
}
INTClearFlag(INT_SOURCE_UART_RX(UART1));
}
}

Schließlich main(void)ist my definiert als:

int32_t main(void) {
__asm__("EI");
UARTBuffer1.inputWriterPos = 0;
SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

INTEnableSystemMultiVectoredInt(); //enable interrupts

uartconfig();

command_print("SF,1");
while (1);
}

Eigentlich läuft mein PIC normal und mein Interrupt wird ausgelöst. Was ich nicht verstehen kann, ist der Grund, warum mein Code nie mehr als ein Zeichen im RXRegTeil (nämlich U1RXREG) innerhalb der ISR erhält. Ich lösche die Flagge am Ende der ISR und ich denke, dass alles gut konfiguriert ist. Lassen Sie mich wissen, was ich tun soll, um meinen Rahmen richtig zu bekommen und nicht nur das erste Zeichen. Ich weiß, dass der UART gut gestaltet ist, und wenn ich versuche, einen anderen Befehl zu senden, als "SF,1"das RX-Register mir ein anderes Zeichen gibt.

EDIT: Ich erreiche nicht, was ich will. Ich verliere Zeichen im Interrupt, also verbinde ich das CTS+ RTS, aber leider bekomme ich keine besseren Ergebnisse. Kann mir jemand bei der CTS+ RTSKonfiguration für die PIC32mx-Familie helfen? Ich weiß, dass ich den CTS mit dem RTS und den RTS mit dem CTS vom Mikrocontroller zur "anderen" Komponente kreuzen muss. Mein Problem hängt eher mit den Funktionen/Konfigurationen zusammen, die ich tun muss.

Sie lesen ein Zeichen nach dem anderen aus dem U1RXREG, ich denke, Sie können damit durchkommen, das gesamte U1RXREG auf einmal in Ihrer Variablen zu speichern.
Ich bin mir nicht sicher. Ich habe mir bereits U1RXREG angesehen und es hat nur 0x00000041 als Wert und es ist kein akzeptables Ergebnis.
0x41 ist 'A'. Was hast du als deinen zweiten Charakter erwartet?
'AOK\r\n' ist das, was ich versuche zu bekommen.
Sollte diese UartBuffer1-Struktur auf jeden Fall 'volatile' machen.
@justing es ist ein guter Tipp und Sie haben Recht mit der Verwendung flüchtiger Strukturen innerhalb eines Interrupts, aber in diesem Fall löst es das Problem nicht. Bitte beachten Sie, ich habe nur 0x00000041 als Wert von U1RXREG.
Funktioniert es mit niedrigeren Baudraten? Verhält es sich besser, wenn Sie das Interrupt-Flag sofort nach der Überprüfung löschen?
Nein. Keiner Ihrer Vorschläge hat Wirkung gezeigt.

Antworten (1)

Bei einer Baudrate von 115200 ohne Parität und 1 Start- und Stoppbit (insgesamt 10 Bits) dauert es 86 Mikrosekunden, bis Daten vom anderen Ende in Ihrem RX-Puffer ankommen.

Wenn ich mir Ihre ISR ansehe, sehe ich, dass Sie viele Anweisungen in Ihrer ISR verarbeiten.

Das Szenario, das passieren könnte, ist folgendes: Ihr erster Charakter kommt an (dh "A"),

Interrupt wird ausgelöst,

es ist kein Fehler aufgetreten (Überlauf, Parität usw.),

jetzt kommen auch die restlichen Zeichen ("OK\r\n"),

Überlaufflag wird gesetzt,

Sie löschen den RX-Interrupt (aber Sie geben ISR nicht erneut ein, da keine weiteren Zeichen empfangen werden).

Debug-Lösungen: 1. Verwenden Sie die Flusssteuerungsmethode (ACK für jedes Byte)

  1. Überprüfen Sie die Größe des Rx FIFO Ihres uC. (Wenn es 16 Bytes sind, benötigen Sie keine Flusskontrolle. Andernfalls benötigen Sie Flusskontrolle, wenn kein FIFO vorhanden ist.)

3.Vermeiden Sie Funktionsaufrufe in der ISR.

4. Sie können den Interrupt für Überlauffehler aktivieren, sodass Sie nicht explizit eine Routine für den Interrupt schreiben müssen. Wenn ein Überlauffehler auftritt, überprüfen Sie einfach den Status des Interrupt-Flags und löschen Sie das Flag und verwerfen Sie die Rx-Daten. Dies hilft Ihnen, die Verarbeitung solcher Fehler in der ISR zu reduzieren, da sie in der Hauptschleife selbst überprüft werden können. Kopieren Sie einfach die empfangenen Daten in einen Puffer und erhöhen Sie einen Zähler. Das könnte helfen.

  1. Reduzieren Sie Ihre Baudrate und prüfen Sie mit demselben Code
Die CPU-Taktrate beträgt 40 MHz und die Baudrate 115200 bps. Jedes Zeichen hat 8 Datenbits, ein Stoppbit und ein Startbit, also insgesamt 10 Bits pro Zeichen. Daher haben Sie 40 MHz / 115200 bps * 10 Bits pro Zeichen = 3.472 CPU-Zyklen, um jedes Zeichen zu verarbeiten, bevor das nächste ankommt. Daher ist es unwahrscheinlich, dass Ihr ISR zu langsam ist, um die eingehenden Zeichen zu verarbeiten. Wenn Sie also Interrupts nicht an anderer Stelle deaktivieren, ist ein Überlauf unwahrscheinlich.
Habe es schon mit der Baudrate auf 19200 probiert und keine besseren Ergebnisse.