Driver UART problems

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: barthess, RoccoMarco

Suky_mtch
Posts: 5
Joined: Wed Jan 29, 2020 9:55 pm

Driver UART problems

Postby Suky_mtch » Wed Jan 29, 2020 10:32 pm

Hi everyone,
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.

User avatar
Giovanni
Site Admin
Posts: 13125
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 769 times
Been thanked: 653 times
Contact:

Re: Driver UART problems

Postby Giovanni » Thu Jan 30, 2020 8:22 am

Hi,

Are you handling communication errors? those cause bytes to not be received so you wait for 20 chars but only get 19, the 20th will be the first of the next message and that is the delay you observe.

Probably you just need robust error handling using a state machine, timeouts etc.

Giovanni

Suky_mtch
Posts: 5
Joined: Wed Jan 29, 2020 9:55 pm

Re: Driver UART problems

Postby Suky_mtch » Thu Jan 30, 2020 1:45 pm

Hi,
No, I don't handle errors. Because no bytes are really lost, but they are queued and pushed when they receive the next frame.
Can it happen that the DMA does not call the callback function for any reason?

Regards

User avatar
Giovanni
Site Admin
Posts: 13125
Joined: Wed May 27, 2009 8:48 am
Location: Salerno, Italy
Has thanked: 769 times
Been thanked: 653 times
Contact:

Re: Driver UART problems

Postby Giovanni » Thu Jan 30, 2020 1:52 pm

The driver would be stuck without DMA IRQ.

Giovanni

Suky_mtch
Posts: 5
Joined: Wed Jan 29, 2020 9:55 pm

Re: Driver UART problems

Postby Suky_mtch » Mon Feb 03, 2020 5:23 pm

Hi,

I solved it by stopping and restarting reception after each transmission:

Code: Select all

void RS485_PutArray(uint8_t *ptrData, uint16_t lenght){
   uint8_t delay;
   UARTDriver *uartp;
   USART_TypeDef *u;

   uartp = &UARTD1;
   u = uartp->usart;
   u->CR1 = u->CR1 & (~USART_CR1_RE);
   dmaStreamDisable(uartp->dmarx);
    RS485_PROTOCOLS_SET_TRANSMISSION();
   chThdSleepMicroseconds(100);
   uartStartSend(uartp, lenght, (const void *)ptrData);
   return;
}

static void RS485_TxEnd(UARTDriver *uartp){
   uint32_t mode;
   USART_TypeDef *u;

   uartp->rxstate = UART_RX_IDLE;
   mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_CIRC | STM32_DMA_CR_TCIE;
   dmaStreamSetMemory0(uartp->dmarx, &uartp->rxbuf);
   dmaStreamSetTransactionSize(uartp->dmarx, 1);
   dmaStreamSetMode(uartp->dmarx, uartp->dmamode | mode);

   RS485_PROTOCOLS_SET_RECEPTION();
   dmaStreamEnable(uartp->dmarx);
   u = uartp->usart;
   u->CR1 = u->CR1 | USART_CR1_RE;
}



Regards


Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 6 guests