hal_dma.c


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
/******************************************************************************/