Use DMA for receiving data from the UART [broken]
authorMatt Mullins <mmullins@mmlx.us>
Sun, 23 Dec 2012 23:19:00 +0000 (15:19 -0800)
committerMatt Mullins <mmullins@mmlx.us>
Mon, 24 Dec 2012 00:49:15 +0000 (16:49 -0800)
Currently, this works for receiving exactly one byte.  It'll give me an
interrupt upon reading a second, but it doesn't DMA it.  And then it just stops
sending the interrupts -- which is slightly better than before.

I can also get it stuck in an infinite loop of calling uart0_isr() by not
clearing the interrupt status.

main.c

diff --git a/main.c b/main.c
index d6cdc51..d647b9c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,6 +1,11 @@
 #include "main.h"
 #include <lm4f120h5qr.h>
 
+#define DMA_BASE ((int*)0x20006000)
+#define UART0_RX_DMA_BASE (DMA_BASE + (0x80/sizeof(int)))
+
+#define UART0_RX_DMA_DEST ((char*) 0x20004000);
+
 static void spin(int);
 
 // Since SysTick is only 24-bits, we'll need to divide it by 4 to produce a
@@ -11,6 +16,9 @@ static int systick_count;
 
 static int bit_count, blink_char;
 
+static void setup_dma();
+static void setup_uart0_dma();
+
 __attribute__((isr))
 void main_isr() {
        // Initialization, since we don't blank out BSS
@@ -54,6 +62,9 @@ void main_isr() {
        UART0_FBRD_R = 26;
        UART0_LCRH_R = UART_LCRH_WLEN_8;
 
+       setup_dma();
+       setup_uart0_dma();
+
        // Enable interrupts
        UART0_IM_R |= UART_IM_RXIM;
        NVIC_EN0_R = NVIC_EN0_INT5;
@@ -92,7 +103,7 @@ void spin(int cycles) {
 __attribute__((isr))
 void uart0_isr() {
        // Receive data, increment by 1 and send it back through the UART
-       int data = UART0_DR_R & 0xFF;
+       int data = *UART0_RX_DMA_DEST;
        if (!bit_count) {
                blink_char = data;
                bit_count = 8;
@@ -100,6 +111,9 @@ void uart0_isr() {
 
        data = (data + 1) & 0xFF;
        UART0_DR_R = data;
+
+       // Enable more DMAs
+       UART0_RX_DMA_BASE[2] |= UDMA_CHCTL_XFERMODE_BASIC;
 }
 
 __attribute__((isr))
@@ -132,3 +146,31 @@ void systick_isr() {
                *(GPIO_PORTF_DATA_BITS_R + 0xE) = 0;
        }
 }
+
+void setup_dma() {
+       // Enable the DMA controller
+       SYSCTL_RCGCDMA_R = 0x1;
+       UDMA_CFG_R = 0x1;
+
+       // Choose the right DMA controller base
+       UDMA_CTLBASE_R = (long) DMA_BASE;
+}
+
+void setup_uart0_dma() {
+       // Transfer from UART0_DR_R into UART0_RX_DMA_DEST
+       UART0_RX_DMA_BASE[0] = (long) &UART0_DR_R;
+       UART0_RX_DMA_BASE[1] = (long) UART0_RX_DMA_DEST;
+       UART0_RX_DMA_BASE[2] = UDMA_CHCTL_DSTINC_NONE | UDMA_CHCTL_DSTSIZE_8 |
+                       UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_SRCSIZE_8 |
+                       UDMA_CHCTL_ARBSIZE_1 | (0 << UDMA_CHCTL_XFERSIZE_S) |
+                       UDMA_CHCTL_XFERMODE_BASIC;
+
+       // Not particularly a priority DMA -- it's all the uC is doing!
+       UDMA_PRIOCLR_R = (1 << 8);
+       // Use primary control structure for the channel
+       UDMA_ALTCLR_R = (1 << 8);
+
+       // Enable the DMA
+       UDMA_ENASET_R = (1 << 8);
+       UART0_DMACTL_R = UART_DMACTL_RXDMAE;
+}