/** * @brief I2C shared ISR code. * * @param[in] i2cp pointer to the @p I2CDriver object * * @notapi */ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) { I2C_TypeDef *dp = i2cp->i2c; /* Interrupts are disabled just before dmaStreamEnable() because there is no need of interrupts until next transaction begin. All the work is done by the DMA.*/ switch (i2c_get_event(i2cp)) { case I2C_EV5_MASTER_MODE_SELECT: dp->DR = i2cp->addr; break; case I2C_EV6_MASTER_REC_MODE_SELECTED: dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmarx); dp->CR2 |= I2C_CR2_LAST; /* Needed in receiver mode. */ break; case I2C_EV6_MASTER_TRA_MODE_SELECTED: dp->CR2 &= ~I2C_CR2_ITEVTEN; dmaStreamEnable(i2cp->dmatx); break; case I2C_EV8_2_MASTER_BYTE_TRANSMITTED: /* Catches BTF event after the end of transmission.*/ if (dmaStreamGetTransactionSize(i2cp->dmarx) > 0) { /* Starts "read after write" operation, LSB = 1 -> receive.*/ i2cp->addr |= 0x01; dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK; return; } dp->CR2 &= ~I2C_CR2_ITEVTEN; dp->CR1 |= I2C_CR1_STOP; wakeup_isr(i2cp, RDY_OK); break; default: break; } }
/** * @brief ADC ISR service routine. * * @param[in] adcp pointer to the @p ADCDriver object * @param[in] isr content of the ISR register */ static void adc_lld_serve_interrupt(ADCDriver *adcp, uint32_t isr) { /* It could be a spurious interrupt caused by overflows after DMA disabling, just ignore it in this case.*/ if (adcp->grpp != NULL) { /* Note, an overflow may occur after the conversion ended before the driver is able to stop the ADC, this is why the DMA channel is checked too.*/ if ((isr & ADC_ISR_OVR) && (dmaStreamGetTransactionSize(adcp->dmastp) > 0)) { /* ADC overflow condition, this could happen only if the DMA is unable to read data fast enough.*/ _adc_isr_error_code(adcp, ADC_ERR_OVERFLOW); } if (isr & ADC_ISR_AWD1) { /* Analog watchdog error.*/ _adc_isr_error_code(adcp, ADC_ERR_AWD1); } if (isr & ADC_ISR_AWD2) { /* Analog watchdog error.*/ _adc_isr_error_code(adcp, ADC_ERR_AWD2); } if (isr & ADC_ISR_AWD3) { /* Analog watchdog error.*/ _adc_isr_error_code(adcp, ADC_ERR_AWD3); } } }
u32 usart_support_n_read(void *sd) { struct usart_support_s *u = (struct usart_support_s *)sd; struct usart_rx_dma_state *s = &u->rx; s32 n_read = s->rd_wraps * USART_RX_BUFFER_LEN + s->rd; s32 n_written = (s->wr_wraps + 1) * USART_RX_BUFFER_LEN - dmaStreamGetTransactionSize(s->dma); s32 n_available = n_written - n_read; if (n_available < 0) { /* This strange and rare case occurs when NDTR has rolled over but the flag * hasn't been raised yet and thus n_wraps hasn't been incremented in the * ISR. Simply return 0 this time and the next time this function is called * (or at some point) the interrupt will have been triggered and the number * of bytes available in the buffer will be a sane amount. */ n_available = 0; } else if (n_available > USART_RX_BUFFER_LEN) { /* If greater than a whole buffer then we have had an overflow. */ log_error("DMA RX buffer overrun"); n_available = 0; /* Disable and re-enable the DMA channel to get back to a known good * state */ dmaStreamDisable(s->dma); usart_support_init_rx(u); } return n_available; }
/** * @brief Stops any ongoing receive operation. * @note Stopping a receive operation also suppresses the receive callbacks. * * @param[in] uartp pointer to the @p UARTDriver object * * @return The number of data frames not received by the * stopped receive operation. * * @notapi */ size_t uart_lld_stop_receive(UARTDriver *uartp) { size_t n; dmaStreamDisable(uartp->dmarx); n = dmaStreamGetTransactionSize(uartp->dmarx); set_rx_idle_loop(uartp); return n; }
/** * @brief I2C shared ISR code. * * @param[in] i2cp pointer to the @p I2CDriver object * @param[in] isr content of the ISR register to be decoded * * @notapi */ static void i2c_lld_serve_interrupt(I2CDriver *i2cp, uint32_t isr) { I2C_TypeDef *dp = i2cp->i2c; if ((isr & I2C_ISR_TC) && (i2cp->state == I2C_ACTIVE_TX)) { size_t rxbytes; /* Make sure no more 'Transfer complete' interrupts.*/ dp->CR1 &= ~I2C_CR1_TCIE; rxbytes = dmaStreamGetTransactionSize(i2cp->dmarx); if (rxbytes > 0) { i2cp->state = I2C_ACTIVE_RX; /* Enable RX DMA */ dmaStreamEnable(i2cp->dmarx); dp->CR2 &= ~I2C_CR2_NBYTES; dp->CR2 |= rxbytes << 16; /* Starts the read operation.*/ dp->CR2 |= I2C_CR2_RD_WRN; dp->CR2 |= I2C_CR2_START; } else { /* Nothing to receive - send STOP immediately.*/ dp->CR2 |= I2C_CR2_STOP; } } if (isr & I2C_ISR_NACKF) { /* Starts a STOP sequence immediately on error.*/ dp->CR2 |= I2C_CR2_STOP; i2cp->errors |= I2CD_ACK_FAILURE; } if (isr & I2C_ISR_STOPF) { /* Stops the associated DMA streams.*/ dmaStreamDisable(i2cp->dmatx); dmaStreamDisable(i2cp->dmarx); if (i2cp->errors) { wakeup_isr(i2cp, RDY_RESET); } else { wakeup_isr(i2cp, RDY_OK); } } }
/* 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 Starts a transmission on the UART peripheral. * @note The buffers are organized as uint8_t arrays for data sizes below * or equal to 8 bits else it is organized as uint16_t arrays. * * @param[in] uartp pointer to the @p UARTDriver object * @param[in] n number of data frames to send * @param[in] txbuf the pointer to the transmit buffer * * @notapi */ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) { /* TX DMA channel preparation.*/ dmaStreamSetMemory0(uartp->dmatx, txbuf); dmaStreamSetTransactionSize(uartp->dmatx, n); dmaStreamSetMode(uartp->dmatx, uartp->dmamode | STM32_DMA_CR_DIR_M2P | STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE); /* Only enable TC interrupt if there's a callback attached to it or if called from uartSendFullTimeout(). Also we need to clear TC flag which could be set before.*/ #if UART_USE_WAIT == TRUE if ((uartp->config->txend2_cb != NULL) || (uartp->early == false)) { #else if (uartp->config->txend2_cb != NULL) { #endif uartp->usart->SR = ~USART_SR_TC; uartp->usart->CR1 |= USART_CR1_TCIE; } /* Starting transfer.*/ dmaStreamEnable(uartp->dmatx); } /** * @brief Stops any ongoing transmission. * @note Stopping a transmission also suppresses the transmission callbacks. * * @param[in] uartp pointer to the @p UARTDriver object * * @return The number of data frames not transmitted by the * stopped transmit operation. * * @notapi */ size_t uart_lld_stop_send(UARTDriver *uartp) { dmaStreamDisable(uartp->dmatx); return dmaStreamGetTransactionSize(uartp->dmatx); }
/** * @brief Stops any ongoing transmission. * @note Stopping a transmission also suppresses the transmission callbacks. * * @param[in] uartp pointer to the @p UARTDriver object * * @return The number of data frames not transmitted by the * stopped transmit operation. * * @notapi */ size_t uart_lld_stop_send(UARTDriver *uartp) { dmaStreamDisable(uartp->dmatx); return dmaStreamGetTransactionSize(uartp->dmatx); }