/** * @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 Common IRQ handler. * * @param[in] sdp pointer to a @p SerialDriver object */ static void serve_interrupt(SerialDriver *sdp) { volatile struct ESCI_tag *escip = sdp->escip; uint32_t sr = escip->SR.R; escip->SR.R = 0x3FFFFFFF; /* Does not clear TDRE | TC.*/ if (sr & 0x0F000000) /* OR | NF | FE | PF. */ set_error(sdp, sr); if (sr & 0x20000000) { /* RDRF. */ osalSysLockFromISR(); sdIncomingDataI(sdp, escip->DR.B.D); osalSysUnlockFromISR(); } if (escip->CR1.B.TIE && (sr & 0x80000000)) { /* TDRE. */ msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); escip->CR1.B.TIE = 0; } else { ESCI_A.SR.B.TDRE = 1; escip->DR.R = (uint16_t)b; } osalSysUnlockFromISR(); } }
/** * @brief Handles outgoing data. * @details Must be called from the output interrupt service routine in order * to get the next byte to be transmitted. * @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 * @return The byte value read from the driver's output queue. * @retval MSG_TIMEOUT if the queue is empty (the lower driver usually * disables the interrupt source when this happens). * * @iclass */ msg_t sdRequestDataI(SerialDriver *sdp) { msg_t b; osalDbgCheckClassI(); osalDbgCheck(sdp != NULL); b = oqGetI(&sdp->oqueue); if (b < MSG_OK) chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return b; }
/** * @brief Common IRQ handler. * * @param[in] sdp communication channel associated to the USART */ static void serve_interrupt(SerialDriver *sdp) { USART_TypeDef *u = sdp->usart; uint16_t cr1 = u->CR1; uint16_t sr = u->SR; /* Special case, LIN break detection.*/ if (sr & USART_SR_LBD) { osalSysLockFromISR(); chnAddFlagsI(sdp, SD_BREAK_DETECTED); u->SR = ~USART_SR_LBD; osalSysUnlockFromISR(); } /* Data available.*/ osalSysLockFromISR(); while (sr & (USART_SR_RXNE | USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) { uint8_t b; /* Error condition detection.*/ if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) set_error(sdp, sr); b = (uint8_t)u->DR & sdp->rxmask; if (sr & USART_SR_RXNE) sdIncomingDataI(sdp, b); sr = u->SR; } osalSysUnlockFromISR(); /* Transmission buffer empty.*/ if ((cr1 & USART_CR1_TXEIE) && (sr & USART_SR_TXE)) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); if (b < MSG_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE; } else u->DR = b; osalSysUnlockFromISR(); } /* Physical transmission end.*/ if ((cr1 & USART_CR1_TCIE) && (sr & USART_SR_TC)) { osalSysLockFromISR(); if (oqIsEmptyI(&sdp->oqueue)) { chnAddFlagsI(sdp, CHN_TRANSMISSION_END); u->CR1 = cr1 & ~USART_CR1_TCIE; } osalSysUnlockFromISR(); } }
/** * @brief Attempts a TX preload */ static void preload(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; if (u->S1 & UARTx_S1_TDRE) { msg_t b = oqGetI(&sdp->oqueue); if (b < MSG_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } u->D = b; u->C2 |= UARTx_C2_TIE; } }
/** * @brief Common IRQ handler. * * @param[in] sdp communication channel associated to the USART */ static void serve_interrupt(SerialDriver *sdp) { USART_TypeDef *u = sdp->usart; uint32_t cr1 = u->CR1; uint32_t isr; /* Reading and clearing status.*/ isr = u->ISR; u->ICR = isr; /* Error condition detection.*/ if (isr & (USART_ISR_ORE | USART_ISR_NE | USART_ISR_FE | USART_ISR_PE)) set_error(sdp, isr); /* Special case, LIN break detection.*/ if (isr & USART_ISR_LBDF) { osalSysLockFromISR(); chnAddFlagsI(sdp, SD_BREAK_DETECTED); osalSysUnlockFromISR(); } /* Data available.*/ if (isr & USART_ISR_RXNE) { osalSysLockFromISR(); sdIncomingDataI(sdp, (uint8_t)u->RDR); osalSysUnlockFromISR(); } /* Transmission buffer empty.*/ if ((cr1 & USART_CR1_TXEIE) && (isr & USART_ISR_TXE)) { msg_t b; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); u->CR1 = (cr1 & ~USART_CR1_TXEIE) | USART_CR1_TCIE; } else u->TDR = b; osalSysUnlockFromISR(); } /* Physical transmission end.*/ if (isr & USART_ISR_TC) { osalSysLockFromISR(); if (oqIsEmptyI(&sdp->oqueue)) chnAddFlagsI(sdp, CHN_TRANSMISSION_END); u->CR1 = cr1 & ~USART_CR1_TCIE; osalSysUnlockFromISR(); } }
/** * @brief */ static void fifo_load(SerialDriver *sdp) { UART_TypeDef *u = sdp->uart; while ((u->FR & TIVA_FR_TXFF) == 0) { msg_t b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } u->DR = b; } u->IM |= TIVA_IM_TXIM; /* transmit interrupt enable */ }
/** * @brief Common TXI IRQ handler. * * @param[in] sdp pointer to a @p SerialDriver object */ static void spc5xx_serve_txi_interrupt(SerialDriver *sdp) { msg_t b; sdp->linflexp->UARTSR.R = SPC5_UARTSR_DTF; osalSysLockFromISR(); b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); sdp->linflexp->UARTCR.B.TXEN = 0; } else sdp->linflexp->BDRL.B.DATA0 = b; osalSysUnlockFromISR(); }
/** * @brief Fill the hardware FIFO of a UART. */ static void fifo_load(SerialDriver *sdp) { uint32_t u = sdp->uart; while ((HWREG(u + UART_O_FR) & UART_FR_TXFF) == 0) { msg_t b = oqGetI(&sdp->oqueue); if (b < Q_OK) { chnAddFlagsI(sdp, CHN_OUTPUT_EMPTY); return; } HWREG(u + UART_O_DR) = b; } HWREG(u + UART_O_IM) |= UART_IM_TXIM; /* transmit interrupt enable */ }
/** * @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. */ }
/** * @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; } } }
/* callback */ static void hid_debug_flush_cb(void *arg) { HIDDebugDriver *hiddp = (HIDDebugDriver *)arg; size_t i, n; uint8_t buf[DEBUG_TX_SIZE]; osalSysLockFromISR(); /* check that the states of things are as they're supposed to */ if((usbGetDriverStateI(hiddp->config->usbp) != USB_ACTIVE) || (hiddp->state != HIDDEBUG_READY)) { /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); return; } /* don't do anything if the queue or has enough stuff in it */ if(((n = oqGetFullI(&hiddp->oqueue)) == 0) || (n >= DEBUG_TX_SIZE)) { /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); return; } /* there's stuff hanging in the queue - so dequeue and send */ for(i = 0; i < n; i++) buf[i] = (uint8_t)oqGetI(&hiddp->oqueue); for(i = n; i < DEBUG_TX_SIZE; i++) buf[i] = 0; osalSysUnlockFromISR(); usbPrepareTransmit(hiddp->config->usbp, hiddp->config->ep_in, buf, DEBUG_TX_SIZE); osalSysLockFromISR(); (void)usbStartTransmitI(hiddp->config->usbp, hiddp->config->ep_in); /* rearm the timer */ chVTSetI(&hid_debug_flush_timer, MS2ST(DEBUG_TX_FLUSH_MS), hid_debug_flush_cb, hiddp); osalSysUnlockFromISR(); }