]> Pileus Git - ~andy/csm213a-hw/blob - yue/serial_dma.c
Fix whitespace error
[~andy/csm213a-hw] / yue / serial_dma.c
1 #include <MKL46Z4.h>\r
2 \r
3 #include <stdint.h>\r
4 #include <stdarg.h>\r
5 #include <stdio.h>\r
6 #include <string.h>\r
7 \r
8 #include "serial_dma.h"\r
9 \r
10 /* Defines */\r
11 #define UART sdma_uart\r
12 #define DMA  (&(DMA0->DMA[sdma_chan]))\r
13 #define MUX  ((dma_mux_t*)&(DMAMUX0->CHCFG[sdma_chan]))\r
14 \r
15 #define NUM  2\r
16 #define LEN  1024\r
17 \r
18 /* Types */\r
19 typedef struct {uint8_t CHCFG;} dma_mux_t;\r
20 \r
21 /* Setup data */\r
22 static UART0_Type *sdma_uart;\r
23 static int         sdma_chan;\r
24 \r
25 /* Error logging */\r
26 static int         sdma_stuck;\r
27 static int         sdma_full;\r
28 \r
29 /* Data buffering */\r
30 static int         sdma_index;\r
31 static int         sdma_length[NUM];\r
32 static uint8_t     sdma_queue[NUM][LEN];\r
33 \r
34 /* DMA Functions */\r
35 void sdma_setup(UART0_Type *uart, int channel)\r
36 {\r
37         // Save configuration data\r
38         sdma_uart = uart;\r
39         sdma_chan = channel;\r
40 \r
41         // Enable DMA Cock\r
42         SIM->SCGC6   |= SIM_SCGC6_DMAMUX_MASK;\r
43         SIM->SCGC7   |= SIM_SCGC7_DMA_MASK;\r
44 \r
45         // Reset channel\r
46         DMA->DSR_BCR  = DMA_DSR_BCR_DONE_MASK;\r
47 \r
48         // Configure DMA transfer\r
49         DMA->DAR      = (uint32_t)&UART0->D;\r
50         DMA->DCR      = DMA_DCR_CS_MASK   |\r
51                         DMA_DCR_SINC_MASK |\r
52                         DMA_DCR_SSIZE(1)  |\r
53                         DMA_DCR_DSIZE(1)  |\r
54                         DMA_DCR_D_REQ_MASK;\r
55 \r
56         // Configure DMA Mux\r
57         MUX->CHCFG    = DMAMUX_CHCFG_SOURCE(3) |\r
58                         DMAMUX_CHCFG_ENBL_MASK;\r
59 \r
60         // Configure UART for DMA Channel 0\r
61         UART->C5     |= UART0_C5_TDMAE_MASK;\r
62 }\r
63 \r
64 /* Write binary data out the DMA output queue */\r
65 void sdma_write(void *data, int len)\r
66 {\r
67         if (sdma_length[sdma_index] + len > LEN) {\r
68                 sdma_full++;\r
69         } else {\r
70                 int   pos = sdma_length[sdma_index];\r
71                 void *dst = &sdma_queue[sdma_index][pos];\r
72                 memcpy(dst, data, len);\r
73                 sdma_length[sdma_index] += len;\r
74         }\r
75 }\r
76 \r
77 /* Write ASCII data to the output queue */\r
78 void sdma_vprintf(const char *fmt, va_list ap)\r
79 {\r
80         int   pos = sdma_length[sdma_index];\r
81         void *dst = &sdma_queue[sdma_index][pos];\r
82         sdma_length[sdma_index] +=\r
83                 vsnprintf((char*)dst, LEN-pos, fmt, ap);\r
84 }\r
85 \r
86 void sdma_printf(const char *fmt, ...)\r
87 {\r
88         va_list ap;\r
89         va_start(ap, fmt);\r
90         sdma_vprintf(fmt, ap);\r
91         va_end(ap);\r
92 }\r
93 \r
94 /* Trigger DMA transmit of the current output queue\r
95  * and swap buffers so we can write into unused space */\r
96 void sdma_flush(void)\r
97 {\r
98         if (sdma_length[sdma_index] == 0)\r
99                 return;\r
100 \r
101         // Wait for transmit complete\r
102         while (DMA->DSR_BCR & DMA_DSR_BCR_BCR_MASK)\r
103                 sdma_stuck++;\r
104 \r
105         // Reset channel\r
106         DMA->DSR_BCR  = DMA_DSR_BCR_DONE_MASK;\r
107 \r
108         // Set source address and length\r
109         DMA->SAR      = (uint32_t)&sdma_queue[sdma_index];\r
110         DMA->DSR_BCR  = DMA_DSR_BCR_BCR(sdma_length[sdma_index]);\r
111 \r
112         // Enable DMA transmit\r
113         DMA->DCR     |= DMA_DCR_ERQ_MASK;\r
114 \r
115         // Swap buffers\r
116         sdma_length[sdma_index] = 0;\r
117         sdma_index = (sdma_index + 1) % NUM;\r
118 }\r