Skip to content

Commit

Permalink
Merge pull request #9385 from Bruin-Spacecraft-Group/main
Browse files Browse the repository at this point in the history
SAMD51 SPI Secondary Mode
  • Loading branch information
tannewt authored Feb 14, 2025
2 parents e5e7c9e + 3b0b4d3 commit 886d225
Show file tree
Hide file tree
Showing 34 changed files with 632 additions and 47 deletions.
1 change: 1 addition & 0 deletions docs/porting.rst
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ as a natural "TODO" list. An example minimal build list is shown below:
CIRCUITPY_FRAMEBUFFERIO = 0
CIRCUITPY_FREQUENCYIO = 0
CIRCUITPY_I2CTARGET = 0
CIRCUITPY_SPITARGET = 0
# Requires SPI, PulseIO (stub ok):
CIRCUITPY_DISPLAYIO = 0
Expand Down
16 changes: 12 additions & 4 deletions locale/circuitpython.pot
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,10 @@ msgstr ""
msgid "Array values should be single bytes."
msgstr ""

#: ports/atmel-samd/common-hal/spitarget/SPITarget.c
msgid "Async SPI transfer in progress on this bus, keep awaiting."
msgstr ""

#: shared-module/memorymonitor/AllocationAlarm.c
#, c-format
msgid "Attempt to allocate %d blocks"
Expand Down Expand Up @@ -1725,6 +1729,10 @@ msgstr ""
msgid "PWM slice channel A already in use"
msgstr ""

#: shared-bindings/spitarget/SPITarget.c
msgid "Packet buffers for an SPI transfer must have the same length."
msgstr ""

#: shared-module/jpegio/JpegDecoder.c
msgid "Parameter error"
msgstr ""
Expand Down Expand Up @@ -2017,8 +2025,8 @@ msgstr ""
msgid "The length of rgb_pins must be 6, 12, 18, 24, or 30"
msgstr ""

#: shared-module/audiodelays/Echo.c shared-module/audiofilters/Filter.c
#: shared-module/audiomixer/MixerVoice.c
#: shared-module/audiodelays/Echo.c shared-module/audiofilters/Distortion.c
#: shared-module/audiofilters/Filter.c shared-module/audiomixer/MixerVoice.c
msgid "The sample's %q does not match"
msgstr ""

Expand Down Expand Up @@ -2570,8 +2578,8 @@ msgstr ""
msgid "bits must be 32 or less"
msgstr ""

#: shared-bindings/audiodelays/Echo.c shared-bindings/audiofilters/Filter.c
#: shared-bindings/audiomixer/Mixer.c
#: shared-bindings/audiodelays/Echo.c shared-bindings/audiofilters/Distortion.c
#: shared-bindings/audiofilters/Filter.c shared-bindings/audiomixer/Mixer.c
msgid "bits_per_sample must be 8 or 16"
msgstr ""

Expand Down
25 changes: 2 additions & 23 deletions ports/atmel-samd/audio_dma.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,6 @@ static audio_dma_t *audio_dma_state[AUDIO_DMA_CHANNEL_COUNT];
// This cannot be in audio_dma_state because it's volatile.
static volatile bool audio_dma_pending[AUDIO_DMA_CHANNEL_COUNT];

static bool audio_dma_allocated[AUDIO_DMA_CHANNEL_COUNT];

uint8_t find_sync_event_channel_raise() {
uint8_t event_channel = find_sync_event_channel();
if (event_channel >= EVSYS_SYNCH_NUM) {
Expand All @@ -40,24 +38,6 @@ uint8_t find_sync_event_channel_raise() {
return event_channel;
}

uint8_t dma_allocate_channel(void) {
uint8_t channel;
for (channel = 0; channel < AUDIO_DMA_CHANNEL_COUNT; channel++) {
if (!audio_dma_allocated[channel]) {
audio_dma_allocated[channel] = true;
return channel;
}
}
return channel; // i.e., return failure
}

void dma_free_channel(uint8_t channel) {
assert(channel < AUDIO_DMA_CHANNEL_COUNT);
assert(audio_dma_allocated[channel]);
audio_dma_disable_channel(channel);
audio_dma_allocated[channel] = false;
}

void audio_dma_disable_channel(uint8_t channel) {
if (channel >= AUDIO_DMA_CHANNEL_COUNT) {
return;
Expand Down Expand Up @@ -191,7 +171,7 @@ audio_dma_result audio_dma_setup_playback(audio_dma_t *dma,
bool output_signed,
uint32_t output_register_address,
uint8_t dma_trigger_source) {
uint8_t dma_channel = dma_allocate_channel();
uint8_t dma_channel = dma_allocate_channel(true);
if (dma_channel >= AUDIO_DMA_CHANNEL_COUNT) {
return AUDIO_DMA_DMA_BUSY;
}
Expand Down Expand Up @@ -342,8 +322,7 @@ void audio_dma_reset(void) {
for (uint8_t i = 0; i < AUDIO_DMA_CHANNEL_COUNT; i++) {
audio_dma_state[i] = NULL;
audio_dma_pending[i] = false;
audio_dma_allocated[i] = false;
audio_dma_disable_channel(i);
dma_free_channel(i);
dma_descriptor(i)->BTCTRL.bit.VALID = false;
MP_STATE_PORT(playing_audio)[i] = NULL;
}
Expand Down
3 changes: 0 additions & 3 deletions ports/atmel-samd/audio_dma.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ typedef enum {
void audio_dma_init(audio_dma_t *dma);
void audio_dma_reset(void);

uint8_t dma_allocate_channel(void);
void dma_free_channel(uint8_t channel);

// This sets everything up but doesn't start the timer.
// Sample is the python object for the sample to play.
// loop is true if we should loop the sample.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ LONGINT_IMPL = MPZ

CIRCUITPY_PS2IO = 1
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_SYNTHIO = 0
1 change: 1 addition & 0 deletions ports/atmel-samd/boards/datalore_ip_m4/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ EXTERNAL_FLASH_DEVICES = "GD25Q16C, W25Q16JVxQ, W25Q16JVxM"
LONGINT_IMPL = MPZ
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
1 change: 1 addition & 0 deletions ports/atmel-samd/boards/pybadge/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ CIRCUITPY_I2CDISPLAYBUS = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_KEYPAD = 1
CIRCUITPY_PARALLELDISPLAYBUS= 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_STAGE = 1

FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pybadge
1 change: 1 addition & 0 deletions ports/atmel-samd/boards/pygamer/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ CIRCUITPY_I2CDISPLAYBUS = 0
CIRCUITPY_JPEGIO = 0
CIRCUITPY_KEYPAD = 1
CIRCUITPY_PARALLELDISPLAYBUS= 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_STAGE = 1

FROZEN_MPY_DIRS += $(TOP)/frozen/circuitpython-stage/pygamer
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ EXTERNAL_FLASH_DEVICES = GD25Q16C
LONGINT_IMPL = MPZ

CIRCUITPY_JPEGIO = 0
CIRCUITPY_SPITARGET = 0
CIRCUITPY_SYNTHIO = 0
1 change: 1 addition & 0 deletions ports/atmel-samd/boards/uartlogger2/mpconfigboard.mk
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ CHIP_FAMILY = samd51
QSPI_FLASH_FILESYSTEM = 1
EXTERNAL_FLASH_DEVICES = "W25Q32JVxQ"
LONGINT_IMPL = MPZ
CIRCUITPY_SPITARGET = 0
CIRCUITPY_SYNTHIO = 0
CIRCUITPY_JPEGIO = 0
2 changes: 1 addition & 1 deletion ports/atmel-samd/common-hal/audiobusio/PDMIn.c
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,7 @@ static uint16_t filter_sample(uint32_t pdm_samples[4]) {
// output_buffer_length is the number of slots, not the number of bytes.
uint32_t common_hal_audiobusio_pdmin_record_to_buffer(audiobusio_pdmin_obj_t *self,
uint16_t *output_buffer, uint32_t output_buffer_length) {
uint8_t dma_channel = dma_allocate_channel();
uint8_t dma_channel = dma_allocate_channel(true);
pdmin_event_channel = find_sync_event_channel_raise();
pdmin_dma_block_done = false;

Expand Down
29 changes: 16 additions & 13 deletions ports/atmel-samd/common-hal/busio/SPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@

#include "hal/include/hal_gpio.h"
#include "hal/include/hal_spi_m_sync.h"
#include "hal/include/hpl_spi_m_sync.h"

#include "samd/dma.h"
#include "samd/sercom.h"

void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux);

void common_hal_busio_spi_construct(busio_spi_obj_t *self,
const mcu_pin_obj_t *clock, const mcu_pin_obj_t *mosi,
const mcu_pin_obj_t *miso, bool half_duplex) {
Expand Down Expand Up @@ -76,6 +77,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (!samd_peripherals_valid_spi_clock_pad(clock_pad)) {
continue;
}
// find mosi_pad first, since it corresponds to dopo which takes limited values
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
if (!mosi_none) {
if (sercom_index == mosi->sercom[j].index) {
Expand Down Expand Up @@ -125,6 +127,8 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,

// Pads must be set after spi_m_sync_init(), which uses default values from
// the prototypical SERCOM.

hri_sercomspi_write_CTRLA_MODE_bf(sercom, 3);
hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo);
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad);

Expand All @@ -137,30 +141,21 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
mp_raise_OSError(MP_EIO);
}

gpio_set_pin_direction(clock->number, GPIO_DIRECTION_OUT);
gpio_set_pin_pull_mode(clock->number, GPIO_PULL_OFF);
gpio_set_pin_function(clock->number, clock_pinmux);
claim_pin(clock);
setup_pin(clock, clock_pinmux);
self->clock_pin = clock->number;

if (mosi_none) {
self->MOSI_pin = NO_PIN;
} else {
gpio_set_pin_direction(mosi->number, GPIO_DIRECTION_OUT);
gpio_set_pin_pull_mode(mosi->number, GPIO_PULL_OFF);
gpio_set_pin_function(mosi->number, mosi_pinmux);
setup_pin(mosi, mosi_pinmux);
self->MOSI_pin = mosi->number;
claim_pin(mosi);
}

if (miso_none) {
self->MISO_pin = NO_PIN;
} else {
gpio_set_pin_direction(miso->number, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(miso->number, GPIO_PULL_OFF);
gpio_set_pin_function(miso->number, miso_pinmux);
setup_pin(miso, miso_pinmux);
self->MISO_pin = miso->number;
claim_pin(miso);
}

spi_m_sync_enable(&self->spi_desc);
Expand Down Expand Up @@ -322,3 +317,11 @@ uint8_t common_hal_busio_spi_get_polarity(busio_spi_obj_t *self) {
void *hw = self->spi_desc.dev.prvt;
return hri_sercomspi_get_CTRLA_CPOL_bit(hw);
}

void setup_pin(const mcu_pin_obj_t *pin, uint32_t pinmux) {
gpio_set_pin_direction(pin->number, GPIO_DIRECTION_OUT);
gpio_set_pin_pull_mode(pin->number, GPIO_PULL_OFF);
gpio_set_pin_function(pin->number, pinmux);
claim_pin(pin);
hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(pin->number), GPIO_PIN(pin->number));
}
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ void common_hal_imagecapture_parallelimagecapture_singleshot_capture(imagecaptur
mp_buffer_info_t bufinfo;
mp_get_buffer_raise(buffer, &bufinfo, MP_BUFFER_RW);

uint8_t dma_channel = dma_allocate_channel();
uint8_t dma_channel = dma_allocate_channel(true);

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

0 comments on commit 886d225

Please sign in to comment.