git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@2095 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
79b97b0f60
commit
8249123228
|
@ -98,3 +98,10 @@
|
|||
#define STM32_SPI1_IRQ_PRIORITY 10
|
||||
#define STM32_SPI2_IRQ_PRIORITY 10
|
||||
#define STM32_SPI1_DMA_ERROR_HOOK() chSysHalt()
|
||||
|
||||
/*
|
||||
* UART driver system settings.
|
||||
*/
|
||||
#define STM32_UART_USE_USART1 TRUE
|
||||
#define STM32_UART_USART1_IRQ_PRIORITY 12
|
||||
#define STM32_UART_USART1_DMA_PRIORITY 1
|
||||
|
|
|
@ -146,6 +146,18 @@ typedef struct {
|
|||
(dmachp)->CCR = (uint32_t)(ccr); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMA channel enable.
|
||||
* @note Channels are numbered from 0 to 6, use the appropriate macro
|
||||
* as parameter.
|
||||
*
|
||||
* @param[in] dmap pointer to a stm32_dma_t structure
|
||||
* @param[in] ch channel number
|
||||
*/
|
||||
#define dmaEnableChannel(dmap, ch) { \
|
||||
(dmap)->channels[ch].CCR |= 1; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief DMA channel disable.
|
||||
* @note Channels are numbered from 0 to 6, use the appropriate macro
|
||||
|
|
|
@ -47,67 +47,46 @@ UARTDriver UARTD1;
|
|||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Status bits translation.
|
||||
*
|
||||
* @param[in] sr USART SR register value
|
||||
*
|
||||
* @return The error flags.
|
||||
*/
|
||||
static uartflags_t translate_errors(uint16_t sr) {
|
||||
uartflags_t sts = 0;
|
||||
|
||||
if (sr & USART_SR_ORE)
|
||||
sts |= UART_OVERRUN_ERROR;
|
||||
if (sr & USART_SR_PE)
|
||||
sts |= UART_PARITY_ERROR;
|
||||
if (sr & USART_SR_FE)
|
||||
sts |= UART_FRAMING_ERROR;
|
||||
if (sr & USART_SR_NE)
|
||||
sts |= UART_NOISE_ERROR;
|
||||
if (sr & USART_SR_LBD)
|
||||
sts |= UART_BREAK_DETECTED;
|
||||
return sts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Puts the receiver in the UART_RX_IDLE state.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void set_rx_idle(UARTDriver *uartp) {
|
||||
static void set_rx_idle_loop(UARTDriver *uartp) {
|
||||
uint32_t ccr;
|
||||
|
||||
dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx);
|
||||
dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx);
|
||||
uartp->ud_rxstate = UART_RX_IDLE;
|
||||
|
||||
/* RX DMA channel preparation, circular 1 frame transfers, an interrupt is
|
||||
generated for each received character if the callback is defined.*/
|
||||
ccr = DMA_CCR1_TEIE | DMA_CCR1_CIRC | DMA_CCR1_EN;
|
||||
if (uartp->ud_config->uc_rxchar != NULL)
|
||||
ccr |= DMA_CCR1_TCIE;
|
||||
/* RX DMA channel preparation, if the char callback is defined then the
|
||||
TCIE interrupt is enabled too.*/
|
||||
if (uartp->ud_config->uc_rxchar == NULL)
|
||||
ccr = DMA_CCR1_CIRC | DMA_CCR1_TEIE;
|
||||
else
|
||||
ccr = DMA_CCR1_CIRC | DMA_CCR1_TEIE | DMA_CCR1_TCIE;
|
||||
dmaSetupChannel(uartp->ud_dmap, uartp->ud_dmarx, 1,
|
||||
&uartp->ud_rxbuf, uartp->ud_dmaccr | ccr);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Puts the transmitter in the UART_TX_IDLE state.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void set_tx_idle(UARTDriver *uartp) {
|
||||
|
||||
dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmatx);
|
||||
dmaClearChannel(uartp->ud_dmap, uartp->ud_dmatx);
|
||||
uartp->ud_txstate = UART_TX_IDLE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART initialization.
|
||||
* @details This function must be invoked with interrupts disabled.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void usart_start(UARTDriver *uartp) {
|
||||
USART_TypeDef *u = uartp->ud_usart;
|
||||
|
||||
/* Baud rate setting.*/
|
||||
if (uartp->ud_usart == USART1)
|
||||
u->BRR = STM32_PCLK2 / uartp->ud_config->uc_speed;
|
||||
else
|
||||
u->BRR = STM32_PCLK1 / uartp->ud_config->uc_speed;
|
||||
|
||||
/* Note that some bits are enforced because required for correct driver
|
||||
operations.*/
|
||||
u->CR1 = uartp->ud_config->uc_cr1 | USART_CR1_UE | USART_CR1_PEIE |
|
||||
USART_CR1_TE | USART_CR1_RE;
|
||||
u->CR2 = uartp->ud_config->uc_cr2 | USART_CR2_LBDIE;
|
||||
u->CR3 = uartp->ud_config->uc_cr3 | USART_CR3_EIE;
|
||||
|
||||
/* Resetting eventual pending status flags.*/
|
||||
(void)u->SR; /* SR reset step 1.*/
|
||||
(void)u->DR; /* SR reset step 2.*/
|
||||
|
||||
set_rx_idle(uartp);
|
||||
set_tx_idle(uartp);
|
||||
dmaEnableChannel(uartp->ud_dmap, uartp->ud_dmarx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -130,6 +109,108 @@ static void usart_stop(UARTDriver *uartp) {
|
|||
uartp->ud_usart->CR3 = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief USART initialization.
|
||||
* @details This function must be invoked with interrupts disabled.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void usart_start(UARTDriver *uartp) {
|
||||
USART_TypeDef *u = uartp->ud_usart;
|
||||
|
||||
/* Defensive programming, starting from a clean state.*/
|
||||
usart_stop(uartp);
|
||||
|
||||
/* Baud rate setting.*/
|
||||
if (uartp->ud_usart == USART1)
|
||||
u->BRR = STM32_PCLK2 / uartp->ud_config->uc_speed;
|
||||
else
|
||||
u->BRR = STM32_PCLK1 / uartp->ud_config->uc_speed;
|
||||
|
||||
/* Note that some bits are enforced because required for correct driver
|
||||
operations.*/
|
||||
u->CR1 = uartp->ud_config->uc_cr1 | USART_CR1_UE | USART_CR1_PEIE |
|
||||
USART_CR1_TE | USART_CR1_RE;
|
||||
u->CR2 = uartp->ud_config->uc_cr2 | USART_CR2_LBDIE;
|
||||
u->CR3 = uartp->ud_config->uc_cr3 | USART_CR3_EIE;
|
||||
|
||||
/* Resetting eventual pending status flags.*/
|
||||
(void)u->SR; /* SR reset step 1.*/
|
||||
(void)u->DR; /* SR reset step 2.*/
|
||||
|
||||
/* Starting the receiver idle loop.*/
|
||||
set_rx_idle_loop(uartp);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief RX DMA common service routine.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void serve_rx_end_irq(UARTDriver *uartp) {
|
||||
|
||||
uartp->ud_rxstate = UART_RX_COMPLETE;
|
||||
if (uartp->ud_config->uc_rxend != NULL)
|
||||
uartp->ud_config->uc_rxend();
|
||||
/* If the callback didn't explicitely change state then the receiver
|
||||
automatically returns to the idle state.*/
|
||||
if (uartp->ud_rxstate == UART_RX_COMPLETE) {
|
||||
uartp->ud_rxstate = UART_RX_IDLE;
|
||||
set_rx_idle_loop(uartp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief TX DMA common service routine.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void serve_tx_end_irq(UARTDriver *uartp) {
|
||||
|
||||
/* A callback is generated, if enabled, after a completed transfer.*/
|
||||
uartp->ud_txstate = UART_TX_COMPLETE;
|
||||
if (uartp->ud_config->uc_txend1 != NULL)
|
||||
uartp->ud_config->uc_txend1();
|
||||
/* If the callback didn't explicitely change state then the transmitter
|
||||
automatically returns to the idle state.*/
|
||||
if (uartp->ud_txstate == UART_TX_COMPLETE)
|
||||
uartp->ud_txstate = UART_TX_IDLE;
|
||||
}
|
||||
/**
|
||||
* @brief USART common service routine.
|
||||
*
|
||||
* @param[in] uartp pointer to the @p UARTDriver object
|
||||
*/
|
||||
static void serve_usart_irq(UARTDriver *uartp) {
|
||||
uint16_t sr;
|
||||
USART_TypeDef *u = uartp->ud_usart;
|
||||
|
||||
sr = u->SR; /* SR reset step 1.*/
|
||||
(void)u->DR; /* SR reset step 2.*/
|
||||
///////////////// u->SR = 0; /* Clears the LBD bit in the SR.*/
|
||||
if (uartp->ud_rxstate == UART_RX_IDLE) {
|
||||
/* Receiver in idle state, a callback is generated, if enabled, for each
|
||||
receive error and then the driver stays in the same state.*/
|
||||
if (uartp->ud_config->uc_rxerr != NULL)
|
||||
uartp->ud_config->uc_rxerr(translate_errors(sr));
|
||||
}
|
||||
else {
|
||||
/* Receiver in active state, a callback is generated and the receive
|
||||
operation aborts.*/
|
||||
dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx);
|
||||
dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx);
|
||||
uartp->ud_rxstate = UART_RX_ERROR;
|
||||
if (uartp->ud_config->uc_rxerr != NULL)
|
||||
uartp->ud_config->uc_rxerr(translate_errors(sr));
|
||||
/* If the callback didn't explicitely change state then the receiver
|
||||
automatically returns to the idle state.*/
|
||||
if (uartp->ud_rxstate == UART_RX_ERROR) {
|
||||
uartp->ud_rxstate = UART_RX_IDLE;
|
||||
set_rx_idle_loop(uartp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
@ -143,25 +224,20 @@ CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
|
|||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
dmaClearChannel(&DMA1, STM32_DMA_CHANNEL_4);
|
||||
|
||||
dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
|
||||
uartp = &UARTD1;
|
||||
if (uartp->ud_rxstate == UART_RX_IDLE) {
|
||||
/* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/
|
||||
/* Receiver in idle state, a callback is generated, if enabled, for each
|
||||
received character.*/
|
||||
received character and then the driver stays in the same state.*/
|
||||
if (uartp->ud_config->uc_rxchar != NULL)
|
||||
uartp->ud_config->uc_rxchar(uartp->ud_rxbuf);
|
||||
}
|
||||
else {
|
||||
/* Receiver in active state, a callback is generated, if enabled, after
|
||||
a completed transfer.*/
|
||||
uartp->ud_rxstate = UART_RX_COMPLETE;
|
||||
if (uartp->ud_config->uc_rxend != NULL)
|
||||
uartp->ud_config->uc_rxend();
|
||||
/* If the callback didn't restart a receive operation then the receiver
|
||||
returns to the idle state.*/
|
||||
if (uartp->ud_rxstate == UART_RX_COMPLETE)
|
||||
set_rx_idle(uartp);
|
||||
dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
|
||||
serve_rx_end_irq(uartp);
|
||||
}
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
|
@ -174,16 +250,9 @@ CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
|
|||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
dmaClearChannel(&DMA1, STM32_DMA_CHANNEL_5);
|
||||
|
||||
/* A callback is generated, if enabled, after a completed transfer.*/
|
||||
uartp->ud_txstate = UART_TX_COMPLETE;
|
||||
if (UARTD1.ud_config->uc_txend1 != NULL)
|
||||
UARTD1.ud_config->uc_txend1();
|
||||
/* If the callback didn't restart a transmit operation then the transmitter
|
||||
returns to the idle state.*/
|
||||
if (uartp->ud_txstate == UART_TX_COMPLETE)
|
||||
set_tx_idle(uartp);
|
||||
dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
|
||||
dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
|
||||
serve_tx_end_irq(&UARTD1);
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
@ -192,6 +261,7 @@ CH_IRQ_HANDLER(USART1_IRQHandler) {
|
|||
|
||||
CH_IRQ_PROLOGUE();
|
||||
|
||||
serve_usart_irq(&UARTD1);
|
||||
|
||||
CH_IRQ_EPILOGUE();
|
||||
}
|
||||
|
@ -246,6 +316,9 @@ void uart_lld_start(UARTDriver *uartp) {
|
|||
uartp->ud_dmap->channels[uartp->ud_dmarx].CPAR = (uint32_t)&uartp->ud_usart->DR;
|
||||
uartp->ud_dmap->channels[uartp->ud_dmatx].CPAR = (uint32_t)&uartp->ud_usart->DR;
|
||||
}
|
||||
|
||||
uartp->ud_rxstate = UART_RX_IDLE;
|
||||
uartp->ud_txstate = UART_TX_IDLE;
|
||||
usart_start(uartp);
|
||||
}
|
||||
|
||||
|
|
|
@ -148,7 +148,7 @@ typedef struct {
|
|||
/** @brief Transmit DMA channel.*/
|
||||
uint8_t ud_dmatx;
|
||||
/** @brief Default receive buffer while into @p UART_RX_IDLE state.*/
|
||||
uint16_t ud_rxbuf;
|
||||
volatile uint16_t ud_rxbuf;
|
||||
} UARTDriver;
|
||||
|
||||
/*===========================================================================*/
|
||||
|
|
Loading…
Reference in New Issue