/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serve_interrupt(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; uint8_t s1 = u->S1; if (s1 & UARTx_S1_RDRF) { osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (iqPutI(&sdp->iqueue, u->D) < MSG_OK) chnAddFlagsI(sdp, SD_OVERRUN_ERROR); osalSysUnlockFromISR(); } if (s1 & UARTx_S1_TDRE) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < MSG_OK) { osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); u->C2 &= ~UARTx_C2_TIE; } else { u->D = b; } } }
/** * @brief Handles incoming data. * @details This function must be called from the input interrupt service * routine in order to enqueue incoming data and generate the * related events. * @note The incoming data event is only generated when the input queue * becomes non-empty. * @note In order to gain some performance it is suggested to not use * this function directly but copy this code directly into the * interrupt service routine. * * @param[in] sdp pointer to a @p SerialDriver structure * @param[in] b the byte to be written in the driver's Input Queue * * @iclass */ void sdIncomingDataI(SerialDriver *sdp, uint8_t b) { osalDbgCheckClassI(); osalDbgCheck(sdp != NULL); if (iqIsEmptyI(&sdp->iqueue)) chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); if (iqPutI(&sdp->iqueue, b) < MSG_OK) chnAddFlagsI(sdp, SD_QUEUE_FULL_ERROR); }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serial_serve_interrupt(SerialDriver *sdp) { uint32_t u = sdp->uart; uint16_t mis = HWREG(u + UART_O_MIS); HWREG(u + UART_O_ICR) = mis; /* clear interrupts */ if (mis & (UART_MIS_FEMIS | UART_MIS_PEMIS | UART_MIS_BEMIS | UART_MIS_OEMIS)) { set_error(sdp, mis); } if ((mis & UART_MIS_RXMIS) || (mis & UART_MIS_RTMIS)) { osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) { chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); } osalSysUnlockFromISR(); while ((HWREG(u + UART_O_FR) & UART_FR_RXFE) == 0) { osalSysLockFromISR(); if (iqPutI(&sdp->iqueue, HWREG(u + UART_O_DR)) < Q_OK) { chnAddFlagsI(sdp, SD_QUEUE_FULL_ERROR); } osalSysUnlockFromISR(); } } if (mis & UART_MIS_TXMIS) { while ((HWREG(u + UART_O_FR) & UART_FR_TXFF) == 0) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < Q_OK) { HWREG(u + UART_O_IM) &= ~UART_IM_TXIM; osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); break; } HWREG(u + UART_O_DR) = b; } } /* TODO: Physical transmission end. */ }
/* Common function for all DMA-UART IRQ handlers. */ static void tsCopyDataFromDMA() { chSysLockFromISR(); // get 0-based DMA buffer position int dmaPos = TS_DMA_BUFFER_SIZE - dmaStreamGetTransactionSize(TS_DMA_UART_DEVICE->dmarx); // if the position is wrapped (circular DMA-mode enabled) if (dmaPos < tsUartDma.readPos) dmaPos += TS_DMA_BUFFER_SIZE; // we need to update the current readPos int newReadPos = tsUartDma.readPos; for (int i = newReadPos; i < dmaPos; ) { if (iqPutI(&tsUartDma.fifoRxQueue, tsUartDma.dmaBuffer[newReadPos]) != Q_OK) { break; // todo: ignore overflow? } // the read position should always stay inside the buffer range newReadPos = (++i) & (TS_DMA_BUFFER_SIZE - 1); } tsUartDma.readPos = newReadPos; chSysUnlockFromISR(); }
/** * @brief Common IRQ handler. * @note Tries hard to clear all the pending interrupt sources, we don't * want to go through the whole ISR and have another interrupt soon * after. * * @param[in] u pointer to an UART I/O block * @param[in] sdp communication channel associated to the UART */ static void serial_serve_interrupt(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; uint16_t mis = u->MIS; u->ICR = mis; /* clear interrupts */ if (mis & (TIVA_MIS_FEMIS | TIVA_MIS_PEMIS | TIVA_MIS_BEMIS | TIVA_MIS_OEMIS)) { set_error(sdp, mis); } if ((mis & TIVA_MIS_RXMIS) || (mis & TIVA_MIS_RTMIS)) { osalSysLockFromISR(); if (iqIsEmptyI(&sdp->iqueue)) { chnAddFlagsI(sdp, CHN_INPUT_AVAILABLE); } osalSysUnlockFromISR(); while ((u->FR & TIVA_FR_RXFE) == 0) { osalSysLockFromISR(); if (iqPutI(&sdp->iqueue, u->DR) < Q_OK) { chnAddFlagsI(sdp, SD_OVERRUN_ERROR); } osalSysUnlockFromISR(); } } if (mis & TIVA_MIS_TXMIS) { while ((u->FR & TIVA_FR_TXFF) == 0) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); osalSysUnlockFromISR(); if (b < Q_OK) { u->IM &= ~TIVA_IM_TXIM; osalSysLockFromISR(); chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); osalSysUnlockFromISR(); break; } u->DR = b; } } }