HAL_ISR_FUNCTION(port1Isr, P1INT_VECTOR) #endif { HAL_ENTER_ISR(); PxIFG = 0; PxIF = 0; dmaRdyIsr = 1; #ifdef POWER_SAVING CLEAR_SLEEP_MODE(); osal_pwrmgr_task_state(Hal_TaskID, PWRMGR_HOLD); #if HAL_UART_TX_BY_ISR if (dmaCfg.txHead == dmaCfg.txTail) { HAL_UART_DMA_CLR_RDY_OUT(); } #endif #endif HAL_EXIT_ISR(); }
HAL_ISR_FUNCTION(port0Isr, P0INT_VECTOR) { unsigned char status; unsigned char i; HAL_ENTER_ISR(); status = P0IFG; status &= P0IEN; if (status) { P0IFG = ~status; P0IF = 0; #if HAL_UART_DMA == 1 extern uint8 Hal_TaskID; extern volatile uint8 dmaRdyIsr; dmaRdyIsr = 1; CLEAR_SLEEP_MODE(); osal_pwrmgr_task_state(Hal_TaskID, PWRMGR_HOLD); #if HAL_UART_TX_BY_ISR if (dmaCfg.txHead == dmaCfg.txTail) { HAL_UART_DMA_CLR_RDY_OUT(); } #endif #endif // HAL_UART_DMA for (i = 0; i < OS_MAX_INTERRUPT; i++) { if (PIN_MAJOR(blueBasic_interrupts[i].pin) == 0 && (status & (1 << PIN_MINOR(blueBasic_interrupts[i].pin)))) { osal_set_event(blueBasic_TaskID, BLUEBASIC_EVENT_INTERRUPT << i); } } } HAL_EXIT_ISR(); }
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 HalUARTInitDMA * * @brief Initialize the UART * * @param none * * @return none *****************************************************************************/ static void HalUARTInitDMA(void) { halDMADesc_t *ch; #if (HAL_UART_DMA == 1) PERCFG &= ~HAL_UART_PERCFG_BIT; // Set UART0 I/O to Alt. 1 location on P0. #else PERCFG |= HAL_UART_PERCFG_BIT; // Set UART1 I/O to Alt. 2 location on P1. #endif PxSEL |= HAL_UART_Px_SEL; // Enable Peripheral control of Rx/Tx on Px. p0.2 P0.3 set peripheral //i0 setting UxCSR = CSR_MODE; // Mode is UART Mode. UxUCR = UCR_FLUSH; // Flush it. P2DIR &= ~P2DIR_PRIPO; //ÓÅÏȼ¶ P2DIR |= HAL_UART_PRIPO; if (DMA_PM) { // Setup GPIO for interrupts by falling edge on DMA_RDY_IN. PxIEN |= DMA_RDYIn_BIT; PICTL |= PICTL_BIT; HAL_UART_DMA_CLR_RDY_OUT(); PxDIR |= DMA_RDYOut_BIT; } #if !HAL_UART_TX_BY_ISR // Setup Tx by DMA. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX ); // Abort any pending DMA operations (in case of a soft reset). HAL_DMA_ABORT_CH( HAL_DMA_CH_TX ); // The start address of the destination. HAL_DMA_SET_DEST( ch, DMA_UxDBUF ); // Using the length field to determine how many bytes to transfer. HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN ); // One byte is transferred each time. HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE ); // The bytes are transferred 1-by-1 on Tx Complete trigger. HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE ); HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX ); // The source address is incremented by 1 byte after each transfer. HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 ); // The destination address is constant - the Tx Data Buffer. HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 ); // The DMA Tx done is serviced by ISR in order to maintain full thruput. HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_ENABLE ); // Xfer all 8 bits of a byte xfer. HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS ); // DMA has highest priority for memory access. HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH); #endif // Setup Rx by DMA. ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX ); // Abort any pending DMA operations (in case of a soft reset). HAL_DMA_ABORT_CH( HAL_DMA_CH_RX ); // The start address of the source. HAL_DMA_SET_SOURCE( ch, DMA_UxDBUF ); // Using the length field to determine how many bytes to transfer. HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN ); /* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx. * The byte after the Rx Data Buffer is the Baud Cfg Register, * which always has a known value. So init Rx buffer to inverse of that * known value. DMA word xfer will flip the bytes, so every valid Rx byte * in the Rx buffer will be preceded by a DMA_PAD char equal to the * Baud Cfg Register value. */ HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD ); // The bytes are transferred 1-by-1 on Rx Complete trigger. HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE_REPEATED ); HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_RX ); // The source address is constant - the Rx Data Buffer. HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 ); // The destination address is incremented by 1 word after each transfer. HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 ); HAL_DMA_SET_DEST( ch, dmaCfg.rxBuf ); HAL_DMA_SET_LEN( ch, HAL_UART_DMA_RX_MAX ); // The DMA is to be polled and shall not issue an IRQ upon completion. HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE ); // Xfer all 8 bits of a byte xfer. HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS ); // DMA has highest priority for memory access. HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH); volatile uint8 dummy = *(volatile uint8 *)DMA_UxDBUF; // Clear the DMA Rx trigger. HAL_DMA_CLEAR_IRQ(HAL_DMA_CH_RX); HAL_DMA_ARM_CH(HAL_DMA_CH_RX); (void)memset(dmaCfg.rxBuf, (DMA_PAD ^ 0xFF), HAL_UART_DMA_RX_MAX * sizeof(uint16)); }