// --------------------------------------------------------------------------- void USART_IRQHandler(int ComPortNum, int Direction) { LPC_USART_T *usart = USART_REG(ComPortNum); char c; switch (Direction) { case 1: // Transmit if (USART_RemoveCharFromTxBuffer(ComPortNum, c)) { usart->THR = c; // Write data } else { CPU_USART_TxBufferEmptyInterruptEnable(ComPortNum, FALSE); // Disable interrupt } Events_Set(SYSTEM_EVENT_FLAG_COM_OUT); break; case 2: // Receive c = (char)(usart->RBR); // Read data USART_AddCharToRxBuffer(ComPortNum, c); Events_Set(SYSTEM_EVENT_FLAG_COM_IN); break; default: break; } }
void USART_TxISR( UINT32 port ) { char c; GLOBAL_LOCK(irq); if(USART_RemoveCharFromTxBuffer( port, c )) { CPU_USART_WriteCharToTxBuffer( port, c ); Events_Set( SYSTEM_EVENT_FLAG_COM_OUT ); } else { CPU_USART_TxBufferEmptyInterruptEnable( port, FALSE ); } }
void USART_Driver::SendXOFF( INT32 ComPortNum, const UINT32 Flag ) { ASSERT_IRQ_MUST_BE_OFF(); HAL_USART_STATE& State = Hal_Usart_State[ComPortNum]; if(IS_POWERSAVE_ENABLED(State)) return; if(RX_XOFF_STATE(State) == 0) { // send the XOFF if we are the first to add the XOFF state SET_USART_FLAG(State, HAL_USART_STATE::c_TX_BUFFERXOFF); // enable interrupts to send the XOFF, but be expedient about it to improve response time CPU_USART_TxBufferEmptyInterruptEnable( ComPortNum, TRUE ); } SET_RX_XOFF_STATE(State,Flag); }
void USART_Driver::SendXON( INT32 ComPortNum, const UINT32 Flag ) { ASSERT_IRQ_MUST_BE_OFF(); HAL_USART_STATE& State = Hal_Usart_State[ComPortNum]; if(IS_POWERSAVE_ENABLED(State)) return; // clear our XOFF state CLEAR_RX_XOFF_STATE(State, Flag); if(RX_XOFF_STATE(State) == 0) { // send the XON if we are the last to remove the XOFF state SET_USART_FLAG(State, HAL_USART_STATE::c_TX_BUFFERXON); // enable interrupts to send the XON CPU_USART_TxBufferEmptyInterruptEnable( ComPortNum, TRUE ); // coming out of XON doesn't benefit from a priority inversion like XOFF does } }
int USART_Driver::Write( int ComPortNum, const char* Data, size_t size ) { NATIVE_PROFILE_PAL_COM(); int totWrite = 0; const char* ptr = Data; int j; if((ComPortNum < 0) || (ComPortNum >= TOTAL_USART_PORT)) {ASSERT(FALSE); return -1;} if(0 == size ) return -1; if(NULL == Data ) {ASSERT(FALSE); return -1;} HAL_USART_STATE& State = Hal_Usart_State[ComPortNum]; if (IS_POWERSAVE_ENABLED(State) || (!IS_USART_INITIALIZED(State)))return -1; if (USART_FLAG_STATE(State, HAL_USART_STATE::c_TX_SWFLOW_CTRL) && (!USART_FLAG_STATE(State, HAL_USART_STATE::c_TX_XON_STATE))) { // A timeout is used for XOFF incase the XOFF value was lost or never sent. // USART_TX_XOFF_TIMEOUT_TICKS is defined in the platform selector file if((USART_TX_XOFF_TIMEOUT_INFINITE != USART_TX_XOFF_TIMEOUT_TICKS ) && (HAL_Time_CurrentTicks() - State.TicksStartTxXOFF) > USART_TX_XOFF_TIMEOUT_TICKS) { SET_USART_FLAG(State, HAL_USART_STATE::c_TX_XON_STATE); } else { return 0; } } // loop twice if needed because of our implementaition of a circular buffered QUEUE for(j=0; (j < 2) && (totWrite < size); j++) { // Keep interrupts off to keep queue access atomic GLOBAL_LOCK(irq); UINT8 *Dst; size_t nWritten; nWritten = size - totWrite; Dst = State.TxQueue.Push( nWritten ); if( Dst != NULL ) { memcpy(Dst, ptr, nWritten); // Move characters to transmit queue from buffer totWrite += nWritten; ptr += nWritten; } else if(!USART_FLAG_STATE(State, HAL_USART_STATE::c_RX_HWFLOW_CTRL)) { SetEvent( ComPortNum, USART_EVENT_ERROR_TXFULL ); break; } } // we need to be atomic on PowerSave/USART_TxBufferEmptyInterruptEnable // since it gets set/cleared from ISR, and disables the clock, but // USART_TxBufferEmptyInterruptEnable turns the clock back on! // We don't want to turn on the USART clock if in power save mode { GLOBAL_LOCK(irq); if(size && !IS_POWERSAVE_ENABLED(State)) { // if we added chars, enable interrupts so characters will actually start flowing // we could do this early, then we race each iteration, and could cause a stall, // so we do this once to be efficient in the common case (buffer has room for all chars) CPU_USART_TxBufferEmptyInterruptEnable( ComPortNum, TRUE ); } } return totWrite; }