Skip to content

Commit

Permalink
Add IDLE-IRQ & circular half-transfer support to USARTv1-DMA driver
Browse files Browse the repository at this point in the history
  • Loading branch information
andreika-git committed May 23, 2017
1 parent fa141e2 commit e081c3c
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
61 changes: 60 additions & 1 deletion os/hal/include/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,23 @@ typedef enum {
#define _uart_wakeup_rx_error_isr(uartp)
#endif /* !UART_USE_WAIT */

#if (UART_USE_WAIT == TRUE) || defined(__DOXYGEN__)
/**
* @brief Wakes up the waiting thread in case of RX timeout.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @notapi
*/
#define _uart_wakeup_rx_timeout_isr(uartp) { \
osalSysLockFromISR(); \
osalThreadResumeI(&(uartp)->threadrx, MSG_TIMEOUT); \
osalSysUnlockFromISR(); \
}
#else /* !UART_USE_WAIT */
#define _uart_wakeup_rx_timeout_isr(uartp)
#endif /* !UART_USE_WAIT */

/**
* @brief Common ISR code for early TX.
* @details This code handles the portable part of the ISR code:
Expand Down Expand Up @@ -257,6 +274,27 @@ typedef enum {
_uart_wakeup_rx_complete_isr(uartp); \
}

/**
* @brief Common ISR code for RX half-transfer data.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] uartp pointer to the @p UARTDriver object
* @param[in] full flag set to 1 for the second half, and 0 for the first half
*
* @notapi
*/
#define _uart_rx_half_isr_code(uartp, full) { \
if ((uartp)->config->rxhalf_cb != NULL) \
(uartp)->config->rxhalf_cb(uartp, full); \
}


/**
* @brief Common ISR code for RX error.
* @details This code handles the portable part of the ISR code:
Expand All @@ -279,7 +317,6 @@ typedef enum {
_uart_wakeup_rx_error_isr(uartp); \
}


/**
* @brief Common ISR code for RX on idle.
* @details This code handles the portable part of the ISR code:
Expand All @@ -298,6 +335,28 @@ typedef enum {
if ((uartp)->config->rxchar_cb != NULL) \
(uartp)->config->rxchar_cb(uartp, (uartp)->rxbuf); \
}

/**
* @brief Timeout ISR code for receiver.
* @details This code handles the portable part of the ISR code:
* - Callback invocation.
* - Waiting thread wakeup, if any.
* - Driver state transitions.
* .
* @note This macro is meant to be used in the low level drivers
* implementation only.
*
* @param[in] uartp pointer to the @p UARTDriver object
*
* @notapi
*/
#define _uart_timeout_isr_code(uartp) { \
if ((uartp)->config->timeout_cb != NULL) { \
(uartp)->config->timeout_cb(uartp); \
} \
_uart_wakeup_rx_timeout_isr(uartp); \
}

/** @} */

/*===========================================================================*/
Expand Down
29 changes: 26 additions & 3 deletions os/hal/ports/STM32/LLD/USARTv1/uart_lld.c
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ static void usart_start(UARTDriver *uartp) {
/* Mustn't ever set TCIE here - if done, it causes an immediate
interrupt.*/
cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;

/* Add Idle interrupt if needed */
if (uartp->config->timeout_cb != NULL)
cr1 |= USART_CR1_IDLEIE;

u->CR1 = uartp->config->cr1 | cr1;

/* Starting the receiver idle loop.*/
Expand Down Expand Up @@ -254,7 +259,14 @@ static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
received character and then the driver stays in the same state.*/
_uart_rx_idle_code(uartp);
}
else {
/* DMA half-transter interrupt handling - for the 1st/2nd half transfers. */
else if (uartp->config->rxhalf_cb != NULL) {
if ((flags & STM32_DMA_ISR_HTIF) != 0) {
_uart_rx_half_isr_code(uartp, 0);
} else if ((flags & STM32_DMA_ISR_TCIF) != 0) {
_uart_rx_half_isr_code(uartp, 1);
}
} else {
/* Receiver in active state, a callback is generated, if enabled, after
a completed transfer.*/
dmaStreamDisable(uartp->dmarx);
Expand Down Expand Up @@ -312,6 +324,11 @@ static void serve_usart_irq(UARTDriver *uartp) {
/* End of transmission, a callback is generated.*/
_uart_tx2_isr_code(uartp);
}

/* Idle interrupt sources are only checked if enabled in CR1.*/
if ((sr & USART_SR_IDLE) && (cr1 & USART_CR1_IDLEIE)) {
_uart_timeout_isr_code(uartp);
}
}

/*===========================================================================*/
Expand Down Expand Up @@ -778,8 +795,14 @@ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
/* RX DMA channel preparation.*/
dmaStreamSetMemory0(uartp->dmarx, rxbuf);
dmaStreamSetTransactionSize(uartp->dmarx, n);
dmaStreamSetMode(uartp->dmarx, uartp->dmamode | STM32_DMA_CR_DIR_P2M |
STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE);

uint32_t mode = STM32_DMA_CR_DIR_P2M | STM32_DMA_CR_MINC | STM32_DMA_CR_TCIE;

/* DMA half-transfer interrupt & circular mode, if needed */
if (uartp->config->rxhalf_cb != NULL)
mode |= STM32_DMA_CR_HTIE | STM32_DMA_CR_CIRC;

dmaStreamSetMode(uartp->dmarx, uartp->dmamode | mode);

/* Starting transfer.*/
dmaStreamEnable(uartp->dmarx);
Expand Down
18 changes: 18 additions & 0 deletions os/hal/ports/STM32/LLD/USARTv1/uart_lld.h
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,14 @@ typedef void (*uartccb_t)(UARTDriver *uartp, uint16_t c);
*/
typedef void (*uartecb_t)(UARTDriver *uartp, uartflags_t e);

/**
* @brief Receive Half-transfer UART notification callback type.
*
* @param[in] uartp pointer to the @p UARTDriver object
* @param[in] full flag set to 1 for the second half, and 0 for the first half
*/
typedef void (*uarthcb_t)(UARTDriver *uartp, uartflags_t full);

/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
Expand Down Expand Up @@ -502,6 +510,16 @@ typedef struct {
* @brief Initialization value for the CR3 register.
*/
uint16_t cr3;
/* Additional (optional) handlers. Placed here for the struct compatibility.*/
/**
* @brief Receiver timeout (idle) callback.
* @details Handles an idle interrupt for USARTv1.
*/
uartcb_t timeout_cb;
/**
* @brief Half-transfer receive buffer callback.
*/
uarthcb_t rxhalf_cb;
} UARTConfig;

/**
Expand Down

0 comments on commit e081c3c

Please sign in to comment.