hal_dma.h


1
/**
2
 * @file hal_dma.h
3
 *
4
 * Created: 28.10.2019 07:49:08
5
 *  Author: A.Patzak
6
 *
7
 * Erklärung:
8
 * - Diese HAL ist für Menschen die wissen was sie tun!
9
 *  + Zur Sicherheit sind die definierten Konstanten zu verwenden
10
 * - Die DMA besteht aus dem Hauptmodul und den max. 12 Kanälen
11
 * - Je Kanal gibt es mind. einen (Block-)Descriptor (oder mehr verlinkte)...
12
 *   ...der Quelle, Ziel und die Übertragungsweise eines Blockes festlegt
13
 * - Ist ein Descriptor abgearbeitet wird der nächste verlinkte Descriptor abgearbeitet
14
 * - Nach dem letzten Descriptor wird die Übertragung des Kanales beendet 
15
 * - DMA-Transfers sind folgendermaßen zusammengesetzt:
16
 *  + Beatsize:    (Bytes) ist ein Buszugriff (fetch) <== Peripherie-Reg-Size
17
 *  + Blocksize:  Anzahl der Beats pro Block (= ein Descriptor!) <-- "beatcnt"
18
 *  + Transaction:  Alle Blöcke (aller verlinkten Descriptoren) 
19
 * - Um die Übertragung anzustoßen gibt es verschiedene DMA-Triggerquellen:
20
 *  + Software-Command
21
 *  + Events
22
 *  + direkte Verbindungen zu Peripherie-Modulen (ählich zu INT-Flags)
23
 * - Pro DMA-Trigger kann entweder ein Beat oder ein Block oder Transfer angestoßen werden.
24
 *  + Für Peripheriemodule verwendet man den Beat-Trigger 
25
 * - Die DMA kann auch selbst Interupts und Events generieren / ausgeben
26
 *
27
 * Benutzung:
28
 *  0.) Anpassung des DMA-Konfigurationsbereiches in hal_dma.h
29
 *  1.) SetupDma()
30
 *  2.) SetupDmaChannel()
31
 *  3.) AddDmaDescriptor() 
32
 *  ?.) Evtl. zusätzliche Konfigurierungen
33
 *  4.) EnableDmaChannel()
34
 *  5.) für weitere Kanäle 2.) -> 4.)
35
 * 
36
 * \defgroup HAL: Funktionen für die DMA
37
 * @{*/
38
#ifndef HAL_DMA_H_
39
#define HAL_DMA_H_
40
/******************************************************************************/
41
/**************************   HAL: DMA-Konstante   ****************************/
42
/******************************************************************************/
43
// !!!!!!!!!!!!!!!!!!!!!!!! DMA-Konfigurationsbereich !!!!!!!!!!!!!!!!!!!!!!!!!
44
// !! Hier muss die maximal benutzte Anzahl an DMA-Kanälen eingestellt werden
45
#define DMA_MAX_CHANNELS    2
46
#define DMA_MORE_DESCRIPTORS  1    // maximale Anzahl aller zusätzlicher Descriptoren aller Kanäle
47
#define DMA_PRI_LEVELS_ENABLE  (0xF)  // Level 0..3 enabled
48
#define DMA_MEMACCESS_PRI_MED  0x2    // mittlerer Speicherzugriffslevel für Fetch, Transaktion und Writeback
49
/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
50
typedef enum dma_channel_id{
51
  DMA_CHID_CHANNEL0= 0,
52
  DMA_CHID_CHANNEL1,
53
  DMA_CHID_CHANNEL2,
54
  DMA_CHID_CHANNEL3,
55
  DMA_CHID_CHANNEL4,
56
  DMA_CHID_CHANNEL5,
57
  DMA_CHID_CHANNEL6,
58
  DMA_CHID_CHANNEL7,
59
} dma_channel_id_t;
60
61
typedef enum dma_transfer_trigger_action{
62
  DMA_TRIGGER_ACTON_BLOCK       = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
63
  DMA_TRIGGER_ACTON_BEAT        = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
64
  DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
65
} dma_transfer_trigger_action_t;
66
67
typedef enum dma_callback_type {
68
  // First item here is for any transfer errors. A transfer error is
69
  // flagged if a bus error is detected during an AHB access or when
70
  // the DMAC fetches an invalid descriptor
71
  DMA_CALLBACK_TRANSFER_ERROR,
72
  DMA_CALLBACK_TRANSFER_DONE,
73
  DMA_CALLBACK_CHANNEL_SUSPEND,
74
  DMA_CALLBACK_N, // Number of available callbacks
75
} dma_callback_type_t;
76
77
typedef enum dma_beat_size {
78
  DMA_BEAT_SIZE_8B = 0, // 8-bit
79
  DMA_BEAT_SIZE_16B,    // 16-bit
80
  DMA_BEAT_SIZE_32B,    // 32-bit
81
} dma_beat_size_t;
82
83
typedef enum dma_event_output_selection {
84
  DMA_EVENT_OUTPUT_DISABLE = 0, // Disable event generation
85
  DMA_EVENT_OUTPUT_BLOCK,       // Event strobe when block xfer complete
86
  DMA_EVENT_OUTPUT_RESERVED,
87
  DMA_EVENT_OUTPUT_BEAT,        // Event strobe when beat xfer complete
88
} dma_evo_sel_t;
89
90
// DMA step selection. This bit determines whether the step size setting
91
// is applied to source or destination address.
92
typedef enum dma_step_selection {
93
  DMA_STEPSEL_DST = 0,
94
  DMA_STEPSEL_SRC,
95
} dma_step_selection_t;
96
97
// Address increment step size. These bits select the address increment step
98
// size. The setting apply to source or destination address, depending on
99
// STEPSEL setting.
100
typedef enum dma_address_increment_stepsize {
101
  DMA_ADDR_INC_NONE = -1,  // kein Adress-Increment
102
  DMA_ADDR_INC_1 = 0,    // beat size * 1
103
  DMA_ADDR_INC_2,      // beat size * 2
104
  DMA_ADDR_INC_4,      // beat size * 4
105
  DMA_ADDR_INC_8,      // etc...
106
  DMA_ADDR_INC_16,
107
  DMA_ADDR_INC_32,
108
  DMA_ADDR_INC_64,
109
  DMA_ADDR_INC_128,
110
} dma_addr_inc_t;
111
112
// higher numbers are higher priority
113
typedef enum dma_priority {
114
  DMA_PRIORITY_0, // lowest (default)
115
  DMA_PRIORITY_1,
116
  DMA_PRIORITY_2,
117
  DMA_PRIORITY_3, // highest
118
} dma_priority_t;
119
120
typedef enum dma_block_action {
121
  DMA_BLOCK_ACTION_NOACT = 0,
122
  // Channel in normal operation and sets transfer complete interrupt
123
  // flag after block transfer
124
  DMA_BLOCK_ACTION_INT,
125
  // Trigger channel suspend after block transfer and sets channel
126
  // suspend interrupt flag once the channel is suspended
127
  DMA_BLOCK_ACTION_SUSPEND,
128
  // Sets transfer complete interrupt flag after a block transfer and
129
  // trigger channel suspend. The channel suspend interrupt flag will
130
  // be set once the channel is suspended.
131
  DMA_BLOCK_ACTION_BOTH
132
} dma_block_action_t;
133
134
// 
135
typedef enum dma_trigact {
136
  DMA_TRIGACT_BLOCK,    //
137
  DMA_TRIGACT_RESERVED,  //
138
  DMA_TRIGACT_BEAT,    //
139
  DMA_TRIGACT_TRANSACTION //
140
} dma_trigact_t;
141
142
// 
143
typedef enum dma_trigsource {
144
  DMA_TRIGSRC_SW_EVENT,  //
145
  DMA_TRIGSRC_SERCOM0_RX,  //
146
  DMA_TRIGSRC_SERCOM0_TX,  //
147
  DMA_TRIGSRC_SERCOM1_RX,  //
148
  DMA_TRIGSRC_SERCOM1_TX,  //
149
  DMA_TRIGSRC_SERCOM2_RX,  //
150
  DMA_TRIGSRC_SERCOM2_TX,  //
151
  DMA_TRIGSRC_SERCOM3_RX,  //
152
  DMA_TRIGSRC_SERCOM3_TX,  //
153
  DMA_TRIGSRC_SERCOM4_RX,  //
154
  DMA_TRIGSRC_SERCOM4_TX,  //
155
  DMA_TRIGSRC_SERCOM5_RX,  //
156
  DMA_TRIGSRC_SERCOM5_TX,  //
157
  DMA_TRIGSRC_TCC0_OVF,  //
158
  DMA_TRIGSRC_TCC0_MC0,  //
159
  DMA_TRIGSRC_TCC0_MC1,  //
160
  DMA_TRIGSRC_TCC0_MC2,  //
161
  DMA_TRIGSRC_TCC0_MC3,  //
162
  DMA_TRIGSRC_TCC1_OVF,  //
163
  DMA_TRIGSRC_TCC1_MC0,  //
164
  DMA_TRIGSRC_TCC1_MC1,  //
165
  DMA_TRIGSRC_TCC2_OVF,  //
166
  DMA_TRIGSRC_TCC2_MC0,  //
167
  DMA_TRIGSRC_TCC2_MC1,  //
168
  DMA_TRIGSRC_TC3_OVF,  //
169
  DMA_TRIGSRC_TC3_MC0,  //
170
  DMA_TRIGSRC_TC3_MC1,  //
171
  DMA_TRIGSRC_TC4_OVF,  //
172
  DMA_TRIGSRC_TC4_MC0,  //
173
  DMA_TRIGSRC_TC4_MC1,  //
174
  DMA_TRIGSRC_TC5_OVF,  //
175
  DMA_TRIGSRC_TC5_MC0,  //
176
  DMA_TRIGSRC_TC5_MC1,  //
177
  DMA_TRIGSRC_TC6_OVF,  //
178
  DMA_TRIGSRC_TC6_MC0,  //
179
  DMA_TRIGSRC_TC6_MC1,  //
180
  DMA_TRIGSRC_TC7_OVF,  //
181
  DMA_TRIGSRC_TC7_MC0,  //
182
  DMA_TRIGSRC_TC7_MC1,  //
183
  DMA_TRIGSRC_ADCRDY,    //
184
  DMA_TRIGSRC_DACEMPTY,  //
185
  DMA_TRIGSRC_I2SRX0,    //
186
  DMA_TRIGSRC_I2SRX1,    //
187
  DMA_TRIGSRC_I2STX0,    //
188
  DMA_TRIGSRC_I2STX1,    //
189
  DMA_TRIGSRC_TCC3_OVF,  //
190
  DMA_TRIGSRC_TCC3_MC0,  //
191
  DMA_TRIGSRC_TCC3_MC1,  //
192
  DMA_TRIGSRC_TCC3_MC2,  //
193
  DMA_TRIGSRC_TCC3_MC3  //
194
} dma_trigsource_t;
195
196
// 
197
typedef enum dma_eventact {
198
  DMA_EVACT_NONE,    // keine Reaktion auf Events
199
  DMA_EVACT_TRIG,    // Event triggert normal
200
  DMA_EVACT_CONTRANS, // conditional Transfer-Trigger
201
  DMA_EVACT_CONBLOCK, // conditional Block-Trigger
202
  DMA_EVACT_SUSPEND,  // Suspend-Aktion
203
  DMA_EVACT_RESUME,  // Resume-Aktion
204
  DMA_EVACT_SSKIP,  // Skip-Aktion
205
} dma_eventact_t;
206
/******************************************************************************/
207
/***************************   HAL: DMA-Routinen   ****************************/
208
/******************************************************************************/
209
/** @brief setzt das CRC-Modul der DMA zurück */
210
void DmaCrcReset(void);
211
212
/** @brief setzt alle DMA-Descriptor-Sections und more_desriptors im RAM zurück */
213
void ResetDmaDescriptorSections(void);
214
215
/** @brief setzt / fügt an (dem angegebenen Kanal), einen DMA-Link-Descriptor & liefert Pointer auf neuen Descriptor zurück
216
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten; 
217
* @param[in] srcendaddr: Die !!letzte!! Adresse des Source-Bereiches
218
* @param[in] srcinc: Bestimmt das Adressincrement für Source; eine der dma_addr_inc_t-Konstanten
219
* @param[in] dstendaddr: Die !!letzte!! Adresse des Destination-Bereiches
220
* @param[in] dstinc: Bestimmt das Adressincrement für Destination; eine der dma_addr_inc_t-Konstanten
221
* @param[in] beatsize: Datenformat der Source in Byte (kleinste Einheit für Trigger); eine der dma_beat_size_t-Konstanten
222
* @param[in] beatcnt: Anzahl der Beat-Transfers pro Block-Transfer
223
* @param[in] evosel: Auswahl, wann ein Event erzeugt wird; eine der dma_evo_sel_t-Konstanten
224
* @return: OK: Pointer auf neuen Descriptor (damit kann man noch händisch nachkonfigurieren!); Fehler: Null */
225
DmacDescriptor* AddDmaDescriptor(const dma_channel_id_t chann, void* const srcendaddr, const dma_addr_inc_t srcinc,
226
                 void* const dstendaddr, const dma_addr_inc_t dstinc,
227
                 const dma_beat_size_t beatsize, const uint16_t beatcnt, const dma_evo_sel_t evosel);
228
229
/** @brief löscht alle Descriptoren eines Kanals
230
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten */
231
void ResetDmaChannelDescriptors(const dma_channel_id_t chann);
232
233
/** @brief resettet einen kompletten DMA-Kanal und disabled ihn
234
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten */
235
void ResetDmaChannel(const dma_channel_id_t chann);
236
237
/** @brief enabled den angegebenen DMA-Kanal
238
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten */
239
void EnableDmaChannel(const dma_channel_id_t chann);
240
241
/** @brief disabled den angegebenen DMA-Kanal
242
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten */
243
void DisableDmaChannel(const dma_channel_id_t chann);
244
245
/** @brief Konfiguriert einen DMA-Kanal ohne ihn zu enablen und ohne Descriptor(en)!
246
* Hinweis:
247
* - Zur vollen Funktionsfähigkeit des Kanals muss danach noch folgendes erfolgen...
248
* - mind. ein Aufruf AddDmaDescriptor(....)
249
* - danach müssen evtl. noch weitere Konfigurationen manuell erledigt werden
250
* - Aufruf von EnableDmaChannel(...)
251
* @param[in] chann: DMA-Kanal, eine der dma_channel_id_t-Konstanten
252
* @param[in] channprio: Priorität des Kanals; eine der dma_priority_t-Konstanten
253
* @param[in] trigact: Auswahl, was getriggert wird; eine der dma_trigact_t-Konstanten 
254
* @param[in] trigsrc: Auswahl der Hardware- / Peripherie-Triggerquellen
255
* @param[in] evact: Ausahl der Event-Trigger-Aktion; eine der dma_eventact_t-Konstanten */
256
void SetupDmaChannel(const dma_channel_id_t chann, const dma_priority_t channprio, const dma_trigact_t trigact,
257
           const dma_trigsource_t trigsrc, const dma_eventact_t evact);
258
259
/** @brief initialisiert die DMA mit den grundlegenden Einstellungen und enabled sie 
260
* Hinweis:
261
* - Zur vollen Funktionsfähigkeit muss danach noch ein/die Kanäle konfiguriert werden:
262
* -> SetupDmaChannel() + n x AddDmaDescriptor() + ?config? + EnableDmaChannel() */
263
void SetupDma(void);
264
/******************************************************************************/
265
/******************************************************************************/
266
/**@}*/
267
#endif /* HAL_DMA_H_ */