@@ -110,7 +110,6 @@ static int32_t shared_dma_transfer(void* peripheral,
110
110
} else {
111
111
#endif
112
112
113
- // sercom index is incorrect for SAMD51
114
113
dma_configure (SHARED_TX_CHANNEL , sercom_index (peripheral ) * 2 + FIRST_SERCOM_TX_TRIGSRC , false);
115
114
tx_active = true;
116
115
if (buffer_in != NULL ) {
@@ -155,8 +154,6 @@ static int32_t shared_dma_transfer(void* peripheral,
155
154
if (sercom ) {
156
155
SercomSpi * s = & ((Sercom * ) peripheral )-> SPI ;
157
156
s -> INTFLAG .reg = SERCOM_SPI_INTFLAG_RXC | SERCOM_SPI_INTFLAG_DRE ;
158
- } else {
159
- //QSPI->INTFLAG.reg = QSPI_INTFLAG_RXC | QSPI_INTFLAG_DRE;
160
157
}
161
158
// Start the RX job first so we don't miss the first byte. The TX job clocks
162
159
// the output.
@@ -168,23 +165,41 @@ static int32_t shared_dma_transfer(void* peripheral,
168
165
}
169
166
170
167
171
- if (sercom ) {
172
- //DMAC->SWTRIGCTRL.reg |= (1 << SHARED_TX_CHANNEL);
173
- } else {
174
- // Do a manual copy to trigger then DMA. We do 32-bit accesses to match the DMA.
175
- #pragma GCC diagnostic push
176
- #pragma GCC diagnostic ignored "-Wcast-align"
168
+ if (!sercom ) {
177
169
if (rx_active ) {
178
- //buffer_in[0] = *src;
179
170
DMAC -> SWTRIGCTRL .reg |= (1 << SHARED_RX_CHANNEL );
180
- } else {
181
- //*(uint32_t*)dest = ((uint32_t*) buffer_out)[0];
182
171
}
183
- #pragma GCC diagnostic pop
184
172
}
185
173
186
- // Channels cycle between Suspend -> Pending -> Busy and back while transfering. So, we check
187
- // the channels transfer status for an error or completion.
174
+ #ifdef SAMD51
175
+ // Sometimes (silicon bug?) this DMA transfer never starts, and another channel sits with
176
+ // CHSTATUS.reg = 0x3 (BUSY | PENDING). On the other hand, this is a
177
+ // legitimate state for a DMA channel to be in (apparently), so we can't use that alone as a check.
178
+ // Instead, let's look at the ACTIVE flag. When DMA is hung, everything in ACTIVE is zeros.
179
+ bool is_okay = false;
180
+ for (int i = 0 ; i < 10 && !is_okay ; i ++ ) {
181
+ bool complete = true;
182
+ if (rx_active ) {
183
+ if (DMAC -> Channel [SHARED_RX_CHANNEL ].CHSTATUS .reg & 0x3 )
184
+ complete = false;
185
+ }
186
+ if (tx_active ) {
187
+ if (DMAC -> Channel [SHARED_TX_CHANNEL ].CHSTATUS .reg & 0x3 )
188
+ complete = false;
189
+ }
190
+ is_okay = is_okay || (DMAC -> ACTIVE .bit .ABUSY || complete );
191
+ }
192
+ if (!is_okay ) {
193
+ for (int i = 0 ; i < AUDIO_DMA_CHANNEL_COUNT ; i ++ ) {
194
+ if (DMAC -> Channel [i ].CHCTRLA .bit .ENABLE ) {
195
+ DMAC -> Channel [i ].CHCTRLA .bit .ENABLE = 0 ;
196
+ DMAC -> Channel [i ].CHCTRLA .bit .ENABLE = 1 ;
197
+ }
198
+ }
199
+ }
200
+ #endif
201
+
202
+ // busy-wait for the RX and TX DMAs to either complete or encounter an error
188
203
if (rx_active ) {
189
204
while ((dma_transfer_status (SHARED_RX_CHANNEL ) & 0x3 ) == 0 ) {}
190
205
}
0 commit comments