From 21e0cf0f1d3917a993bed01da8914ab4ab5bd5ff Mon Sep 17 00:00:00 2001 From: Matt Mullins Date: Sun, 23 Dec 2012 15:19:00 -0800 Subject: [PATCH] Use DMA for receiving data from the UART [broken] 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 | 44 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/main.c b/main.c index d6cdc51..d647b9c 100644 --- a/main.c +++ b/main.c @@ -1,6 +1,11 @@ #include "main.h" #include +#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; +} -- 2.11.0