Skip to main content
Explorer
November 28, 2024
Solved

USART receiving 8-bit data with parity

  • November 28, 2024
  • 6 replies
  • 3843 views

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. 

    This topic has been closed for replies.
    Best answer by Robert Ritchey

    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. 

    6 replies

    Technical Moderator
    November 29, 2024

    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?

    Explorer
    November 29, 2024

    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) {};
     }
    Explorer
    December 2, 2024

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

    Explorer
    November 29, 2024

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

    Explorer
    November 29, 2024

    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. 

    Explorer
    December 1, 2024

    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.

    Super User
    December 2, 2024

    @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

     

     

    Explorer
    December 2, 2024

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

    Super User
    December 2, 2024

    Read out and check/post the UART registers content. Check the real system clock, too, and by that I don't mean just to look at what you've clicked in CubeMX, but actually measure it in some way. One good way to do that may be to transmit some pattern e.g. 0b0101010101 through the UART (with disconnected other transmitter of course), and observe using oscilloscope/LA.

    JW

    Explorer
    December 2, 2024

    I checked the clock, it is 64MHz.  I did it by configuring a timer channel to divide the system clock by 16 and output a square wave.  It showed a 250nsec period, or 16 MHz.  I also captured the USART registers.  They look fine but I am posting them. 

    Explorer
    December 3, 2024

    Have you observed the s-bus signal on a scope, and compared with the spec ?
    I think a logic analyser would do as well, AFAIK sigrok/pulseview even support protocol interpreters.

    Explorer
    December 3, 2024

    By the way, here are some of the values I have captured.  You can see its repeating, just not the right values.  Also, do either of you know if the IDLE bit is set when it's not set to interrupt?  It doesn't say.  I keep expecting to see an IDLE when I am polling but it does not seem to get set. 

    Super User
    December 4, 2024

    Try to transmit and observe the signal you've transmitted.

    JW

    Explorer
    December 4, 2024

    Thanks for stick with me though this.  The data was inverted.  I misread the documentation.  It's confusing as to what the USART expects.  

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