blob: ed576b4910ad7de0181f0186a6bc26bd47c70f65 [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"
Brian Silvermaned030062013-12-20 21:03:47 -08006#include "cape/led.h"
Brian Silverman2df84412013-12-10 14:00:40 -08007
Brian Silvermaned030062013-12-20 21:03:47 -08008#define DMA DMA2
9#define DMA_Stream DMA2_Stream7
10#define DMA_SR DMA2->HISR
11#define DMA_FCR DMA2->HIFCR
Brian Silverman2df84412013-12-10 14:00:40 -080012#define DMA_SR_SHIFT 3
Brian Silvermaned030062013-12-20 21:03:47 -080013#define DMA_Stream_IRQHandler DMA2_Stream7_IRQHandler
14#define DMA_Stream_IRQn DMA2_Stream7_IRQn
15#define DMA_CHANNEL_NUMBER 4
16#define RCC_AHB1ENR_DMAEN RCC_AHB1ENR_DMA2EN
Brian Silverman2df84412013-12-10 14:00:40 -080017
18#define DMA_SR_BIT(bit) (1 << (bit + 6 * DMA_SR_SHIFT))
19
20void uart_dma_callback(uint8_t *new_buffer) __attribute__((weak));
21void uart_dma_callback(uint8_t *new_buffer) {}
22
23static uint8_t *volatile buffer1, *volatile buffer2;
24
25void DMA_Stream_IRQHandler(void) {
Brian Silvermaned030062013-12-20 21:03:47 -080026 led_set(LED_DB, 1);
Brian Silverman2df84412013-12-10 14:00:40 -080027 uint32_t status = DMA_SR;
28 if (status & DMA_SR_BIT(5)) { // transfer completed
29 DMA_FCR = DMA_SR_BIT(5);
30 uart_dma_callback(((DMA_Stream->CR & DMA_SxCR_CT) == 0) ? buffer2
31 : buffer1);
32 } else if (status & DMA_SR_BIT(3)) { // transfer error
33 DMA_FCR = DMA_SR_BIT(3);
34 // Somebody probably wrote to the wrong buffer, which disables the DMA, so
35 // we now need to re-enable it.
36 // If we're fighting somebody else writing stuff, we'll do this a bunch of
37 // times, but oh well.
38 DMA_Stream->CR |= DMA_SxCR_EN;
Brian Silvermaned030062013-12-20 21:03:47 -080039 led_set(LED_ERR, 1);
Brian Silverman2df84412013-12-10 14:00:40 -080040 }
41}
42
Brian Silvermandf49fe32013-12-11 14:21:37 -080043void uart_dma_configure(int bytes, uint8_t *buffer1_in, uint8_t *buffer2_in) {
Brian Silverman2df84412013-12-10 14:00:40 -080044 buffer1 = buffer1_in;
45 buffer2 = buffer2_in;
46 uart_dma_callback(buffer1);
47
Brian Silvermaned030062013-12-20 21:03:47 -080048 UART->CR3 = USART_CR3_DMAT;
Brian Silverman53f29182013-12-21 15:16:27 -080049 UART->CR1 |= USART_CR1_TE;
Brian Silvermaned030062013-12-20 21:03:47 -080050
Brian Silverman2df84412013-12-10 14:00:40 -080051 RCC->AHB1ENR |= RCC_AHB1ENR_DMAEN;
Brian Silverman53f29182013-12-21 15:16:27 -080052 DMA_Stream->CR = 0;
53 while (DMA_Stream->CR & DMA_SxCR_EN); // make sure it's disabled
Brian Silverman2df84412013-12-10 14:00:40 -080054 DMA_Stream->PAR = (uint32_t)&UART->DR;
55 DMA_Stream->M0AR = (uint32_t)buffer1;
56 DMA_Stream->M1AR = (uint32_t)buffer2;
57 // This is measured in chunks of PSIZE bytes, not MSIZE.
58 DMA_Stream->NDTR = bytes;
Brian Silverman53f29182013-12-21 15:16:27 -080059 DMA_Stream->CR = DMA_CHANNEL_NUMBER << 25 |
60 DMA_SxCR_DBM /* enable double buffer mode */ |
61 2 << 16 /* priority */ |
62 2 << 13 /* memory data size = 32 bits */ |
63 0 << 11 /* peripherial data size = 8 bits */ |
64 DMA_SxCR_MINC /* increment memory address */ |
65 1 << 6 /* memory to peripherial */ |
66 //DMA_SxCR_PFCTRL /* peripherial controls flow */ |
67 DMA_SxCR_TCIE | DMA_SxCR_TEIE;
Brian Silverman2df84412013-12-10 14:00:40 -080068 DMA_Stream->FCR =
69 DMA_SxFCR_DMDIS /* disable direct mode (enable the FIFO) */ |
Brian Silverman53f29182013-12-21 15:16:27 -080070 1 /* 1/2 full threshold */;
71 UART->SR = ~USART_SR_TC;
72 DMA_FCR = 0xF << DMA_SR_SHIFT;
Brian Silverman2df84412013-12-10 14:00:40 -080073 DMA_Stream->CR |= DMA_SxCR_EN; // enable it
Brian Silverman95244d82013-12-14 12:15:46 -080074 NVIC_SetPriority(DMA_Stream_IRQn, 8);
Brian Silverman2df84412013-12-10 14:00:40 -080075 NVIC_EnableIRQ(DMA_Stream_IRQn);
76
77 uart_dma_callback(buffer2);
Brian Silvermaned030062013-12-20 21:03:47 -080078 led_set(LED_Z, 1);
Brian Silverman2df84412013-12-10 14:00:40 -080079}