]> Pileus Git - ~andy/csm213a-hw/blob - hw2/timer_dma.c
Fix whitespace error
[~andy/csm213a-hw] / hw2 / timer_dma.c
1 #include <MKL46Z4.h>
2
3 #include <stdint.h>
4 #include <stdarg.h>
5 #include <stdio.h>
6 #include <string.h>
7
8 #include "timer_dma.h"
9 #include "serial_irq.h"
10
11 /* Defines */
12 enum {
13         TDMA_REQ_PTA  = 49,
14         TDMA_REQ_PTC  = 51,
15         TDMA_REQ_PTD  = 52,
16 };
17
18 /* Port structure */
19 struct tdma_t {
20         /* DMA channel */
21         struct {
22                 uint32_t sar; // offset 0x00, Source Address Register
23                 uint32_t dar; // offset 0x04, Destination Address Register
24                 uint32_t dsr; // offset 0x08, DMA Status Register / Byte Count Register
25                 uint32_t dcr; // offset 0x0C, DMA Control Register
26         } *dma;
27
28         /* DMA mux */
29         struct {
30                 uint8_t  cfg; // offset 0x00, Channel Configuration register
31         } *mux;
32
33         /* Pin names */
34         struct {
35                 uint32_t pcr; // offset 0x00, Pin Control register
36         } *pin;
37
38         /* Time stamping */
39         uint32_t time[2];
40
41         /* Save state */
42         int      req;
43         int      irqc;
44 };
45
46 /* Port data */
47 static tdma_t tdma_ports[TDMA_NUM_CHAN];
48
49 /* Global timer initialization */
50 void tdma_init(void)
51 {
52         static int tdma_init_done = 0;
53         if (tdma_init_done)
54                 return;
55
56         // Enable DMA Cock
57         SIM->SCGC5 |= SIM_SCGC5_PORTA_MASK;
58         SIM->SCGC5 |= SIM_SCGC5_PORTC_MASK;
59         SIM->SCGC5 |= SIM_SCGC5_PORTD_MASK;
60         SIM->SCGC6 |= SIM_SCGC6_DMAMUX_MASK;
61         SIM->SCGC7 |= SIM_SCGC7_DMA_MASK;
62
63         // Enable timer Clock
64         SIM->SCGC6 |= SIM_SCGC6_PIT_MASK;
65
66         // Enable PIT
67         PIT->MCR               = 0;
68
69         // Channel 0
70         PIT->CHANNEL[0].LDVAL  = 0xFFFFFFFF;
71         PIT->CHANNEL[0].TCTRL  = 0;
72
73         // Channel 1
74         PIT->CHANNEL[1].LDVAL  = 0xFFFFFFFF;
75         PIT->CHANNEL[1].TCTRL  = PIT_TCTRL_CHN_MASK;
76
77         // Start timers
78         PIT->CHANNEL[0].TCTRL |= PIT_TCTRL_TEN_MASK;
79         PIT->CHANNEL[1].TCTRL |= PIT_TCTRL_TEN_MASK;
80
81         // Done
82         tdma_init_done = 1;
83 }
84
85 /* DMA Functions */
86 tdma_t *tdma_open(tdma_chan_t chan, int alt, PinName pin, PinMode mode)
87 {
88         int req  = pin >= PTD0 ? TDMA_REQ_PTD :
89                    pin >= PTC0 ? TDMA_REQ_PTC :
90                    pin >= PTA0 ? TDMA_REQ_PTA : 0;
91
92         int irqc = mode == PullDown ? 1 : 2;
93
94         // Initialize global registers
95         tdma_init();
96
97         // Allocate port
98         tdma_t *port    = &tdma_ports[chan];
99
100         // Setup port pointers
101         port->dma       = (void*)&DMA0->DMA[chan];
102         port->mux       = (void*)&DMAMUX0->CHCFG[chan];
103         port->pin       = (void*)(PORTA_BASE + pin);
104
105         // Reset DMA channel
106         port->dma->dsr  = DMA_DSR_BCR_DONE_MASK;
107
108         // Configure DMA channel
109         port->dma->dcr  = DMA_DCR_SINC_MASK         // Source increment
110                         | DMA_DCR_DINC_MASK         // Dest increment
111                         | DMA_DCR_SSIZE(0)          // 32-bit access
112                         | DMA_DCR_DSIZE(0)          // 32-bit access
113                         | DMA_DCR_D_REQ_MASK;       // Only run once
114
115         // Setup and enable DMA MUX
116         port->mux->cfg  = DMAMUX_CHCFG_SOURCE(req)  // Request source
117                         | DMAMUX_CHCFG_ENBL_MASK;   // Enable DMA mux
118
119         // Set pin to generate DMA req
120         port->pin->pcr  = PORT_PCR_ISF_MASK         // Clear ISR flag
121                         | PORT_PCR_MUX(alt)         // Pin mapping
122                         | PORT_PCR_IRQC(irqc)       // DMA on falling edge
123                         | mode;                     // Pin pull up/down
124
125         // Save IRC for later
126         port->req       = req;
127         port->irqc      = irqc;
128
129         return port;
130 }
131
132 void tdma_start(tdma_t *port)
133 {
134         if (!port)
135                 return;
136
137         //sirq_printf("isfr2: %08x\r\n", PORTD->ISFR);
138
139         // Clear previous time
140         port->time[0] = 0;
141         port->time[1] = 0;
142
143         // Reset DMA Mux
144         port->mux->cfg &= DMAMUX_CHCFG_ENBL_MASK;
145
146         // Freeze DMA channel
147         port->dma->dcr &= ~DMA_DCR_ERQ_MASK;
148
149         // Reset DMA channel
150         port->dma->dsr  =  DMA_DSR_BCR_DONE_MASK;
151
152         // Set addresses and size
153         port->dma->sar  =  (uint32_t)&PIT->LTMR64H;  // Global timer
154         port->dma->dar  =  (uint32_t)&port->time;    // Temp timer buffer
155         port->dma->dsr  =  DMA_DSR_BCR_BCR(8);       // 64-bit timer
156
157         // Set pin to generate DMA req
158         port->pin->pcr |=  PORT_PCR_ISF_MASK;
159         port->pin->pcr |=  PORT_PCR_IRQC(port->irqc);
160
161         // Enable port request
162         port->dma->dcr |=  DMA_DCR_ERQ_MASK;
163
164         // Enable DMA Mux
165         port->mux->cfg  = DMAMUX_CHCFG_SOURCE(port->req)
166                         | DMAMUX_CHCFG_ENBL_MASK;
167
168         //sirq_printf("isfr3: %08x\r\n", PORTD->ISFR);
169 }
170
171 void tdma_stop(tdma_t *port, int wait)
172 {
173         if (!port)
174                 return;
175
176         //sirq_printf("isfr0: %08x\r\n", PORTD->ISFR);
177
178         for (int i = 0; port->dma->dsr & DMA_DSR_BCR_BCR_MASK; i++)
179                 if (i > wait)
180                         return;
181
182         // Disable DMA Mux
183         port->mux->cfg &= DMAMUX_CHCFG_ENBL_MASK;
184
185         // Freeze DMA channel
186         port->dma->dcr &= ~DMA_DCR_ERQ_MASK;
187
188         // Reset DMA channel
189         port->dma->dsr  =  DMA_DSR_BCR_DONE_MASK;
190
191         // Disable pin DMA request
192         port->pin->pcr &= ~PORT_PCR_IRQC_MASK;
193         port->pin->pcr |=  PORT_PCR_ISF_MASK;
194
195         //sirq_printf("isfr1: %08x\r\n", PORTD->ISFR);
196 }
197
198 int tdma_stamp(tdma_t *port, uint64_t *time)
199 {
200         uint64_t clocks;
201
202         if (!port)
203                 return 0;
204
205         if (port->dma->dsr & DMA_DSR_BCR_BCR_MASK)
206                 return 0;
207
208         // Read the timestamp
209         clocks = ((uint64_t)~port->time[0]) << 32
210                | ((uint64_t)~port->time[1]) << 0;
211
212         // Convert to nanoseconds
213         *time  = clocks * 1000 / 24;
214
215         return 1;
216 }
217
218 uint64_t tdma_time(void)
219 {
220         uint32_t tmh = PIT->LTMR64H;
221         uint32_t tml = PIT->LTMR64L;
222
223         // Read the timestamp
224         uint64_t clocks = ((uint64_t)~tmh) << 32
225                         | ((uint64_t)~tml) << 0;
226
227         // Convert to nanoseconds
228         return clocks * 125 / 3;
229 }
230
231 void tdma_debug(tdma_t *port)
232 {
233         int dsr = port->dma->dsr;
234         int dcr = port->dma->dcr;
235
236         printf("dsr: %s %s %s %s %s %s %d\r\n",
237                          dsr & DMA_DSR_BCR_CE_MASK   ? "CE"      : "ce",
238                          dsr & DMA_DSR_BCR_BES_MASK  ? "BSE"     : "bse",
239                          dsr & DMA_DSR_BCR_BED_MASK  ? "BED"     : "bed",
240                          dsr & DMA_DSR_BCR_REQ_MASK  ? "REQ"     : "req",
241                          dsr & DMA_DSR_BCR_BSY_MASK  ? "BSY"     : "bsy",
242                          dsr & DMA_DSR_BCR_DONE_MASK ? "DONE"    : "done",
243                          dsr & DMA_DSR_BCR_BCR_MASK);
244
245         printf("dcr: %s %s %s %s %s %s %s %s ssize=%d:%d mod=%d:%d link=%d:%d:%d\r\n",
246                          dcr & DMA_DCR_EINT_MASK     ? "EINT"    : "eint",
247                          dcr & DMA_DCR_ERQ_MASK      ? "ERQ"     : "erq",
248                          dcr & DMA_DCR_CS_MASK       ? "CS"      : "cs",
249                          dcr & DMA_DCR_AA_MASK       ? "AA"      : "aa",
250                          dcr & DMA_DCR_EADREQ_MASK   ? "EADRREQ" : "eadrreq",
251                          dcr & DMA_DCR_SINC_MASK     ? "SINC"    : "sinc",
252                          dcr & DMA_DCR_DINC_MASK     ? "DINC"    : "dinc",
253                          dcr & DMA_DCR_D_REQ_MASK    ? "DREQ"    : "dreq",
254                         (dcr & DMA_DCR_SSIZE_MASK ) >> DMA_DCR_SSIZE_SHIFT,
255                         (dcr & DMA_DCR_DSIZE_MASK ) >> DMA_DCR_DSIZE_SHIFT,
256                         (dcr & DMA_DCR_SMOD_MASK  ) >> DMA_DCR_SMOD_SHIFT,
257                         (dcr & DMA_DCR_DMOD_MASK  ) >> DMA_DCR_DMOD_SHIFT,
258                         (dcr & DMA_DCR_LINKCC_MASK) >> DMA_DCR_LINKCC_SHIFT,
259                         (dcr & DMA_DCR_LCH1_MASK  ) >> DMA_DCR_LCH1_SHIFT,
260                         (dcr & DMA_DCR_LCH2_MASK  ) >> DMA_DCR_LCH2_SHIFT);
261 }