@@ -379,27 +379,89 @@ STATIC bool uart_tx_wait(pyb_uart_obj_t *self, uint32_t timeout) {
379379 }
380380}
381381
382- STATIC HAL_StatusTypeDef uart_tx_data (pyb_uart_obj_t * self , uint8_t * data , uint16_t len ) {
382+ // Waits at most timeout milliseconds for UART flag to be set.
383+ // Returns true if flag is/was set, false on timeout.
384+ STATIC bool uart_wait_flag_set (pyb_uart_obj_t * self , uint32_t flag , uint32_t timeout ) {
385+ // Note: we don't use WFI to idle in this loop because UART tx doesn't generate
386+ // an interrupt and the flag can be set quickly if the baudrate is large.
387+ uint32_t start = HAL_GetTick ();
388+ for (;;) {
389+ if (__HAL_UART_GET_FLAG (& self -> uart , flag )) {
390+ return true;
391+ }
392+ if (timeout == 0 || HAL_GetTick () - start >= timeout ) {
393+ return false; // timeout
394+ }
395+ }
396+ }
397+
398+ // src - a pointer to the data to send (16-bit aligned for 9-bit chars)
399+ // num_chars - number of characters to send (9-bit chars count for 2 bytes from src)
400+ // *errcode - returns 0 for success, MP_Exxx on error
401+ // returns the number of characters sent (valid even if there was an error)
402+ STATIC size_t uart_tx_data (pyb_uart_obj_t * self , const void * src_in , size_t num_chars , int * errcode ) {
403+ if (num_chars == 0 ) {
404+ * errcode = 0 ;
405+ return 0 ;
406+ }
407+
408+ uint32_t timeout ;
383409 if (self -> uart .Init .HwFlowCtl & UART_HWCONTROL_CTS ) {
384410 // CTS can hold off transmission for an arbitrarily long time. Apply
385411 // the overall timeout rather than the character timeout.
386- return HAL_UART_Transmit (& self -> uart , data , len , self -> timeout );
387- }
388- // The timeout specified here is for waiting for the TX data register to
389- // become empty (ie between chars), as well as for the final char to be
390- // completely transferred. The default value for timeout_char is long
391- // enough for 1 char, but we need to double it to wait for the last char
392- // to be transferred to the data register, and then to be transmitted.
393- return HAL_UART_Transmit (& self -> uart , data , len , 2 * self -> timeout_char );
412+ timeout = self -> timeout ;
413+ } else {
414+ // The timeout specified here is for waiting for the TX data register to
415+ // become empty (ie between chars), as well as for the final char to be
416+ // completely transferred. The default value for timeout_char is long
417+ // enough for 1 char, but we need to double it to wait for the last char
418+ // to be transferred to the data register, and then to be transmitted.
419+ timeout = 2 * self -> timeout_char ;
420+ }
421+
422+ const uint8_t * src = (const uint8_t * )src_in ;
423+ size_t num_tx = 0 ;
424+ USART_TypeDef * uart = self -> uart .Instance ;
425+
426+ while (num_tx < num_chars ) {
427+ if (!uart_wait_flag_set (self , UART_FLAG_TXE , timeout )) {
428+ * errcode = MP_ETIMEDOUT ;
429+ return num_tx ;
430+ }
431+ uint32_t data ;
432+ if (self -> char_width == CHAR_WIDTH_9BIT ) {
433+ data = * ((uint16_t * )src ) & 0x1ff ;
434+ src += 2 ;
435+ } else {
436+ data = * src ++ ;
437+ }
438+ #if defined(MCU_SERIES_F4 )
439+ uart -> DR = data ;
440+ #else
441+ uart -> TDR = data ;
442+ #endif
443+ ++ num_tx ;
444+ }
445+
446+ // wait for the UART frame to complete
447+ if (!uart_wait_flag_set (self , UART_FLAG_TC , timeout )) {
448+ * errcode = MP_ETIMEDOUT ;
449+ return num_tx ;
450+ }
451+
452+ * errcode = 0 ;
453+ return num_tx ;
394454}
395455
396456STATIC void uart_tx_char (pyb_uart_obj_t * uart_obj , int c ) {
397- uint8_t ch = c ;
398- uart_tx_data (uart_obj , & ch , 1 );
457+ uint16_t ch = c ;
458+ int errcode ;
459+ uart_tx_data (uart_obj , & ch , 1 , & errcode );
399460}
400461
401462void uart_tx_strn (pyb_uart_obj_t * uart_obj , const char * str , uint len ) {
402- uart_tx_data (uart_obj , (uint8_t * )str , len );
463+ int errcode ;
464+ uart_tx_data (uart_obj , str , len , & errcode );
403465}
404466
405467void uart_tx_strn_cooked (pyb_uart_obj_t * uart_obj , const char * str , uint len ) {
@@ -806,15 +868,15 @@ STATIC mp_obj_t pyb_uart_writechar(mp_obj_t self_in, mp_obj_t char_in) {
806868 uint16_t data = mp_obj_get_int (char_in );
807869
808870 // write the character
809- HAL_StatusTypeDef status ;
871+ int errcode ;
810872 if (uart_tx_wait (self , self -> timeout )) {
811- status = uart_tx_data (self , ( uint8_t * ) & data , 1 );
873+ uart_tx_data (self , & data , 1 , & errcode );
812874 } else {
813- status = HAL_TIMEOUT ;
875+ errcode = MP_ETIMEDOUT ;
814876 }
815877
816- if (status != HAL_OK ) {
817- mp_hal_raise ( status );
878+ if (errcode != 0 ) {
879+ mp_raise_OSError ( errcode );
818880 }
819881
820882 return mp_const_none ;
@@ -933,24 +995,12 @@ STATIC mp_uint_t pyb_uart_write(mp_obj_t self_in, const void *buf_in, mp_uint_t
933995 }
934996
935997 // write the data
936- HAL_StatusTypeDef status = uart_tx_data (self , (uint8_t * )buf , size >> self -> char_width );
937-
938- if (status == HAL_OK ) {
939- // return number of bytes written
940- return size ;
941- } else if (status == HAL_TIMEOUT ) { // UART_WaitOnFlagUntilTimeout() disables RXNE interrupt on timeout
942- if (self -> read_buf_len > 0 ) {
943- __HAL_UART_ENABLE_IT (& self -> uart , UART_IT_RXNE ); // re-enable RXNE
944- }
945- // return number of bytes written
946- if (self -> char_width == CHAR_WIDTH_8BIT ) {
947- return size - self -> uart .TxXferCount - 1 ;
948- } else {
949- int written = self -> uart .TxXferCount * 2 ;
950- return size - written - 2 ;
951- }
998+ size_t num_tx = uart_tx_data (self , buf , size >> self -> char_width , errcode );
999+
1000+ if (* errcode == 0 || * errcode == MP_ETIMEDOUT ) {
1001+ // return number of bytes written, even if there was a timeout
1002+ return num_tx << self -> char_width ;
9521003 } else {
953- * errcode = mp_hal_status_to_errno_table [status ];
9541004 return MP_STREAM_ERROR ;
9551005 }
9561006}
0 commit comments