cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 UART using interrupt transmitts by byte or data elements array?

ManhPham
Associate III

Hello everyone,

I sent the data by UART with command:

uint16_t Size[8];

HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

Question: Size on this command is 16 bytes or Size is 8 data elements of array?

1 ACCEPTED SOLUTION

Accepted Solutions

@Andrew Neil wrote:


The setting is based on the current configuration of the UART


It's tested at runtime:

    /* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (const uint16_t *) pData;
    }
    else
    {
      pdata8bits  = pData;
      pdata16bits = NULL;
    }

this is where it makes the decision to treat the buffer as 8 or 16 bits.

 


@Andrew Neil wrote:
 whether it is sending 9-bit data frames, or 8-bit data frames.

Clearly, you can't fill a 9-bit data frame from a single 8-bit buffer entry - you need something at least 9 bits.

C doesn't provide a 9-bit datatype - the next available option after 8 bits (single byte) is 16 bits (two bytes).

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

View solution in original post

21 REPLIES 21
Andrew Neil
Super User

See the documentation:

 

/**
  * @brief Send an amount of data in interrupt mode.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the sent data is handled as a set of u16. In this case, Size must indicate the number
  *         of u16 provided through pData.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         address of user data buffer containing data to be sent, should be aligned on a half word frontier (16 bits)
  *         (as sent data will be handled using u16 pointer cast). Depending on compilation chain,
  *         use of specific alignment compilation directives or pragmas might be required
  *         to ensure proper alignment for pData.
  *  huart UART handle.
  *  pData Pointer to data buffer (u8 or u16 data elements).
  *  Size  Amount of data elements (u8 or u16) to be sent.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, const uint8_t *pData, uint16_t Size)

 

See also the User Manual for the HAL; eg,

https://www.st.com/resource/en/user_manual/um2217-description-of-stm32h7-hal-and-lowlayer-drivers-stmicroelectronics.pdf#page=1876

 

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

I read this but I fill data elements, the received data is lost

I fill the byte, I received all data

So this document is not clearly, Size must be 2*data element arry (u16) or 4*data element arry (u32), right?

As it says, you use u16 when the UART frame's data payload size is larger than 8 bits - therefore can't be filled using a single u8 item.

So, if you are receiving complete data byte-by-byte, that means your data must fit in 8 bit payloads - so you should not be using a u16 buffer.

Show a minimal but complete complete example which illustrates your issue.

PS:

See also the device Reference Manual - see how the parity and extra data payload bits are handled...

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

My example:

uint16_t tx_data[7];

HAL_UART_Transmit_IT(&huart1, tx_data, 7);

or

HAL_UART_Transmit_IT(&huart1, tx_data, 14);

Which transmit command is correct?

 

that's not a complete example - is it?

 


@ManhPham wrote:

Which transmit command is correct?


As the documentation says, It depends on how you UART is configured - 8-bit (or smaller) data, or 9-bit data.

For 9-bit data, you need two buffer bytes for each transmitted UART Frame:

        |<-------------------------------------u16------------------------------------->|
+---------------------------------------+---------------------------------------+
Buffer: | -- : -- : -- : -- : -- : -- : -- : b8 | b7 : b6 : b5 : b4 : b3 : b2 : b1 : b0 |
+---------------------------------------+---------------------------------------+

 

PS - disclaimer: I don't know if that's the right bit/byte ordering - but you see how it takes two buffer bytes to contain the 9-bit payload?

 

PPS:

It's exactly the same when you use the non-interrupt method:

/**
  * @brief Send an amount of data in blocking mode.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         the sent data is handled as a set of u16. In this case, Size must indicate the number
  *         of u16 provided through pData.
  * @note   When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
  *         address of user data buffer containing data to be sent, should be aligned on a half word frontier (16 bits)
  *         (as sent data will be handled using u16 pointer cast). Depending on compilation chain,
  *         use of specific alignment compilation directives or pragmas might be required
  *         to ensure proper alignment for pData.
  * @PAram huart   UART handle.
  * @PAram pData   Pointer to data buffer (u8 or u16 data elements).
  * @PAram Size    Amount of data elements (u8 or u16) to be sent.
  * @PAram Timeout Timeout duration.
  * @retval HAL status
  */

 

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

AndrewNeil_0-1727079333199.png

 

AndrewNeil_1-1727079789001.png

 

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.
Techn
Senior III

By default it is uint8_t which is transmitted via uart. If you want to send integers, convert them to uint8_t and send . in the receiving side you have to take care to assemble it again. Does it answer your question?

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

@Techn wrote:

By default it is uint8_t ?


No.

The setting is based on the current configuration of the UART - whether it is sending 9-bit data frames, or 8-bit data frames.

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

@Andrew Neil wrote:


The setting is based on the current configuration of the UART


It's tested at runtime:

    /* In case of 9bits/No Parity transfer, pData needs to be handled as a uint16_t pointer */
    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
    {
      pdata8bits  = NULL;
      pdata16bits = (const uint16_t *) pData;
    }
    else
    {
      pdata8bits  = pData;
      pdata16bits = NULL;
    }

this is where it makes the decision to treat the buffer as 8 or 16 bits.

 


@Andrew Neil wrote:
 whether it is sending 9-bit data frames, or 8-bit data frames.

Clearly, you can't fill a 9-bit data frame from a single 8-bit buffer entry - you need something at least 9 bits.

C doesn't provide a 9-bit datatype - the next available option after 8 bits (single byte) is 16 bits (two bytes).

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.