I am working on a project that implements RS485 half duplex messages. To implement it, use UART1 on an STM32F750 as follows:
Code: Select all
static RS485_DATA rs485Data;
static void RS485_RxChar(UARTDriver *uartp, uint16_t c) {
(void)uartp;
// circular buffer
if(rs485Data.flags.fullBufferRx == 0){
rs485Data.bufferRx[rs485Data.ptrRxWData++] = c;
if(++rs485Data.countRxData == LENGTH_BUFFER_UART_RX){
rs485Data.flags.fullBufferRx = 1;
}
if(rs485Data.ptrRxWData == LENGTH_BUFFER_UART_RX){
rs485Data.ptrRxWData = 0;
}
}
}
static void RS485_TxEnd(UARTDriver *uartp){
RS485_SET_RECEPTION();
}
static UARTConfig uart_cfg1 = {
NULL, // End of transmission buffer callback.
RS485_TxEnd, // Physical end of transmission callback.
NULL, // Receive buffer filled callback.
RS485_RxChar, // Character received while out if the @p UART_RECEIVE state.
NULL, // Receive error callback.
NULL, // Receiver timeout callback.
0, // Receiver timeout value in terms of number of bit duration.
9600, // Bit rate.
0 | (USART_CR1_M0 | USART_CR1_PCE), // CR1 register. 9 bits (8 + paridad) Even
0, // CR2 register.
0 // CR3 register.
};
void RS485_PutArray(uint8_t *ptrData, uint16_t lenght){
RS485_SET_TRANSMISSION();
chThdSleepMicroseconds(100);
uartStartSend(uartp, lenght, (const void *)ptrData);
return;
}
void RS485_ProcessBuffer(void){
static uint8_t buffer[256];
uint16_t length;
switch(rs485Data.state){
case RS485_GET_HEADER1:
if(rs485Data.countRxData == 0){
return;
}
length = rs485Data.countRxData;
do{
RS485_GetArray(&buffer[0], 1);
if(buffer[0] == ((RS485_HEADER >> 8) & 0xFF)){
rs485Data.state = RS485_GET_HEADER2;
return;
}
length--;
}while(length != 0);
break;
case RS485_GET_HEADER2:
if(rs485Data.countRxData < 2){
return;
}
RS485_GetArray(&buffer[1], 1);
if(buffer[1] == (RS485_HEADER & 0xFF)){
RS485_GetArray(&buffer[2], 1);
rs485Data.totalLength = buffer[2];
if(rs485Data.totalLength != 0){
if(rs485Data.countRxData >= (rs485Data.totalLength - 1)){
rs485Data.state = RS485_PROCESS_DATA;
}else{
rs485Data.state = RS485_GET_ALL_DATA;
}
}else{
rs485Data.state = RS485_GET_HEADER1;
}
}else{
rs485Data.state = RS485_GET_HEADER1;
}
break;
case RS485_GET_ALL_DATA:
if(rs485Data.countRxData >= (rs485Data.totalLength - 1)){
rs485Data.state = RS485_PROCESS_DATA;
}
break;
case RS485_PROCESS_DATA:
RS485_GetArray(&buffer[0], rs485Data.totalLength - 1);
// ...
rs485Data.state = RS485_GET_HEADER1;
break;
case RS485_PUT_DATA:
break;
}
}
static THD_WORKING_AREA(wa_rs485, 1024);
static THD_FUNCTION(RS485_Tasks, arg) {
(void)arg;
while(TRUE){
chThdSleepMilliseconds(10);
RS485_ProcessBuffer();
}
}
void RS485_Initialize(void){
RS485_SET_RECEPTION();
uartStart(&UARTD1, &uart_cfg1);
rs485Data.state = RS485_GET_HEADER1;
chThdCreateStatic(wa_rs485, sizeof(wa_rs485), NORMALPRIO + 2, RS485_Tasks, NULL);
}
The problem that occurs is that after a couple of hours running (messages are received every 2 sec of about 20 bytes in average), it begins to be observed that a package (header, length, data, checksum) is not received immediately, but it seems to be in a queue. That is, I send a 20-byte message, receive 8, stays in a state of "waiting for the total" (RS485_GET_ALL_DATA), which occurs when another message is sent.
Then it is like the second message "pushes" the data that was queued and the entire frame is received.
Can you think of what the mistake might be?
Thanks! regards.