/***************************************************************************** * @fn HalUARTReadDMA * * @brief Read a buffer from the UART * * @param buf - valid data buffer at least 'len' bytes in size * len - max length number of bytes to copy to 'buf' * * @return length of buffer that was read *****************************************************************************/ static uint16 HalUARTReadDMA(uint8 *buf, uint16 len) { uint16 cnt; for (cnt = 0; cnt < len; cnt++) { if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { break; } *buf++ = HAL_UART_DMA_GET_RX_BYTE(dmaCfg.rxHead); HAL_UART_DMA_CLR_RX_BYTE(dmaCfg.rxHead); HAL_UART_RX_IDX_T_INCR(dmaCfg.rxHead); } /* Update pointers after reading the bytes */ dmaCfg.rxTail = dmaCfg.rxHead; if (!DMA_PM && (UxUCR & UCR_FLOW)) { HAL_UART_DMA_SET_RDY_OUT(); // Re-enable the flow asap (i.e. not wait until next uart poll). } return cnt; }
/***************************************************************************** * @fn HalUARTReadDMA * * @brief Read a buffer from the UART * * @param buf - valid data buffer at least 'len' bytes in size * len - max length number of bytes to copy to 'buf' * * @return length of buffer that was read *****************************************************************************/ static uint16 HalUARTReadDMA(uint8 *buf, uint16 len) { uint16 cnt; for (cnt = 0; cnt < len; cnt++) { if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { break; } *buf++ = HAL_UART_DMA_GET_RX_BYTE(dmaCfg.rxHead); HAL_UART_DMA_CLR_RX_BYTE(dmaCfg.rxHead); HAL_UART_RX_IDX_T_INCR(dmaCfg.rxHead); } if (!DMA_PM && (UxUCR & UCR_FLOW)) { if (HalUARTRxAvailDMA() < HAL_UART_DMA_HIGH) { HAL_UART_DMA_SET_RDY_OUT(); // Re-enable the flow asap (i.e. not wait until next uart poll). } } return cnt; }
/****************************************************************************** * @fn HalUARTArmTxDMA * * @brief Arm the Tx DMA channel. * * @param None * * @return None *****************************************************************************/ static void HalUARTArmTxDMA(void) { halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; dmaCfg.txTrig = 1; HAL_DMA_ARM_CH(HAL_DMA_CH_TX); HalUARTPollTxTrigDMA(); if (DMA_PM) { HAL_UART_DMA_SET_RDY_OUT(); } }
/****************************************************************************** * @fn HalUARTArmTxDMA * * @brief Arm the Tx DMA channel. * * @param None * * @return None *****************************************************************************/ static void HalUARTArmTxDMA(void) { halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; dmaCfg.txTrig = 1; HAL_DMA_ARM_CH(HAL_DMA_CH_TX); /* Time to arm each DMA channel is 9 cycles as per the user's guide */ asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); asm("nop"); HalUARTPollTxTrigDMA(); if (DMA_PM) { HAL_UART_DMA_SET_RDY_OUT(); } }
static uint16 HalUARTRxAvailDMA(void) { uint16 cnt = 0; #ifndef POWER_SAVING bool detectOverflow = FALSE; #endif // First, synchronize the Rx tail marker with where the DMA Rx engine is working. rxIdx_t tail = dmaCfg.rxTail; #ifndef POWER_SAVING if (!DMA_PM && (UxUCR & UCR_FLOW)) { HAL_UART_DMA_CLR_RDY_OUT(); // Stop the inflow for counting the bytes } #endif do { if (!HAL_UART_DMA_NEW_RX_BYTE(tail)) { break; } else { cnt++; } HAL_UART_RX_IDX_T_INCR(tail); } while (cnt < HAL_UART_DMA_RX_MAX); if(!cnt) { while(sweepIdx < HAL_UART_DMA_RX_MAX) { if (HAL_UART_DMA_NEW_RX_BYTE(sweepIdx)) { dmaCfg.rxTail = sweepIdx; dmaCfg.rxHead = sweepIdx; cnt = 0; #ifndef POWER_SAVING detectOverflow = TRUE; #endif break; } sweepIdx++; } if ( sweepIdx == HAL_UART_DMA_RX_MAX ) { sweepIdx = 0; } } #ifndef POWER_SAVING if ( (!DMA_PM && (UxUCR & UCR_FLOW)) && (!detectOverflow ) ) { HAL_UART_DMA_SET_RDY_OUT(); // Re-enable the flow asap } #endif return cnt; }
/****************************************************************************** * @fn HalUARTPollDMA * * @brief Poll a USART module implemented by DMA, including the hybrid solution in which the Rx * is driven by DMA but the Tx is driven by ISR. * * @param none * * @return none *****************************************************************************/ static void HalUARTPollDMA(void) { uint8 evt = 0; uint16 cnt; #if DMA_PM PxIEN &= ~DMA_RDYIn_BIT; // Clear to not race with DMA_RDY_IN ISR. { if (dmaRdyIsr || HAL_UART_DMA_RDY_IN() || HalUARTBusyDMA()) { // Master may have timed-out the SRDY asserted state & may need a new edge. #if HAL_UART_TX_BY_ISR if (!HAL_UART_DMA_RDY_IN() && (dmaCfg.txHead != dmaCfg.txTail)) #else if (!HAL_UART_DMA_RDY_IN() && ((dmaCfg.txIdx[0] != 0) || (dmaCfg.txIdx[1] != 0))) #endif { HAL_UART_DMA_CLR_RDY_OUT(); } dmaRdyIsr = 0; if (dmaRdyDly == 0) { (void)osal_set_event(Hal_TaskID, HAL_PWRMGR_HOLD_EVENT); } if ((dmaRdyDly = ST0) == 0) // Reserve zero to signify that the delay expired. { dmaRdyDly = 0xFF; } HAL_UART_DMA_SET_RDY_OUT(); } else if ((dmaRdyDly != 0) && (!DMA_PM_DLY || ((uint8)(ST0 - dmaRdyDly) > DMA_PM_DLY))) { dmaRdyDly = 0; (void)osal_set_event(Hal_TaskID, HAL_PWRMGR_CONSERVE_EVENT); } } PxIEN |= DMA_RDYIn_BIT; #endif #if !HAL_UART_TX_BY_ISR HalUARTPollTxTrigDMA(); #endif cnt = HalUARTRxAvailDMA(); // Wait to call until after the above DMA Rx bug work-around. #if HAL_UART_DMA_IDLE if (dmaCfg.rxTick) { // Use the LSB of the sleep timer (ST0 must be read first anyway) to measure the Rx timeout. if ((ST0 - dmaCfg.rxTick) > HAL_UART_DMA_IDLE) { dmaCfg.rxTick = 0; evt = HAL_UART_RX_TIMEOUT; } } else if (cnt != 0) { if ((dmaCfg.rxTick = ST0) == 0) // Zero signifies that the Rx timeout is not running. { dmaCfg.rxTick = 0xFF; } } #else if (cnt != 0) { evt = HAL_UART_RX_TIMEOUT; } #endif if (cnt >= HAL_UART_DMA_FULL) { evt |= HAL_UART_RX_FULL; } else if (cnt >= HAL_UART_DMA_HIGH) { evt |= HAL_UART_RX_ABOUT_FULL; if (!DMA_PM && (UxUCR & UCR_FLOW)) { HAL_UART_DMA_CLR_RDY_OUT(); // Disable Rx flow. } } if (dmaCfg.txMT) { dmaCfg.txMT = FALSE; evt |= HAL_UART_TX_EMPTY; } if ((evt != 0) && (dmaCfg.uartCB != NULL)) { dmaCfg.uartCB(HAL_UART_DMA-1, evt); } if (DMA_PM && (dmaRdyDly == 0) && !HalUARTBusyDMA()) { HAL_UART_DMA_CLR_RDY_OUT(); } }
/****************************************************************************** * @fn HalUARTOpenDMA * * @brief Open a port according tp the configuration specified by parameter. * * @param config - contains configuration information * * @return none *****************************************************************************/ static void HalUARTOpenDMA(halUARTCfg_t *config) { dmaCfg.uartCB = config->callBackFunc; // Only supporting subset of baudrate for code size - other is possible. HAL_ASSERT((config->baudRate == HAL_UART_BR_9600) || (config->baudRate == HAL_UART_BR_19200) || (config->baudRate == HAL_UART_BR_38400) || (config->baudRate == HAL_UART_BR_57600) || (config->baudRate == HAL_UART_BR_115200)); if (config->baudRate == HAL_UART_BR_57600 || config->baudRate == HAL_UART_BR_115200) { UxBAUD = 216; } else { UxBAUD = 59; } switch (config->baudRate) { case HAL_UART_BR_9600: UxGCR = 8; break; case HAL_UART_BR_19200: UxGCR = 9; break; case HAL_UART_BR_38400: case HAL_UART_BR_57600: UxGCR = 10; break; default: // HAL_UART_BR_115200 UxGCR = 11; break; } if (DMA_PM || config->flowControl) { UxUCR = UCR_FLOW | UCR_STOP; // 8 bits/char; no parity; 1 stop bit; stop bit hi. PxSEL |= HAL_UART_Px_CTS; // Enable Peripheral control of CTS flow control on Px. } else { UxUCR = UCR_STOP; // 8 bits/char; no parity; 1 stop bit; stop bit hi. } UxCSR = (CSR_MODE | CSR_RE); if (DMA_PM) { PxIFG = 0; PxIF = 0; IENx |= IEN_BIT; } else if (UxUCR & UCR_FLOW) { // DMA Rx is always on (self-resetting). So flow must be controlled by the S/W polling the // circular Rx queue depth. Start by allowing flow. HAL_UART_DMA_SET_RDY_OUT(); PxDIR |= HAL_UART_Px_RTS; } #if HAL_UART_TX_BY_ISR UTXxIF = 1; // Prime the ISR pump. #endif }