cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F404VG USART 9 bit communication

Tcubells
Associate II

I am working on a system where I send HEX commands through the USART3 of the STM32F407VG to the COM machine with its corresponding PC.

The particularity of this communication is that in each sending of frames, the first byte of the frame must be sent with the wake up bit activated. (9 bits - 9n1), the rest of the bytes must be sent with the wake up deactivated (8 bits - 8N1)

I have used this code in the CUBE ID but it doesn't work

    void EnviarComando(uint8_t cmdEnTx[], int lenEnTx)
      {
                    int InterByte = 5; // Tiempo Interbyte
           int i = 1;
        /*Envío del primer byte (address) en 9 bits */
           huart3.Init.WordLength = UART_WORDLENGTH_9B;
        
           HAL_UART_Transmit(&huart3, cmdEnTx, 1, InterByte);
        /*Envío del resto de bytes en 8 bits */
        huart3.Init.WordLength = UART_WORDLENGTH_8B;
        
        while (i< lenEnTx)
        {
         
        HAL_UART_Transmit(&huart3, &cmdEnTx[i], 1, InterByte);
        i++;
        
        }
      }

The initial configuration of the USART 3 is this:

    static void MX_USART3_UART_Init(void)
    {
     
      huart3.Instance = USART3;
      huart3.Init.BaudRate = 19200;
      huart3.Init.WordLength = UART_WORDLENGTH_8B;
      huart3.Init.StopBits = UART_STOPBITS_1;
      huart3.Init.Parity = UART_PARITY_NONE;
      huart3.Init.Mode = UART_MODE_TX_RX;
      huart3.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart3.Init.OverSampling = UART_OVERSAMPLING_16;
      if (HAL_UART_Init(&huart3) != HAL_OK)
      {
        Error_Handler();
      }
     
    } 

The same I did with Arduino Mega and it works perfectly acting on the bits of the UART register.

This is the code I used for the Mega 2560

    void sendCommand(byte temp[], int len) //Envío de trama a EGM 
    {
      UCSR1B = 0b10011101; //9 bits on 
      serEgm.write(temp[0]); //envía primer byte( address máquina )
      delay(5); //Default 1
      UCSR1B = 0b10011100; //9 bits off
      for (int i=1; i<len;i++)
      {
        serEgm.write(temp[i]); //envía el resto de bytes de la trama
        delay(5);//Default 1
      }
    } 

I am blocked with this matter, so I appreciate in advance any ideas or contributions that allow me to solve this problem

Regards

11 REPLIES 11

As in the Arduino code you write directly to the mcu's UART peripheral registers (UCSR1B), here, you need to write to the UART registers. Writing to the init struct members does nothing, it's just a variable in memory.

First, read the USART chapter in RM. The number of bits per frame in 'F4 is governed by USART_CR1.M bit, but you must be sure all transfers are finished if you want to modify it. Then, you do

USART3->CR1 &= ~USART_CR1_M; // set to 8-bit

or

USART3->CR1 |= USART_CR1_M; // set to 9-bit

JW

TDK
Guru

Calling HAL_UART_Init after you change the value in huart3.Init.WordLength will probably also work.

Switching between 9 bits and 8 bits is an abnormal setup. Are you sure that's what is required?

If you feel a post has answered your question, please click "Accept as Solution".
Tcubells
Associate II

Yes, this is indicated in the specifications of this protocol

Watch

In wakeup mode, the host sets the 9th (wakeup) bit each time it sends the first byte of a message to the gaming machine. For all additional bytes in the message, this bit is cleared. Gaming machines use the wakeup bit to determine whether the received byte is the first byte of a new message or an additional byte of the current message. Gaming machines clear the wakeup bit for all bytes when responding to the host, except when reporting a loop break condition (refer to 4.2 Loop Break Indication on page 4-1). Note: For UARTs / DUARTs that do not directly support wakeup mode, the parity bit can be used in place of the wakeup bit.

That's permanently 9-bit protocol, it's just the 9th bit's value which is supposed to change.

Read the venerable Intel 8051's manual, this is called Multiprocessor Communication there.

JW

PS. TDK, well spotted.

PS2. And this is also exactly what UCRSnB does in AVR:

  • Bit 0 – TXB8n: Transmit Data Bit 8 - TXB8n is the ninth data bit in the character to be transmitted when operating with serial frames with nine data bits.
  •  Bit 2 – UCSZn2: Character Size - The UCSZn2 bits combined with the UCSZn1:0 bit in UCSRnC sets the number of data bits (Character SiZe) in a frame the Receiver and Transmitter use.
TDK
Guru

Yup. There's still a stop bit after the wakeup bit.

If you feel a post has answered your question, please click "Accept as Solution".
Tcubells
Associate II

Except for the initial example that I have shown you in Arduino (it is not my code, it was a contribution that was suggested to me in a forum), I have never worked with 9 bits, but I think the specifications do not establish it as you say, they are always 8 data bits, the ninth bit is only set to identify the first byte of the sent frame.

Communication between the host and gaming machines occurs through a serial data link operating at 19.2 KBaud in a "wakeup" mode. The 11-bit data packet consists of one start bit, eight data bits, a ninth ‘wakeup’ bit, and one stop bit.

It's SET on the first transaction and RESET on later transactions. It is present in all transactions.

*> The 11-bit data packet consists of one start bit, eight data bits, a
ninth ‘wakeup’ bit, and one stop bit. *
If you feel a post has answered your question, please click "Accept as Solution".
Tcubells
Associate II

Are you suggesting that the USART3 should be set to 9 bit and only disable the ninth bit for sending after the first byte?

I have tested the statements waclawek.jan has sent me

USART3-> CR1 & = ~ USART_CR1_M; // set to 8-bit and USART3-> CR1 | = USART_CR1_M; // set to 9-bit

It has not worked, perhaps because in that test the USART was set to 8 bits.

I will try again setting the USART to 9 bit

As I've said, this mode of usage originates in 8051. The standard you quoted from originates at a company which indeed used 8051s in their products.

In STM32, you need to set USART to 9-bit mode, and write 16-bit words to USART->DR, with 9th bit set as the protocol requires. I don't know if Cube is suitable for this, I don't use Cube.

JW