summaryrefslogtreecommitdiff
path: root/chip/stm32/uart.c
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-09-11 14:40:27 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2013-09-16 23:31:07 +0000
commitcdd5c206cd2125983f83ef3a54470b5e99f82031 (patch)
treeaab6c92edc49fb51a13298feeba7a2afa3dc599f /chip/stm32/uart.c
parentb718dfc0598c324772171c1df94b68d5546893b5 (diff)
downloadchrome-ec-cdd5c206cd2125983f83ef3a54470b5e99f82031.tar.gz
stm32: Use DMA for UART receive
STM32 has a single-byte mailbox for UART I/O. When the core clock runs at 16Mhz we can service interrupts fast enough to handle 115200 baud input, but when we drop to 1MHz we drop characters. Using DMA to receive input solves this problem. The STM32 DMA engine can only generate interrupts when the transfer is half-done / all-done, so we need to poll the DMA receive-head-pointer to see if individual characters have been received. Do this in the tick task (every 250ms). When a character is received, poll more quickly for a bit (5 times before the next tick) so the input console is more responsive to typing. BUG=chrome-os-partner:20485 BRANCH=none TEST=Console is responsive to debug commands. For example, help -> prints help apshutdown -> shuts down AP arrow keys -> move cursor and scroll through command history Ctrl+Q, help, wait a second, Ctrl+S -> help output printed after Ctrl+S Then in chip/stm32/config_chip.h, comment out #define CONFIG_UART_RX_DMA and rebuild/reflash the EC. When the AP is up, the console works normally but after 'apshutdown', the EC drops to 1MHz core clock, and the arrow keys don't work. (This step confirms that adding DMA support did not change the behavior of systems where CONFIG_UART_RX_DMA is not defined.) Change-Id: I199448354824bd747c7b290ea7fd5ccf354c11bb Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/169406 Reviewed-by: Simon Glass <sjg@chromium.org>
Diffstat (limited to 'chip/stm32/uart.c')
-rw-r--r--chip/stm32/uart.c52
1 files changed, 47 insertions, 5 deletions
diff --git a/chip/stm32/uart.c b/chip/stm32/uart.c
index 3d510c16f1..78bbcc3e58 100644
--- a/chip/stm32/uart.c
+++ b/chip/stm32/uart.c
@@ -31,6 +31,17 @@ static const struct dma_option dma_tx_option = {
#define UART_TX_INT_ENABLE STM32_USART_CR1_TXEIE
#endif
+#ifdef CONFIG_UART_RX_DMA
+/* DMA channel options; assumes UART1 */
+static const struct dma_option dma_rx_option = {
+ STM32_DMAC_USART1_RX, (void *)&STM32_USART_DR(UARTN),
+ STM32_DMA_CCR_MSIZE_8_BIT | STM32_DMA_CCR_PSIZE_8_BIT |
+ STM32_DMA_CCR_CIRC
+};
+
+static int dma_rx_len; /* Size of receive DMA circular buffer */
+#endif
+
static int init_done; /* Initialization done? */
static int should_stop; /* Last TX control action */
@@ -95,6 +106,23 @@ int uart_rx_available(void)
return STM32_USART_SR(UARTN) & STM32_USART_SR_RXNE;
}
+#ifdef CONFIG_UART_RX_DMA
+
+void uart_rx_dma_start(char *dest, int len)
+{
+ /* Start receiving */
+ dma_rx_len = len;
+ dma_start_rx(&dma_rx_option, len, dest);
+}
+
+int uart_rx_dma_head(void)
+{
+ return dma_bytes_done(dma_get_channel(STM32_DMAC_USART1_RX),
+ dma_rx_len);
+}
+
+#endif
+
void uart_write_char(char c)
{
/* Wait for space */
@@ -134,14 +162,21 @@ static void uart_interrupt(void)
STM32_USART_CR1(UARTN) &= ~STM32_USART_CR1_TXEIE;
#endif
- /* Read input FIFO until empty, then fill output FIFO */
+#ifndef CONFIG_UART_RX_DMA
+ /*
+ * Read input FIFO until empty. DMA-based receive does this from a
+ * hook in the UART buffering module.
+ */
uart_process_input();
+#endif
+
+ /* Fill output FIFO */
uart_process_output();
#ifndef CONFIG_UART_TX_DMA
/*
* Re-enable TX empty interrupt only if it was not disabled by
- * uart_process.
+ * uart_process_output().
*/
if (!should_stop)
STM32_USART_CR1(UARTN) |= STM32_USART_CR1_TXEIE;
@@ -194,11 +229,10 @@ void uart_init(void)
/*
* UART enabled, 8 Data bits, oversampling x16, no parity,
- * RXNE interrupt, TX and RX enabled.
+ * TX and RX enabled.
*/
STM32_USART_CR1(UARTN) =
- STM32_USART_CR1_UE | STM32_USART_CR1_RXNEIE |
- STM32_USART_CR1_TE | STM32_USART_CR1_RE;
+ STM32_USART_CR1_UE | STM32_USART_CR1_TE | STM32_USART_CR1_RE;
/* 1 stop bit, no fancy stuff */
STM32_USART_CR2(UARTN) = 0x0000;
@@ -211,6 +245,14 @@ void uart_init(void)
STM32_USART_CR3(UARTN) = 0x0000;
#endif
+#ifdef CONFIG_UART_RX_DMA
+ /* Enable DMA receiver */
+ STM32_USART_CR3(UARTN) |= STM32_USART_CR3_DMAR;
+#else
+ /* Enable receive-not-empty interrupt */
+ STM32_USART_CR1(UARTN) |= STM32_USART_CR1_RXNEIE;
+#endif
+
#ifdef CHIP_FAMILY_stm32l
/* Use single-bit sampling */
STM32_USART_CR3(UARTN) |= STM32_USART_CR3_ONEBIT;