/** * * This function handles the interrupt when data has been sent, the transmit * FIFO is empty (transmitter holding register). * * @param InstancePtr is a pointer to the XUartPs instance * @param IsrStatus is the register value for channel status register * * @return None. * * @note None. * *****************************************************************************/ static void SendDataHandler(XUartPs *InstancePtr, u32 IsrStatus) { /* * If there are not bytes to be sent from the specified buffer then disable * the transmit interrupt so it will stop interrupting as it interrupts * any time the FIFO is empty */ if (InstancePtr->SendBuffer.RemainingBytes == (u32)0) { XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IDR_OFFSET, ((u32)XUARTPS_IXR_TXEMPTY | (u32)XUARTPS_IXR_TXFULL)); /* Call the application handler to indicate the sending is done */ InstancePtr->Handler(InstancePtr->CallBackRef, XUARTPS_EVENT_SENT_DATA, InstancePtr->SendBuffer.RequestedBytes - InstancePtr->SendBuffer.RemainingBytes); } /* * If TX FIFO is empty, send more. */ else if((IsrStatus & ((u32)XUARTPS_IXR_TXEMPTY)) != (u32)0) { (void)XUartPs_SendBuffer(InstancePtr); } else { /* Else with dummy entry for MISRA-C Compliance.*/ ; } }
/** * * This functions sends the specified buffer using the device in either * polled or interrupt driven mode. This function is non-blocking, if the device * is busy sending data, it will return and indicate zero bytes were sent. * Otherwise, it fills the TX FIFO as much as it can, and return the number of * bytes sent. * * In a polled mode, this function will only send as much data as TX FIFO can * buffer. The application may need to call it repeatedly to send the entire * buffer. * * In interrupt mode, this function will start sending the specified buffer, * then the interrupt handler will continue sending data until the entire * buffer has been sent. A callback function, as specified by the application, * will be called to indicate the completion of sending. * * @param InstancePtr is a pointer to the XUartPs instance. * @param BufferPtr is pointer to a buffer of data to be sent. * @param NumBytes contains the number of bytes to be sent. A value of * zero will stop a previous send operation that is in progress * in interrupt mode. Any data that was already put into the * transmit FIFO will be sent. * * @return The number of bytes actually sent. * * @note * * The number of bytes is not asserted so that this function may be called with * a value of zero to stop an operation that is already in progress. * <br><br> * *****************************************************************************/ u32 XUartPs_Send(XUartPs *InstancePtr, u8 *BufferPtr, u32 NumBytes) { u32 BytesSent; /* * Asserts validate the input arguments */ Xil_AssertNonvoid(InstancePtr != NULL); Xil_AssertNonvoid(BufferPtr != NULL); Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY); /* * Disable the UART transmit interrupts to allow this call to stop a * previous operation that may be interrupt driven. */ XUartPs_WriteReg(InstancePtr->Config.BaseAddress, XUARTPS_IDR_OFFSET, (XUARTPS_IXR_TXEMPTY | XUARTPS_IXR_TXFULL)); /* * Setup the buffer parameters */ InstancePtr->SendBuffer.RequestedBytes = NumBytes; InstancePtr->SendBuffer.RemainingBytes = NumBytes; InstancePtr->SendBuffer.NextBytePtr = BufferPtr; /* * Transmit interrupts will be enabled in XUartPs_SendBuffer(), after * filling the TX FIFO. */ BytesSent = XUartPs_SendBuffer(InstancePtr); return BytesSent; }
void prvUART_Handler( void *pvNotUsed ) { extern unsigned int XUartPs_SendBuffer( XUartPs *InstancePtr ); uint32_t ulActiveInterrupts, ulChannelStatusRegister; BaseType_t xHigherPriorityTaskWoken = pdFALSE; char cChar; configASSERT( pvNotUsed == &xUARTInstance ); /* Remove compile warnings if configASSERT() is not defined. */ ( void ) pvNotUsed; /* Read the interrupt ID register to see which interrupt is active. */ ulActiveInterrupts = XUartPs_ReadReg(XPAR_PS7_UART_1_BASEADDR, XUARTPS_IMR_OFFSET); ulActiveInterrupts &= XUartPs_ReadReg(XPAR_PS7_UART_1_BASEADDR, XUARTPS_ISR_OFFSET); /* Are any receive events of interest active? */ if( ( ulActiveInterrupts & serRECEIVE_INTERRUPT_MASK ) != 0 ) { /* Read the Channel Status Register to determine if there is any data in the RX FIFO. */ ulChannelStatusRegister = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_SR_OFFSET ); /* Move data from the Rx FIFO to the Rx queue. NOTE THE COMMENTS AT THE TOP OF THIS FILE ABOUT USING QUEUES FOR THIS PURPSOE. */ while( ( ulChannelStatusRegister & XUARTPS_SR_RXEMPTY ) == 0 ) { cChar = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_FIFO_OFFSET ); /* If writing to the queue unblocks a task, and the unblocked task has a priority above the currently running task (the task that this interrupt interrupted), then xHigherPriorityTaskWoken will be set to pdTRUE inside the xQueueSendFromISR() function. xHigherPriorityTaskWoken is then passed to portYIELD_FROM_ISR() at the end of this interrupt handler to request a context switch so the interrupt returns directly to the (higher priority) unblocked task. */ xQueueSendFromISR( xRxQueue, &cChar, &xHigherPriorityTaskWoken ); ulChannelStatusRegister = XUartPs_ReadReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_SR_OFFSET ); } } /* Are any transmit events of interest active? */ if( ( ulActiveInterrupts & serTRANSMIT_IINTERRUPT_MASK ) != 0 ) { if( xUARTInstance.SendBuffer.RemainingBytes == 0 ) { /* Give back the semaphore to indicate that the tranmission is complete. If giving the semaphore unblocks a task, and the unblocked task has a priority above the currently running task (the task that this interrupt interrupted), then xHigherPriorityTaskWoken will be set to pdTRUE inside the xSemaphoreGiveFromISR() function. xHigherPriorityTaskWoken is then passed to portYIELD_FROM_ISR() at the end of this interrupt handler to request a context switch so the interrupt returns directly to the (higher priority) unblocked task. */ xSemaphoreGiveFromISR( xTxCompleteSemaphore, &xHigherPriorityTaskWoken ); /* No more data to transmit. */ XUartPs_WriteReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_IDR_OFFSET, XUARTPS_IXR_TXEMPTY ); } else { /* More data to send. */ XUartPs_SendBuffer( &xUARTInstance ); } } /* portYIELD_FROM_ISR() will request a context switch if executing this interrupt handler caused a task to leave the blocked state, and the task that left the blocked state has a higher priority than the currently running task (the task this interrupt interrupted). See the comment above the calls to xSemaphoreGiveFromISR() and xQueueSendFromISR() within this function. */ portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); /* Clear the interrupt status. */ XUartPs_WriteReg( XPAR_PS7_UART_1_BASEADDR, XUARTPS_ISR_OFFSET, ulActiveInterrupts ); }