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)
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.