/************************************************************************************************** * @fn HalUARTRxAvailDMA() * * @brief Calculate Rx Buffer length - the number of bytes in the buffer. * * @param none * * @return length of current Rx Buffer **************************************************************************************************/ static uint16 HalUARTRxAvailDMA(void) { // First, synchronize the Rx tail marker with where the DMA Rx engine is working. rxIdx_t tail = dmaCfg.rxTail; do { if (!HAL_UART_DMA_NEW_RX_BYTE(tail)) { break; } HAL_UART_RX_IDX_T_INCR(tail); } while (tail != dmaCfg.rxHead); dmaCfg.rxTail = tail; uint16 cnt = tail - dmaCfg.rxHead; // If the DMA Rx may have overrun the circular queue, investigate further. if ((cnt == 0) && HAL_UART_DMA_NEW_RX_BYTE(tail)) { /* Ascertain whether this polling is racing with the DMA Rx which may have clocked in a byte * since walking the tail. The Rx queue has wrapped only if the byte before the head is new. */ tail = dmaCfg.rxHead; HAL_UART_RX_IDX_T_DECR(tail); if (HAL_UART_DMA_NEW_RX_BYTE(tail)) { if (HAL_UART_RX_FLUSH) { (void)memset(dmaCfg.rxBuf, (DMA_PAD ^ 0xFF), HAL_UART_DMA_RX_MAX*2); uartRxBug = dmaCfg.rxHead; dmaCfg.rxTail = dmaCfg.rxHead; } else { cnt = HAL_UART_DMA_RX_MAX; } } else { cnt = 1; } } else if (cnt > HAL_UART_DMA_RX_MAX) // If the tail has wrapped at the end of the Rx queue. { cnt += HAL_UART_DMA_RX_MAX; } 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); } /* 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 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); #if HAL_UART_DMA_RX_MAX == 256 (dmaCfg.rxHead)++; #else if (++(dmaCfg.rxHead) >= HAL_UART_DMA_RX_MAX) { dmaCfg.rxHead = 0; } #endif } PxOUT &= ~HAL_UART_Px_RTS; // Re-enable the flow on any read. return cnt; }
/************************************************************************************************** * @fn HalUARTRxAvailDMA() * * @brief Calculate Rx Buffer length - the number of bytes in the buffer. * * @param none * * @return length of current Rx Buffer **************************************************************************************************/ static uint16 HalUARTRxAvailDMA(void) { uint16 cnt = 0; if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { uint16 idx; for (idx = 0; idx < HAL_UART_DMA_RX_MAX; idx++) { if (HAL_UART_DMA_NEW_RX_BYTE(idx)) { cnt++; } } } return cnt; }
/***************************************************************************** * @fn findTail * * @brief Find the rxBuf index where the DMA RX engine is working. * * @param None. * * @return Index of tail of rxBuf. *****************************************************************************/ static rxIdx_t findTail(void) { rxIdx_t idx = dmaCfg.rxHead; do { if (!HAL_UART_DMA_NEW_RX_BYTE(idx)) { break; } #if HAL_UART_DMA_RX_MAX == 256 idx++; #else if (++idx >= HAL_UART_DMA_RX_MAX) { idx = 0; } #endif } while (idx != dmaCfg.rxHead); return idx; }
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 if (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { if (HAL_UART_DMA_NEW_RX_BYTE(uartRxBug)) { do { HAL_UART_RX_IDX_T_INCR(dmaCfg.rxHead); } while (!HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)); uartRxBug = dmaCfg.rxHead; dmaCfg.rxTail = dmaCfg.rxHead; } HAL_UART_RX_IDX_T_INCR(uartRxBug); } 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 HalUARTPollDMA * * @brief Poll a USART module implemented by DMA. * * @param none * * @return none *****************************************************************************/ static void HalUARTPollDMA(void) { uint16 cnt = 0; uint8 evt = 0; if (HAL_UART_DMA_NEW_RX_BYTE(dmaCfg.rxHead)) { rxIdx_t tail = findTail(); // If the DMA has transferred in more Rx bytes, reset the Rx idle timer. if (dmaCfg.rxTail != tail) { dmaCfg.rxTail = tail; // Re-sync the shadow on any 1st byte(s) received. if (dmaCfg.rxTick == 0) { dmaCfg.rxShdw = ST0; } dmaCfg.rxTick = HAL_UART_DMA_IDLE; } else if (dmaCfg.rxTick) { // Use the LSB of the sleep timer (ST0 must be read first anyway). uint8 decr = ST0 - dmaCfg.rxShdw; if (dmaCfg.rxTick > decr) { dmaCfg.rxTick -= decr; dmaCfg.rxShdw = ST0; } else { dmaCfg.rxTick = 0; } } cnt = HalUARTRxAvailDMA(); } else { dmaCfg.rxTick = 0; } if (cnt >= HAL_UART_DMA_FULL) { evt = HAL_UART_RX_FULL; } else if (cnt >= HAL_UART_DMA_HIGH) { evt = HAL_UART_RX_ABOUT_FULL; PxOUT |= HAL_UART_Px_RTS; // Disable Rx flow. } else if (cnt && !dmaCfg.rxTick) { evt = HAL_UART_RX_TIMEOUT; } if (dmaCfg.txMT) { dmaCfg.txMT = FALSE; evt |= HAL_UART_TX_EMPTY; } if (dmaCfg.txShdwValid) { uint8 decr = ST0; decr -= dmaCfg.txShdw; if (decr > dmaCfg.txTick) { // No protection for txShdwValid is required // because while the shadow was valid, DMA ISR cannot be triggered // to cause concurrent access to this variable. dmaCfg.txShdwValid = FALSE; } } if (dmaCfg.txDMAPending && !dmaCfg.txShdwValid) { // UART TX DMA is expected to be fired and enough time has lapsed since last DMA ISR // to know that DBUF can be overwritten halDMADesc_t *ch = HAL_DMA_GET_DESC1234(HAL_DMA_CH_TX); halIntState_t intState; // Clear the DMA pending flag dmaCfg.txDMAPending = FALSE; HAL_DMA_SET_SOURCE(ch, dmaCfg.txBuf[dmaCfg.txSel]); HAL_DMA_SET_LEN(ch, dmaCfg.txIdx[dmaCfg.txSel]); dmaCfg.txSel ^= 1; HAL_ENTER_CRITICAL_SECTION(intState); HAL_DMA_ARM_CH(HAL_DMA_CH_TX); do { asm("NOP"); } while (!HAL_DMA_CH_ARMED(HAL_DMA_CH_TX)); HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_TX); HAL_DMA_MAN_TRIGGER(HAL_DMA_CH_TX); HAL_EXIT_CRITICAL_SECTION(intState); } else { halIntState_t his; HAL_ENTER_CRITICAL_SECTION(his); if ((dmaCfg.txIdx[dmaCfg.txSel] != 0) && !HAL_DMA_CH_ARMED(HAL_DMA_CH_TX) && !HAL_DMA_CHECK_IRQ(HAL_DMA_CH_TX)) { HAL_EXIT_CRITICAL_SECTION(his); HalUARTIsrDMA(); } else { HAL_EXIT_CRITICAL_SECTION(his); } } if (evt && (dmaCfg.uartCB != NULL)) { dmaCfg.uartCB(HAL_UART_DMA-1, evt); } }