summaryrefslogtreecommitdiff
path: root/chip/stm32/usart_rx_dma.h
diff options
context:
space:
mode:
authorAnton Staaf <robotboy@chromium.org>2015-07-21 12:04:42 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-08-24 19:08:35 +0000
commit69bd4ce351ca56a3141281bf25431a07ea10512f (patch)
tree4486849beac1b26caf5d6ff8ac691a568869651f /chip/stm32/usart_rx_dma.h
parent16f63703c9ccc46ec48abcc586a595456e99fc9a (diff)
downloadchrome-ec-69bd4ce351ca56a3141281bf25431a07ea10512f.tar.gz
USART: Add DMA based receiver
This DMA receiver uses a separate small circular buffer to DMA into. This allows the DMA transaction to be made circular, and thus it does not require the interrupt latency to be low enough to setup the next transfer before the next character comes in. Additional diagnostics output have been added to the usart_info console command to facilitate tuning of the FIFO size. Signed-off-by: Anton Staaf <robotboy@chromium.org> BRANCH=None BUG=None TEST=make buildall -j Verify DMA works by cross connecting two discovery boards Change-Id: Idcdf95a47fadf21ec2154f0c9128cd3586e568ec Reviewed-on: https://chromium-review.googlesource.com/292870 Tested-by: Anton Staaf <robotboy@chromium.org> Reviewed-by: Anton Staaf <robotboy@chromium.org> Commit-Queue: Anton Staaf <robotboy@chromium.org> Trybot-Ready: Anton Staaf <robotboy@chromium.org>
Diffstat (limited to 'chip/stm32/usart_rx_dma.h')
-rw-r--r--chip/stm32/usart_rx_dma.h109
1 files changed, 109 insertions, 0 deletions
diff --git a/chip/stm32/usart_rx_dma.h b/chip/stm32/usart_rx_dma.h
new file mode 100644
index 0000000000..8056c2635e
--- /dev/null
+++ b/chip/stm32/usart_rx_dma.h
@@ -0,0 +1,109 @@
+/* Copyright 2015 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ *
+ * Hybrid DMA/Interrupt based USART RX driver for STM32
+ */
+#ifndef __CROS_EC_USART_RX_DMA_H
+#define __CROS_EC_USART_RX_DMA_H
+
+#include "producer.h"
+#include "dma.h"
+#include "queue.h"
+#include "usart.h"
+
+/*
+ * Only reference the usart_rx_dma_info function if CONFIG_CMD_USART_INFO
+ * is defined. This allows the compiler to remove this function as dead code
+ * when CONFIG_CMD_USART_INFO is not defined.
+ */
+#ifdef CONFIG_CMD_USART_INFO
+#define USART_RX_DMA_INFO usart_rx_dma_info
+#else
+#define USART_RX_DMA_INFO NULL
+#endif
+
+/*
+ * Construct a USART RX instance for DMA using the given DMA channel.
+ *
+ * This macro creates a new usart_rx_dma struct, complete with in RAM state,
+ * the contained usart_rx struct can be used in initializing a usart_config
+ * struct.
+ *
+ * CHANNEL is the DMA channel to be used for reception. This must be a valid
+ * DMA channel for the USART peripheral and any alternate channel mappings must
+ * be handled by the board specific code.
+ *
+ * FIFO_SIZE is the number of bytes (which does not need to be a power of two)
+ * to use for the DMA circular buffer. This buffer must be large enough to
+ * hide the worst case interrupt latency the system will encounter. The DMA
+ * RX driver adds to the output of the usart_info command a high water mark
+ * of how many bytes were transfered out of this FIFO on any one interrupt.
+ * This value can be used to correctly size the FIFO by setting the FIFO_SIZE
+ * to something large, stress test the USART, and run usart_info. After a
+ * reasonable stress test the "DMA RX max_bytes" value will be a reasonable
+ * size for the FIFO (perhaps +10% for safety).
+ */
+#define USART_RX_DMA(CHANNEL, FIFO_SIZE) \
+ ((struct usart_rx_dma const) { \
+ .usart_rx = { \
+ .producer_ops = { \
+ .read = NULL, \
+ }, \
+ \
+ .init = usart_rx_dma_init, \
+ .interrupt = usart_rx_dma_interrupt, \
+ .info = USART_RX_DMA_INFO, \
+ }, \
+ \
+ .state = &((struct usart_rx_dma_state) {}), \
+ .fifo_buffer = ((uint8_t[FIFO_SIZE]) {}), \
+ .fifo_size = FIFO_SIZE, \
+ .channel = CHANNEL, \
+ })
+
+/*
+ * In RAM state required to manage DMA based transmission.
+ */
+struct usart_rx_dma_state {
+ /*
+ * Previous value of dma_bytes_done. This will wrap when the DMA fills
+ * the queue.
+ */
+ size_t index;
+
+ /*
+ * Maximum number of bytes transfered in any one RX interrupt.
+ */
+ uint32_t max_bytes;
+};
+
+/*
+ * Extension of the usart_rx struct to include required configuration for
+ * DMA based transmission.
+ */
+struct usart_rx_dma {
+ struct usart_rx usart_rx;
+
+ struct usart_rx_dma_state volatile *state;
+
+ uint8_t *fifo_buffer;
+ size_t fifo_size;
+
+ enum dma_channel channel;
+};
+
+/*
+ * Function pointers needed to intialize a usart_rx struct. These shouldn't
+ * be called in any other context as they assume that the producer or config
+ * that they are passed was initialized with a complete usart_rx_dma struct.
+ */
+void usart_rx_dma_init(struct usart_config const *config);
+void usart_rx_dma_interrupt(struct usart_config const *config);
+
+/*
+ * Debug function, used to print DMA RX statistics to the console.
+ */
+void usart_rx_dma_info(struct usart_config const *config);
+
+#endif /* __CROS_EC_USART_RX_DMA_H */