/* Copyright (C) 2014..2017 Marco Veeneman 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. */ /** * @file UART/hal_uart_lld.c * @brief Tiva low level UART driver code. * * @addtogroup UART * @{ */ #include "hal.h" #if HAL_USE_UART || defined(__DOXYGEN__) /*===========================================================================*/ /* Driver local definitions. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver exported variables. */ /*===========================================================================*/ /** @brief UART0 UART driver identifier.*/ #if TIVA_UART_USE_UART0 || defined(__DOXYGEN__) UARTDriver UARTD1; #endif /** @brief UART1 UART driver identifier.*/ #if TIVA_UART_USE_UART1 || defined(__DOXYGEN__) UARTDriver UARTD2; #endif /** @brief UART2 UART driver identifier.*/ #if TIVA_UART_USE_UART2 || defined(__DOXYGEN__) UARTDriver UARTD3; #endif /** @brief UART3 UART driver identifier.*/ #if TIVA_UART_USE_UART3 || defined(__DOXYGEN__) UARTDriver UARTD4; #endif /** @brief UART4 UART driver identifier.*/ #if TIVA_UART_USE_UART4 || defined(__DOXYGEN__) UARTDriver UARTD5; #endif /** @brief UART5 UART driver identifier.*/ #if TIVA_UART_USE_UART5 || defined(__DOXYGEN__) UARTDriver UARTD6; #endif /** @brief UART6 UART driver identifier.*/ #if TIVA_UART_USE_UART6 || defined(__DOXYGEN__) UARTDriver UARTD7; #endif /** @brief UART7 UART driver identifier.*/ #if TIVA_UART_USE_UART7 || defined(__DOXYGEN__) UARTDriver UARTD8; #endif /*===========================================================================*/ /* Driver local variables and types. */ /*===========================================================================*/ /*===========================================================================*/ /* Driver local functions. */ /*===========================================================================*/ /** * @brief Status bits translation. * * @param[in] err UART LSR register value * * @return The error flags. */ static uartflags_t translate_errors(uint32_t err) { uartflags_t sts = 0; if (err & UART_MIS_FEMIS) sts |= UART_FRAMING_ERROR; if (err & UART_MIS_PEMIS) sts |= UART_PARITY_ERROR; if (err & UART_MIS_BEMIS) sts |= UART_BREAK_DETECTED; if (err & UART_MIS_OEMIS) sts |= UART_OVERRUN_ERROR; return sts; } /** * @brief Puts the receiver in the UART_RX_IDLE state. * * @param[in] uartp pointer to the @p UARTDriver object */ static void uart_enter_rx_idle_loop(UARTDriver *uartp) { tiva_udma_table_entry_t *primary = udmaControlTable.primary; dmaChannelDisable(uartp->dmarxnr); /* Configure for 8-bit transfers.*/ primary[uartp->dmarxnr].srcendp = (void *)(uartp->uart + UART_O_DR); primary[uartp->dmarxnr].dstendp = (volatile void *)&uartp->rxbuf; primary[uartp->dmarxnr].chctl = UDMA_CHCTL_DSTSIZE_8 | UDMA_CHCTL_DSTINC_8 | UDMA_CHCTL_SRCSIZE_8 | UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_ARBSIZE_4 | UDMA_CHCTL_XFERSIZE(1) | UDMA_CHCTL_XFERMODE_BASIC; dmaChannelSingleBurst(uartp->dmarxnr); dmaChannelPrimary(uartp->dmarxnr); dmaChannelPriorityDefault(uartp->dmarxnr); dmaChannelEnableRequest(uartp->dmarxnr); /* Enable DMA channel, transfer starts immediately.*/ dmaChannelEnable(uartp->dmarxnr); } /** * @brief UART de-initialization. * * @param[in] uartp pointer to the @p UARTDriver object */ static void uart_stop(UARTDriver *uartp) { /* Stops RX and TX DMA channels.*/ dmaChannelDisable(uartp->dmarxnr); dmaChannelDisable(uartp->dmatxnr); /* Stops USART operations.*/ HWREG(uartp->uart + UART_O_CTL) &= ~UART_CTL_UARTEN; } /** * @brief UART initialization. * * @param[in] uartp pointer to a @p UARTDriver object */ static void uart_init(UARTDriver *uartp) { uint32_t u = uartp->uart; const UARTConfig *config = uartp->config; uint32_t brd; uint32_t speed = config->speed; uint32_t clock_source; if (uartp->config->ctl & UART_CTL_HSE) { /* High speed mode is enabled, half the baud rate to compensate * for high speed mode.*/ speed = (speed + 1) / 2; } if ((config->cc & UART_CC_CS_M) == UART_CC_CS_SYSCLK) { /* UART is clocked using the SYSCLK.*/ clock_source = TIVA_SYSCLK * 8; } else { /* UART is clocked using the PIOSC.*/ clock_source = 16000000 * 8; } /* Calculate the baud rate divisor */ brd = ((clock_source / speed) + 1) / 2; /* Disable UART.*/ HWREG(u + UART_O_CTL) &= ~UART_CTL_UARTEN; /* Set baud rate.*/ HWREG(u + UART_O_IBRD) = brd / 64; HWREG(u + UART_O_FBRD) = brd % 64; /* Line control/*/ HWREG(u + UART_O_LCRH) = config->lcrh; /* Select clock source.*/ HWREG(u + UART_O_CC) = config->cc & UART_CC_CS_M; /* FIFO configuration.*/ HWREG(u + UART_O_IFLS) = config->ifls & (UART_IFLS_RX_M | UART_IFLS_TX_M); /* Enable interrupts.*/ HWREG(u + UART_O_IM) = UART_IM_TXIM | UART_IM_OEIM | UART_IM_BEIM | UART_IM_PEIM | UART_IM_FEIM; /* Enable DMA for the UART */ HWREG(u + UART_O_DMACTL) = UART_DMACTL_TXDMAE | UART_DMACTL_RXDMAE | UART_DMACTL_DMAERR; /* Note that some bits are enforced.*/ HWREG(u + UART_O_CTL) = config->ctl | UART_CTL_RXE | UART_CTL_TXE | UART_CTL_UARTEN | UART_CTL_EOT; /* Starting the receiver idle loop.*/ uart_enter_rx_idle_loop(uartp); } /** * @brief UART common service routine. * * @param[in] uartp pointer to the @p UARTDriver object */ static void uart_serve_interrupt(UARTDriver *uartp) { uint32_t dmachis = HWREG(UDMA_CHIS); uint32_t mis = HWREG(uartp->uart + UART_O_MIS); if (mis & UART_MIS_TXMIS) { /* End of transfer */ _uart_tx2_isr_code(uartp); } if (mis & (UART_MIS_OEMIS | UART_MIS_BEMIS | UART_MIS_PEMIS | UART_MIS_FEMIS)) { /* Error occurred */ _uart_rx_error_isr_code(uartp, translate_errors(mis)); } if (dmachis & (1 << uartp->dmarxnr)) { if (uartp->rxstate == UART_RX_IDLE) { /* Receiver in idle state, a callback is generated, if enabled, for each received character and then the driver stays in the same state.*/ _uart_rx_idle_code(uartp); uart_enter_rx_idle_loop(uartp); } else { /* Receiver in active state, a callback is generated, if enabled, after a completed transfer.*/ _uart_rx_complete_isr_code(uartp); } } if (dmachis & (1 << uartp->dmatxnr)) { /* A callback is generated, if enabled, after a completed transfer.*/ _uart_tx1_isr_code(uartp); } } /*===========================================================================*/ /* Driver interrupt handlers. */ /*===========================================================================*/ #if TIVA_UART_USE_UART0 || defined(__DOXYGEN__) #if !defined(TIVA_UART0_HANDLER) #error "TIVA_UART0_HANDLER not defined" #endif /** * @brief UART0 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART0_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD1); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART1 || defined(__DOXYGEN__) #if !defined(TIVA_UART1_HANDLER) #error "TIVA_UART1_HANDLER not defined" #endif /** * @brief UART1 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART1_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD2); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART2 || defined(__DOXYGEN__) #if !defined(TIVA_UART2_HANDLER) #error "TIVA_UART2_HANDLER not defined" #endif /** * @brief UART2 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART2_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD3); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART3 || defined(__DOXYGEN__) #if !defined(TIVA_UART3_HANDLER) #error "TIVA_UART3_HANDLER not defined" #endif /** * @brief UART3 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART3_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD4); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART4 || defined(__DOXYGEN__) #if !defined(TIVA_UART4_HANDLER) #error "TIVA_UART4_HANDLER not defined" #endif /** * @brief UART4 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART4_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD5); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART5 || defined(__DOXYGEN__) #if !defined(TIVA_UART5_HANDLER) #error "TIVA_UART5_HANDLER not defined" #endif /** * @brief UART5 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART5_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD6); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART6 || defined(__DOXYGEN__) #if !defined(TIVA_UART6_HANDLER) #error "TIVA_UART6_HANDLER not defined" #endif /** * @brief UART6 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART6_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD7); OSAL_IRQ_EPILOGUE(); } #endif #if TIVA_UART_USE_UART7 || defined(__DOXYGEN__) #if !defined(TIVA_UART7_HANDLER) #error "TIVA_UART7_HANDLER not defined" #endif /** * @brief UART7 interrupt handler. * * @isr */ OSAL_IRQ_HANDLER(TIVA_UART7_HANDLER) { OSAL_IRQ_PROLOGUE(); uart_serve_interrupt(&UARTD8); OSAL_IRQ_EPILOGUE(); } #endif /*===========================================================================*/ /* Driver exported functions. */ /*===========================================================================*/ /** * @brief Low level UART driver initialization. * * @notapi */ void uart_lld_init(void) { #if TIVA_UART_USE_UART0 uartObjectInit(&UARTD1); UARTD1.uart = UART0_BASE; UARTD1.dmarxnr = TIVA_UART_UART0_RX_UDMA_CHANNEL; UARTD1.dmatxnr = TIVA_UART_UART0_TX_UDMA_CHANNEL; UARTD1.rxchnmap = TIVA_UART_UART0_RX_UDMA_MAPPING; UARTD1.txchnmap = TIVA_UART_UART0_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART1 uartObjectInit(&UARTD2); UARTD2.uart = UART1_BASE; UARTD2.dmarxnr = TIVA_UART_UART1_RX_UDMA_CHANNEL; UARTD2.dmatxnr = TIVA_UART_UART1_TX_UDMA_CHANNEL; UARTD2.rxchnmap = TIVA_UART_UART1_RX_UDMA_MAPPING; UARTD2.txchnmap = TIVA_UART_UART1_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART2 uartObjectInit(&UARTD3); UARTD2.uart = UART2_BASE; UARTD2.dmarxnr = TIVA_UART_UART2_RX_UDMA_CHANNEL; UARTD2.dmatxnr = TIVA_UART_UART2_TX_UDMA_CHANNEL; UARTD2.rxchnmap = TIVA_UART_UART2_RX_UDMA_MAPPING; UARTD2.txchnmap = TIVA_UART_UART2_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART3 uartObjectInit(&UARTD4); UARTD4.uart = UART3_BASE; UARTD4.dmarxnr = TIVA_UART_UART3_RX_UDMA_CHANNEL; UARTD4.dmatxnr = TIVA_UART_UART3_TX_UDMA_CHANNEL; UARTD4.rxchnmap = TIVA_UART_UART3_RX_UDMA_MAPPING; UARTD4.txchnmap = TIVA_UART_UART3_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART4 uartObjectInit(&UARTD5); UARTD5.uart = UART4_BASE; UARTD5.dmarxnr = TIVA_UART_UART4_RX_UDMA_CHANNEL; UARTD5.dmatxnr = TIVA_UART_UART4_TX_UDMA_CHANNEL; UARTD5.rxchnmap = TIVA_UART_UART4_RX_UDMA_MAPPING; UARTD5.txchnmap = TIVA_UART_UART4_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART5 uartObjectInit(&UARTD6); UARTD6.uart = UART5_BASE; UARTD6.dmarxnr = TIVA_UART_UART5_RX_UDMA_CHANNEL; UARTD6.dmatxnr = TIVA_UART_UART5_TX_UDMA_CHANNEL; UARTD6.rxchnmap = TIVA_UART_UART5_RX_UDMA_MAPPING; UARTD6.txchnmap = TIVA_UART_UART5_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART6 uartObjectInit(&UARTD7); UARTD7.uart = UART6_BASE; UARTD7.dmarxnr = TIVA_UART_UART6_RX_UDMA_CHANNEL; UARTD7.dmatxnr = TIVA_UART_UART6_TX_UDMA_CHANNEL; UARTD7.rxchnmap = TIVA_UART_UART6_RX_UDMA_MAPPING; UARTD7.txchnmap = TIVA_UART_UART6_TX_UDMA_MAPPING; #endif #if TIVA_UART_USE_UART7 uartObjectInit(&UARTD8); UARTD8.uart = UART7_BASE; UARTD8.dmarxnr = TIVA_UART_UART7_RX_UDMA_CHANNEL; UARTD8.dmatxnr = TIVA_UART_UART7_TX_UDMA_CHANNEL; UARTD8.rxchnmap = TIVA_UART_UART7_RX_UDMA_MAPPING; UARTD8.txchnmap = TIVA_UART_UART7_TX_UDMA_MAPPING; #endif } /** * @brief Configures and activates the UART peripheral. * * @param[in] uartp pointer to the @p UARTDriver object * * @notapi */ void uart_lld_start(UARTDriver *uartp) { if (uartp->state == UART_STOP) { #if TIVA_UART_USE_UART0 if (&UARTD1 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 0); while (!(HWREG(SYSCTL_PRUART) & (1 << 0))) ; nvicEnableVector(TIVA_UART0_NUMBER, TIVA_UART_UART0_PRIORITY); } #endif #if TIVA_UART_USE_UART1 if (&UARTD2 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 1); while (!(HWREG(SYSCTL_PRUART) & (1 << 1))) ; nvicEnableVector(TIVA_UART1_NUMBER, TIVA_UART_UART1_PRIORITY); } #endif #if TIVA_UART_USE_UART2 if (&UARTD3 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 2); while (!(HWREG(SYSCTL_PRUART) & (1 << 2))) ; nvicEnableVector(TIVA_UART2_NUMBER, TIVA_UART_UART2_PRIORITY); } #endif #if TIVA_UART_USE_UART3 if (&UARTD4 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 3); while (!(HWREG(SYSCTL_PRUART) & (1 << 3))) ; nvicEnableVector(TIVA_UART3_NUMBER, TIVA_UART_UART3_PRIORITY); } #endif #if TIVA_UART_USE_UART4 if (&UARTD5 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 4); while (!(HWREG(SYSCTL_PRUART) & (1 << 4))) ; nvicEnableVector(TIVA_UART4_NUMBER, TIVA_UART_UART4_PRIORITY); } #endif #if TIVA_UART_USE_UART5 if (&UARTD6 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 5); while (!(HWREG(SYSCTL_PRUART) & (1 << 5))) ; nvicEnableVector(TIVA_UART5_NUMBER, TIVA_UART_UART5_PRIORITY); } #endif #if TIVA_UART_USE_UART6 if (&UARTD7 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 6); while (!(HWREG(SYSCTL_PRUART) & (1 << 6))) ; nvicEnableVector(TIVA_UART6_NUMBER, TIVA_UART_UART6_PRIORITY); } #endif #if TIVA_UART_USE_UART7 if (&UARTD8 == uartp) { bool b; b = udmaChannelAllocate(uartp->dmarxnr); osalDbgAssert(!b, "channel already allocated"); b = udmaChannelAllocate(uartp->dmatxnr); osalDbgAssert(!b, "channel already allocated"); HWREG(SYSCTL_RCGCUART) |= (1 << 7); while (!(HWREG(SYSCTL_PRUART) & (1 << 7))) ; nvicEnableVector(TIVA_UART7_NUMBER, TIVA_UART_UART7_PRIORITY); } #endif uartp->rxbuf = 0; HWREG(UDMA_CHMAP0 + (uartp->dmarxnr / 8) * 4) |= (uartp->rxchnmap << (uartp->dmarxnr % 8)); HWREG(UDMA_CHMAP0 + (uartp->dmatxnr / 8) * 4) |= (uartp->txchnmap << (uartp->dmatxnr % 8)); } uartp->rxstate = UART_RX_IDLE; uartp->txstate = UART_TX_IDLE; uart_init(uartp); } /** * @brief Deactivates the UART peripheral. * * @param[in] uartp pointer to the @p UARTDriver object * * @notapi */ void uart_lld_stop(UARTDriver *uartp) { if (uartp->state == UART_READY) { uart_stop(uartp); udmaChannelRelease(uartp->dmarxnr); udmaChannelRelease(uartp->dmatxnr); #if TIVA_UART_USE_UART0 if (&UARTD1 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 0); return; } #endif #if TIVA_UART_USE_UART1 if (&UARTD2 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 1); return; } #endif #if TIVA_UART_USE_UART2 if (&UARTD3 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 2); return; } #endif #if TIVA_UART_USE_UART3 if (&UARTD4 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 3); return; } #endif #if TIVA_UART_USE_UART4 if (&UARTD5 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 4); return; } #endif #if TIVA_UART_USE_UART5 if (&UARTD6 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 5); return; } #endif #if TIVA_UART_USE_UART6 if (&UARTD7 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 6); return; } #endif #if TIVA_UART_USE_UART7 if (&UARTD8 == uartp) { HWREG(SYSCTL_RCGCUART) &= ~(1 << 7); return; } #endif } } /** * @brief Starts a transmission on the UART peripheral. * @note The buffers are organized as uint8_t arrays for data sizes below * or equal to 8 bits else it is organized as uint16_t arrays. * * @param[in] uartp pointer to the @p UARTDriver object * @param[in] n number of data frames to send * @param[in] txbuf the pointer to the transmit buffer * * @notapi */ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { tiva_udma_table_entry_t *primary = udmaControlTable.primary; /* TODO: This assert should be moved to the dma helper driver */ osalDbgAssert((uint32_t)txbuf >= SRAM_BASE, "txbuf should be in SRAM region."); dmaChannelDisable(uartp->dmatxnr); /* Configure for 8-bit transfers.*/ primary[uartp->dmatxnr].srcendp = (volatile void *)txbuf+n-1; primary[uartp->dmatxnr].dstendp = (void *)(uartp->uart + UART_O_DR); primary[uartp->dmatxnr].chctl = UDMA_CHCTL_DSTSIZE_8 | UDMA_CHCTL_DSTINC_NONE | UDMA_CHCTL_SRCSIZE_8 | UDMA_CHCTL_SRCINC_8 | UDMA_CHCTL_ARBSIZE_4 | UDMA_CHCTL_XFERSIZE(n) | UDMA_CHCTL_XFERMODE_BASIC; dmaChannelSingleBurst(uartp->dmatxnr); dmaChannelPrimary(uartp->dmatxnr); dmaChannelPriorityDefault(uartp->dmatxnr); dmaChannelEnableRequest(uartp->dmatxnr); /* Enable DMA channel, transfer starts immediately.*/ dmaChannelEnable(uartp->dmatxnr); } /** * @brief Stops any ongoing transmission. * @note Stopping a transmission also suppresses the transmission callbacks. * * @param[in] uartp pointer to the @p UARTDriver object * * @return The number of data frames not transmitted by the * stopped transmit operation. * * @notapi */ size_t uart_lld_stop_send(UARTDriver *uartp) { tiva_udma_table_entry_t *primary = udmaControlTable.primary; uint16_t left; dmaChannelDisable(uartp->dmatxnr); left = ((primary[uartp->dmatxnr].chctl & UDMA_CHCTL_XFERSIZE_M) + 1) >> 4; return left; } /** * @brief Starts a receive operation on the UART peripheral. * @note The buffers are organized as uint8_t arrays for data sizes below * or equal to 8 bits else it is organized as uint16_t arrays. * * @param[in] uartp pointer to the @p UARTDriver object * @param[in] n number of data frames to send * @param[out] rxbuf the pointer to the receive buffer * * @notapi */ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) { tiva_udma_table_entry_t *primary = udmaControlTable.primary; /* TODO: This assert should be moved to the dma helper driver */ osalDbgAssert((uint32_t)rxbuf >= SRAM_BASE, "rxbuf should be in SRAM region."); dmaChannelDisable(uartp->dmarxnr); /* Configure for 8-bit transfers.*/ primary[uartp->dmarxnr].srcendp = (void *)(uartp->uart + UART_O_DR); primary[uartp->dmarxnr].dstendp = (volatile void *)rxbuf+n-1; primary[uartp->dmarxnr].chctl = UDMA_CHCTL_DSTSIZE_8 | UDMA_CHCTL_DSTINC_8 | UDMA_CHCTL_SRCSIZE_8 | UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_ARBSIZE_4 | UDMA_CHCTL_XFERSIZE(n) | UDMA_CHCTL_XFERMODE_BASIC; dmaChannelSingleBurst(uartp->dmarxnr); dmaChannelPrimary(uartp->dmarxnr); dmaChannelPriorityDefault(uartp->dmarxnr); dmaChannelEnableRequest(uartp->dmarxnr); /* Enable DMA channel, transfer starts immediately.*/ dmaChannelEnable(uartp->dmarxnr); } /** * @brief Stops any ongoing receive operation. * @note Stopping a receive operation also suppresses the receive callbacks. * * @param[in] uartp pointer to the @p UARTDriver object * * @return The number of data frames not received by the * stopped receive operation. * * @notapi */ size_t uart_lld_stop_receive(UARTDriver *uartp) { tiva_udma_table_entry_t *primary = udmaControlTable.primary; uint16_t left; dmaChannelDisable(uartp->dmatxnr); left = ((primary[uartp->dmatxnr].chctl & UDMA_CHCTL_XFERSIZE_M) + 1) >> 4; uart_enter_rx_idle_loop(uartp); return left; } #endif /* HAL_USE_UART */ /** @} */