blob: 4b2ec4579efafbeb1d58fe5109ba4b15804d180b [file] [log] [blame]
Brian Silverman2df84412013-12-10 14:00:40 -08001#include "cape/uart_dma.h"
2#include "cape/uart_common_private.h"
3
4#include "cape/util.h"
5#include "cape/uart_common.h"
6
7#define DMA DMA1
8#define DMA_STREAM_NUMBER 7
9#define DMA_Stream DMA1_Stream7
10#define DMA_SR DMA1->HISR
11#define DMA_FCR DMA1->HIFCR
12#define DMA_SR_SHIFT 3
13#define DMA_Stream_IRQHandler DMA1_Stream7_IRQHandler
14#define DMA_Stream_IRQn DMA1_Stream7_IRQn
15#define RCC_AHB1ENR_DMAEN RCC_AHB1ENR_DMA1EN
16
17#define DMA_SR_BIT(bit) (1 << (bit + 6 * DMA_SR_SHIFT))
18
19void uart_dma_callback(uint8_t *new_buffer) __attribute__((weak));
20void uart_dma_callback(uint8_t *new_buffer) {}
21
22static uint8_t *volatile buffer1, *volatile buffer2;
23
24void DMA_Stream_IRQHandler(void) {
25 uint32_t status = DMA_SR;
26 if (status & DMA_SR_BIT(5)) { // transfer completed
27 DMA_FCR = DMA_SR_BIT(5);
28 uart_dma_callback(((DMA_Stream->CR & DMA_SxCR_CT) == 0) ? buffer2
29 : buffer1);
30 } else if (status & DMA_SR_BIT(3)) { // transfer error
31 DMA_FCR = DMA_SR_BIT(3);
32 // Somebody probably wrote to the wrong buffer, which disables the DMA, so
33 // we now need to re-enable it.
34 // If we're fighting somebody else writing stuff, we'll do this a bunch of
35 // times, but oh well.
36 DMA_Stream->CR |= DMA_SxCR_EN;
37 }
38}
39
40void uart_dma_configure(int baud, int bytes,
41 uint8_t *buffer1_in, uint8_t *buffer2_in) {
42 uart_common_configure(baud);
43
44 buffer1 = buffer1_in;
45 buffer2 = buffer2_in;
46 uart_dma_callback(buffer1);
47
48 RCC->AHB1ENR |= RCC_AHB1ENR_DMAEN;
49 DMA_Stream->PAR = (uint32_t)&UART->DR;
50 DMA_Stream->M0AR = (uint32_t)buffer1;
51 DMA_Stream->M1AR = (uint32_t)buffer2;
52 // This is measured in chunks of PSIZE bytes, not MSIZE.
53 DMA_Stream->NDTR = bytes;
54 DMA_FCR = 0xF << DMA_SR_SHIFT;
55 DMA_Stream->CR = DMA_STREAM_NUMBER << 25 |
56 DMA_SxCR_DBM /* enable double buffer mode */ |
57 2 << 16 /* priority */ |
58 2 << 13 /* memory data size = 32 bits */ |
59 0 << 11 /* peripherial data size = 8 bits */ |
60 DMA_SxCR_MINC /* increment memory address */ |
61 1 << 6 /* memory to peripherial */ |
62 DMA_SxCR_TCIE | DMA_SxCR_TEIE;
63 DMA_Stream->FCR =
64 DMA_SxFCR_DMDIS /* disable direct mode (enable the FIFO) */ |
65 1 /* 1/2 full threshold */;
66 DMA_Stream->CR |= DMA_SxCR_EN; // enable it
67 NVIC_SetPriority(DMA_Stream_IRQn, 6);
68 NVIC_EnableIRQ(DMA_Stream_IRQn);
69
70 uart_dma_callback(buffer2);
71}