@@ -153,7 +153,6 @@ typedef struct {
153153 bool tx_waiting_fifo ; /*!< this flag indicates that some task is waiting for FIFO empty interrupt, used to send all data without any data buffer*/
154154 uint8_t * tx_ptr ; /*!< TX data pointer to push to FIFO in TX buffer mode*/
155155 uart_tx_data_t * tx_head ; /*!< TX data pointer to head of the current buffer in TX ring buffer*/
156- uint32_t trans_total_remaining_len ; /*!< Remaining data length of the current processing transaction in TX ring buffer*/
157156 uint32_t trans_chunk_remaining_len ; /*!< Remaining data length of the current processing chunk of the transaction in TX ring buffer*/
158157 uint8_t tx_brk_flg ; /*!< Flag to indicate to send a break signal in the end of the item sending procedure */
159158 uint8_t tx_brk_len ; /*!< TX break signal cycle length/number */
@@ -1248,56 +1247,48 @@ static void UART_ISR_ATTR uart_rx_intr_handler_default(void *param)
12481247 //That would cause a watch_dog reset because empty interrupt happens so often.
12491248 //Although this is a loop in ISR, this loop will execute at most 128 turns.
12501249 while (tx_fifo_rem ) {
1251- if (p_uart -> trans_total_remaining_len == 0 || p_uart -> tx_ptr == NULL || p_uart -> trans_chunk_remaining_len == 0 ) {
1250+ if (p_uart -> tx_ptr == NULL || p_uart -> trans_chunk_remaining_len == 0 ) {
12521251 size_t size ;
12531252 p_uart -> tx_head = (uart_tx_data_t * ) xRingbufferReceiveFromISR (p_uart -> tx_ring_buf , & size );
12541253 if (p_uart -> tx_head ) {
1255- //The first item is the data description
1256- //Get the first item to get the data information
1257- if (p_uart -> trans_total_remaining_len == 0 ) {
1258- p_uart -> tx_ptr = NULL ;
1259- p_uart -> trans_total_remaining_len = p_uart -> tx_head -> tx_data .size ;
1260- if (p_uart -> tx_head -> type == UART_DATA_BREAK ) {
1261- p_uart -> tx_brk_flg = 1 ;
1262- p_uart -> tx_brk_len = p_uart -> tx_head -> tx_data .brk_len ;
1263- }
1264- //We have saved the data description from the 1st item, return buffer.
1265- vRingbufferReturnItemFromISR (p_uart -> tx_ring_buf , p_uart -> tx_head , & HPTaskAwoken );
1266- need_yield |= (HPTaskAwoken == pdTRUE );
1267- } else if (p_uart -> tx_ptr == NULL ) {
1268- //Update the TX item pointer, we will need this to return item to buffer.
1269- p_uart -> tx_ptr = (uint8_t * )p_uart -> tx_head ;
1270- en_tx_flg = true;
1271- p_uart -> trans_chunk_remaining_len = size ;
1254+ // Atomic item: header + data combined
1255+ // Extract break info if present
1256+ if (p_uart -> tx_head -> type == UART_DATA_BREAK ) {
1257+ p_uart -> tx_brk_flg = 1 ;
1258+ p_uart -> tx_brk_len = p_uart -> tx_head -> tx_data .brk_len ;
12721259 }
1260+ // Data starts immediately after header
1261+ p_uart -> tx_ptr = p_uart -> tx_head -> tx_data .data ;
1262+ p_uart -> trans_chunk_remaining_len = p_uart -> tx_head -> tx_data .size ;
1263+ en_tx_flg = true;
12731264 } else {
12741265 //Can not get data from ring buffer, return;
12751266 break ;
12761267 }
12771268 }
1278- if (p_uart -> trans_total_remaining_len > 0 && p_uart -> tx_ptr && p_uart -> trans_chunk_remaining_len > 0 ) {
1269+ if (p_uart -> tx_ptr && p_uart -> trans_chunk_remaining_len > 0 ) {
12791270 // To fill the TX FIFO.
12801271 uint32_t send_len = uart_enable_tx_write_fifo (uart_num , (const uint8_t * ) p_uart -> tx_ptr ,
12811272 MIN (p_uart -> trans_chunk_remaining_len , tx_fifo_rem ));
12821273 p_uart -> tx_ptr += send_len ;
1283- p_uart -> trans_total_remaining_len -= send_len ;
12841274 p_uart -> trans_chunk_remaining_len -= send_len ;
12851275 tx_fifo_rem -= send_len ;
12861276 if (p_uart -> trans_chunk_remaining_len == 0 ) {
1287- //Return item to ring buffer.
1277+ //Return atomic item to ring buffer.
12881278 vRingbufferReturnItemFromISR (p_uart -> tx_ring_buf , p_uart -> tx_head , & HPTaskAwoken );
12891279 need_yield |= (HPTaskAwoken == pdTRUE );
12901280 p_uart -> tx_head = NULL ;
12911281 p_uart -> tx_ptr = NULL ;
12921282 //Sending item done, now we need to send break if there is a record.
12931283 //Set TX break signal after FIFO is empty
1294- if (p_uart -> trans_total_remaining_len == 0 && p_uart -> tx_brk_flg == 1 ) {
1284+ if (p_uart -> tx_brk_flg == 1 ) {
12951285 uart_hal_clr_intsts_mask (& (uart_context [uart_num ].hal ), UART_INTR_TX_BRK_DONE );
12961286 UART_ENTER_CRITICAL_ISR (& (uart_context [uart_num ].spinlock ));
12971287 uart_hal_tx_break (& (uart_context [uart_num ].hal ), p_uart -> tx_brk_len );
12981288 uart_hal_ena_intr_mask (& (uart_context [uart_num ].hal ), UART_INTR_TX_BRK_DONE );
12991289 UART_EXIT_CRITICAL_ISR (& (uart_context [uart_num ].spinlock ));
13001290 p_uart -> tx_waiting_brk = 1 ;
1291+ p_uart -> tx_brk_flg = 0 ;
13011292 //do not enable TX empty interrupt
13021293 en_tx_flg = false;
13031294 } else {
@@ -1634,26 +1625,51 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool
16341625#endif
16351626 p_uart_obj [uart_num ]-> coll_det_flg = false;
16361627 if (p_uart_obj [uart_num ]-> tx_buf_size > 0 ) {
1637- int offset = 0 ;
1638- uart_tx_data_t evt ;
1639- evt .tx_data .size = size ;
1640- evt .tx_data .brk_len = brk_len ;
1641- if (brk_en ) {
1642- evt .type = UART_DATA_BREAK ;
1643- } else {
1644- evt .type = UART_DATA ;
1645- }
1646- xRingbufferSend (p_uart_obj [uart_num ]-> tx_ring_buf , (void * ) & evt , sizeof (uart_tx_data_t ), portMAX_DELAY );
1628+ const char * offset = src ;
16471629 while (size > 0 ) {
1630+
1631+ size_t acquire_size = size + sizeof (uart_tx_data_t ); // Optimally, fit all data plus description in one round
1632+
1633+ // Fall back if not enough space in ring buffer
16481634 size_t free_size = xRingbufferGetCurFreeSize (p_uart_obj [uart_num ]-> tx_ring_buf );
1649- size_t send_size = MIN (size , free_size );
1650- if (send_size > 0 ) {
1651- xRingbufferSend (p_uart_obj [uart_num ]-> tx_ring_buf , (void * )(src + offset ), send_size , portMAX_DELAY );
1652- size -= send_size ;
1653- offset += send_size ;
1654- uart_enable_tx_intr (uart_num , 1 , UART_THRESHOLD_NUM (uart_num , UART_EMPTY_THRESH_DEFAULT ));
1635+
1636+ // If there is enough space for data description and 'some' data, send as much as possible in one round that
1637+ // is likely to fit in the ring buffer without blocking
1638+ if (free_size > sizeof (uart_tx_data_t )) {
1639+ acquire_size = MIN (acquire_size , free_size );
16551640 }
1641+
1642+ // Limit an item to a quarter of the ring buffer size, if we allow a full item size the ring buffer
1643+ // needs to completely empty before we can send another large item, which can cause stalls.
1644+ // also makes sure that we dont try to add an item larger than the ring buffer itself
1645+ acquire_size = MIN (acquire_size , xRingbufferGetMaxItemSize (p_uart_obj [uart_num ]-> tx_ring_buf ) / 4 );
1646+
1647+ // Accuire space for data description and data chunk, this gives a strong
1648+ // guarantee that data chunk can be copied in one go
1649+ uart_tx_data_t * tx_data = NULL ;
1650+ xRingbufferSendAcquire (p_uart_obj [uart_num ]-> tx_ring_buf , (void * * )& tx_data , acquire_size , portMAX_DELAY );
1651+
1652+ size_t send_size = acquire_size - sizeof (uart_tx_data_t );
1653+
1654+ // Check if this is the last chunk and we need to attach break
1655+ bool is_last_chunk = (send_size >= size );
1656+
1657+ * tx_data = (uart_tx_data_t ) {
1658+ .tx_data = {
1659+ .size = send_size ,
1660+ .brk_len = (is_last_chunk && brk_en ) ? brk_len : 0
1661+ },
1662+ .type = (is_last_chunk && brk_en ) ? UART_DATA_BREAK : UART_DATA ,
1663+ };
1664+
1665+ memcpy (tx_data -> tx_data .data , offset , send_size );
1666+ xRingbufferSendComplete (p_uart_obj [uart_num ]-> tx_ring_buf , tx_data );
1667+
1668+ size -= send_size ;
1669+ offset += send_size ;
16561670 }
1671+
1672+ uart_enable_tx_intr (uart_num , 1 , UART_THRESHOLD_NUM (uart_num , UART_EMPTY_THRESH_DEFAULT ));
16571673 } else {
16581674 while (size ) {
16591675 //semaphore for tx_fifo available
@@ -1665,6 +1681,8 @@ static int uart_tx_all(uart_port_t uart_num, const char *src, size_t size, bool
16651681 }
16661682 size -= sent ;
16671683 src += sent ;
1684+ } else {
1685+ break ;
16681686 }
16691687 }
16701688 if (brk_en ) {
@@ -2024,7 +2042,6 @@ esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_b
20242042 p_uart_obj [uart_num ]-> event_queue_size = event_queue_size ;
20252043 p_uart_obj [uart_num ]-> tx_ptr = NULL ;
20262044 p_uart_obj [uart_num ]-> tx_head = NULL ;
2027- p_uart_obj [uart_num ]-> trans_total_remaining_len = 0 ;
20282045 p_uart_obj [uart_num ]-> trans_chunk_remaining_len = 0 ;
20292046 p_uart_obj [uart_num ]-> tx_brk_flg = 0 ;
20302047 p_uart_obj [uart_num ]-> tx_brk_len = 0 ;
0 commit comments