1 | /**
|
2 | * @file hal_dma.c
|
3 | *
|
4 | * Created: 28.10.2019 07:48:51
|
5 | * Author: A.Patzak
|
6 | */
|
7 | #include <stdbool.h>
|
8 | #include "sam.h"
|
9 | //#include "hal_clocks.h"
|
10 | #include "hal_dma.h"
|
11 | /******************************************************************************/
|
12 | /************************** HAL: DMA-Funktionen ***************************/
|
13 | /******************************************************************************/
|
14 | DmacDescriptor dma_descriptor_section[DMA_MAX_CHANNELS] __attribute__((aligned(16)));
|
15 | DmacDescriptor dma_writeback_section[DMA_MAX_CHANNELS] __attribute__((aligned(16)));
|
16 | DmacDescriptor more_desriptors[DMA_MORE_DESCRIPTORS] __attribute__((aligned(16)));
|
17 | /******************************************************************************/
|
18 | void DmaCrcReset(void)
|
19 | {
|
20 | DMAC->CTRL.bit.CRCENABLE= 0;
|
21 | DMAC->CRCCTRL.reg= 0;
|
22 | DMAC->CRCDATAIN.reg= 0;
|
23 | DMAC->CRCCHKSUM.reg= 0;
|
24 | }
|
25 | /******************************************************************************/
|
26 | void ResetDmaDescriptorSections(void)
|
27 | {
|
28 | uint8_t chann, idx;
|
29 | DmacDescriptor descr= {
|
30 | .BTCTRL.reg= 0,
|
31 | .BTCNT.reg= 0,
|
32 | .SRCADDR.reg= 0,
|
33 | .DSTADDR.reg= 0,
|
34 | .DESCADDR.reg= 0
|
35 | };
|
36 | for(chann= 0; chann < DMA_MAX_CHANNELS; chann++)
|
37 | dma_descriptor_section[chann]= descr;
|
38 | for(idx= 0; idx < DMA_MORE_DESCRIPTORS; idx++)
|
39 | more_desriptors[idx]= descr;
|
40 | }
|
41 | /******************************************************************************/
|
42 | DmacDescriptor* AddDmaDescriptor(const dma_channel_id_t chann, void* const srcendaddr, const dma_addr_inc_t srcinc,
|
43 | void* const dstendaddr, const dma_addr_inc_t dstinc, const dma_beat_size_t beatsize,
|
44 | const uint16_t beatcnt, const dma_evo_sel_t evosel)
|
45 | {
|
46 | uint8_t idx;
|
47 | DmacDescriptor *descr_ptr, descr= {
|
48 | .BTCTRL.bit.BEATSIZE= beatsize,
|
49 | .BTCTRL.bit.BLOCKACT= DMA_BLOCK_ACTION_NOACT,
|
50 | .BTCTRL.bit.EVOSEL= evosel,
|
51 | .BTCTRL.bit.VALID= 1,
|
52 | .BTCNT.reg= beatcnt,
|
53 | .SRCADDR.reg= (uint32_t)srcendaddr,
|
54 | .DSTADDR.reg= (uint32_t)dstendaddr,
|
55 | .DESCADDR.reg= 0
|
56 | };
|
57 | // Address-Increment setzen
|
58 | descr.BTCTRL.bit.DSTINC= (dstinc >= DMA_ADDR_INC_1);
|
59 | descr.BTCTRL.bit.SRCINC= (srcinc >= DMA_ADDR_INC_1);
|
60 | if(srcinc > DMA_ADDR_INC_1) // Source-Inc spezial!
|
61 | {
|
62 | if(dstinc > DMA_ADDR_INC_1) // beides gleichzeitig geht nicht!
|
63 | return(0);
|
64 | else // Source-Inc spezial!
|
65 | {
|
66 | descr.BTCTRL.bit.STEPSEL= DMA_STEPSEL_SRC; // Source-StepSel
|
67 | descr.BTCTRL.bit.STEPSIZE= srcinc; // Source-Increment
|
68 | descr.BTCTRL.bit.SRCINC= 1;
|
69 | descr.BTCTRL.bit.DSTINC= (dstinc != DMA_ADDR_INC_NONE);
|
70 | }
|
71 | }
|
72 | else // Source-Inc KEIN spezial!
|
73 | {
|
74 | if(dstinc > DMA_ADDR_INC_1) // Dest-Inc spezial!
|
75 | {
|
76 | descr.BTCTRL.bit.STEPSEL= DMA_STEPSEL_DST; // Dest-StepSel
|
77 | descr.BTCTRL.bit.STEPSIZE= dstinc; // Dest-Increment
|
78 | descr.BTCTRL.bit.DSTINC= 1;
|
79 | descr.BTCTRL.bit.SRCINC= (srcinc != DMA_ADDR_INC_NONE);
|
80 | }
|
81 | else // weder Source- noch Dest-Inc spezial!
|
82 | {
|
83 |
|
84 | descr.BTCTRL.bit.STEPSEL= DMA_STEPSEL_DST; // Dest-StepSel
|
85 | descr.BTCTRL.bit.STEPSIZE= DMA_ADDR_INC_1; // Dest-Increment 1
|
86 | descr.BTCTRL.bit.SRCINC= (srcinc != DMA_ADDR_INC_NONE);
|
87 | descr.BTCTRL.bit.DSTINC= (dstinc != DMA_ADDR_INC_NONE);
|
88 | }
|
89 | }
|
90 | // DMA-Descriptor finden & setzen
|
91 | if(!dma_descriptor_section[chann].BTCTRL.bit.VALID) // Section noch leer / invalid, add in Section
|
92 | {
|
93 | dma_descriptor_section[chann]= descr; // neuen Descriptor in Section eingetragen
|
94 | return((DmacDescriptor*)&dma_descriptor_section[chann]);
|
95 | }
|
96 | else
|
97 | {
|
98 | // suche nach erstem leeren more-Descriptor
|
99 | for(idx= 0; idx < DMA_MORE_DESCRIPTORS; idx++)
|
100 | {
|
101 | if(!more_desriptors[idx].BTCTRL.bit.VALID)
|
102 | break;
|
103 | }
|
104 | if(idx >= DMA_MORE_DESCRIPTORS) // Fehler: zu wenige DMA_MORE_DESCRIPTORS definiert!!!!!!!!!!!!!!!!!!!
|
105 | return((DmacDescriptor*)0x0);
|
106 | // den neuen Descriptor erzeugen & verlinken...
|
107 | descr_ptr= (DmacDescriptor*)&(dma_descriptor_section[chann]); // Pointer auf Kanal-Knoten initialisieren
|
108 | // letzten verlinkten Descriptor suchen...
|
109 | while(descr_ptr->DESCADDR.reg != 0)
|
110 | descr_ptr= (DmacDescriptor*)(descr_ptr->DESCADDR.reg);
|
111 | // ...und neuen more-Descriptor anhängen
|
112 | descr_ptr->DESCADDR.reg= (uint32_t)(&more_desriptors[idx]);
|
113 | // neuen more-Descriptor Werte setzen
|
114 | more_desriptors[idx]= descr;
|
115 | }
|
116 | return((DmacDescriptor*)&more_desriptors[idx]);
|
117 | }
|
118 | /******************************************************************************/
|
119 | void ResetDmaChannelDescriptors(const dma_channel_id_t chann)
|
120 | {
|
121 | DmacDescriptor *act_descr_ptr= (DmacDescriptor*)&(dma_descriptor_section[chann]); // Pointer auf Kanal-Knoten initialisieren
|
122 | DmacDescriptor *next_descr_ptr;
|
123 | // komplette Link-Liste löschen (DSTADDR=0!)
|
124 |
|
125 | do {
|
126 | next_descr_ptr= (DmacDescriptor*)act_descr_ptr->DESCADDR.reg;
|
127 | act_descr_ptr->DESCADDR.reg= 0;
|
128 | act_descr_ptr->BTCTRL.reg= 0;
|
129 | act_descr_ptr= next_descr_ptr;
|
130 | }
|
131 | while(act_descr_ptr != 0);
|
132 | }
|
133 | /******************************************************************************/
|
134 | void ResetDmaChannel(const dma_channel_id_t chann)
|
135 | {
|
136 | // Kanal-Selektor zuerst einstellen
|
137 | DMAC->CHID.bit.ID= DMAC_CHID_ID(chann);
|
138 | DMAC->CHCTRLA.reg= 0;
|
139 | while(DMAC->CHCTRLA.reg != 0);
|
140 | ResetDmaChannelDescriptors(chann);
|
141 | }
|
142 | /******************************************************************************/
|
143 | void SetupDmaChannel(const dma_channel_id_t chann, const dma_priority_t prio, const dma_trigact_t trig,
|
144 | const dma_trigsource_t trigsrc, const dma_eventact_t evact)
|
145 | {
|
146 | // Kanal-Selektor zuerst einstellen
|
147 | DMAC->CHID.bit.ID= DMAC_CHID_ID(chann);
|
148 | DMAC->CHCTRLA.reg= 0;
|
149 | while(DMAC->CHCTRLA.reg != 0);
|
150 | ResetDmaChannelDescriptors(chann);
|
151 | DMAC->SWTRIGCTRL.reg= 0;
|
152 | DMAC->PRICTRL0.reg= 0;
|
153 | // Kanal einstellen: CHCTRLB...
|
154 | DMAC_CHCTRLB_Type chctrlb= {
|
155 | .bit.LVL= prio,
|
156 | .bit.TRIGACT= trig,
|
157 | .bit.TRIGSRC= trigsrc,
|
158 | .bit.CMD= 0,
|
159 | .bit.EVOE= 0
|
160 | };
|
161 | if(evact == DMA_EVACT_NONE)
|
162 | {
|
163 | chctrlb.bit.EVIE= 0;
|
164 | chctrlb.bit.EVACT= DMA_EVACT_NONE;
|
165 | }
|
166 | else
|
167 | {
|
168 | chctrlb.bit.EVIE= 1;
|
169 | chctrlb.bit.EVACT= evact;
|
170 | }
|
171 | DMAC->CHCTRLB.reg= chctrlb.reg;
|
172 | DMAC->CHINTENCLR.reg= 0x3; // Interupts löschen
|
173 | }
|
174 | /******************************************************************************/
|
175 | void EnableDmaChannel(const dma_channel_id_t chann)
|
176 | {
|
177 | // Kanal-Selektor zuerst einstellen
|
178 | DMAC->CHID.bit.ID= DMAC_CHID_ID(chann);
|
179 | DMAC->CHCTRLA.bit.ENABLE= 1;
|
180 | while(!DMAC->CHCTRLA.bit.ENABLE);
|
181 | }
|
182 | /******************************************************************************/
|
183 | void DisableDmaChannel(const dma_channel_id_t chann)
|
184 | {
|
185 | // Kanal-Selektor zuerst einstellen
|
186 | DMAC->CHID.bit.ID= DMAC_CHID_ID(chann);
|
187 | DMAC->CHCTRLA.bit.ENABLE= 0;
|
188 | while(DMAC->CHCTRLA.bit.ENABLE);
|
189 | }
|
190 | /******************************************************************************/
|
191 | void SetupDma(void)
|
192 | {
|
193 | // Turn on the clocks
|
194 | PM->AHBMASK.reg |= PM_AHBMASK_DMAC;
|
195 | PM->APBBMASK.reg |= PM_APBBMASK_DMAC;
|
196 | // kompletter DMA-Reset... zuerst DMA ausschalten
|
197 | DMAC->CTRL.bit.DMAENABLE= 0;
|
198 | while(DMAC->CTRL.bit.DMAENABLE);
|
199 | DMAC->CTRL.bit.CRCENABLE= 0;
|
200 | while(DMAC->CTRL.bit.CRCENABLE);
|
201 | DMAC->CTRL.bit.SWRST = DMAC_CTRL_SWRST;
|
202 | while(DMAC->CTRL.bit.SWRST);
|
203 | // Descriptoren initialisieren
|
204 | ResetDmaDescriptorSections();
|
205 | DMAC->BASEADDR.reg = (uint32_t)dma_descriptor_section;
|
206 | DMAC->WRBADDR.reg = (uint32_t)dma_writeback_section;
|
207 | // SW-Trig aus & statische Priorität
|
208 | DMAC->SWTRIGCTRL.reg= 0;
|
209 | DMAC->PRICTRL0.reg= 0;
|
210 | // DMA-Zugriffsprioritäten setzen
|
211 | DMAC->QOSCTRL.bit.DQOS= DMA_MEMACCESS_PRI_MED; // Transfer-Priorität
|
212 | DMAC->QOSCTRL.bit.FQOS= DMA_MEMACCESS_PRI_MED; // Fetch-Priorität
|
213 | DMAC->QOSCTRL.bit.WRBQOS= DMA_MEMACCESS_PRI_MED; // Writeback-Priorität
|
214 | // alle Prioritätslevel freischalten
|
215 | DMAC->CTRL.reg |= DMAC_CTRL_LVLEN(DMA_PRI_LEVELS_ENABLE);
|
216 | // DMA einschalten
|
217 | DMAC->CTRL.bit.DMAENABLE= 1;
|
218 | while(!DMAC->CTRL.bit.DMAENABLE);
|
219 | }
|
220 | /******************************************************************************/
|
221 | /******************************************************************************/
|