Electronic – UART Interrupt does not get more than one Char – PIC32MX110F106B

interruptsmicrochipmicrocontrollerpicuart

I am really struggling with an UART communication with my PIC32MX110F016. It is the first time I am trying to implement an UART communication with PIC32MX family but I find it difficult and I don't know why it's not working properly. So I decided to post all my code in a tutorial way (step-by-step) in order to get some help from you guys. I hope it helps in the future for other people who face the same problem.

So firstly I imported the libraries and declared this microcontoller configs:

#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

Then I implemented my uartconfig() function:

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();
}

Then I have decided to create a command_print function to send data through UART:

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

I have decided to create a struct in order to create a buffer for the TX/RX pin (from now I am just using the 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 my interrupt service routine ISR I decided to ignore the U1TX part and clear the flag always. For the U1RX I defined the as:

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));
}
}

Finally my main(void) is defined as:

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);
}

Actually my PIC is running normally and my interrupt is being triggered. What I can not understand is the reason why my code never get more than one character in the RXReg Part (namely U1RXREG) inside the ISR. I am clearing the flag by the end of the ISR and I think everything is well configured. Let me know what should I do to get my frame properly and not only the first character.
I know the UART is well designed and if I will try to send another command than "SF,1" the RX register gives me a different char.

EDIT: I am not achieving what I want. I am losing characters in the interrupt so I connect the CTS + RTS but unfortunately I am not getting better results. Is anybody available to help me with the CTS + RTS configuration for the PIC32mx family? I know I have to cross the CTS with the RTS and the RTS with the CTS from the microcontroller to the "other" component. My problem is more related with the functions/configs do I have to do.

Best Answer

At a baudrate of 115200,using no parity and 1 start & stop bit(total of 10 bits), it takes 86 microseconds for data to arrive at your RX buffer from the other end.

Looking at your ISR, i see that you are processing a lot of instructions in your ISR.

The scenario that might be happening is this: Your first character arrives(i.e "A"),

Interrupt is triggered,

no error has occurred(overflow,parity etc),

now the rest of the characters also arrive("OK\r\n"),

overflow flag gets set,

you clear RX interrupt(But you dont enter ISR again cause no more characters will be received).

Debug solutions: 1. Use flow control method(ACK for every byte)

  1. Check the size of the Rx FIFO of your uC.(if its 16 bytes then you dont need flow control.Else if no FIFO, you need flow control)

3.Avoid function calls in the ISR.

4.You can enable interrupt for overflow errors such that you dont explicitly have to write a routine for the interrupt. If overflow error occurs,just check the status of the Interrupt flag and clear the flag and discard the Rx data.This will help you reduce processing of such errors in the ISR as they can be checked in the main loop itself. Just copy the received data into a buffer and increment a count.This might help.

  1. Reduce your baud rate and check using your same code