Skip to content

Commit 3d94daa

Browse files
authored
Merge pull request #10668 from dhalbert/spi-dma-fix
Fix SPI DMA on SAMD
2 parents 0d88686 + c8377c7 commit 3d94daa

File tree

7 files changed

+34
-30
lines changed

7 files changed

+34
-30
lines changed

ports/atmel-samd/audio_dma.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ uint8_t find_sync_event_channel_raise(void) {
3939
}
4040

4141
void audio_dma_disable_channel(uint8_t channel) {
42-
if (channel >= AUDIO_DMA_CHANNEL_COUNT) {
42+
if (channel == NO_DMA_CHANNEL) {
4343
return;
4444
}
4545
dma_disable_channel(channel);
4646
}
4747

4848
void audio_dma_enable_channel(uint8_t channel) {
49-
if (channel >= AUDIO_DMA_CHANNEL_COUNT) {
49+
if (channel == NO_DMA_CHANNEL) {
5050
return;
5151
}
5252
dma_enable_channel(channel);
@@ -171,8 +171,8 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
171171
bool output_signed,
172172
uint32_t output_register_address,
173173
uint8_t dma_trigger_source) {
174-
uint8_t dma_channel = dma_allocate_channel(true);
175-
if (dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
174+
uint8_t dma_channel = dma_allocate_audio_channel();
175+
if (dma_channel == NO_DMA_CHANNEL) {
176176
return AUDIO_DMA_DMA_BUSY;
177177
}
178178

@@ -298,14 +298,14 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
298298

299299
void audio_dma_stop(audio_dma_t *dma) {
300300
uint8_t channel = dma->dma_channel;
301-
if (channel < AUDIO_DMA_CHANNEL_COUNT) {
301+
if (channel != NO_DMA_CHANNEL) {
302302
audio_dma_disable_channel(channel);
303303
disable_event_channel(dma->event_channel);
304304
MP_STATE_PORT(playing_audio)[channel] = NULL;
305305
audio_dma_state[channel] = NULL;
306306
dma_free_channel(dma->dma_channel);
307307
}
308-
dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT;
308+
dma->dma_channel = NO_DMA_CHANNEL;
309309
dma->playing_in_progress = false;
310310
}
311311

@@ -318,7 +318,7 @@ void audio_dma_resume(audio_dma_t *dma) {
318318
}
319319

320320
bool audio_dma_get_paused(audio_dma_t *dma) {
321-
if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
321+
if (dma->dma_channel == NO_DMA_CHANNEL) {
322322
return false;
323323
}
324324
uint32_t status = dma_transfer_status(dma->dma_channel);
@@ -327,7 +327,7 @@ bool audio_dma_get_paused(audio_dma_t *dma) {
327327
}
328328

329329
void audio_dma_init(audio_dma_t *dma) {
330-
dma->dma_channel = AUDIO_DMA_CHANNEL_COUNT;
330+
dma->dma_channel = NO_DMA_CHANNEL;
331331
}
332332

333333
void audio_dma_reset(void) {
@@ -341,7 +341,7 @@ void audio_dma_reset(void) {
341341
}
342342

343343
bool audio_dma_get_playing(audio_dma_t *dma) {
344-
if (dma->dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
344+
if (dma->dma_channel == NO_DMA_CHANNEL) {
345345
return false;
346346
}
347347
return dma->playing_in_progress;

ports/atmel-samd/common-hal/audiobusio/PDMIn.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) {
364364
// output_buffer_length is the number of slots, not the number of bytes.
365365
uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self,
366366
uint16_t *output_buffer, uint32_t output_buffer_length) {
367-
uint8_t dma_channel = dma_allocate_channel(true);
367+
uint8_t dma_channel = dma_allocate_audio_channel();
368368
pdmin_event_channel = find_sync_event_channel_raise();
369369
pdmin_dma_block_done = false;
370370

ports/atmel-samd/common-hal/busio/SPI.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,17 @@
2121
#include "samd/dma.h"
2222
#include "samd/sercom.h"
2323

24-
void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux);
24+
25+
static void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux, const enum gpio_direction direction) {
26+
gpio_set_pin_direction(pin->number, direction);
27+
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF);
28+
gpio_set_pin_function(pin->number, pinmux);
29+
if (direction == GPIO_DIRECTION_OUT) {
30+
// Use strong drive strength for SPI outputs.
31+
hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number));
32+
}
33+
claim_pin(pin);
34+
}
2535

2636
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
2737
const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi,
@@ -128,6 +138,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
128138
// Pads must be set after spi_m_sync_init(), which uses default values from
129139
// the prototypical SERCOM.
130140

141+
// Set to SPI host mode and choose pads.
131142
hri_sercomspi_write_CTRLA_MODE_bf(sercom, 3);
132143
hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo);
133144
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad);
@@ -141,20 +152,20 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
141152
mp_raise_OSError(MP_EIO);
142153
}
143154

144-
setup_pin(clock, clock_pinmux);
155+
setup_pin(clock, clock_pinmux, GPIO_DIRECTION_OUT);
145156
self->clock_pin = clock->number;
146157

147158
if (mosi_none) {
148159
self->MOSI_pin = NO_PIN;
149160
} else {
150-
setup_pin(mosi, mosi_pinmux);
161+
setup_pin(mosi, mosi_pinmux, GPIO_DIRECTION_OUT);
151162
self->MOSI_pin = mosi->number;
152163
}
153164

154165
if (miso_none) {
155166
self->MISO_pin = NO_PIN;
156167
} else {
157-
setup_pin(miso, miso_pinmux);
168+
setup_pin(miso, miso_pinmux, GPIO_DIRECTION_IN);
158169
self->MISO_pin = miso->number;
159170
}
160171

@@ -317,11 +328,3 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) {
317328
void *hw = self->spi_desc.dev.prvt;
318329
return hri_sercomspi_get_CTRLA_CPOL_bit(hw);
319330
}
320-
321-
void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux) {
322-
gpio_set_pin_direction(pin->number, GPIO_DIRECTION_OUT);
323-
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF);
324-
gpio_set_pin_function(pin->number, pinmux);
325-
claim_pin(pin);
326-
hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number));
327-
}

ports/atmel-samd/common-hal/imagecapture/ParallelImageCapture.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,8 @@ void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecaptur
135135
mp_buffer_info_t bufinfo;
136136
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW);
137137

138-
uint8_t dma_channel = dma_allocate_channel(true);
138+
// Allocate a permanent channel (not really audio).
139+
uint8_t dma_channel = dma_allocate_audio_channel();
139140

140141
uint32_t *dest = bufinfo.buf;
141142
size_t count = bufinfo.len / 4; // PCC receives 4 bytes (2 pixels) at a time

ports/atmel-samd/common-hal/spitarget/SPITarget.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,15 +192,15 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t *
192192
self->miso_packet = miso_packet;
193193

194194
Sercom *sercom = self->spi_desc.dev.prvt;
195-
self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
195+
shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
196196

197197
// There is an issue where if an unexpected SPI transfer is received before the user calls "end" for the in-progress, expected
198198
// transfer, the SERCOM has an error and gets confused. This can be detected from INTFLAG.ERROR. I think the code in
199199
// ports/atmel-samd/peripherals/samd/dma.c at line 277 (as of this commit; it's the part that reads s->SPI.INTFLAG.bit.RXC and
200200
// s->SPI.DATA.reg) is supposed to fix this, but experimentation seems to show that it does not in fact fix anything. Anyways, if
201201
// the ERROR bit is set, let's just reset the peripheral and then setup the transfer again -- that seems to work.
202202
if (hri_sercomspi_get_INTFLAG_ERROR_bit(sercom)) {
203-
shared_dma_transfer_close(self->running_dma);
203+
shared_dma_transfer_close(&self->running_dma);
204204

205205
// disable the sercom
206206
spi_m_sync_disable(&self->spi_desc);
@@ -223,19 +223,19 @@ void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t *
223223
spi_m_sync_enable(&self->spi_desc);
224224
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
225225

226-
self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
226+
shared_dma_transfer_start(&self->running_dma, sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
227227
}
228228
}
229229

230230
bool common_hal_spitarget_spi_target_transfer_is_finished(spitarget_spi_target_obj_t *self) {
231-
return self->running_dma.failure == 1 || shared_dma_transfer_finished(self->running_dma);
231+
return self->running_dma.failure == 1 || shared_dma_transfer_finished(&self->running_dma);
232232
}
233233

234234
int common_hal_spitarget_spi_target_transfer_close(spitarget_spi_target_obj_t *self) {
235235
if (self->running_dma.failure == 1) {
236236
return 0;
237237
}
238-
int res = shared_dma_transfer_close(self->running_dma);
238+
int res = shared_dma_transfer_close(&self->running_dma);
239239
self->running_dma.failure = 1;
240240

241241
self->mosi_packet = NULL;

ports/atmel-samd/common-hal/spitarget/SPITarget.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ typedef struct {
1818
uint8_t *mosi_packet;
1919
const uint8_t *miso_packet;
2020

21-
dma_descr_t running_dma;
21+
dma_transfer_t running_dma;
2222
} spitarget_spi_target_obj_t;
2323

2424
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H

0 commit comments

Comments
 (0)