]> Pileus Git - ~andy/csm213a-hw/blob - hw2/timer_dma.c
Add dma timestamper
[~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, 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_ERQ_MASK;         // Enable port request\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(3)           // Pin mapping\r
107                         | PORT_PCR_IRQC(ircq)       // DMA on falling edge\r
108                         | mode;                     // Pin pull up/down\r
109 \r
110         return port;\r
111 }\r
112 \r
113 void tdma_reset(tdma_t *port)\r
114 {\r
115         // Clear previous time\r
116         port->time[0] = 0;\r
117         port->time[1] = 0;\r
118 \r
119         // Reset DMA channel\r
120         port->dma->dsr  = DMA_DSR_BCR_DONE_MASK;\r
121 \r
122         // Set addresses and size\r
123         port->dma->sar  = (uint32_t)&PIT->LTMR64H;  // Global timer\r
124         port->dma->dar  = (uint32_t)&port->time;    // Temp timer buffer\r
125         port->dma->dsr  = DMA_DSR_BCR_BCR(8);       // 64-bit timer\r
126 }\r
127 \r
128 int tdma_stamp(tdma_t *port, uint64_t *time)\r
129 {\r
130         if (port->dma->dsr & DMA_DSR_BCR_BCR_MASK)\r
131                 return 0;\r
132 \r
133         // Read the timestamp\r
134         *time = ((uint64_t)~port->time[0]) << 32\r
135               | ((uint64_t)~port->time[1]) << 0;\r
136 \r
137         // Debug output..\r
138         //printf(" - sar:%08lx dar:%08lx pcr:%08lx dsr:%08lx time:%08lx:%08lx",\r
139         //      port->dma->sar, port->dma->dar,\r
140         //      port->pin->pcr, port->dma->dsr,\r
141         //      (uint32_t)(*time >> 32), (uint32_t)*time);\r
142 \r
143         return 1;\r
144 }\r