#include "system.h" #include "usart.h" static Usart * pInstance = nullptr; static constexpr unsigned HCLK = SYSTEM_CORE_CLOCK >> 1; extern "C" { [[gnu::interrupt]] extern void USART2_IRQHandler (void); }; void USART2_IRQHandler (void) { if (pInstance) pInstance->irq(); }; Usart::Usart(const uint32_t _baud) noexcept : BaseLayer (), tx_ring () { pInstance = this; // 1. Clock Enable RCC.APB1PCENR.B.USART2EN = SET; RCC.APB2PCENR.modify([](RCC_Type::APB2PCENR_DEF & r) -> auto { r.B.IOPAEN = SET; r.B.IOPBEN = SET; //r.B.AFIOEN = SET; return r.R; }); // 2. GPIO Alternate Config - default TX/PA2, RX/PA3, DEN/PB1 (TXEN=H) GPIOA.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.MODE2 = 1u; r.B.CNF2 = 2u; // or 3u for open drain r.B.MODE3 = 0u; r.B.CNF3 = 1u; // floating input return r.R; }); GPIOB.CFGLR.modify([](GPIOA_Type::CFGLR_DEF & r) -> auto { r.B.MODE1 = 1u; r.B.CNF1 = 0u; return r.R; }); RCC.APB1PRSTR.B.USART2RST = SET; RCC.APB1PRSTR.B.USART2RST = RESET; // 5. USART registry 8.bit bez parity USART2.CTLR1.modify([] (USART1_Type::CTLR1_DEF & r) -> auto { r.B.RE = SET; r.B.TE = SET; r.B.RXNEIE = SET; return r.R; }); USART2.CTLR2.modify ([](USART1_Type::CTLR2_DEF & r) -> auto { r.B.STOP = 0u; return r.R; }); const uint32_t tmp = HCLK / _baud; USART2.BRR.R = tmp; // NVIC NVIC.EnableIRQ (USART2_IRQn); USART2.CTLR1.B.UE = SET; // nakonec povolit globálně } void Usart::irq () { volatile USART1_Type::STATR_DEF status (USART2.STATR); // načti status přerušení char rdata, tdata; if (status.B.TC) { // od vysílače if (tx_ring.Read (tdata)) { // pokud máme data USART2.DATAR.B.DR = (uint8_t) tdata; // zapíšeme do výstupu } else { // pokud ne // Předpoklad je half-duplex i.e. RS485, jinak jen zakázat TCIE rdata = (USART2.DATAR.B.DR); // dummy read USART2.CTLR1.modify([](USART1_Type::CTLR1_DEF & r) -> auto { r.B.RE = SET; // povol prijem r.B.TCIE = RESET; // je nutné zakázat přerušení od vysílače return r.R; }); GPIOB.BSHR.B.BR1 = SET; // ukončit vysílání na linku } } if (status.B.RXNE) { // od přijímače rdata = (USART2.DATAR.B.DR); // načteme data Up (&rdata, 1u); // a pošleme dál } } uint32_t Usart::Down(const char * data, const uint32_t len) { unsigned n = 0u; for (n=0u; n auto { r.B.RE = RESET; r.B.TCIE = SET; // po povolení přerušení okamžitě přeruší return r.R; }); return n; }