merge implementation of new spitarget api

This commit is contained in:
Randall Scharpf 2024-11-13 18:34:10 -08:00
commit 821b7f2cbf
66 changed files with 668 additions and 450 deletions

53
.github/workflows/build-rapid-0.yaml vendored Normal file
View file

@ -0,0 +1,53 @@
name: Build RAPID-0 Boards
on:
push:
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
board: [rapid0_adcs, rapid0_cdh, rapid0_eps]
steps:
- name: Set up repository
uses: actions/checkout@v4
with:
submodules: false
show-progress: false
fetch-depth: 1
- name: Set up python
uses: actions/setup-python@v5
with:
python-version: 3.x
- name: Set up ports
id: set-up-port
uses: ./.github/actions/deps/ports
with:
board: ${{ matrix.board }}
- name: Set up submodules
id: set-up-submodules
uses: ./.github/actions/deps/submodules
with:
action: cache
version: true
- name: Set up external
uses: ./.github/actions/deps/external
with:
action: cache
port: ${{ steps.set-up-port.outputs.port }}
- name: Set up mpy-cross
if: steps.set-up-submodules.outputs.frozen == 'True'
uses: ./.github/actions/mpy_cross
with:
cp-version: ${{ steps.set-up-submodules.outputs.version }}
download: false
- name: Build boards
run: make -j4 -C ports/atmel-samd BOARD=${{ matrix.board }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.board }}
path: ports/atmel-samd/build-${{ matrix.board }}/firmware.*
overwrite: true

18
build-rapid0-mac Executable file
View file

@ -0,0 +1,18 @@
if echo $PATH | grep "gcc-arm-none-eabi" >/dev/null; then
true
else
export PATH=/Volumes/Circuit_Python_Case_Sensitive_Disk/bruinspace-circuitpython/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH
fi
cd ports/atmel-samd
make --debug -j8 BOARD=rapid0_adcs
make --debug -j8 BOARD=rapid0_cdh
make --debug -j8 BOARD=rapid0_eps
cd ../..
echo "Compilation complete! Press ^C to confirm and exit."
while true; do
afplay /System/Library/Sounds/Ping.aiff
sleep 5s
done

17
build-rapid0-ubuntu Normal file
View file

@ -0,0 +1,17 @@
if echo $PATH | grep "gcc-arm-none-eabi" >/dev/null
then
true
else
export PATH=/mnt/d/Files/Documents/School/UCLA/Organizations/BruinSpace/Rapid-CDH/gcc-arm-none-eabi-10-2020-q4-major/bin:$PATH
fi
cd ports/atmel-samd
make --debug -j8 BOARD=rapid0_adcs
make --debug -j8 BOARD=rapid0_cdh
make --debug -j8 BOARD=rapid0_eps
cd ../..
echo "Compilation complete! Press ^C to confirm and exit."
while true;
do
paplay /usr/share/sounds/freedesktop/stereo/complete.oga
sleep 5s
done

View file

@ -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

View file

@ -1055,10 +1055,6 @@ msgstr ""
msgid "Hard fault: memory access or instruction error."
msgstr ""
#: shared-bindings/busio/SPI.c
msgid "Hardware SS pin only supported for slave mode"
msgstr ""
#: ports/mimxrt10xx/common-hal/busio/SPI.c
#: ports/mimxrt10xx/common-hal/busio/UART.c ports/stm/common-hal/busio/I2C.c
#: ports/stm/common-hal/busio/SPI.c ports/stm/common-hal/busio/UART.c
@ -1343,10 +1339,6 @@ msgstr ""
msgid "Must provide MISO or MOSI pin"
msgstr ""
#: shared-bindings/busio/SPI.c
msgid "Must provide SS pin to operate in slave mode"
msgstr ""
#: shared-bindings/rgbmatrix/RGBMatrix.c
#, c-format
msgid "Must use a multiple of 6 rgb pins, not %d"
@ -1891,12 +1883,6 @@ msgstr ""
msgid "Size not supported"
msgstr ""
#: ports/cxd56/common-hal/busio/SPI.c ports/espressif/common-hal/busio/SPI.c
#: ports/mimxrt10xx/common-hal/busio/SPI.c ports/nrf/common-hal/busio/SPI.c
#: ports/raspberrypi/common-hal/busio/SPI.c ports/stm/common-hal/busio/SPI.c
msgid "Slave mode SPI is not implemented"
msgstr ""
#: shared-bindings/alarm/SleepMemory.c shared-bindings/memorymap/AddressRange.c
#: shared-bindings/nvm/ByteArray.c
msgid "Slice and value different lengths."

View file

@ -50,7 +50,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PA01, &pin_PA00, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PA01, &pin_PA00, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -50,7 +50,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA12, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA12, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -59,7 +59,7 @@ uint8_t refresh_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -70,7 +70,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PA23, &pin_PA22, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PA23, &pin_PA22, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -99,7 +99,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PA13, &pin_PA15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -70,7 +70,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -72,7 +72,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PB13, &pin_PB15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -67,7 +67,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_PB20, &pin_PB19, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_PB20, &pin_PB19, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -37,14 +37,13 @@
#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 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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *miso, bool half_duplex) {
Sercom *sercom = NULL;
uint8_t sercom_index;
uint32_t clock_pinmux = 0;
@ -52,7 +51,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
bool miso_none = miso == NULL;
uint32_t mosi_pinmux = 0;
uint32_t miso_pinmux = 0;
uint32_t ss_pinmux = 0;
uint8_t clock_pad = 0;
uint8_t mosi_pad = 0;
uint8_t miso_pad = 0;
@ -97,87 +95,36 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (!samd_peripherals_valid_spi_clock_pad(clock_pad)) {
continue;
}
if (slave_mode) {
// find miso_pad first, since it corresponds to dopo which takes limited values
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
if (!miso_none) {
if (sercom_index == miso->sercom[j].index) {
miso_pinmux = PINMUX(miso->number, (j == 0) ? MUX_C : MUX_D);
miso_pad = miso->sercom[j].pad;
dopo = samd_peripherals_get_spi_dopo(clock_pad, miso_pad);
if (dopo > 0x3) {
continue; // pad combination not possible
}
if (mosi_none) {
for (int m = 0; m < NUM_SERCOMS_PER_PIN; m++) {
if (sercom_index == ss->sercom[m].index) {
ss_pinmux = PINMUX(ss->number, (m == 0) ? MUX_C : MUX_D);
sercom = potential_sercom;
break;
}
}
if (sercom != NULL) {
break;
}
}
} else {
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) {
mosi_pinmux = PINMUX(mosi->number, (j == 0) ? MUX_C : MUX_D);
mosi_pad = mosi->sercom[j].pad;
dopo = samd_peripherals_get_spi_dopo(clock_pad, mosi_pad);
if (dopo > 0x3) {
continue; // pad combination not possible
}
}
if (!mosi_none) {
for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) {
if (sercom_index == mosi->sercom[k].index) {
mosi_pinmux = PINMUX(mosi->number, (k == 0) ? MUX_C : MUX_D);
mosi_pad = mosi->sercom[k].pad;
for (int m = 0; m < NUM_SERCOMS_PER_PIN; m++) {
if (sercom_index == ss->sercom[m].index) {
ss_pinmux = PINMUX(ss->number, (m == 0) ? MUX_C : MUX_D);
sercom = potential_sercom;
break;
}
}
if (sercom != NULL) {
break;
}
}
if (miso_none) {
sercom = potential_sercom;
break;
}
}
if (sercom != NULL) {
break;
} else {
continue;
}
}
} else {
// 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) {
mosi_pinmux = PINMUX(mosi->number, (j == 0) ? MUX_C : MUX_D);
mosi_pad = mosi->sercom[j].pad;
dopo = samd_peripherals_get_spi_dopo(clock_pad, mosi_pad);
if (dopo > 0x3) {
continue; // pad combination not possible
}
if (miso_none) {
sercom = potential_sercom;
break;
}
} else {
continue;
if (!miso_none) {
for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) {
if (sercom_index == miso->sercom[k].index) {
miso_pinmux = PINMUX(miso->number, (k == 0) ? MUX_C : MUX_D);
miso_pad = miso->sercom[k].pad;
sercom = potential_sercom;
break;
}
}
if (!miso_none) {
for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) {
if (sercom_index == miso->sercom[k].index) {
miso_pinmux = PINMUX(miso->number, (k == 0) ? MUX_C : MUX_D);
miso_pad = miso->sercom[k].pad;
sercom = potential_sercom;
break;
}
}
}
if (sercom != NULL) {
break;
}
}
if (sercom != NULL) {
break;
}
}
if (sercom != NULL) {
@ -199,11 +146,9 @@ 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, slave_mode ? 2 : 3);
self->slave_mode = slave_mode;
hri_sercomspi_write_CTRLA_MODE_bf(sercom, 3);
hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo);
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, slave_mode ? mosi_pad : miso_pad);
hri_sercomspi_write_CTRLB_PLOADEN_bit(sercom, slave_mode);
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, miso_pad);
// Always start at 250khz which is what SD cards need. They are sensitive to
// SPI bus noise before they are put into SPI mode.
@ -214,7 +159,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
mp_raise_OSError(MP_EIO);
}
gpio_set_pin_direction(clock->number, slave_mode ? GPIO_DIRECTION_IN : GPIO_DIRECTION_OUT);
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);
@ -224,7 +169,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (mosi_none) {
self->MOSI_pin = NO_PIN;
} else {
gpio_set_pin_direction(mosi->number, slave_mode ? GPIO_DIRECTION_IN : GPIO_DIRECTION_OUT);
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);
self->MOSI_pin = mosi->number;
@ -235,7 +180,7 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (miso_none) {
self->MISO_pin = NO_PIN;
} else {
gpio_set_pin_direction(miso->number, slave_mode ? GPIO_DIRECTION_OUT : GPIO_DIRECTION_IN);
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);
self->MISO_pin = miso->number;
@ -243,17 +188,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(miso->number), GPIO_PIN(miso->number));
}
if (slave_mode) {
gpio_set_pin_direction(ss->number, slave_mode ? GPIO_DIRECTION_OUT : GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(ss->number, GPIO_PULL_OFF);
gpio_set_pin_function(ss->number, ss_pinmux);
self->SS_pin = ss->number;
claim_pin(ss);
hri_port_set_PINCFG_DRVSTR_bit(PORT, (enum gpio_port)GPIO_PORT(ss->number), GPIO_PIN(ss->number));
}
self->running_dma.failure = 1; // not started
spi_m_sync_enable(&self->spi_desc);
}
@ -336,9 +270,6 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self,
if (len == 0) {
return true;
}
if (self->running_dma.failure != 1) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Async SPI transfer in progress on this bus, keep awaiting."));
}
int32_t status;
if (len >= 16) {
size_t bytes_remaining = len;
@ -369,9 +300,6 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self,
if (len == 0) {
return true;
}
if (self->running_dma.failure != 1) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Async SPI transfer in progress on this bus, keep awaiting."));
}
int32_t status;
if (len >= 16) {
status = sercom_dma_read(self->spi_desc.dev.prvt, data, len, write_value);
@ -390,9 +318,6 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou
if (len == 0) {
return true;
}
if (self->running_dma.failure != 1) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Async SPI transfer in progress on this bus, keep awaiting."));
}
int32_t status;
if (len >= 16) {
status = sercom_dma_transfer(self->spi_desc.dev.prvt, data_out, data_in, len);
@ -406,62 +331,6 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_ou
return status >= 0; // Status is number of chars read or an error code < 0.
}
void common_hal_busio_spi_transfer_async_start(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len) {
if (len == 0) {
return;
}
if (self->running_dma.failure != 1) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Async SPI transfer in progress on this bus, keep awaiting."));
}
Sercom* sercom = self->spi_desc.dev.prvt;
self->running_dma = shared_dma_transfer_start(sercom, data_out, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, data_in, len, 0);
// There is an issue where if an unexpected SPI transfer is received before the user calls "end" for the in-progress, expected
// transfer, the SERCOM has an error and gets confused. This can be detected from INTFLAG.ERROR. I think the code in
// 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
// s->SPI.DATA.reg) is supposed to fix this, but experimentation seems to show that it does not in fact fix anything. Anyways, if
// the ERROR bit is set, let's just reset the peripheral and then setup the transfer again -- that seems to work.
if (hri_sercomspi_get_INTFLAG_ERROR_bit(sercom)) {
shared_dma_transfer_close(self->running_dma);
// disable the sercom
spi_m_sync_disable(&self->spi_desc);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// save configurations
hri_sercomspi_ctrla_reg_t ctrla_saved_val = hri_sercomspi_get_CTRLA_reg(sercom, -1); // -1 mask is all ones: save all bits
hri_sercomspi_ctrlb_reg_t ctrlb_saved_val = hri_sercomspi_get_CTRLB_reg(sercom, -1); // -1 mask is all ones: save all bits
hri_sercomspi_baud_reg_t baud_saved_val = hri_sercomspi_get_BAUD_reg(sercom, -1); // -1 mask is all ones: save all bits
// reset
hri_sercomspi_set_CTRLA_SWRST_bit(sercom);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// re-write configurations
hri_sercomspi_write_CTRLA_reg(sercom, ctrla_saved_val);
hri_sercomspi_write_CTRLB_reg(sercom, ctrlb_saved_val);
hri_sercomspi_write_BAUD_reg (sercom, baud_saved_val);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// re-enable the sercom
spi_m_sync_enable(&self->spi_desc);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
self->running_dma = shared_dma_transfer_start(sercom, data_out, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, data_in, len, 0);
}
}
bool common_hal_busio_spi_transfer_async_check(busio_spi_obj_t *self) {
return self->running_dma.failure == 1 || shared_dma_transfer_finished(self->running_dma);
}
int common_hal_busio_spi_transfer_async_end(busio_spi_obj_t *self) {
if (self->running_dma.failure == 1) {
return 0;
}
int res = shared_dma_transfer_close(self->running_dma);
self->running_dma.failure = 1;
return res;
}
uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self) {
return samd_peripherals_spi_baud_reg_value_to_baudrate(hri_sercomspi_read_BAUD_reg(self->spi_desc.dev.prvt));
}

View file

@ -40,9 +40,6 @@ typedef struct {
uint8_t clock_pin;
uint8_t MOSI_pin;
uint8_t MISO_pin;
uint8_t SS_pin;
bool slave_mode;
dma_descr_t running_dma;
} busio_spi_obj_t;
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_H

View file

@ -0,0 +1,235 @@
#include "common-hal/spitarget/SPITarget.h"
#include "common-hal/busio/__init__.h"
#include "shared-bindings/spitarget/SPITarget.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "py/mperrno.h"
#include "py/runtime.h"
#include "hpl_sercom_config.h"
#include "peripheral_clk_config.h"
#include "hal/include/hal_gpio.h"
#include "hal/include/hal_spi_m_sync.h"
#include "hpl_sercom_config.h"
#include "samd/sercom.h"
void common_hal_spitarget_spi_target_construct(spitarget_spi_target_obj_t *self,
const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi,
const mcu_pin_obj_t *miso, const mcu_pin_obj_t *ss) {
Sercom *sercom = NULL;
uint8_t sercom_index;
uint32_t clock_pinmux = 0;
uint32_t mosi_pinmux = 0;
uint32_t miso_pinmux = 0;
uint32_t ss_pinmux = 0;
uint8_t clock_pad = 0;
uint8_t mosi_pad = 0;
uint8_t miso_pad = 0;
uint8_t dopo = 255;
// Ensure the object starts in its deinit state.
self->clock_pin = NO_PIN;
// Special case for SAMR21 boards. (feather_radiofruit_zigbee)
#if defined(PIN_PC19F_SERCOM4_PAD0)
if (miso == &pin_PC19) {
if (mosi == &pin_PB30 && sck == &pin_PC18) {
sercom = SERCOM4;
sercom_index = 4;
clock_pinmux = MUX_F;
mosi_pinmux = MUX_F;
miso_pinmux = MUX_F;
clock_pad = 3;
mosi_pad = 2;
miso_pad = 0;
dopo = samd_peripherals_get_spi_dopo(clock_pad, mosi_pad);
}
// Error, leave SERCOM unset to throw an exception later.
} else
#endif
{
for (int i = 0; i < NUM_SERCOMS_PER_PIN; i++) {
sercom_index = sck->sercom[i].index; // 2 for SERCOM2, etc.
if (sercom_index >= SERCOM_INST_NUM) {
continue;
}
Sercom *potential_sercom = sercom_insts[sercom_index];
if (potential_sercom->SPI.CTRLA.bit.ENABLE != 0) {
continue;
}
clock_pinmux = PINMUX(sck->number, (i == 0) ? MUX_C : MUX_D);
clock_pad = sck->sercom[i].pad;
if (!samd_peripherals_valid_spi_clock_pad(clock_pad)) {
continue;
}
// find miso_pad first, since it corresponds to dopo which takes limited values
for (int j = 0; j < NUM_SERCOMS_PER_PIN; j++) {
if (sercom_index == miso->sercom[j].index) {
miso_pinmux = PINMUX(miso->number, (j == 0) ? MUX_C : MUX_D);
miso_pad = miso->sercom[j].pad;
dopo = samd_peripherals_get_spi_dopo(clock_pad, miso_pad);
if (dopo > 0x3) {
continue; // pad combination not possible
}
} else {
continue;
}
for (int k = 0; k < NUM_SERCOMS_PER_PIN; k++) {
if (sercom_index == mosi->sercom[k].index) {
mosi_pinmux = PINMUX(mosi->number, (k == 0) ? MUX_C : MUX_D);
mosi_pad = mosi->sercom[k].pad;
for (int m = 0; m < NUM_SERCOMS_PER_PIN; m++) {
if (sercom_index == ss->sercom[m].index) {
ss_pinmux = PINMUX(ss->number, (m == 0) ? MUX_C : MUX_D);
sercom = potential_sercom;
break;
}
}
if (sercom != NULL) {
break;
}
}
}
if (sercom != NULL) {
break;
}
}
if (sercom != NULL) {
break;
}
}
}
if (sercom == NULL) {
raise_ValueError_invalid_pins();
}
// Set up SPI clocks on SERCOM.
samd_peripherals_sercom_clock_init(sercom, sercom_index);
if (spi_m_sync_init(&self->spi_desc, sercom) != ERR_NONE) {
mp_raise_OSError(MP_EIO);
}
// Pads must be set after spi_m_sync_init(), which uses default values from
// the prototypical SERCOM.
hri_sercomspi_write_CTRLA_MODE_bf(sercom, 2);
hri_sercomspi_write_CTRLA_DOPO_bf(sercom, dopo);
hri_sercomspi_write_CTRLA_DIPO_bf(sercom, mosi_pad);
hri_sercomspi_write_CTRLB_PLOADEN_bit(sercom, 1);
// Always start at 250khz which is what SD cards need. They are sensitive to
// SPI bus noise before they are put into SPI mode.
uint8_t baud_value = samd_peripherals_spi_baudrate_to_baud_reg_value(250000);
if (spi_m_sync_set_baudrate(&self->spi_desc, baud_value) != ERR_NONE) {
// spi_m_sync_set_baudrate does not check for validity, just whether the device is
// busy or not
mp_raise_OSError(MP_EIO);
}
gpio_set_pin_direction(sck->number, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(sck->number, GPIO_PULL_OFF);
gpio_set_pin_function(sck->number, clock_pinmux);
claim_pin(sck);
self->clock_pin = sck->number;
gpio_set_pin_direction(mosi->number, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(mosi->number, GPIO_PULL_OFF);
gpio_set_pin_function(mosi->number, mosi_pinmux);
self->MOSI_pin = mosi->number;
claim_pin(mosi);
gpio_set_pin_direction(miso->number, GPIO_DIRECTION_OUT);
gpio_set_pin_pull_mode(miso->number, GPIO_PULL_OFF);
gpio_set_pin_function(miso->number, miso_pinmux);
self->MISO_pin = miso->number;
claim_pin(miso);
gpio_set_pin_direction(ss->number, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(ss->number, GPIO_PULL_OFF);
gpio_set_pin_function(ss->number, ss_pinmux);
self->SS_pin = ss->number;
claim_pin(ss);
self->running_dma.failure = 1; // not started
spi_m_sync_enable(&self->spi_desc);
}
bool common_hal_spitarget_spi_target_deinited(spitarget_spi_target_obj_t *self) {
return self->clock_pin == NO_PIN;
}
void common_hal_spitarget_spi_target_deinit(spitarget_spi_target_obj_t *self) {
if (common_hal_spitarget_spi_target_deinited(self)) {
return;
}
allow_reset_sercom(self->spi_desc.dev.prvt);
spi_m_sync_disable(&self->spi_desc);
spi_m_sync_deinit(&self->spi_desc);
reset_pin_number(self->clock_pin);
reset_pin_number(self->MOSI_pin);
reset_pin_number(self->MISO_pin);
reset_pin_number(self->SS_pin);
self->clock_pin = NO_PIN;
}
void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t *self,
uint8_t *mosi_packet, const uint8_t *miso_packet, size_t len) {
if (len == 0) {
return;
}
if (self->running_dma.failure != 1) {
mp_raise_RuntimeError(MP_ERROR_TEXT("Async SPI transfer in progress on this bus, keep awaiting."));
}
Sercom* sercom = self->spi_desc.dev.prvt;
self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
// There is an issue where if an unexpected SPI transfer is received before the user calls "end" for the in-progress, expected
// transfer, the SERCOM has an error and gets confused. This can be detected from INTFLAG.ERROR. I think the code in
// 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
// s->SPI.DATA.reg) is supposed to fix this, but experimentation seems to show that it does not in fact fix anything. Anyways, if
// the ERROR bit is set, let's just reset the peripheral and then setup the transfer again -- that seems to work.
if (hri_sercomspi_get_INTFLAG_ERROR_bit(sercom)) {
shared_dma_transfer_close(self->running_dma);
// disable the sercom
spi_m_sync_disable(&self->spi_desc);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// save configurations
hri_sercomspi_ctrla_reg_t ctrla_saved_val = hri_sercomspi_get_CTRLA_reg(sercom, -1); // -1 mask is all ones: save all bits
hri_sercomspi_ctrlb_reg_t ctrlb_saved_val = hri_sercomspi_get_CTRLB_reg(sercom, -1); // -1 mask is all ones: save all bits
hri_sercomspi_baud_reg_t baud_saved_val = hri_sercomspi_get_BAUD_reg(sercom, -1); // -1 mask is all ones: save all bits
// reset
hri_sercomspi_set_CTRLA_SWRST_bit(sercom);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// re-write configurations
hri_sercomspi_write_CTRLA_reg(sercom, ctrla_saved_val);
hri_sercomspi_write_CTRLB_reg(sercom, ctrlb_saved_val);
hri_sercomspi_write_BAUD_reg (sercom, baud_saved_val);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
// re-enable the sercom
spi_m_sync_enable(&self->spi_desc);
hri_sercomspi_wait_for_sync(sercom, SERCOM_SPI_SYNCBUSY_MASK);
self->running_dma = shared_dma_transfer_start(sercom, miso_packet, &sercom->SPI.DATA.reg, &sercom->SPI.DATA.reg, mosi_packet, len, 0);
}
}
bool common_hal_spitarget_spi_target_transfer_is_finished(spitarget_spi_target_obj_t *self) {
return self->running_dma.failure == 1 || shared_dma_transfer_finished(self->running_dma);
}
int common_hal_spitarget_spi_target_transfer_close(spitarget_spi_target_obj_t *self) {
if (self->running_dma.failure == 1) {
return 0;
}
int res = shared_dma_transfer_close(self->running_dma);
self->running_dma.failure = 1;
return res;
}

View file

@ -0,0 +1,21 @@
#ifndef MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H
#define MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H
#include "common-hal/microcontroller/Pin.h"
#include "hal/include/hal_spi_m_sync.h"
#include "py/obj.h"
typedef struct {
mp_obj_base_t base;
struct spi_m_sync_descriptor spi_desc;
uint8_t clock_pin;
uint8_t MOSI_pin;
uint8_t MISO_pin;
uint8_t SS_pin;
dma_descr_t running_dma;
} spitarget_spi_target_obj_t;
#endif // MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_BUSIO_SPI_TARGET_H

View file

@ -0,0 +1 @@
// No spitarget module functions.

View file

@ -46,6 +46,7 @@ CIRCUITPY_OS_GETENV ?= 0
CIRCUITPY_PIXELMAP ?= 0
CIRCUITPY_RE ?= 0
CIRCUITPY_SDCARDIO ?= 0
CIRCUITPY_SPITARGET ?= 0
CIRCUITPY_SYNTHIO ?= 0
CIRCUITPY_TOUCHIO_USE_NATIVE ?= 1
CIRCUITPY_TRACEBACK ?= 0
@ -105,6 +106,7 @@ CIRCUITPY_FRAMEBUFFERIO ?= $(CIRCUITPY_FULL_BUILD)
CIRCUITPY_PS2IO ?= 1
CIRCUITPY_RGBMATRIX ?= $(CIRCUITPY_FRAMEBUFFERIO)
CIRCUITPY_SAMD ?= 1
CIRCUITPY_SPITARGET ?= 1
CIRCUITPY_SYNTHIO_MAX_CHANNELS = 12
CIRCUITPY_ULAB_OPTIMIZE_SIZE ?= 1
CIRCUITPY_WATCHDOG ?= 1

View file

@ -77,7 +77,7 @@ void reset_spi(void) {
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *miso, bool half_duplex) {
size_t instance_index = NUM_SPI;
BP_Function_Enum clock_alt = 0;
BP_Function_Enum mosi_alt = 0;
@ -86,9 +86,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (half_duplex) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Half duplex SPI is not implemented"));
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
// BCM_VERSION != 2711 have 3 SPI but as listed in peripherals/gen/pins.c two are on
// index 0, once one index 0 SPI is found the other will throw an invalid_pins error.

View file

@ -36,15 +36,12 @@
#include "shared-bindings/microcontroller/Pin.h"
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, bool half_duplex) {
int port = -1;
if (half_duplex) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex);
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
if (clock->number == PIN_SPI4_SCK &&
(mosi == NULL || mosi->number == PIN_SPI4_MOSI) &&

View file

@ -52,7 +52,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -116,7 +116,7 @@ const uint8_t refresh_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO36, &pin_GPIO35, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -45,7 +45,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO7, &pin_GPIO6, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO7, &pin_GPIO6, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -46,7 +46,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO7, &pin_GPIO6, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO7, &pin_GPIO6, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -73,7 +73,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO6, &pin_GPIO7, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO6, &pin_GPIO7, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -65,7 +65,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO23, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO23, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -73,10 +73,7 @@ static void display_init(void) {
&pin_GPIO34, // CLK
&pin_GPIO33, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -45,7 +45,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO12, &pin_GPIO11, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO12, &pin_GPIO11, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -73,10 +73,7 @@ static void display_init(void) {
&pin_GPIO36, // CLK
&pin_GPIO35, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -53,10 +53,7 @@ static void display_init(void) {
&pin_GPIO18, // CLK
&pin_GPIO19, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -56,9 +56,7 @@ static void display_init(void) {
&pin_GPIO18, // CLK
&pin_GPIO19, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
false // Not half-duplex
);
common_hal_busio_spi_never_reset(spi);

View file

@ -53,7 +53,7 @@ void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
// busio_spi_obj_t *spi = common_hal_board_create_spi(0);
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO17, &pin_GPIO21, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO17, &pin_GPIO21, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -167,7 +167,7 @@ static bool pmic_init(busio_i2c_obj_t *i2c) {
static bool display_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO13, &pin_GPIO15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO13, &pin_GPIO15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -167,7 +167,7 @@ static bool pmic_init(busio_i2c_obj_t *i2c) {
static bool display_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO13, &pin_GPIO15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO13, &pin_GPIO15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -149,10 +149,7 @@ void board_init(void) {
&pin_GPIO12, // CLK
&pin_GPIO11, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -72,10 +72,7 @@ static void display_init(void) {
&pin_GPIO10, // CLK
&pin_GPIO11, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -77,7 +77,7 @@ static void set_spi_config(busio_spi_obj_t *self,
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *miso, bool half_duplex) {
const spi_bus_config_t bus_config = {
.mosi_io_num = mosi != NULL ? mosi->number : -1,
@ -90,9 +90,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (half_duplex) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex);
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
for (spi_host_device_t host_id = SPI2_HOST; host_id < SOC_SPI_PERIPH_NUM; host_id++) {
if (spi_bus_is_free(host_id)) {

View file

@ -91,7 +91,7 @@ void spi_reset(void) {
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *miso, bool half_duplex) {
const uint32_t sck_count = MP_ARRAY_SIZE(mcu_spi_sck_list);
const uint32_t miso_count = MP_ARRAY_SIZE(mcu_spi_sdi_list);
@ -101,9 +101,6 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
if (half_duplex) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex);
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
for (uint i = 0; i < sck_count; i++) {
if (mcu_spi_sck_list[i].pin != clock) {

View file

@ -49,7 +49,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_14, &pin_P0_15, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_P0_14, &pin_P0_15, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -52,7 +52,7 @@ void board_init(void) {
fb->base.type = &sharpdisplay_framebuffer_type;
busio_spi_obj_t *spi = &fb->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_26, &pin_P0_27, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_P0_26, &pin_P0_27, NULL, false);
common_hal_busio_spi_never_reset(spi);
common_hal_sharpdisplay_framebuffer_construct(fb, spi, &pin_P0_05, 500000, 176, 176, true);

View file

@ -49,7 +49,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_07, &pin_P1_08, NULL, NULL, false, false); // SCK, MOSI, MISO, not half-duplex
common_hal_busio_spi_construct(spi, &pin_P0_07, &pin_P1_08, NULL, false); // SCK, MOSI, MISO, not half-duplex
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -50,7 +50,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_11, &pin_P0_12, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_P0_11, &pin_P0_12, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -49,7 +49,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_P0_11, &pin_P0_12, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_P0_11, &pin_P0_12, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -143,14 +143,11 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate)
return 0;
}
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
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) {
if (half_duplex) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex);
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
// Find a free instance, with most desirable (highest freq and not shared) allocated first.
self->spim_peripheral = NULL;

View file

@ -61,7 +61,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO26, &pin_GPIO27, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO26, &pin_GPIO27, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -80,7 +80,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -74,10 +74,7 @@ static void display_init(void) {
&pin_GPIO2, // CLK
&pin_GPIO3, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
);
false); // Not half-duplex
common_hal_busio_spi_never_reset(spi);

View file

@ -66,7 +66,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -276,7 +276,7 @@ void board_init(void) {
// Set up the SPI object used to control the display
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO18, &pin_GPIO19, &pin_GPIO16, false);
common_hal_busio_spi_never_reset(spi);
// Set up the DisplayIO pin object

View file

@ -66,7 +66,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO6, &pin_GPIO7, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO6, &pin_GPIO7, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -66,7 +66,7 @@ uint8_t display_init_sequence[] = {
void board_init(void) {
fourwire_fourwire_obj_t *bus = &allocate_display_bus()->fourwire_bus;
busio_spi_obj_t *spi = &bus->inline_bus;
common_hal_busio_spi_construct(spi, &pin_GPIO2, &pin_GPIO3, NULL, NULL, false, false);
common_hal_busio_spi_construct(spi, &pin_GPIO2, &pin_GPIO3, NULL, false);
common_hal_busio_spi_never_reset(spi);
bus->base.type = &fourwire_fourwire_type;

View file

@ -70,9 +70,7 @@ static void display_init(void) {
&pin_GPIO10, // CLK
&pin_GPIO11, // MOSI
NULL, // MISO not connected
NULL, // SS not connected
false, // Not half-duplex
false // operate SPI bus as master
false // Not half-duplex
);
common_hal_busio_spi_never_reset(spi);

View file

@ -54,15 +54,12 @@ void reset_spi(void) {
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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
const mcu_pin_obj_t *miso, bool half_duplex) {
size_t instance_index = NO_INSTANCE;
if (half_duplex) {
mp_raise_NotImplementedError_varg(MP_ERROR_TEXT("%q"), MP_QSTR_half_duplex);
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
if (clock->number % 4 == 2) {
instance_index = (clock->number / 8) % 2;

View file

@ -53,17 +53,13 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self,
const mcu_pin_obj_t *sck,
const mcu_pin_obj_t *mosi,
const mcu_pin_obj_t *miso,
const mcu_pin_obj_t *ss,
bool half_duplex, bool slave_mode) {
bool half_duplex) {
Ecode_t sc = ECODE_OK;
if (half_duplex) {
mp_raise_NotImplementedError(
MP_ERROR_TEXT("Half duplex SPI is not implemented"));
}
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
if ((sck != NULL) && (mosi != NULL) && (miso != NULL)) {
if (sck->function_list[FN_EUSART1_SCLK] == 1

View file

@ -167,10 +167,7 @@ STATIC int check_pins(busio_spi_obj_t *self,
void common_hal_busio_spi_construct(busio_spi_obj_t *self,
const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi,
const mcu_pin_obj_t *miso, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode) {
if (slave_mode) {
mp_raise_NotImplementedError(MP_ERROR_TEXT("Slave mode SPI is not implemented"));
}
const mcu_pin_obj_t *miso, bool half_duplex) {
int periph_index = check_pins(self, sck, mosi, miso);
SPI_TypeDef *SPIx = mcu_spi_banks[periph_index - 1];

View file

@ -351,6 +351,9 @@ endif
ifeq ($(CIRCUITPY_SOCKETPOOL),1)
SRC_PATTERNS += socketpool/%
endif
ifeq ($(CIRCUITPY_SPITARGET),1)
SRC_PATTERNS += spitarget/%
endif
ifeq ($(CIRCUITPY_SSL),1)
SRC_PATTERNS += ssl/%
endif
@ -516,6 +519,8 @@ SRC_COMMON_HAL_ALL = \
socketpool/__init__.c \
socketpool/SocketPool.c \
socketpool/Socket.c \
spitarget/SPITarget.c \
spitarget/__init__.c \
supervisor/Runtime.c \
supervisor/__init__.c \
usb_host/__init__.c \

View file

@ -476,6 +476,9 @@ CFLAGS += -DCIRCUITPY_SKIP_SAFE_MODE_WAIT=$(CIRCUITPY_SKIP_SAFE_MODE_WAIT)
CIRCUITPY_SOCKETPOOL ?= $(CIRCUITPY_WIFI)
CFLAGS += -DCIRCUITPY_SOCKETPOOL=$(CIRCUITPY_SOCKETPOOL)
CIRCUITPY_SPITARGET ?= 0
CFLAGS += -DCIRCUITPY_SPITARGET=$(CIRCUITPY_SPITARGET)
CIRCUITPY_SSL ?= $(CIRCUITPY_WIFI)
CFLAGS += -DCIRCUITPY_SSL=$(CIRCUITPY_SSL)

View file

@ -73,9 +73,7 @@
//| clock: microcontroller.Pin,
//| MOSI: Optional[microcontroller.Pin] = None,
//| MISO: Optional[microcontroller.Pin] = None,
//| SS: Optional[microcontroller.Pin] = None,
//| half_duplex: bool = False,
//| slave_mode: bool = False,
//| half_duplex: bool = False
//| ) -> None:
//| """Construct an SPI object on the given pins.
//|
@ -98,10 +96,8 @@
//| :param ~microcontroller.Pin MOSI: the Main Out Selected In pin.
//| :param ~microcontroller.Pin MISO: the Main In Selected Out pin.
//| :param bool half_duplex: True when MOSI is used for bidirectional data. False when SPI is full-duplex or simplex.
//| :param-bool slave_mode: True when the chip is operating as a slave. False when the chip is operating as a master.
//|
//| **Limitations:** ``half_duplex`` is available only on STM; other chips do not have the hardware support.
//| **Limitations:** ``slave_mode`` is available only on SAMD51; other chips do not have the firmware support.
//| """
//| ...
@ -110,14 +106,12 @@
STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
#if CIRCUITPY_BUSIO_SPI
busio_spi_obj_t *self = mp_obj_malloc(busio_spi_obj_t, &busio_spi_type);
enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_SS, ARG_half_duplex, ARG_slave_mode };
enum { ARG_clock, ARG_MOSI, ARG_MISO, ARG_half_duplex };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_clock, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_MOSI, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_MISO, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_SS, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_half_duplex, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
{ MP_QSTR_slave_mode, MP_ARG_BOOL | MP_ARG_KW_ONLY, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
@ -125,19 +119,12 @@ STATIC mp_obj_t busio_spi_make_new(const mp_obj_type_t *type, size_t n_args, siz
const mcu_pin_obj_t *clock = validate_obj_is_free_pin(args[ARG_clock].u_obj, MP_QSTR_clock);
const mcu_pin_obj_t *mosi = validate_obj_is_free_pin_or_none(args[ARG_MOSI].u_obj, MP_QSTR_mosi);
const mcu_pin_obj_t *miso = validate_obj_is_free_pin_or_none(args[ARG_MISO].u_obj, MP_QSTR_miso);
const mcu_pin_obj_t *ss = validate_obj_is_free_pin_or_none(args[ARG_SS].u_obj, MP_QSTR_ss);
if (!miso && !mosi) {
mp_raise_ValueError(MP_ERROR_TEXT("Must provide MISO or MOSI pin"));
}
if (args[ARG_slave_mode].u_bool && !ss) {
mp_raise_ValueError(MP_ERROR_TEXT("Must provide SS pin to operate in slave mode"));
}
if (!args[ARG_slave_mode].u_bool && ss) {
mp_raise_ValueError(MP_ERROR_TEXT("Hardware SS pin only supported for slave mode"));
}
common_hal_busio_spi_construct(self, clock, mosi, miso, ss, args[ARG_half_duplex].u_bool, args[ARG_slave_mode].u_bool);
common_hal_busio_spi_construct(self, clock, mosi, miso, args[ARG_half_duplex].u_bool);
return MP_OBJ_FROM_PTR(self);
#else
raise_ValueError_invalid_pins();
@ -482,145 +469,6 @@ MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_get_frequency_obj, busio_spi_obj_get_frequen
MP_PROPERTY_GETTER(busio_spi_frequency_obj,
(mp_obj_t)&busio_spi_get_frequency_obj);
#if CIRCUITPY_SAMD
//| import sys
//| def async_transfer_start(
//| self,
//| out_buffer: ReadableBuffer,
//| in_buffer: WriteableBuffer,
//| *,
//| out_start: int = 0,
//| out_end: int = sys.maxsize,
//| in_start: int = 0,
//| in_end: int = sys.maxsize
//| ) -> None:
//| """Write out the data in ``out_buffer`` while simultaneously reading data into ``in_buffer``.
//| The SPI object must be locked. Note: this method returns immediately, and the data will not
//| actually be transferred until some time has passed. Use `async_transfer_finished` and
//| `async_transfer_end` to check on the status of the transfer and close out its resources.
//|
//| If ``out_start`` or ``out_end`` is provided, then the buffer will be sliced
//| as if ``out_buffer[out_start:out_end]`` were passed, but without copying the data.
//| The number of bytes written will be the length of ``out_buffer[out_start:out_end]``.
//|
//| If ``in_start`` or ``in_end`` is provided, then the input buffer will be sliced
//| as if ``in_buffer[in_start:in_end]`` were passed,
//| The number of bytes read will be the length of ``out_buffer[in_start:in_end]``.
//|
//| The lengths of the slices defined by ``out_buffer[out_start:out_end]``
//| and ``in_buffer[in_start:in_end]`` must be equal.
//| If buffer slice lengths are both 0, nothing happens.
//|
//| Note: This method is currently only available on atmel-samd` ports of CircuitPython.
//|
//| :param ReadableBuffer out_buffer: write out bytes from this buffer
//| :param WriteableBuffer in_buffer: read bytes into this buffer
//| :param int out_start: beginning of ``out_buffer`` slice
//| :param int out_end: end of ``out_buffer`` slice; if not specified, use ``len(out_buffer)``
//| :param int in_start: beginning of ``in_buffer`` slice
//| :param int in_end: end of ``in_buffer slice``; if not specified, use ``len(in_buffer)``
//| """
//| ...
STATIC mp_obj_t busio_spi_start_async_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_out_buffer, ARG_in_buffer, ARG_out_start, ARG_out_end, ARG_in_start, ARG_in_end };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_out_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_in_buffer, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_out_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_out_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
{ MP_QSTR_in_start, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_in_end, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = INT_MAX} },
};
busio_spi_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
check_for_deinit(self);
check_lock(self);
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t buf_out_info;
mp_get_buffer_raise(args[ARG_out_buffer].u_obj, &buf_out_info, MP_BUFFER_READ);
int out_stride_in_bytes = mp_binary_get_size('@', buf_out_info.typecode, NULL);
int32_t out_start = args[ARG_out_start].u_int;
size_t out_length = buf_out_info.len / out_stride_in_bytes;
normalize_buffer_bounds(&out_start, args[ARG_out_end].u_int, &out_length);
mp_buffer_info_t buf_in_info;
mp_get_buffer_raise(args[ARG_in_buffer].u_obj, &buf_in_info, MP_BUFFER_WRITE);
int in_stride_in_bytes = mp_binary_get_size('@', buf_in_info.typecode, NULL);
int32_t in_start = args[ARG_in_start].u_int;
size_t in_length = buf_in_info.len / in_stride_in_bytes;
normalize_buffer_bounds(&in_start, args[ARG_in_end].u_int, &in_length);
// Treat start and length in terms of bytes from now on.
out_start *= out_stride_in_bytes;
out_length *= out_stride_in_bytes;
in_start *= in_stride_in_bytes;
in_length *= in_stride_in_bytes;
if (out_length != in_length) {
mp_raise_ValueError(MP_ERROR_TEXT("buffer slices must be of equal length"));
}
common_hal_busio_spi_transfer_async_start(self,
((uint8_t *)buf_out_info.buf) + out_start,
((uint8_t *)buf_in_info.buf) + in_start,
out_length);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(busio_spi_start_transfer_obj, 1, busio_spi_start_async_transfer);
//| import sys
//| def async_transfer_finished(
//| self
//| ) -> None:
//| """Check whether or not the last async transfer started on this SPI object has finished. If
//| no transfer was started, this method behaves as though the most recent transfer has finished
//| and returns `True`. Otherwise, it returns `False`.
//|
//| Note: This method is currently only available on atmel-samd` ports of CircuitPython.
//| """
//| ...
STATIC mp_obj_t busio_spi_obj_check_async_transfer(mp_obj_t self_in) {
busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return common_hal_busio_spi_transfer_async_check(self) ? mp_const_true : mp_const_false;
}
MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_check_transfer_obj, busio_spi_obj_check_async_transfer);
//| import sys
//| def async_transfer_end(
//| self
//| ) -> None:
//| """Return the status code with which the last async transfer on this SPI object completed. This
//| method MUST be called for all transfers, regardless of user interest in status code. The resources
//| for the transfer will be left open until this method is called. Once this method is called, the
//| peripheral resets and is ready for another transfer. The return code of this method also resets to
//| its pre-transfer state: repeated calls to this method may produce different codes.
//|
//| Return code 0: No transfer has occured, either because `start_async_transfer` was never called, or because
//| it was called with zero-length buffers.
//| Return code -1: The transfer failed because no DMA channels are available.
//| Return code -2: The transfer executed, but the DMA controller indicates that either some data is
//| untransferred, that a software issue prevented the data transfer from completing, or that some other error
//| has occured within the DMA controller.
//| Return code -3: An unaligned buffer was passed to the QSPI peripheral, which prevents the DMA controller from
//| appropriately chunking the transfer.
//| Return code n>0: A transfer of `n` bytes in each direction has succeeded.
//|
//| Note: This method is currently only available on atmel-samd` ports of CircuitPython.
//| """
//| ...
STATIC mp_obj_t busio_spi_obj_end_async_transfer(mp_obj_t self_in) {
busio_spi_obj_t *self = MP_OBJ_TO_PTR(self_in);
check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_busio_spi_transfer_async_end(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(busio_spi_end_transfer_obj, busio_spi_obj_end_async_transfer);
#endif // CIRCUITPY_SAMD
#endif // CIRCUITPY_BUSIO_SPI
@ -639,13 +487,6 @@ STATIC const mp_rom_map_elem_t busio_spi_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_write_readinto), MP_ROM_PTR(&busio_spi_write_readinto_obj) },
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&busio_spi_frequency_obj) }
#if CIRCUITPY_SAMD
,
{ MP_ROM_QSTR(MP_QSTR_async_transfer_start), MP_ROM_PTR(&busio_spi_start_transfer_obj) },
{ MP_ROM_QSTR(MP_QSTR_async_transfer_finished), MP_ROM_PTR(&busio_spi_check_transfer_obj) },
{ MP_ROM_QSTR(MP_QSTR_async_transfer_end), MP_ROM_PTR(&busio_spi_end_transfer_obj) }
#endif // CIRCUITPY_SAMD
#endif // CIRCUITPY_BUSIO_SPI
};
STATIC MP_DEFINE_CONST_DICT(busio_spi_locals_dict, busio_spi_locals_dict_table);

View file

@ -38,7 +38,7 @@ extern const mp_obj_type_t busio_spi_type;
// Construct an underlying SPI object.
extern 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, const mcu_pin_obj_t *ss, bool half_duplex, bool slave_mode);
const mcu_pin_obj_t *miso, bool half_duplex);
extern void common_hal_busio_spi_deinit(busio_spi_obj_t *self);
extern bool common_hal_busio_spi_deinited(busio_spi_obj_t *self);
@ -58,19 +58,6 @@ extern bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size
// Reads and write len bytes simultaneously.
extern bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len);
#if CIRCUITPY_SAMD
// Initiates a transfer that reads and write len bytes simultaneously
extern void common_hal_busio_spi_transfer_async_start(busio_spi_obj_t *self, const uint8_t *data_out, uint8_t *data_in, size_t len);
// Reads the state of the in-progress transfer
extern bool common_hal_busio_spi_transfer_async_check(busio_spi_obj_t *self);
// Cleans up the completed transfer and returns any error code produced by the transfer
extern int common_hal_busio_spi_transfer_async_end(busio_spi_obj_t *self);
#endif // CIRCUITPY_SAMD
// Return actual SPI bus frequency.
uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t *self);

View file

@ -0,0 +1,182 @@
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/spitarget/SPITarget.h"
#include "shared-bindings/time/__init__.h"
#include "shared-bindings/util.h"
#include "shared/runtime/buffer_helper.h"
#include "shared/runtime/context_manager_helpers.h"
#include "shared/runtime/interrupt_char.h"
#include "py/mperrno.h"
#include "py/mphal.h"
#include "py/obj.h"
#include "py/objproperty.h"
#include "py/runtime.h"
//| class SPITarget:
//| """Serial Peripheral Interface protocol target"""
//|
//| def __init__(
//| self,
//| sck: microcontroller.Pin,
//| mosi: microcontroller.Pin,
//| miso: microcontroller.Pin,
//| ss: microcontroller.Pin
//| ) -> None:
//| """SPI is a four-wire protocol for communicating between devices.
//| This implements the secondary (aka target or peripheral) side.
//|
//| :param ~microcontroller.Pin sck: The SPI clock pin
//| :param ~microcontroller.Pin mosi: The pin transferring data from the main to the secondary
//| :param ~microcontroller.Pin miso: The pin transferring data from the secondary to the main
//| :param ~microcontroller.Pin ss: The secondary selection pin"""
//| ...
STATIC mp_obj_t spitarget_spi_target_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *all_args) {
spitarget_spi_target_obj_t *self = mp_obj_malloc(spitarget_spi_target_obj_t, &spitarget_spi_target_type);
enum { ARG_sck, ARG_mosi, ARG_miso, ARG_ss };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_sck, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_mosi, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_miso, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_ss, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all_kw_array(n_args, n_kw, all_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
const mcu_pin_obj_t *sck = validate_obj_is_free_pin(args[ARG_sck].u_obj, MP_QSTR_sck);
const mcu_pin_obj_t *mosi = validate_obj_is_free_pin(args[ARG_mosi].u_obj, MP_QSTR_mosi);
const mcu_pin_obj_t *miso = validate_obj_is_free_pin(args[ARG_miso].u_obj, MP_QSTR_miso);
const mcu_pin_obj_t *ss = validate_obj_is_free_pin(args[ARG_ss].u_obj, MP_QSTR_ss);
common_hal_spitarget_spi_target_construct(self, sck, mosi, miso, ss);
return MP_OBJ_FROM_PTR(self);
}
//| def deinit(self) -> None:
//| """Releases control of the underlying hardware so other classes can use it."""
//| ...
STATIC mp_obj_t spitarget_spi_target_obj_deinit(mp_obj_t self_in) {
mp_check_self(mp_obj_is_type(self_in, &spitarget_spi_target_type));
spitarget_spi_target_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_spitarget_spi_target_deinit(self);
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(spitarget_spi_target_deinit_obj, spitarget_spi_target_obj_deinit);
//| def __enter__(self) -> SPITarget:
//| """No-op used in Context Managers."""
//| ...
// Provided by context manager helper.
//| def __exit__(self) -> None:
//| """Automatically deinitializes the hardware on context exit. See
//| :ref:`lifetime-and-contextmanagers` for more info."""
//| ...
STATIC mp_obj_t spitarget_spi_target_obj___exit__(size_t n_args, const mp_obj_t *args) {
mp_check_self(mp_obj_is_type(args[0], &spitarget_spi_target_target_type));
spitarget_spi_target_obj_t *self = MP_OBJ_TO_PTR(args[0]);
common_hal_spitarget_spi_target_deinit(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(spitarget_spi_target___exit___obj, 4, 4, spitarget_spi_target_obj___exit__);
//| def load_packet(self, mosi_packet: bytearray, miso_packet: bytearray) -> None:
//| """Queue data for the next SPI transfer from the main device.
//| If a packet has already been queued for this SPI bus but has not yet been transferred, an error will be raised.
//|
//| :param bytearray miso_packet: Packet data to be sent from secondary to main on next request."""
//|
STATIC mp_obj_t spitarget_spi_target_load_packet(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_check_self(mp_obj_is_type(pos_args[0], &spitarget_spi_target_type));
spitarget_spi_target_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
if (common_hal_spitarget_spi_target_deinited(self)) {
raise_deinited_error();
}
enum { ARG_mosi_packet, ARG_miso_packet };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_mosi_packet, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_miso_packet, MP_ARG_REQUIRED | MP_ARG_OBJ },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
mp_buffer_info_t mosi_bufinfo;
mp_get_buffer_raise(args[ARG_mosi_packet].u_obj, &mosi_bufinfo, MP_BUFFER_WRITE);
mp_buffer_info_t miso_bufinfo;
mp_get_buffer_raise(args[ARG_miso_packet].u_obj, &miso_bufinfo, MP_BUFFER_READ);
if (miso_bufinfo.len != mosi_bufinfo.len) {
mp_raise_ValueError(MP_ERROR_TEXT("Packet buffers for an SPI transfer must have the same length."));
}
common_hal_spitarget_spi_target_transfer_start(self, ((uint8_t *)mosi_bufinfo.buf), ((uint8_t *)miso_bufinfo.buf), mosi_bufinfo.len);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(spitarget_spi_target_load_packet_obj, 1, spitarget_spi_target_load_packet);
//| def try_transfer(self, *, timeout: float = -1) -> bool:
//| """Wait for an SPI transfer from the main device.
//|
//| :param float timeout: Timeout in seconds. Zero means wait forever, a negative value means check once
//| :return: True if the transfer is complete, or False if no response received before the timeout
//| :rtype: ~bool"""
//|
STATIC mp_obj_t spitarget_spi_target_try_transfer(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
mp_check_self(mp_obj_is_type(pos_args[0], &spitarget_spi_target_type));
spitarget_spi_target_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
if (common_hal_spitarget_spi_target_deinited(self)) {
raise_deinited_error();
}
enum { ARG_timeout };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_OBJ, {.u_obj = MP_OBJ_NEW_SMALL_INT(-1)} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
#if MICROPY_PY_BUILTINS_FLOAT
float f = mp_obj_get_float(args[ARG_timeout].u_obj) * 1000;
int timeout_ms = (int)f;
#else
int timeout_ms = mp_obj_get_int(args[ARG_timeout].u_obj) * 1000;
#endif
bool forever = false;
uint64_t timeout_end = 0;
if (timeout_ms == 0) {
forever = true;
} else if (timeout_ms > 0) {
timeout_end = common_hal_time_monotonic_ms() + timeout_ms;
}
do {
if (common_hal_spitarget_spi_target_transfer_is_finished(self)) {
common_hal_spitarget_spi_target_transfer_close(self); // implicitly discards error indicator code
return mp_const_true;
}
mp_hal_delay_us(10);
} while (forever || common_hal_time_monotonic_ms() < timeout_end);
return mp_const_false;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(spitarget_spi_target_try_transfer_obj, 1, spitarget_spi_target_try_transfer);
STATIC const mp_rom_map_elem_t spitarget_spi_target_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&spitarget_spi_target_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&spitarget_spi_target___exit___obj) },
{ MP_ROM_QSTR(MP_QSTR_load_packet), MP_ROM_PTR(&spitarget_spi_target_load_packet_obj) },
{ MP_ROM_QSTR(MP_QSTR_try_transfer), MP_ROM_PTR(&spitarget_spi_target_try_transfer_obj) },
};
STATIC MP_DEFINE_CONST_DICT(spitarget_spi_target_locals_dict, spitarget_spi_target_locals_dict_table);
MP_DEFINE_CONST_OBJ_TYPE(
spitarget_spi_target_type,
MP_QSTR_SPITarget,
MP_TYPE_FLAG_NONE,
make_new, spitarget_spi_target_make_new,
locals_dict, &spitarget_spi_target_locals_dict
);

View file

@ -0,0 +1,21 @@
#ifndef MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_TARGET_H
#define MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_TARGET_H
#include "py/obj.h"
#include "common-hal/microcontroller/Pin.h"
#include "common-hal/spitarget/SPITarget.h"
extern const mp_obj_type_t spitarget_spi_target_type;
extern void common_hal_spitarget_spi_target_construct(spitarget_spi_target_obj_t *self,
const mcu_pin_obj_t *sck, const mcu_pin_obj_t *mosi, const mcu_pin_obj_t *miso, const mcu_pin_obj_t *ss);
extern void common_hal_spitarget_spi_target_deinit(spitarget_spi_target_obj_t *self);
extern bool common_hal_spitarget_spi_target_deinited(spitarget_spi_target_obj_t *self);
extern void common_hal_spitarget_spi_target_transfer_start(spitarget_spi_target_obj_t *self,
uint8_t *mosi_packet, const uint8_t *miso_packet, size_t len);
extern bool common_hal_spitarget_spi_target_transfer_is_finished(spitarget_spi_target_obj_t *self);
extern int common_hal_spitarget_spi_target_transfer_close(spitarget_spi_target_obj_t *self);
#endif // MICROPY_INCLUDED_SHARED_BINDINGS_BUSIO_SPI_TARGET_H

View file

@ -0,0 +1,28 @@
#include <stdint.h>
#include "py/obj.h"
#include "py/runtime.h"
#include "shared-bindings/microcontroller/Pin.h"
#include "shared-bindings/spitarget/SPITarget.h"
#include "py/runtime.h"
//| """Serial Peripheral Interface protocol target
//|
//| The `spitarget` module contains classes to support an SPI target.
STATIC const mp_rom_map_elem_t spitarget_module_globals_table[] = {
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_spitarget) },
{ MP_ROM_QSTR(MP_QSTR_SPITarget), MP_ROM_PTR(&spitarget_spi_target_type) },
};
STATIC MP_DEFINE_CONST_DICT(spitarget_module_globals, spitarget_module_globals_table);
const mp_obj_module_t spitarget_module = {
.base = { &mp_type_module },
.globals = (mp_obj_dict_t *)&spitarget_module_globals,
};
MP_REGISTER_MODULE(MP_QSTR_spitarget, spitarget_module);

View file

@ -130,7 +130,7 @@ mp_obj_t common_hal_board_create_spi(const mp_int_t instance) {
assert_pin_free(spi_pin[instance].mosi);
assert_pin_free(spi_pin[instance].miso);
common_hal_busio_spi_construct(self, spi_pin[instance].clock, spi_pin[instance].mosi, spi_pin[instance].miso, NULL, false, false);
common_hal_busio_spi_construct(self, spi_pin[instance].clock, spi_pin[instance].mosi, spi_pin[instance].miso, false);
spi_obj_created[instance] = true;
return &spi_obj[instance];

View file

@ -149,7 +149,7 @@ void spi_flash_init(void) {
common_hal_digitalio_digitalinout_never_reset(&cs_pin);
supervisor_flash_spi_bus.base.type = &busio_spi_type;
common_hal_busio_spi_construct(&supervisor_flash_spi_bus, SPI_FLASH_SCK_PIN, SPI_FLASH_MOSI_PIN, SPI_FLASH_MISO_PIN, NULL, false, false);
common_hal_busio_spi_construct(&supervisor_flash_spi_bus, SPI_FLASH_SCK_PIN, SPI_FLASH_MOSI_PIN, SPI_FLASH_MISO_PIN, false);
common_hal_busio_spi_never_reset(&supervisor_flash_spi_bus);
common_hal_busio_spi_configure(&supervisor_flash_spi_bus, SPI_FLASH_MAX_BAUDRATE, 0, 0, 8);

View file

@ -164,8 +164,6 @@ void status_led_init() {
MICROPY_HW_APA102_SCK,
MICROPY_HW_APA102_MOSI,
NULL,
NULL,
false,
false);
#endif
#if CIRCUITPY_BITBANG_APA102