diff --git a/drivers/include/drivers/SerialBase.h b/drivers/include/drivers/SerialBase.h index 9288c271e15..de3229fcfd3 100644 --- a/drivers/include/drivers/SerialBase.h +++ b/drivers/include/drivers/SerialBase.h @@ -119,6 +119,14 @@ class SerialBase : private NonCopyable { */ void send_break(); + /** Ensures all data stored in peripheral buffers is transmitted to the bus + * + * The function shall block until all the content of peripheral buffers is transmitted. + * + * @return 0 on success, negative error code on failure + */ + int sync(); + /** Enable serial input * * If both serial input and serial output are disabled, the diff --git a/drivers/include/drivers/UnbufferedSerial.h b/drivers/include/drivers/UnbufferedSerial.h index a330d6e92bc..d2e1eb3d269 100644 --- a/drivers/include/drivers/UnbufferedSerial.h +++ b/drivers/include/drivers/UnbufferedSerial.h @@ -114,6 +114,12 @@ class UnbufferedSerial: return -ESPIPE; } + /** Flush any buffers associated with the file + * + * @return 0 on success, negative error code on failure + */ + int sync() override; + /** Get the size of the file * * @return Size of the file in bytes diff --git a/drivers/source/BufferedSerial.cpp b/drivers/source/BufferedSerial.cpp index a2c8873b031..0548e04797d 100644 --- a/drivers/source/BufferedSerial.cpp +++ b/drivers/source/BufferedSerial.cpp @@ -115,7 +115,7 @@ int BufferedSerial::sync() api_unlock(); - return 0; + return SerialBase::sync(); } void BufferedSerial::sigio(Callback func) diff --git a/drivers/source/SerialBase.cpp b/drivers/source/SerialBase.cpp index 40bf7d0b618..b269c5bb569 100644 --- a/drivers/source/SerialBase.cpp +++ b/drivers/source/SerialBase.cpp @@ -18,6 +18,8 @@ #include "platform/mbed_wait_api.h" #include "platform/mbed_critical.h" #include "platform/mbed_power_mgmt.h" +#include "platform/mbed_chrono.h" +#include "rtos/ThisThread.h" #if DEVICE_SERIAL @@ -164,6 +166,29 @@ void SerialBase::_deinit() serial_free(&_serial); } +int SerialBase::sync() +{ + int count = 0; + // See send_break(), ensure at least 1ms sleep time + auto char_time_allowance = chrono::milliseconds_u32((18000 / _baud) + 1); + lock(); + // Assuming the biggest Tx FIFO of 128 bytes (as for CY8CPROTO_062_4343W) + while ((!serial_tx_empty(&_serial)) && (count < 128)) { + rtos::ThisThread::sleep_for(char_time_allowance); +#if DEVICE_SERIAL_FC + if ((_flow_type == RTS) || (_flow_type == Disabled)) +#endif + count++; + } + unlock(); + + if (count < 128) { + return 0; + } else { + return -ETIME; + } +} + void SerialBase::enable_input(bool enable) { lock(); diff --git a/drivers/source/UnbufferedSerial.cpp b/drivers/source/UnbufferedSerial.cpp index cc86530344d..1b92760d26c 100644 --- a/drivers/source/UnbufferedSerial.cpp +++ b/drivers/source/UnbufferedSerial.cpp @@ -99,6 +99,11 @@ short UnbufferedSerial::poll(short events) const return revents; } +int UnbufferedSerial::sync() +{ + return SerialBase::sync(); +} + int UnbufferedSerial::enable_input(bool enabled) { SerialBase::enable_input(enabled); diff --git a/drivers/tests/TESTS/host_tests/serial_comms.py b/drivers/tests/TESTS/host_tests/serial_comms.py index f51ac7d60f0..d453a1e0c29 100644 --- a/drivers/tests/TESTS/host_tests/serial_comms.py +++ b/drivers/tests/TESTS/host_tests/serial_comms.py @@ -20,6 +20,7 @@ MSG_KEY_ECHO_MESSAGE = "echo_message" +MSG_KEY_SYNC_MESSAGE = "sync_message" class SerialComms(BaseHostTest): @@ -32,7 +33,12 @@ def __init__(self): def setup(self): """Register call backs to handle message from the target.""" self.register_callback(MSG_KEY_ECHO_MESSAGE, self.cb_echo_message) + self.register_callback(MSG_KEY_SYNC_MESSAGE, self.cb_sync_message) def cb_echo_message(self, key, value, timestamp): """Send back the key and value received.""" self.send_kv(key, value) + + def cb_sync_message(self, key, value, timestamp): + """Test completed.""" + self.notify_complete(True) diff --git a/drivers/tests/TESTS/mbed_drivers/sync_serial/CMakeLists.txt b/drivers/tests/TESTS/mbed_drivers/sync_serial/CMakeLists.txt new file mode 100644 index 00000000000..21451ef751d --- /dev/null +++ b/drivers/tests/TESTS/mbed_drivers/sync_serial/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (c) 2020 ARM Limited. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 + +cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR) + +set(MBED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../../../.. CACHE INTERNAL "") +set(TEST_TARGET mbed-drivers-sync-serial) + +include(${MBED_PATH}/tools/cmake/mbed_greentea.cmake) + +project(${TEST_TARGET}) + +mbed_greentea_add_test(TEST_NAME ${TEST_TARGET}) diff --git a/drivers/tests/TESTS/mbed_drivers/sync_serial/main.cpp b/drivers/tests/TESTS/mbed_drivers/sync_serial/main.cpp new file mode 100644 index 00000000000..a40640875c2 --- /dev/null +++ b/drivers/tests/TESTS/mbed_drivers/sync_serial/main.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2019 Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#if !DEVICE_SERIAL +#error [NOT_SUPPORTED] serial communication not supported for this target +#else + +#include "mbed.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "greentea-client/test_env.h" +#include "platform/FileHandle.h" +#include "drivers/BufferedSerial.h" + + +using namespace utest::v1; + + +/** + * Macros for setting console flow control. + */ +#define CONSOLE_FLOWCONTROL_RTS 1 +#define CONSOLE_FLOWCONTROL_CTS 2 +#define CONSOLE_FLOWCONTROL_RTSCTS 3 +#define mbed_console_concat_(x) CONSOLE_FLOWCONTROL_##x +#define mbed_console_concat(x) mbed_console_concat_(x) +#define CONSOLE_FLOWCONTROL mbed_console_concat(MBED_CONF_TARGET_CONSOLE_UART_FLOW_CONTROL) + + +#define MSG_KEY_SYNC_MESSAGE "sync_message" +#define MSG_VALUE_HELLO_WORLD "Hello, world!" + + +#define EXPECTED_SYNCED_STRING "{{" MSG_KEY_SYNC_MESSAGE ";" MSG_VALUE_HELLO_WORLD "}}" +// The target is expected to transmit Greentea messages with \n (or \r\n) or they are not detected by the host +#define SYNC_STRING_TO_SEND EXPECTED_SYNCED_STRING "\n" + + +static BufferedSerial buffered_serial_obj( + CONSOLE_TX, CONSOLE_RX, MBED_CONF_PLATFORM_STDIO_BAUD_RATE +); + + +FileHandle *mbed::mbed_override_console(int fd) +{ + return &buffered_serial_obj; +} + + +static void test_serial_sync() +{ + char tx_msg[] = SYNC_STRING_TO_SEND; + + TEST_ASSERT_EQUAL_UINT( + strlen(tx_msg) + 1, + buffered_serial_obj.write(tx_msg, strlen(tx_msg) + 1) + ); + + // Wait the message is completely sent to the bus + buffered_serial_obj.sync(); + system_reset(); + TEST_ASSERT_MESSAGE(0, "The device did not reset as expected."); +} + + +int main() +{ +#if CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTS + buffered_serial_obj.set_flow_control( + SerialBase::RTS, STDIO_UART_RTS, NC + ); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_CTS + buffered_serial_obj.set_flow_control( + SerialBase::CTS, NC, STDIO_UART_CTS + ); +#elif CONSOLE_FLOWCONTROL == CONSOLE_FLOWCONTROL_RTSCTS + buffered_serial_obj.set_flow_control( + SerialBase::RTSCTS, STDIO_UART_RTS, STDIO_UART_CTS + ); +#endif + GREENTEA_SETUP(12, "serial_comms"); + test_serial_sync(); // The result of this test suite is reported by the host side. + GREENTEA_TESTSUITE_RESULT(0); // Fail on any error. +} + +#endif // !DEVICE_SERIAL diff --git a/hal/include/hal/serial_api.h b/hal/include/hal/serial_api.h index 78a1ee8aa40..eacf8c9824a 100644 --- a/hal/include/hal/serial_api.h +++ b/hal/include/hal/serial_api.h @@ -296,6 +296,14 @@ int serial_readable(serial_t *obj); */ int serial_writable(serial_t *obj); +/** Check if the serial peripheral tx buffer or tx FIFO is empty and the last byte has + * been completely transmitted from the shift register to the bus. + * + * @param obj The serial object + * @return Non-zero value if tx is empty, 0 otherwise. + */ +int serial_tx_empty(serial_t *obj); + /** Clear the serial peripheral * * @param obj The serial object diff --git a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp index 3719f035447..8d0322b438f 100644 --- a/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp +++ b/hal/tests/TESTS/mbed_hal_fpga_ci_test_shield/uart/main.cpp @@ -123,7 +123,7 @@ static void uart_test_common(int baudrate, int data_bits, SerialParity parity, i // start_bit + data_bits + parity_bit + stop_bits int packet_bits = 1 + data_bits + stop_bits + (parity == ParityNone ? 0 : 1); - us_timestamp_t packet_tx_time = 1000000 * packet_bits / baudrate; + us_timestamp_t packet_tx_time = (1000000 * packet_bits / baudrate) + 0.5; const ticker_data_t *const us_ticker = get_us_ticker_data(); bool use_flow_control = (cts != NC && rts != NC) ? true : false; @@ -211,10 +211,12 @@ static void uart_test_common(int baudrate, int data_bits, SerialParity parity, i checksum += tx_val; serial_putc(&serial, tx_val); us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; - while (tester.rx_get_count() != reps && ticker_read_us(us_ticker) <= end_ts) { + while ((!serial_tx_empty(&serial) || tester.rx_get_count() != reps) && ticker_read_us(us_ticker) <= end_ts) { // Wait (no longer than twice the time of one packet transfer) for + // the DUT to send all buffered data to the bus and for // the FPGA to receive data and update the byte counter. } + TEST_ASSERT_EQUAL(1, serial_tx_empty(&serial)); TEST_ASSERT_EQUAL_UINT32(reps, tester.rx_get_count()); TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); TEST_ASSERT_EQUAL(0, tester.rx_get_stop_errors()); @@ -265,10 +267,12 @@ static void uart_test_common(int baudrate, int data_bits, SerialParity parity, i serial_irq_set(&serial, TxIrq, 0); core_util_critical_section_exit(); us_timestamp_t end_ts = ticker_read_us(us_ticker) + 2 * packet_tx_time; - while (ticker_read_us(us_ticker) <= end_ts) { - // Wait twice the time of one packet transfer for the FPGA - // to receive and process data. + while (!serial_tx_empty(&serial) && ticker_read_us(us_ticker) <= end_ts) { + // Wait (no longer than twice the time of one packet transfer) for + // the DUT to send all buffered data to the bus and for + // the FPGA to receive and process data. }; + TEST_ASSERT_EQUAL(1, serial_tx_empty(&serial)); tester.rx_stop(); TEST_ASSERT_EQUAL_UINT32(2 * PUTC_REPS, tester.rx_get_count()); TEST_ASSERT_EQUAL(0, tester.rx_get_parity_errors()); diff --git a/platform/include/platform/FileHandle.h b/platform/include/platform/FileHandle.h index b666301d91c..a3d23588242 100644 --- a/platform/include/platform/FileHandle.h +++ b/platform/include/platform/FileHandle.h @@ -92,7 +92,7 @@ class FileHandle : private NonCopyable { */ virtual int close() = 0; - /** Flush any buffers associated with the file + /** Synchronize the contents of a file with storage device * * @return 0 on success, negative error code on failure */ diff --git a/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/serial_api.c b/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/serial_api.c index 296b383816c..8ac3233c4af 100644 --- a/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/serial_api.c +++ b/targets/TARGET_ARM_FM/TARGET_FVP_MPS2/serial_api.c @@ -361,6 +361,11 @@ int serial_writable(serial_t *obj) return !(obj->uart->STATE & 0x1); } +int serial_tx_empty(serial_t *obj) +{ + return !(obj->uart->STATE & 0x1); +} + void serial_clear(serial_t *obj) { obj->uart->DATA = 0x00; diff --git a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/serial_api.c b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/serial_api.c index 466e70599c2..7f9ae372b81 100644 --- a/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/serial_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/serial_api.c @@ -355,6 +355,11 @@ int serial_writable(serial_t *obj) return arm_uart_tx_ready(obj->uart); } +int serial_tx_empty(serial_t *obj) +{ + return arm_uart_tx_ready(obj->uart); +} + void serial_clear(serial_t *obj) { (void)arm_uart_write(obj->uart, 0x00); diff --git a/targets/TARGET_ARM_SSG/TARGET_MPS2/serial_api.c b/targets/TARGET_ARM_SSG/TARGET_MPS2/serial_api.c index 6cf18c98c5b..8cf37bdf624 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MPS2/serial_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_MPS2/serial_api.c @@ -354,6 +354,10 @@ int serial_writable(serial_t *obj) { return obj->uart->STATE & 0x1; } +int serial_tx_empty(serial_t *obj) { + return obj->uart->STATE & 0x1; +} + void serial_clear(serial_t *obj) { obj->uart->DATA = 0x00; } diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.c index 5de1b4e0209..4add826b20f 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.c +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.c @@ -97,6 +97,8 @@ struct _uart_pl011_reg_map_t { 0x1u<cfg->base; + + if( ((p_uart->uartfr & UART_PL011_UARTFR_TX_FIFO_EMPTY) == 1) && + /* Transmit Fifo is empty */ + ((p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT) == 0)) { + /* Tx is not BUSY */ + return true; + } + return false; + +} + void uart_pl011_write(struct uart_pl011_dev_t* dev, uint8_t byte) { struct _uart_pl011_reg_map_t* p_uart = diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.h index 0ec6a64f517..2b3f5c97bb6 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.h +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/device/drivers/uart_pl011_drv.h @@ -496,6 +496,17 @@ enum uart_pl011_error_t uart_pl011_read(struct uart_pl011_dev_t* dev, */ bool uart_pl011_is_writable(struct uart_pl011_dev_t* dev); +/** + * \brief Check if the UART tx buffer is empty + * + * \param[in] dev UART device struct \ref uart_pl011_dev_t + * + * \return Returns bool, true if UART is tx buffer is empty, false otherwise + * + * \note This function doesn't check if dev is NULL. + */ +bool uart_pl011_is_tx_empty(struct uart_pl011_dev_t* dev); + /** * \brief Writes a byte to UART dev. * diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/serial_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/serial_api.c index d01b6e57994..79fd871cc4f 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/serial_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_B1/serial_api.c @@ -175,6 +175,11 @@ int serial_writable(serial_t *obj) return (int)uart_pl011_is_writable(obj->uart_dev); } +int serial_tx_empty(serial_t *obj) +{ + return (int)uart_pl011_is_tx_empty(obj->uart_dev); +} + int serial_getc(serial_t *obj) { uint8_t byte = 0; diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c index 557f2565ef5..a7b885b85c6 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.c @@ -98,6 +98,8 @@ struct _uart_pl011_reg_map_t { 0x1u<cfg->base; + + if( ((p_uart->uartfr & UART_PL011_UARTFR_TX_FIFO_EMPTY) == 1) && + /* Transmit Fifo is empty */ + ((p_uart->uartfr & UART_PL011_UARTFR_BUSYBIT) == 0)) { + /* Tx is not BUSY */ + return true; + } + return false; + +} + void uart_pl011_write(struct uart_pl011_dev_t* dev, uint8_t byte) { struct _uart_pl011_reg_map_t* p_uart = diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h index 1cf5b622c38..02fdac92d93 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/device/drivers/uart_pl011_drv.h @@ -497,6 +497,17 @@ enum uart_pl011_error_t uart_pl011_read(struct uart_pl011_dev_t* dev, */ bool uart_pl011_is_writable(struct uart_pl011_dev_t* dev); +/** + * \brief Check if the UART tx buffer is empty + * + * \param[in] dev UART device struct \ref uart_pl011_dev_t + * + * \return Returns bool, true if UART is tx buffer is empty, false otherwise + * + * \note This function doesn't check if dev is NULL. + */ +bool uart_pl011_is_tx_empty(struct uart_pl011_dev_t* dev); + /** * \brief Writes a byte to UART dev. * diff --git a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/serial_api.c b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/serial_api.c index d6a85011aad..bd70a433d27 100644 --- a/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/serial_api.c +++ b/targets/TARGET_ARM_SSG/TARGET_MUSCA_S1/serial_api.c @@ -176,6 +176,11 @@ int serial_writable(serial_t *obj) return (int)uart_pl011_is_writable(obj->uart_dev); } +int serial_tx_empty(serial_t *obj) +{ + return (int)uart_pl011_is_tx_empty(obj->uart_dev); +} + int serial_getc(serial_t *obj) { uint8_t byte = 0; diff --git a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c index 83d23f34834..30794d4cd7c 100644 --- a/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c +++ b/targets/TARGET_Ambiq_Micro/TARGET_Apollo3/device/serial_api.c @@ -68,6 +68,7 @@ void uart_configure_pin_function(PinName pin, UARTName uart, const PinMap *map); * * ::serial_putc is a blocking call (waits for a peripheral to be available). * * ::serial_readable returns non-zero value if a character can be read, 0 otherwise. * * ::serial_writable returns non-zero value if a character can be written, 0 otherwise. + * * ::serial_tx_empty returns non-zero value if tx is empty, 0 otherwise. * * ::serial_clear clears the ::serial_t RX/TX buffers * * ::serial_break_set sets the break signal. * * ::serial_break_clear clears the break signal. @@ -308,6 +309,12 @@ int serial_writable(serial_t *obj) return !(UARTn(obj->serial.uart_control->inst)->FR_b.TXFF); } +int serial_tx_empty(serial_t *obj) +{ + MBED_ASSERT(obj->serial.uart_control != NULL); + return ((UARTn(obj->serial.uart_control->inst)->FR_b.TXFE) && (!(UARTn(obj->serial.uart_control->inst)->FR_b.TXBUSY))); +} + void serial_clear(serial_t *obj) { // todo: diff --git a/targets/TARGET_Analog_Devices/TARGET_ADUCM302X/TARGET_ADUCM3029/api/serial_api.c b/targets/TARGET_Analog_Devices/TARGET_ADUCM302X/TARGET_ADUCM3029/api/serial_api.c index cd0d2b2bf76..29c4689b286 100755 --- a/targets/TARGET_Analog_Devices/TARGET_ADUCM302X/TARGET_ADUCM3029/api/serial_api.c +++ b/targets/TARGET_Analog_Devices/TARGET_ADUCM302X/TARGET_ADUCM3029/api/serial_api.c @@ -262,6 +262,13 @@ int serial_writable(serial_t *obj) return bAvailable; } +int serial_tx_empty(serial_t *obj) +{ + bool bAvailable = false; + adi_uart_IsTxComplete(hDevice, &bAvailable); + return bAvailable; +} + void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { MBED_ASSERT(obj); diff --git a/targets/TARGET_Analog_Devices/TARGET_ADUCM4X50/TARGET_ADUCM4050/api/serial_api.c b/targets/TARGET_Analog_Devices/TARGET_ADUCM4X50/TARGET_ADUCM4050/api/serial_api.c index ef48996dc9a..52055fa4b2d 100755 --- a/targets/TARGET_Analog_Devices/TARGET_ADUCM4X50/TARGET_ADUCM4050/api/serial_api.c +++ b/targets/TARGET_Analog_Devices/TARGET_ADUCM4X50/TARGET_ADUCM4050/api/serial_api.c @@ -204,6 +204,13 @@ int serial_writable(serial_t *obj) return bAvailable; } +int serial_tx_empty(serial_t *obj) +{ + bool bAvailable = false; + adi_uart_IsTxComplete(hDevice[obj->index], &bAvailable); + return bAvailable; +} + void serial_putc(serial_t *obj, int c) { void *pBuff; diff --git a/targets/TARGET_Cypress/TARGET_PSOC6/cy_serial_api.c b/targets/TARGET_Cypress/TARGET_PSOC6/cy_serial_api.c index 26086aa7bf2..3822ade724e 100644 --- a/targets/TARGET_Cypress/TARGET_PSOC6/cy_serial_api.c +++ b/targets/TARGET_Cypress/TARGET_PSOC6/cy_serial_api.c @@ -194,6 +194,12 @@ int serial_writable(serial_t *obj) return cyhal_uart_writable(&(ser->hal_obj)) > 0 ? 1 : 0; } +int serial_tx_empty(serial_t *obj) +{ + struct serial_s *ser = cy_serial_get_struct(obj); + return cyhal_uart_is_tx_active(&(ser->hal_obj)) ? 0 : 1; +} + void serial_clear(serial_t *obj) { struct serial_s *ser = cy_serial_get_struct(obj); diff --git a/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/serial_api.c b/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/serial_api.c index 7da437b5197..4952d8086b4 100644 --- a/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL25Z/serial_api.c @@ -290,6 +290,11 @@ int serial_writable(serial_t *obj) { return (obj->uart->S1 & UARTLP_S1_TDRE_MASK); } +int serial_tx_empty(serial_t *obj) { + // check transmission complete + return (obj->uart->S1 & UARTLP_S1_TC_MASK); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/serial_api.c b/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/serial_api.c index f38c3c8424a..701475b6e4a 100644 --- a/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_KLXX/TARGET_KL46Z/serial_api.c @@ -290,6 +290,11 @@ int serial_writable(serial_t *obj) { return (obj->uart->S1 & UARTLP_S1_TDRE_MASK); } +int serial_tx_empty(serial_t *obj) { + // check transmission complete + return (obj->uart->S1 & UARTLP_S1_TC_MASK); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/serial_api.c index 44f776d2e1b..20cec9cc326 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K66F/serial_api.c @@ -284,6 +284,12 @@ int serial_writable(serial_t *obj) return (status_flags & kUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->serial.index]); + return ((status_flags & kUART_TxDataRegEmptyFlag) && (status_flags & kUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/serial_api.c index 7e54d19c021..a690b16ec7e 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_K82F/serial_api.c @@ -294,6 +294,12 @@ int serial_writable(serial_t *obj) return (status_flags & kLPUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = LPUART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kLPUART_TxDataRegEmptyFlag) && (status_flags & kLPUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/serial_api.c index 340400927e5..924975c40be 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KL43Z/serial_api.c @@ -250,6 +250,12 @@ int serial_writable(serial_t *obj) return (status_flags & kLPUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = LPUART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kLPUART_TxDataRegEmptyFlag) && (status_flags & kLPUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/serial_api.c index 675e101e007..d99a7199fee 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_KW41Z/serial_api.c @@ -231,6 +231,12 @@ int serial_writable(serial_t *obj) return (status_flags & kLPUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = LPUART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kLPUART_TxDataRegEmptyFlag) && (status_flags & kLPUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/serial_api.c index 25e8b8bd255..56a6137a737 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K22F/serial_api.c @@ -252,6 +252,12 @@ int serial_writable(serial_t *obj) return (status_flags & kUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kUART_TxDataRegEmptyFlag) && (status_flags & kUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/serial_api.c b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/serial_api.c index 0b16d007069..7998152f0f6 100644 --- a/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/serial_api.c +++ b/targets/TARGET_Freescale/TARGET_MCUXpresso_MCUS/TARGET_MCU_K64F/serial_api.c @@ -309,6 +309,12 @@ int serial_writable(serial_t *obj) return (status_flags & kUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = UART_GetStatusFlags(uart_addrs[obj->serial.index]); + return ((status_flags & kUART_TxDataRegEmptyFlag) && (status_flags & kUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_GigaDevice/TARGET_GD32F30X/serial_api.c b/targets/TARGET_GigaDevice/TARGET_GD32F30X/serial_api.c index 50347de3ff0..1b093abbd82 100644 --- a/targets/TARGET_GigaDevice/TARGET_GD32F30X/serial_api.c +++ b/targets/TARGET_GigaDevice/TARGET_GD32F30X/serial_api.c @@ -439,6 +439,18 @@ int serial_writable(serial_t *obj) return (usart_flag_get(p_obj->uart, USART_FLAG_TBE) != RESET) ? 1 : 0; } +/** Check if the serial peripheral tx buffer is empty + * + * @param obj The serial object + * @return Non-zero value if the tx buffer is empty, 0 otherwise. + */ +int serial_tx_empty(serial_t *obj) +{ + struct serial_s *p_obj = GET_SERIAL_S(obj); + + return ((usart_flag_get(p_obj->uart, USART_FLAG_TBE) != RESET) && (usart_flag_get(p_obj->uart, USART_FLAG_TC) != RESET)) ? 1 : 0; +} + /** Clear the serial peripheral * * @param obj The serial object diff --git a/targets/TARGET_GigaDevice/TARGET_GD32F4XX/serial_api.c b/targets/TARGET_GigaDevice/TARGET_GD32F4XX/serial_api.c index 5fd4ee48355..59b830590c8 100644 --- a/targets/TARGET_GigaDevice/TARGET_GD32F4XX/serial_api.c +++ b/targets/TARGET_GigaDevice/TARGET_GD32F4XX/serial_api.c @@ -501,6 +501,18 @@ int serial_writable(serial_t *obj) return (usart_flag_get(p_obj->uart, USART_FLAG_TBE) != RESET) ? 1 : 0; } +/** Check if the serial peripheral tx buffer is empty + * + * @param obj The serial object + * @return Non-zero value if the tx buffer is empty, 0 otherwise. + */ +int serial_tx_empty(serial_t *obj) +{ + struct serial_s *p_obj = GET_SERIAL_S(obj); + + return ((usart_flag_get(p_obj->uart, USART_FLAG_TBE) != RESET) && (usart_flag_get(p_obj->uart, USART_FLAG_TC) != RESET)) ? 1 : 0; +} + /** Clear the serial peripheral * * @param obj The serial object diff --git a/targets/TARGET_Maxim/TARGET_MAX32620C/serial_api.c b/targets/TARGET_Maxim/TARGET_MAX32620C/serial_api.c index b51826815bf..61f06b5eca1 100644 --- a/targets/TARGET_Maxim/TARGET_MAX32620C/serial_api.c +++ b/targets/TARGET_Maxim/TARGET_MAX32620C/serial_api.c @@ -312,6 +312,12 @@ int serial_writable(serial_t *obj) return UART_NumWriteAvail(obj->uart); } +//****************************************************************************** +int serial_tx_empty(serial_t *obj) +{ + return (MXC_UART_FIFO_DEPTH == UART_NumWriteAvail(obj->uart)) ? 1 : 0; +} + //****************************************************************************** void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c b/targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c index 7fc1cc09001..6ca35349771 100644 --- a/targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c +++ b/targets/TARGET_Maxim/TARGET_MAX32625/serial_api.c @@ -307,6 +307,12 @@ int serial_writable(serial_t *obj) return UART_NumWriteAvail(obj->uart); } +//****************************************************************************** +int serial_tx_empty(serial_t *obj) +{ + return (MXC_UART_FIFO_DEPTH == UART_NumWriteAvail(obj->uart)) ? 1 : 0; +} + //****************************************************************************** void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_Maxim/TARGET_MAX32630/serial_api.c b/targets/TARGET_Maxim/TARGET_MAX32630/serial_api.c index b9bbc9ed78f..6da121df1da 100644 --- a/targets/TARGET_Maxim/TARGET_MAX32630/serial_api.c +++ b/targets/TARGET_Maxim/TARGET_MAX32630/serial_api.c @@ -307,6 +307,12 @@ int serial_writable(serial_t *obj) return UART_NumWriteAvail(obj->uart); } +//****************************************************************************** +int serial_tx_empty(serial_t *obj) +{ + return (MXC_UART_FIFO_DEPTH == UART_NumWriteAvail(obj->uart)) ? 1 : 0; +} + //****************************************************************************** void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c index 7db9639f519..cb9beb6ea9d 100644 --- a/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c +++ b/targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/serial_api.c @@ -1429,6 +1429,27 @@ int serial_writable(serial_t *obj) (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDDY))); } +/** Check if the serial peripheral tx buffer + * + * Param obj The serial object + * Return Non-zero value if a character can be written, 0 otherwise. + */ +int serial_tx_empty(serial_t *obj) +{ + MBED_ASSERT(obj); + +#if DEVICE_SERIAL_ASYNCH + struct serial_s *uart_object = &obj->serial; +#else + struct serial_s *uart_object = obj; +#endif + + int instance = uart_object->instance; + + return (!core_util_atomic_load_bool(&nordic_nrf5_uart_state[instance].tx_in_progress) && + (nrf_uarte_event_check(nordic_nrf5_uart_register[instance], NRF_UARTE_EVENT_TXDDY))); +} + const PinMap *serial_tx_pinmap() { return PinMap_UART_testing; diff --git a/targets/TARGET_NUVOTON/TARGET_M251/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M251/serial_api.c index aefd9673197..78edc8477bf 100644 --- a/targets/TARGET_NUVOTON/TARGET_M251/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M251/serial_api.c @@ -448,6 +448,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NUVOTON/TARGET_M261/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M261/serial_api.c index a57c20204d4..b0e550daa52 100644 --- a/targets/TARGET_NUVOTON/TARGET_M261/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M261/serial_api.c @@ -493,6 +493,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c index 7d7bce7e7a9..82516513981 100644 --- a/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M451/serial_api.c @@ -448,6 +448,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c b/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c index fdf825a4b46..49ffb834005 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/serial_api.c @@ -525,6 +525,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c b/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c index 2da2c9d3606..ce72f86b953 100644 --- a/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NANO100/serial_api.c @@ -410,6 +410,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c b/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c index 6c1f8889b0c..5b85cac33d2 100644 --- a/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c +++ b/targets/TARGET_NUVOTON/TARGET_NUC472/serial_api.c @@ -488,6 +488,11 @@ int serial_writable(serial_t *obj) return ! UART_IS_TX_FULL(((UART_T *) NU_MODBASE(obj->serial.uart))); } +int serial_tx_empty(serial_t *obj) +{ + return UART_IS_TX_EMPTY(((UART_T *) NU_MODBASE(obj->serial.uart))); +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c b/targets/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c index c993f1d3f85..3b2e464acf4 100644 --- a/targets/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c +++ b/targets/TARGET_NXP/TARGET_LPC11XX_11CXX/serial_api.c @@ -283,6 +283,10 @@ int serial_writable(serial_t *obj) { return obj->uart->LSR & 0x20; } +int serial_tx_empty(serial_t *obj) { + return obj->uart->LSR & 0x20; +} + void serial_clear(serial_t *obj) { obj->uart->FCR = 1 << 1 // rx FIFO reset | 1 << 2 // tx FIFO reset diff --git a/targets/TARGET_NXP/TARGET_LPC176X/serial_api.c b/targets/TARGET_NXP/TARGET_LPC176X/serial_api.c index 15358039f6c..a2f74cdc19c 100644 --- a/targets/TARGET_NXP/TARGET_LPC176X/serial_api.c +++ b/targets/TARGET_NXP/TARGET_LPC176X/serial_api.c @@ -377,6 +377,10 @@ int serial_writable(serial_t *obj) { return isWritable; } +int serial_tx_empty(serial_t *obj) { + return obj->uart->LSR & 0x20; +} + void serial_clear(serial_t *obj) { obj->uart->FCR = 1 << 0 // FIFO Enable - 0 = Disables, 1 = Enabled | 1 << 1 // rx FIFO reset diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC/serial_api.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC/serial_api.c index 4e7bfe62b00..169c98c4bf9 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC/serial_api.c +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_LPC/serial_api.c @@ -383,6 +383,13 @@ int serial_writable(serial_t *obj) return (status_flags & kUSART_TxFifoNotFullFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = USART_GetStatusFlags(uart_addrs[obj->index]); + + return (status_flags & kUSART_TxFifoEmptyFlag); +} + void serial_clear(serial_t *obj) { } diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/serial_api.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/serial_api.c index 0af83e98d30..6c622855adb 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/serial_api.c +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1050/TARGET_EVK/serial_api.c @@ -266,6 +266,12 @@ int serial_writable(serial_t *obj) return (status_flags & kLPUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = LPUART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kLPUART_TxDataRegEmptyFlag) && (status_flags & kLPUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1170/TARGET_EVK/serial_api.c b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1170/TARGET_EVK/serial_api.c index c479ade934e..618979f6f15 100644 --- a/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1170/TARGET_EVK/serial_api.c +++ b/targets/TARGET_NXP/TARGET_MCUXpresso_MCUS/TARGET_MIMXRT1170/TARGET_EVK/serial_api.c @@ -266,6 +266,12 @@ int serial_writable(serial_t *obj) return (status_flags & kLPUART_TxDataRegEmptyFlag); } +int serial_tx_empty(serial_t *obj) +{ + uint32_t status_flags = LPUART_GetStatusFlags(uart_addrs[obj->index]); + return ((status_flags & kLPUART_TxDataRegEmptyFlag) && (status_flags & kLPUART_TransmissionCompleteFlag)); +} + void serial_clear(serial_t *obj) { diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/serial_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/serial_api.c index ace09575e81..e450a9e6cef 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A1XX/serial_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A1XX/serial_api.c @@ -614,6 +614,15 @@ int serial_writable(serial_t *obj) { return ((obj->serial.uart->SCFSR & 0x20) != 0); // TDFE } +int serial_tx_empty(serial_t *obj) { + if(((obj->serial.uart->SCFSR & 0x20) != 0) && // TDFE = 1 && TEND = 1 + ((obj->serial.uart->SCFSR & 0x40) != 0)) { + return 1; + } else { + return 0; + } +} + void serial_clear(serial_t *obj) { core_util_critical_section_enter(); diff --git a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/serial_api.c b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/serial_api.c index fc8513c1adc..65c608ab5c4 100644 --- a/targets/TARGET_RENESAS/TARGET_RZ_A2XX/serial_api.c +++ b/targets/TARGET_RENESAS/TARGET_RZ_A2XX/serial_api.c @@ -627,6 +627,21 @@ int serial_writable(serial_t *obj) } } +int serial_tx_empty(serial_t *obj) +{ +#if defined(PRINTF_NOT_USE) + if ((int)obj->serial.ch == NC) { + return 0; + } +#endif + if((obj->serial.uart->FSR.BIT.TDFE != 0) && // TDFE = 1 && TEND = 1 + (obj->serial.uart->FSR.BIT.TEND != 0)) { + return 1; + } else { + return 0; + } +} + void serial_clear(serial_t *obj) { #if defined(PRINTF_NOT_USE) diff --git a/targets/TARGET_STM/serial_api.c b/targets/TARGET_STM/serial_api.c index 259c7b8719b..73dfc6c7d5a 100644 --- a/targets/TARGET_STM/serial_api.c +++ b/targets/TARGET_STM/serial_api.c @@ -585,6 +585,18 @@ int serial_writable(serial_t *obj) return (__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE) != RESET) ? 1 : 0; } +int serial_tx_empty(serial_t *obj) +{ + struct serial_s *obj_s = SERIAL_S(obj); + UART_HandleTypeDef *huart = &uart_handlers[obj_s->index]; + + if((__HAL_UART_GET_FLAG(huart, UART_FLAG_TXE) != RESET) && + (__HAL_UART_GET_FLAG(huart, UART_FLAG_TC) != RESET) ) { + return 1; + } + return 0; +} + void serial_pinout_tx(PinName tx) { pinmap_pinout(tx, PinMap_UART_TX); diff --git a/targets/TARGET_Samsung/TARGET_SIDK_S1SBP6A/serial_api.c b/targets/TARGET_Samsung/TARGET_SIDK_S1SBP6A/serial_api.c index 99f9c13bb3e..be51573a486 100644 --- a/targets/TARGET_Samsung/TARGET_SIDK_S1SBP6A/serial_api.c +++ b/targets/TARGET_Samsung/TARGET_SIDK_S1SBP6A/serial_api.c @@ -336,6 +336,13 @@ int serial_writable(serial_t *obj) #endif } +int serial_tx_empty(serial_t *obj) +{ + struct serial_s *objs = serial_s(obj); + + return ((getreg32(objs->uart + UART_UTRSTAT_OFFSET) & UART_UTRSTAT_TX_EMPTY_MASK)); +} + void serial_clear(serial_t *obj) { struct serial_s *objs = serial_s(obj); diff --git a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/objects.h b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/objects.h index 8513b23e8f5..ab121804c93 100644 --- a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/objects.h +++ b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/objects.h @@ -71,6 +71,7 @@ struct uart_ops_s { void (*serial_irq_set)(void *obj, SerialIrq irq, uint32_t enable); void (*serial_putc)(void *obj, int c); int (*serial_writable)(void *obj); + int (*serial_tx_empty)(void *obj); int (*serial_getc)(void *obj); int (*serial_readable)(void *obj); #if DEVICE_SERIAL_FC diff --git a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_api.c b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_api.c index 394ab65835e..c5995da6b43 100644 --- a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_api.c +++ b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_api.c @@ -238,6 +238,11 @@ int serial_writable(serial_t *obj) return obj->ops.serial_writable(obj); } +int serial_tx_empty(serial_t *obj) +{ + return obj->ops.serial_tx_empty(obj); +} + /* Shall it be ever used ??? void serial_clear(serial_t *obj) diff --git a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_dummy_api.c b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_dummy_api.c index c510e31fa44..aeb50a049b3 100644 --- a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_dummy_api.c +++ b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_dummy_api.c @@ -67,6 +67,11 @@ static int dummy_serial_writable(void *obj) return 1; } +static int dummy_serial_tx_empty(void *obj) +{ + return 1; +} + static int dummy_serial_getc(void *obj) @@ -111,6 +116,7 @@ void dummy_serial_init(void *obj, PinName tx, PinName rx) priv->ops.serial_writable = dummy_serial_writable; priv->ops.serial_getc = dummy_serial_getc; priv->ops.serial_readable = dummy_serial_readable; + priv->ops.serial_tx_empty = dummy_serial_tx_empty; #if DEVICE_SERIAL_FC priv->ops.serial_set_flow_control = dummy_serial_set_flow_control; #endif diff --git a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c index 860138226f5..53235ef8775 100644 --- a/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c +++ b/targets/TARGET_Samsung/TARGET_SIDK_S5JS100/serial_pl011_api.c @@ -234,6 +234,13 @@ static int pl011_serial_writable(void *obj) return !(p_PL011_UART->FR & (1u << 5)); } +static int pl011_serial_tx_empty(void *obj) +{ + struct serial_s *priv = (struct serial_s *)obj; + S5JS100_UART_TypeDef *p_PL011_UART = UART_PTR(priv->uart); + return ((p_PL011_UART->FR & (1u << 7)) && (!(p_PL011_UART->FR & (1u << 3)))); +} + static int pl011_serial_getc(void *obj) @@ -306,6 +313,7 @@ void pl011_serial_init(void *obj, PinName tx, PinName rx) priv->ops.serial_writable = pl011_serial_writable; priv->ops.serial_getc = pl011_serial_getc; priv->ops.serial_readable = pl011_serial_readable; + priv->ops.serial_tx_empty = pl011_serial_tx_empty; #if DEVICE_SERIAL_FC priv->ops.serial_set_flow_control = pl011_serial_set_flow_control; #endif diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_leuart.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_leuart.h index c8a33cc3a7e..a1971e9cd11 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_leuart.h +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_leuart.h @@ -246,6 +246,7 @@ typedef struct { #define _LEUART_STATUS_RXDATAV_MASK 0x20UL /**< Bit mask for LEUART_RXDATAV */ #define _LEUART_STATUS_RXDATAV_DEFAULT 0x00000000UL /**< Mode DEFAULT for LEUART_STATUS */ #define LEUART_STATUS_RXDATAV_DEFAULT (_LEUART_STATUS_RXDATAV_DEFAULT << 5) /**< Shifted mode DEFAULT for LEUART_STATUS */ +#define LEUART_STATUS_TXIDLE (0x1UL << 6) /**< TX Idle */ /* Bit fields for LEUART CLKDIV */ #define _LEUART_CLKDIV_RESETVALUE 0x00000000UL /**< Default value for LEUART_CLKDIV */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_usart.h b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_usart.h index 0cf8b999dc9..c4bb95e39b2 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_usart.h +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/TARGET_EFM32GG/device/efm32gg_usart.h @@ -471,6 +471,11 @@ typedef struct { #define _USART_STATUS_RXFULLRIGHT_MASK 0x1000UL /**< Bit mask for USART_RXFULLRIGHT */ #define _USART_STATUS_RXFULLRIGHT_DEFAULT 0x00000000UL /**< Mode DEFAULT for USART_STATUS */ #define USART_STATUS_RXFULLRIGHT_DEFAULT (_USART_STATUS_RXFULLRIGHT_DEFAULT << 12) /**< Shifted mode DEFAULT for USART_STATUS */ +#define USART_STATUS_TXIDLE (0x1UL << 13) /**< TX Idle */ +#define _USART_STATUS_TXIDLE_SHIFT 13 /**< Shift value for USART_TXIDLE */ +#define _USART_STATUS_TXIDLE_MASK 0x2000UL /**< Bit mask for USART_TXIDLE */ +#define _USART_STATUS_TXIDLE_DEFAULT 0x00000001UL /**< Mode DEFAULT for USART_STATUS */ +#define USART_STATUS_TXIDLE_DEFAULT (_USART_STATUS_TXIDLE_DEFAULT << 13) /**< Shifted mode DEFAULT for USART_STATUS */ /* Bit fields for USART CLKDIV */ #define _USART_CLKDIV_RESETVALUE 0x00000000UL /**< Default value for USART_CLKDIV */ diff --git a/targets/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c b/targets/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c index ede181441ef..dbf27833326 100644 --- a/targets/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c +++ b/targets/TARGET_Silicon_Labs/TARGET_EFM32/serial_api.c @@ -1149,6 +1149,18 @@ int serial_writable(serial_t *obj) } } +/** + * Check if TX buffer is empty + */ +int serial_tx_empty(serial_t *obj) +{ + if(LEUART_REF_VALID(obj->serial.periph.leuart)) { + return ((obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXBL) && (obj->serial.periph.leuart->STATUS & LEUART_STATUS_TXIDLE)); + } else { + return ((obj->serial.periph.uart->STATUS & USART_STATUS_TXBL) && (obj->serial.periph.uart->STATUS & USART_STATUS_TXIDLE)); + } +} + /** * Clear UART interrupts */ diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM46B/serial_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/serial_api.c index 090b1599fbd..19696f12a6c 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM46B/serial_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM46B/serial_api.c @@ -491,6 +491,31 @@ int serial_writable(serial_t *obj) return ret; } +int serial_tx_empty(serial_t *obj) +{ + int ret = 0; + + switch (obj->index) { + case SERIAL_0: + case SERIAL_1: + case SERIAL_2: + case SERIAL_3: + if (UART_GetBufState(obj->UARTx, UART_TX) == DONE) { + ret = 1; + } + break; + case SERIAL_4: + case SERIAL_5: + if (FUART_GetStorageStatus(obj->FUART, FUART_TX) == FUART_STORAGE_EMPTY) { + ret = 1; + } + break; + default: + break; + } + return ret; +} + void serial_clear(serial_t *obj) { switch (obj->index) { diff --git a/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/serial_api.c b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/serial_api.c index bd14d8a566f..0ced078f17f 100644 --- a/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/serial_api.c +++ b/targets/TARGET_TOSHIBA/TARGET_TMPM4G9/serial_api.c @@ -538,6 +538,23 @@ int serial_writable(serial_t *obj) return ret; } +int serial_tx_empty(serial_t *obj) +{ + int ret = 0; + + if(!(obj->is_using_fuart)) { + if ((obj->UARTx->SR & 0x8000) == 0) { + ret = 1; + } + } else { + if(obj->FUARTx->FR & (1 << 7U)) { + ret = 1; + } + } + + return ret; +} + void serial_clear(serial_t *obj) { uint32_t dummy;