cancel
Showing results for 
Search instead for 
Did you mean: 

Receiving incorrect responses from STM32G071RB with 9600 baudrate

rtl
Associate II

Hello!

I am very new to STM32 boards and MCU-s overall. I am using a Nucleo-G071RB and I implemeted this Modbus library: /ceremcem/modbus_lib. For testing I use Comtest Pro. The code was working without issues on a Nucleo-F446RE. On Nucleo-F030R8 I am having the same issue as with G071RB.

When trying to read registers I get a CRC error most of the times. The error comes from incomplete responses. Some bytes get cut off and appear at the beginning of the next receive message. There are times where I am able to get several valid responses in a row, but the errors start happening again.

Here is the code that handles the data. dataHandler does it's job while data is coming in and if the data coming in ends, the idleHandler takes over and sends the data to processing.

void USART2_dataHandler(void)
{
	uint8_t buff[1];
	HAL_UART_Receive (&huart2, buff, 1, 400);
	modbus_lib_append_data(buff[0]); // append byte-by-byte
}
 
void USART2_idleHandler(void)
{
  modbus_lib_end_of_telegram();
}

The data processing is done by this code. First the incoming data is checked. I haven't had any errors with the incoming data.

void modbus_lib_end_of_telegram(){
    (void) 0; //// debugger: p/x *g_modbus_lib_received_telegram@g_modbus_lib_received_length
 
    // Check length 
    if (g_modbus_lib_received_length < MODBUS_LIB_MIN_TELEGRAM_SIZE){
        modbus_lib_send_error(MBUS_RESPONSE_NONE);
        return;
    }
 
    // Check CRC
    CRC_t expected = usMBCRC16(g_modbus_lib_received_telegram, g_modbus_lib_received_length-2);
    UCHAR got_low = g_modbus_lib_received_telegram[g_modbus_lib_received_length-2];
    UCHAR got_high = g_modbus_lib_received_telegram[g_modbus_lib_received_length-1];
    if ((expected.bytes.low != got_low) || (expected.bytes.high != got_high)){
        modbus_lib_send_error(MBUS_RESPONSE_NONE);
        return;
    } 
 
    // Check address 
    if (config->address != g_modbus_lib_received_telegram[0]){
        modbus_lib_send_error(MBUS_RESPONSE_NONE);
        return;
    }
 
    // Telegram is okay, call the relevant handler 
    // -------------------------------------------
    uint8_t outgoing_telegram[MODBUS_LIB_MAX_BUFFER];
    uint16_t oindex = 0; 
	uint16_t errorCode = 0;
	uint16_t noOfBytes = 0;
    outgoing_telegram[oindex++] = config->address; 
 
    volatile MbDataField start_addr, count, res, addr, value;
 
    switch (g_modbus_lib_received_telegram[1]){
 
        case MB_FUNC_READ_HOLDING_REGISTERS: 
            start_addr.bytes.high = g_modbus_lib_received_telegram[2];
            start_addr.bytes.low = g_modbus_lib_received_telegram[3];
            count.bytes.high = g_modbus_lib_received_telegram[4];
            count.bytes.low = g_modbus_lib_received_telegram[5];
 
            outgoing_telegram[oindex++] = g_modbus_lib_received_telegram[1];
            outgoing_telegram[oindex++] = count.value * 2;
 
            for (uint16_t i=0; i < count.value; i++){  
                res.value = modbus_lib_read_handler(start_addr.value + i + MB_ADDRESS_HOLDING_REGISTER_OFFSET);
                if (g_modbus_lib_exception_occurred){
                    g_modbus_lib_exception_occurred = 0; 
                    return; 
                }
                outgoing_telegram[oindex++] = res.bytes.high; 
                outgoing_telegram[oindex++] = res.bytes.low; 
            }
 
            CRC_t crc = usMBCRC16(outgoing_telegram, oindex);
            outgoing_telegram[oindex++] = crc.bytes.low; 
            outgoing_telegram[oindex++] = crc.bytes.high;
 
            modbus_lib_transport_write(outgoing_telegram, oindex);
            break;

Data out is done by this function:

int modbus_lib_transport_write(uint8_t *buffer, uint16_t length)
{
  HAL_UART_Transmit(&huart2, buffer, length, 1000);
  return 0;
}

UART connection is done by interrupts.

static void MX_USART2_UART_Init(void)
{
 
  /* USER CODE BEGIN USART2_Init 0 */
 
  /* USER CODE END USART2_Init 0 */
 
  /* USER CODE BEGIN USART2_Init 1 */
 
  /* USER CODE END USART2_Init 1 */
  huart2.Instance = USART2;
  huart2.Init.BaudRate = 9600;
  huart2.Init.WordLength = UART_WORDLENGTH_8B;
  huart2.Init.StopBits = UART_STOPBITS_1;
  huart2.Init.Parity = UART_PARITY_NONE;
  huart2.Init.Mode = UART_MODE_TX_RX;
  huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart2.Init.OverSampling = UART_OVERSAMPLING_16;
  huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
  huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
  huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  if (HAL_UART_Init(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART2_Init 2 */
  __HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE); // enable receive interrupts
  __HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE); // enable idle line detection
  /* USER CODE END USART2_Init 2 */
 
}

Here are some examples of the reponses I get:

Data out:
[001d] [003d] [002d] [088d] [000d] [001d] [004d] [097d]
 
Expected data in:
[001d] [003d] [002d] [000d] [000d] [184d] [068d] 
 
 
Data in 1:
[001d] [003d] [002d] [000d] [000d] [184d] [068d]  (valid)
 
Data in 2:
[001d] 
 
Data in 3:
[001d] [003d] [002d] [000d] [000d] [184d] 
 
Data in 4:
[001d] [003d] [002d] [000d] 
 
Data in 5:
[000d] [184d] [068d] [001d] [003d] [002d] [000d] [000d] [184d] [068d]

Changing baudrate from 9600 to 19200 fixes the issue, but I need to be able to use 9600 also. What could be the problem?

2 REPLIES 2

Toggle a bit in the IDLE callback, and observe it using LA/oscilloscope together with the Rx line.

JW

DangerousDave
Associate

I am, by no means, an expert on this but I note you have said "changing to 19.2k fixes the problem".

Have a look at how the end of packet is detected. There is a minimum number of bit times for baud rates to 9600, but I think from memory this changes to a fixed period for 19.2 and greater baud rates. Could it be that the software is using too short a inter-message period for end of packet detection?