cancel
Showing results for 
Search instead for 
Did you mean: 

USART receiving 8-bit data with parity

I am supposed to be receiving 8-bit data with even parity.  The blocks are defined with a header of 'F0', this is S.Bus data if anyone knows that that is.  I setup a simple program that just does receive data.  I get data but nowhere does it show an 'F0'.  Am I supposed to use 'LL_USART_ReceiveData8' or 'LL_USART_ReceiveData9' to read this data?  Is the parity supposed to be read with the data and discarded?  It's not at all clear how the parity is handled. 

1 ACCEPTED SOLUTION

Accepted Solutions

You are correct.  I had the pin inverted at first, then re-read the documention, and set it to non-inverted. You try to make sense of this:

Bit 16 RXINV: RX pin active level inversion
This bit is set and cleared by software.
0: RX pin signal works using the standard logic levels (VDD =1/idle, Gnd=0/mark)
1: RX pin signal values are inverted (VDD =0/mark, Gnd=1/idle).

Anyway, I misread this documentation.   The 9-bit data is correct with parity.  I don't know what you mean by "2 parity" bits.  The format is 8-bit data, parity and 2 stop bits.  

It works now, at least I get the "0F" where I expect it.  I need to check the number if IDLEs I got. 

Thanks for sticking with me though this. 

View solution in original post

22 REPLIES 22
SofLit
ST Employee

Hello,

You posted your thread in STM32CubeIDE (MCUs) which is not the right forum board. I moved it to STM32 MCUs Products.

Could you please also provide the MCU part number you are using?

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.

Sorry.  I am using STM32G030C6.  My code is 

 

    while (1)
    {
        int i = 0;
        while(i < 500)
        {
            if(LL_USART_IsActiveFlag_FE(USART2))
            {
                LL_USART_ClearFlag_FE(USART2);
                FE++;
            }
            if(LL_USART_IsActiveFlag_PE(USART2))
            {
                LL_USART_ClearFlag_PE(USART2);
                PE++;
            }
            if(LL_USART_IsActiveFlag_NE(USART2))
            {
                LL_USART_ClearFlag_NE(USART2);
                NE++;
            }
            if(LL_USART_IsActiveFlag_ORE(USART2))
            {
                LL_USART_ClearFlag_ORE(USART2);
                ORE++;
            }
             if(LL_USART_IsActiveFlag_IDLE(USART2))
            {
                LL_USART_ClearFlag_IDLE(USART2);
                IDLE++;
            }
           if(LL_USART_IsActiveFlag_RXNE_RXFNE(USART2))
            {
//                array[i] = LL_USART_ReceiveData8(USART2);
                array[i] = LL_USART_ReceiveData9(USART2);
                i++;
            }
        }
        while(1) {};
    }
Ozone
Lead II

> I get data but nowhere does it show an 'F0'.  

I had to read it up, to be honest.
But yes, you should read the header value. Although the first hit I found suggests it is "0x0F", and not "0xF0". 

Additionally, S.Bus requires 2 stop bits, and the uncommon baudrate of 100.000 bps.
Perhaps you can share the UART init code.

> Is the parity supposed to be read with the data and discarded?  It's not at all clear how the parity is handled.

If the received parity value doesn't match, the PE error should trigger -> a.k.a. "parity error". In this case, the RD register values is usually not updated, and invalid.

Here is the init code.  The funny thing is that I do not see any 'IDLE"s.  I should use these to delimit the blocks. 

 

 LL_USART_InitTypeDef USART_InitStruct = {0};

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);

  LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
  /**USART2 GPIO Configuration
  PA2   ------> USART2_TX
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_2;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_1;
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN USART2_Init 1 */

  /* USER CODE END USART2_Init 1 */
  USART_InitStruct.PrescalerValue = LL_USART_PRESCALER_DIV1;
  USART_InitStruct.BaudRate = 100000;
  USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_9B;
  USART_InitStruct.StopBits = LL_USART_STOPBITS_2;
  USART_InitStruct.Parity = LL_USART_PARITY_EVEN;
  USART_InitStruct.TransferDirection = LL_USART_DIRECTION_RX;
  USART_InitStruct.OverSampling = LL_USART_OVERSAMPLING_16;
  LL_USART_Init(USART2, &USART_InitStruct);
  LL_USART_DisableDMADeactOnRxErr(USART2);
  LL_USART_ConfigHalfDuplexMode(USART2);

  /* USER CODE BEGIN WKUPType USART2 */

  /* USER CODE END WKUPType USART2 */

  LL_USART_Enable(USART2);

  /* Polling USART2 initialisation */
  while((!(LL_USART_IsActiveFlag_TEACK(USART2))) || (!(LL_USART_IsActiveFlag_REACK(USART2))))
  {
  }

 

 Also, I enable the receive bit just before entering the loop. I should point out that I am getting a lot of parity errors (250) and framing errors (147).  These are pretty consistent run to run. 

Is this all the init code ?
Being accustomed to either SPL code or direct access, the init for PA2 looks strange.  What alternate function (many pins of F3/F4 MCUs I frequently use have 7 alternate functions). And pull-up & OD at the same time ?

But most important, is there no Rx pin initialisation ?

If in doubt, I always check the respective reference manual section, and observe the peripheral register settings in a debugger.

Yes, this is all init code as generated by MX.  For some reason, MX treats alternate function inputs as outputs.  I don't know what you mean by Rx pin initialization.  If you look at the code, the last entry to GPIO init function is the alternate function code of 1.  

@Robert Ritchey,

> I get data but nowhere does it show an 'F0'.

And what does it show?

Is there any external pullup? The internal is nominally 40kOhm, it may not be enough to produce clean edges.

@Ozone,

The UART is here set to HalfDuplex, and in that case it uses the Tx pin as the single IO pin.

JW

 

 

> The UART is here set to HalfDuplex, and in that case it uses the Tx pin as the single IO pin.

I suspected that much.
But I have never used such half-duplex UART mode, especially not on the C0 devices.

> I am using STM32G030C6.  My code is  ...

If you debug the code, can you see any of the error counters go up ?


And on a related note ...
Serial communication, including the UART, can be tricky to debug.
The debugger might clear receive flags, and thus change the code execution path.