8 #include "serial_dma.h"
\r
12 #define SDMA_LEN 1024
\r
30 /* Port structure */
\r
34 uint32_t sar; // offset 0x00, Source Address Register
\r
35 uint32_t dar; // offset 0x04, Destination Address Register
\r
36 uint32_t dsr; // offset 0x08, DMA Status Register / Byte Count Register
\r
37 uint32_t dcr; // offset 0x0C, DMA Control Register
\r
38 } *dma_xmt, *dma_rcv;
\r
42 uint8_t cfg; // offset 0x00, Channel Configuration register
\r
43 } *mux_xmt, *mux_rcv;
\r
47 uint32_t pcr; // offset 0x00, Pin Control register
\r
48 } *pin_xmt, *pin_rcv;
\r
52 uint8_t bdh; // offset 0x00, Baud Rate Register High
\r
53 uint8_t bdl; // offset 0x01, Baud Rate Register Low
\r
54 uint8_t c1; // offset 0x02, Control Register 1
\r
55 uint8_t c2; // offset 0x03, Control Register 2
\r
56 uint8_t s1; // offset 0x04, Status Register 1
\r
57 uint8_t s2; // offset 0x05, Status Register 2
\r
58 uint8_t c3; // offset 0x06, Control Register 3
\r
59 uint8_t d; // offset 0x07, Data Register
\r
62 /* Data buffering */
\r
64 int length[SDMA_NUM];
\r
65 uint8_t queue[SDMA_NUM][SDMA_LEN];
\r
68 uint32_t time_xmt[2];
\r
69 uint32_t time_rcv[2];
\r
76 /* DMA Request Sources */
\r
77 static int sdma_req_rx[] = {
\r
78 [SDMA_UART0] SDMA_REQ_U0RX,
\r
79 [SDMA_UART1] SDMA_REQ_U1RX,
\r
80 [SDMA_UART2] SDMA_REQ_U2RX,
\r
82 static int sdma_req_tx[] = {
\r
83 [SDMA_UART0] SDMA_REQ_U0TX,
\r
84 [SDMA_UART1] SDMA_REQ_U1TX,
\r
85 [SDMA_UART2] SDMA_REQ_U2TX,
\r
87 static int sdma_uart[] = {
\r
88 [SDMA_UART0] UART0_BASE,
\r
89 [SDMA_UART1] UART1_BASE,
\r
90 [SDMA_UART2] UART2_BASE,
\r
94 static sdma_t sdma_ports[SDMA_NUM_UART];
\r
97 sdma_t *sdma_open(sdma_uart_t uart, sdma_dma_t tx_chan, sdma_dma_t rx_chan)
\r
99 int rxreq = sdma_req_rx[uart]; (void)rxreq;
\r
100 int txreq = sdma_req_tx[uart]; (void)txreq;
\r
103 sdma_t *port = &sdma_ports[uart];
\r
105 port->uart = (void*)sdma_uart[uart];
\r
106 port->dma_xmt = (void*)&DMA0->DMA[tx_chan];
\r
107 port->dma_rcv = (void*)&DMA0->DMA[rx_chan];
\r
108 port->mux_xmt = (void*)&DMAMUX0->CHCFG[tx_chan];
\r
109 port->mux_rcv = (void*)&DMAMUX0->CHCFG[rx_chan];
\r
112 SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
\r
113 SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK;
\r
114 SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK;
\r
115 SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
\r
116 SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
\r
119 port->dma_xmt->dsr = DMA_DSR_BCR_DONE_MASK;
\r
121 // Configure DMA transfer
\r
122 port->dma_xmt->dar = (uint32_t)&port->uart->d;
\r
123 port->dma_xmt->dcr = DMA_DCR_CS_MASK
\r
124 | DMA_DCR_SINC_MASK
\r
127 | DMA_DCR_D_REQ_MASK;
\r
129 // Configure DMA Mux
\r
130 port->mux_xmt->cfg = DMAMUX_CHCFG_SOURCE(txreq)
\r
131 | DMAMUX_CHCFG_ENBL_MASK;
\r
133 // Configure UART for DMA Channel 0
\r
136 UART0->C5 |= UART0_C5_TDMAE_MASK;
\r
140 UART1->C2 = UART_C2_TIE_MASK
\r
143 UART1->C4 = UART_C4_TDMAS_MASK;
\r
147 UART2->C2 = UART_C2_TIE_MASK
\r
150 UART2->C4 = UART_C4_TDMAS_MASK;
\r
156 /* Map port to pins - for now, just save for timing */
\r
157 void sdma_pinmap(sdma_t *port, PinName tx, PinName rx)
\r
159 port->pin_xmt = (void*)(PORTA_BASE+tx);
\r
160 port->pin_rcv = (void*)(PORTA_BASE+rx);
\r
163 /* Write binary data out the DMA output queue */
\r
164 void sdma_write(sdma_t *port, void *data, int len)
\r
166 if (port->length[port->index] + len > SDMA_LEN) {
\r
169 int pos = port->length[port->index];
\r
170 void *dst = &port->queue[port->index][pos];
\r
171 memcpy(dst, data, len);
\r
172 port->length[port->index] += len;
\r
176 /* Read binary data from the channel */
\r
177 void sdma_read(sdma_t *port, void *data, int len)
\r
179 for (int i = 0; i < len; i++) {
\r
181 while (!(port->uart->s1 & UART_S1_RDRF_MASK))
\r
182 if (port->uart->s1 & UART_S1_OR_MASK)
\r
183 port->uart->s1 |= UART_S1_OR_MASK;
\r
186 ((uint8_t*)data)[i] = port->uart->d;
\r
190 /* Trigger DMA transmit of the current output queue
\r
191 * and swap buffers so we can write into unused space */
\r
192 void sdma_flush(sdma_t *port, uint64_t *time)
\r
194 if (port->length[port->index] == 0)
\r
197 // Wait for transmit complete
\r
198 while (port->dma_xmt->dsr & DMA_DSR_BCR_BCR_MASK)
\r
202 port->dma_xmt->dsr = DMA_DSR_BCR_DONE_MASK;
\r
204 // Set source address and length
\r
205 port->dma_xmt->sar = (uint32_t)&port->queue[port->index];
\r
206 port->dma_xmt->dsr = DMA_DSR_BCR_BCR(port->length[port->index]);
\r
208 // Enable DMA transmit
\r
209 port->dma_xmt->dcr |= DMA_DCR_ERQ_MASK;
\r
212 port->length[port->index] = 0;
\r
213 port->index = (port->index + 1) % SDMA_NUM;
\r
216 /* Wait for DMA receive complete */
\r
217 void sdma_wait(sdma_t *port, uint64_t *time)
\r
219 int req = (void*)port->pin_rcv > (void*)PORTD ? SDMA_REQ_PTD :
\r
220 (void*)port->pin_rcv > (void*)PORTC ? SDMA_REQ_PTC :
\r
221 (void*)port->pin_rcv > (void*)PORTA ? SDMA_REQ_PTA : 0;
\r
224 port->dma_rcv->dsr = DMA_DSR_BCR_DONE_MASK;
\r
226 // Configure channel
\r
227 port->dma_rcv->dcr = DMA_DCR_SINC_MASK
\r
228 | DMA_DCR_DINC_MASK
\r
231 | DMA_DCR_D_REQ_MASK;
\r
234 port->mux_rcv->cfg = DMAMUX_CHCFG_SOURCE(req)
\r
235 | DMAMUX_CHCFG_ENBL_MASK;
\r
237 // Set address and size
\r
238 port->dma_rcv->sar = (uint32_t)&PIT->LTMR64H;
\r
239 port->dma_rcv->dar = (uint32_t)&port->time_rcv;
\r
240 port->dma_rcv->dsr = DMA_DSR_BCR_BCR(sizeof(uint64_t));
\r
242 // Enable DMA transmit
\r
243 port->dma_rcv->dcr |= DMA_DCR_ERQ_MASK;
\r
245 // set pin to generate DMA req
\r
246 port->pin_rcv->pcr = PORT_PCR_ISF_MASK
\r
249 | PORT_PCR_PE_MASK;
\r
251 // Wait for transmit complete
\r
252 while ((port->dma_rcv->dsr & DMA_DSR_BCR_BCR_MASK))
\r
256 *time = ((uint64_t)~port->time_rcv[0]) << 32
\r
257 | ((uint64_t)~port->time_rcv[1]) << 0;
\r
259 // pcr:00030302 dsr:41000008
\r
260 printf(" - pcr:%08lx dsr:%08lx time:%08lx:%08lx",
\r
261 port->pin_rcv->pcr, port->dma_rcv->dsr,
\r
262 (uint32_t)(*time >> 32), (uint32_t)*time);
\r
265 /* Write ASCII data to the output queue */
\r
266 void sdma_vprintf(sdma_t *port, const char *fmt, va_list ap)
\r
268 int pos = port->length[port->index];
\r
269 void *dst = &port->queue[port->index][pos];
\r
270 port->length[port->index] +=
\r
271 vsnprintf((char*)dst, SDMA_LEN-pos, fmt, ap);
\r
274 void sdma_printf(sdma_t *port, const char *fmt, ...)
\r
278 sdma_vprintf(port, fmt, ap);
\r