diff --git a/pureboot/pureboot.cpp b/pureboot/pureboot.cpp index dab1429..7881008 100644 --- a/pureboot/pureboot.cpp +++ b/pureboot/pureboot.cpp @@ -166,6 +166,27 @@ constexpr char usart_digit = '0' + PUREBOOT_USART; constexpr char usart_digit = '0'; #endif +// Release a hardware USART the application may have left enabled onto a +// bit-banged link's pins. A software transmitter drives its TX pin through the +// port register, but while that USART's TXEN is set the USART owns the pin and +// the port write does nothing — the loader would receive and obey yet never +// answer. Writing UCSRnB zero hands the pin back to the port. Guarded on the +// pin actually being a USART's TXD, so a link on non-USART pins emits nothing. +template +[[gnu::always_inline]] inline void release_usart_on() +{ + if constexpr (avr::uart::has_usart()) + if constexpr (avr::uart::detail::usart_pin("TXD") == Tx) + avr::hw::reg_impl()>::write(0); +} + +template +[[gnu::always_inline]] inline void release_usarts_on() +{ + release_usart_on<'0', Tx>(); + release_usart_on<'1', Tx>(); +} + template struct hardware_link { using uart = avr::uart::usart; @@ -212,6 +233,7 @@ struct software_link { static void init() { avr::init(); + release_usarts_on(); } static bool pending() @@ -245,6 +267,7 @@ struct autobaud_link { static void init() { avr::init(); + release_usarts_on(); } static std::uint8_t rx()