Skip to content

Commit 2789053

Browse files
committed
DM: in progress i2s / dma support
1 parent 01232bf commit 2789053

File tree

5 files changed

+417
-10
lines changed

5 files changed

+417
-10
lines changed

libraries/I2S/src/I2S.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,21 @@
2020
#include <wiring_private.h>
2121

2222
#include "utility/DMA.h"
23+
24+
#if defined(__SAMD51__)
25+
26+
#include "utility/SAMD51_I2SDevice.h"
27+
28+
static I2SDevice_SAMD51 i2sd(*I2S);
29+
30+
#else
31+
2332
#include "utility/SAMD21_I2SDevice.h"
2433

2534
static I2SDevice_SAMD21G18x i2sd(*I2S);
2635

36+
#endif
37+
2738
#include "I2S.h"
2839

2940
int I2SClass::_beginCount = 0;
@@ -98,7 +109,11 @@ int I2SClass::begin(int mode, long sampleRate, int bitsPerSample, bool driveCloc
98109

99110
if (_beginCount == 0) {
100111
// enable the I2S interface
112+
#if defined(__SAMD51__)
113+
MCLK->APBDMASK.reg |= MCLK_APBDMASK_I2S;
114+
#else
101115
PM->APBCMASK.reg |= PM_APBCMASK_I2S;
116+
#endif
102117

103118
// reset the device
104119
i2sd.reset();
@@ -176,7 +191,11 @@ void I2SClass::end()
176191
i2sd.disable();
177192

178193
// disable the I2S interface
194+
#if defined(__SAMD51__)
195+
MCLK->APBDMASK.reg &= ~(MCLK_APBDMASK_I2S);
196+
#else
179197
PM->APBCMASK.reg &= ~PM_APBCMASK_I2S;
198+
#endif
180199
}
181200
}
182201

@@ -398,6 +417,13 @@ void I2SClass::onReceive(void(*function)(void))
398417

399418
void I2SClass::enableClock(int divider)
400419
{
420+
421+
#if defined(__SAMD51__)
422+
if(_deviceIndex == 0)
423+
GCLK->PCHCTRL[I2S_GCLK_ID_0].reg = GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //48 MHz for now (max is 100)
424+
else
425+
GCLK->PCHCTRL[I2S_GCLK_ID_1].reg = GCLK_PCHCTRL_GEN_GCLK2_Val | (1 << GCLK_PCHCTRL_CHEN_Pos); //48 MHz for now (max is 100)
426+
#else
401427
// configure the clock divider
402428
while (GCLK->STATUS.bit.SYNCBUSY);
403429
GCLK->GENDIV.bit.ID = _clockGenerator;
@@ -417,10 +443,17 @@ void I2SClass::enableClock(int divider)
417443
GCLK->CLKCTRL.bit.CLKEN = 1;
418444

419445
while (GCLK->STATUS.bit.SYNCBUSY);
446+
#endif
420447
}
421448

422449
void I2SClass::disableClock()
423450
{
451+
#if defined(__SAMD51__)
452+
if(_deviceIndex == 0)
453+
GCLK->PCHCTRL[I2S_GCLK_ID_0].bit.CHEN = 0;
454+
else
455+
GCLK->PCHCTRL[I2S_GCLK_ID_1].bit.CHEN = 0;
456+
#else
424457
while (GCLK->STATUS.bit.SYNCBUSY);
425458
GCLK->GENCTRL.bit.ID = _clockGenerator;
426459
GCLK->GENCTRL.bit.SRC = GCLK_GENCTRL_SRC_DFLL48M_Val;
@@ -433,6 +466,7 @@ void I2SClass::disableClock()
433466
GCLK->CLKCTRL.bit.CLKEN = 0;
434467

435468
while (GCLK->STATUS.bit.SYNCBUSY);
469+
#endif
436470
}
437471

438472
void I2SClass::enableTransmitter()

libraries/I2S/src/utility/DMA.cpp

Lines changed: 147 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,14 @@ DMAClass::~DMAClass()
3939
void DMAClass::begin()
4040
{
4141
if (_beginCount == 0) {
42+
43+
#if defined(__SAMD51__)
44+
MCLK->AHBMASK.bit.DMAC_ = 1;
45+
#else
4246
// enable the DMA interface
4347
PM->AHBMASK.bit.DMAC_ = 1;
4448
PM->APBBMASK.bit.DMAC_ = 1;
49+
#endif
4550

4651
// perform a reset
4752
DMAC->CTRL.bit.SWRST = 1;
@@ -57,9 +62,35 @@ void DMAClass::begin()
5762
DMAC->CTRL.bit.LVLEN3 = 1;
5863
DMAC->CTRL.bit.DMAENABLE = 1;
5964

60-
// enable the interrupt at lowest priority
65+
#if defined(__SAMD51__)
66+
NVIC_DisableIRQ(DMAC_0_IRQn);
67+
NVIC_ClearPendingIRQ(DMAC_0_IRQn);
68+
NVIC_EnableIRQ(DMAC_0_IRQn);
69+
NVIC_SetPriority(DMAC_0_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
70+
71+
NVIC_DisableIRQ(DMAC_1_IRQn);
72+
NVIC_ClearPendingIRQ(DMAC_1_IRQn);
73+
NVIC_EnableIRQ(DMAC_1_IRQn);
74+
NVIC_SetPriority(DMAC_1_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
75+
76+
NVIC_DisableIRQ(DMAC_2_IRQn);
77+
NVIC_ClearPendingIRQ(DMAC_2_IRQn);
78+
NVIC_EnableIRQ(DMAC_2_IRQn);
79+
NVIC_SetPriority(DMAC_2_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
80+
81+
NVIC_DisableIRQ(DMAC_3_IRQn);
82+
NVIC_ClearPendingIRQ(DMAC_3_IRQn);
83+
NVIC_EnableIRQ(DMAC_3_IRQn);
84+
NVIC_SetPriority(DMAC_3_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
85+
86+
NVIC_DisableIRQ(DMAC_4_IRQn);
87+
NVIC_ClearPendingIRQ(DMAC_4_IRQn);
88+
NVIC_EnableIRQ(DMAC_4_IRQn);
89+
NVIC_SetPriority(DMAC_4_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
90+
#else
6191
NVIC_EnableIRQ(DMAC_IRQn);
6292
NVIC_SetPriority(DMAC_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
93+
#endif
6394
}
6495

6596
_beginCount++;
@@ -71,14 +102,27 @@ void DMAClass::end()
71102

72103
if (_beginCount == 0) {
73104
// disable the interrupt
105+
#if defined(__SAMD51__)
106+
NVIC_DisableIRQ(DMAC_0_IRQn);
107+
NVIC_DisableIRQ(DMAC_1_IRQn);
108+
NVIC_DisableIRQ(DMAC_2_IRQn);
109+
NVIC_DisableIRQ(DMAC_3_IRQn);
110+
NVIC_DisableIRQ(DMAC_4_IRQn);
111+
#else
74112
NVIC_DisableIRQ(DMAC_IRQn);
113+
#endif
75114

76115
// disable
77116
DMAC->CTRL.bit.DMAENABLE = 0;
78117

79118
// disable the DMA interface
80-
PM->APBBMASK.bit.DMAC_ = 0;
119+
#if defined(__SAMD51__)
120+
MCLK->AHBMASK.bit.DMAC_ = 0;
121+
#else
122+
// enable the DMA interface
81123
PM->AHBMASK.bit.DMAC_ = 0;
124+
PM->APBBMASK.bit.DMAC_ = 0;
125+
#endif
82126
}
83127
}
84128

@@ -96,9 +140,14 @@ int DMAClass::allocateChannel()
96140
memset((void*)&_descriptors[i], 0x00, sizeof(_descriptors[i]));
97141

98142
// select the channel and reset it
143+
#if defined(__SAMD51__)
144+
DMAC->Channel[i].CHCTRLA.bit.ENABLE = 0;
145+
DMAC->Channel[i].CHCTRLA.bit.SWRST = 1;
146+
#else
99147
DMAC->CHID.bit.ID = i;
100148
DMAC->CHCTRLA.bit.ENABLE = 0;
101149
DMAC->CHCTRLA.bit.SWRST = 1;
150+
#endif
102151

103152
channel = i;
104153
break;
@@ -111,21 +160,34 @@ int DMAClass::allocateChannel()
111160
void DMAClass::freeChannel(int channel)
112161
{
113162
// select the channel and disable it
114-
DMAC->CHID.bit.ID = channel;
115-
DMAC->CHCTRLA.bit.ENABLE = 0;
163+
#if defined(__SAMD51__)
164+
DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 0;
165+
#else
166+
DMAC->CHID.bit.ID = channel;
167+
DMAC->CHCTRLA.bit.ENABLE = 0;
168+
#endif
116169

117170
_channelMask &= ~(1 << channel);
118171
}
119172

120173
void DMAClass::setPriorityLevel(int channel, int level)
121174
{
122175
// select the channel and set priority level
123-
DMAC->CHID.bit.ID = channel;
124-
DMAC->CHCTRLB.bit.LVL = level;
176+
#if defined(__SAMD51__)
177+
178+
DMAC->Channel[channel].CHPRILVL.reg = level;
179+
#else
180+
DMAC->CHID.bit.ID = channel;
181+
DMAC->CHCTRLB.bit.LVL = level;
182+
#endif
125183
}
126184

127185
void DMAClass::setTriggerSource(int channel, int source)
128186
{
187+
#if defined(__SAMD51__)
188+
DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC = source;
189+
DMAC->Channel[channel].CHCTRLA.bit.TRIGACT = DMAC_CHCTRLA_TRIGACT_BLOCK_Val;
190+
#else
129191
// select the channel and set a trigger source
130192
DMAC->CHID.bit.ID = channel;
131193
DMAC->CHCTRLB.bit.TRIGSRC = source;
@@ -136,6 +198,7 @@ void DMAClass::setTriggerSource(int channel, int source)
136198
} else {
137199
DMAC->CHCTRLB.bit.TRIGACT = DMAC_CHCTRLB_TRIGACT_BLOCK_Val;
138200
}
201+
#endif
139202
}
140203

141204
void DMAClass::setTransferWidth(int channel, int transferWidth)
@@ -178,8 +241,11 @@ int DMAClass::transfer(int channel, void* src, void* dst, uint16_t size)
178241
return 1;
179242
}
180243

244+
245+
#if !defined(__SAMD51__)
181246
// select the channel
182247
DMAC->CHID.bit.ID = channel;
248+
#endif
183249

184250
// disable event output generation and block actions
185251
_descriptors[channel].BTCTRL.bit.EVOSEL = DMAC_BTCTRL_EVOSEL_DISABLE_Val;
@@ -223,16 +289,26 @@ int DMAClass::transfer(int channel, void* src, void* dst, uint16_t size)
223289
// validate the descriptor
224290
_descriptors[channel].BTCTRL.bit.VALID = 1;
225291

292+
#if defined(__SAMD51__)
293+
DMAC->Channel[channel].CHINTENSET.bit.TERR = 1;
294+
DMAC->Channel[channel].CHINTENSET.bit.TCMPL = 1;
295+
DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 1;
296+
297+
if (DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC == 0) {
298+
// uses software trigger, so trigger it
299+
DMAC->SWTRIGCTRL.reg |= (1 << channel);
300+
}
301+
#else
226302
// enable channel and transfer error + complete interrupts
227303
DMAC->CHINTENSET.bit.TERR = 1;
228304
DMAC->CHINTENSET.bit.TCMPL = 1;
229305
DMAC->CHCTRLA.bit.ENABLE = 1;
230306

231-
232307
if (DMAC->CHCTRLB.bit.TRIGSRC == 0) {
233308
// uses software trigger, so trigger it
234309
DMAC->SWTRIGCTRL.reg |= (1 << channel);
235310
}
311+
#endif
236312

237313
return 0;
238314
}
@@ -251,11 +327,32 @@ void DMAClass::onService()
251327
{
252328
// get the channel and select it
253329
int channel = DMAC->INTPEND.bit.ID;
330+
#if !defined(__SAMD51__)
254331
DMAC->CHID.bit.ID = channel;
332+
#endif
255333

256334
// invalidate the channel
257335
_descriptors[channel].BTCTRL.bit.VALID = 0;
258336

337+
#if defined(__SAMD51__)
338+
if (DMAC->Channel[channel].CHINTFLAG.bit.TERR) {
339+
// clear the error interrupt and call the error callback if there is one
340+
DMAC->Channel[channel].CHINTFLAG.bit.TERR = 1;
341+
342+
if (_transferErrorCallbacks[channel]) {
343+
_transferErrorCallbacks[channel](channel);
344+
}
345+
}
346+
347+
if (DMAC->Channel[channel].CHINTFLAG.bit.TCMPL) {
348+
// clear the complete interrupt and call the callback if there is one
349+
DMAC->Channel[channel].CHINTFLAG.bit.TCMPL = 1;
350+
351+
if (_transferCompleteCallbacks[channel]) {
352+
_transferCompleteCallbacks[channel](channel);
353+
}
354+
}
355+
#else
259356
if (DMAC->CHINTFLAG.bit.TERR) {
260357
// clear the error interrupt and call the error callback if there is one
261358
DMAC->CHINTFLAG.bit.TERR = 1;
@@ -273,12 +370,55 @@ void DMAClass::onService()
273370
_transferCompleteCallbacks[channel](channel);
274371
}
275372
}
373+
#endif
276374
}
277375

278376
extern "C" {
377+
#if defined(__SAMD51__)
378+
static void _dmac_handler(void)
379+
{
380+
DMA.onService();
381+
}
382+
/**
383+
* \brief DMAC interrupt handler
384+
*/
385+
void DMAC_0_Handler(void)
386+
{
387+
_dmac_handler();
388+
}
389+
/**
390+
* \brief DMAC interrupt handler
391+
*/
392+
void DMAC_1_Handler(void)
393+
{
394+
_dmac_handler();
395+
}
396+
/**
397+
* \brief DMAC interrupt handler
398+
*/
399+
void DMAC_2_Handler(void)
400+
{
401+
_dmac_handler();
402+
}
403+
/**
404+
* \brief DMAC interrupt handler
405+
*/
406+
void DMAC_3_Handler(void)
407+
{
408+
_dmac_handler();
409+
}
410+
/**
411+
* \brief DMAC interrupt handler
412+
*/
413+
void DMAC_4_Handler(void)
414+
{
415+
_dmac_handler();
416+
}
417+
#else
279418
void DMAC_Handler() {
280419
DMA.onService();
281420
}
421+
#endif
282422
}
283423

284424
DMAClass DMA;

libraries/I2S/src/utility/DMA.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
*/
1818
#pragma once
1919

20+
#if defined(__SAMD51__)
21+
#define NUM_DMA_CHANNELS 4
22+
#else
2023
#define NUM_DMA_CHANNELS 1
24+
#endif
2125

2226
/*
2327
WARNING: The API for this class may change and it's not intended for public use!

0 commit comments

Comments
 (0)