Skip to main content
Tcubells
Associate
November 20, 2020
Question

STM32F404VG USART 9 bit communication

  • November 20, 2020
  • 11 replies
  • 3357 views

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

This topic has been closed for replies.

11 replies

waclawek.jan
Super User
November 20, 2020

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
November 20, 2020

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
TcubellsAuthor
Associate
November 20, 2020

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.

waclawek.jan
Super User
November 20, 2020

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
November 20, 2020

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
TcubellsAuthor
Associate
November 20, 2020

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.

TDK
November 20, 2020
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
TcubellsAuthor
Associate
November 20, 2020

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

waclawek.jan
Super User
November 20, 2020

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

Pavel A.
November 21, 2020

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

A PC likely will have a problem with 9-bit characters where the 9th bit is not used for parity or set permanently to 0/1 (aka "mark"/"space").

Unless there is a specialized UART adapter on the PC side, such as FTDI in "advanced" mode or another microcontroller with USB interface.

-- pa

Tcubells
TcubellsAuthor
Associate
November 23, 2020

Hello everyone

I've finally gotten it to work,

I have followed the suggestion from waclawek.jan to enable 9 bits

The problem was how to insert these statements in my code with the HAL library format.

Finally I have found the way to do it and with the help of the reference manual I have added two more sentences, activate the parity control (PCE - bit 10) and activate the Wake Up (WAKE - bit 11)

huart3.Instance-> CR1 | = USART_CR1_M

huart3.Instance-> CR1 | = USART_CR1_WAKE

huart3.Instance-> CR1 | = USART_CR1_PCE

With this temporary configuration I can send the first byte of the frame as recommended by the specifications of the protocol I use, for the rest of the frame you just have to disable wake up and parity control.

Initially the USART must be set to 8 bits, once it makes the first activation to 9 bits, only when this function is called will it activate the WAKE UP (11) and Parity Control (10) bits, the rest of the program flow will work with these bits off.

I tried setting to 9 bit from the start and it doesn't work, I don't know why.

I attach the final code of the function that is working

Thank you all

void EnviarComando(uint8_t cmdEnTx[], int lenEnTx)
		{
 
 int InterByte = 1;//Tiempo Interbyte
			 int i = 1;
			 
				/*Envío del primer byte (address) en 9 bits M=1; WakeUP=1; PCE=1*/
 
			 huart3.Instance->CR1 |= USART_CR1_M; // 9 bits on
			 huart3.Instance->CR1 |= USART_CR1_PCE; // parity control enable
			 huart3.Instance->CR1 |= USART_CR1_WAKE; // wake up on*/
 
 
				HAL_UART_Transmit(&huart3, (uint16_t*)&cmdEnTx[0], 1, InterByte);
 
 
 
				/*Envío del resto de bytes WakeUp=0 and PCE=0 */
 
				huart3.Instance->CR1 &= ~USART_CR1_PCE; // parity control disable
				huart3.Instance->CR1 &= ~USART_CR1_WAKE; // wake up off*/
 
 
				while (i< lenEnTx)
				{
				HAL_UART_Transmit(&huart3, &cmdEnTx[i], 1, InterByte);
				i++;
				}
		}