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