From bc581fbdfb10f9cf89f2e7572cd67e1dc10b8451 Mon Sep 17 00:00:00 2001 From: Lucian Copeland Date: Fri, 1 May 2020 10:06:40 -0400 Subject: [PATCH] Add-unidirectional-SPI --- ports/mimxrt10xx/Makefile | 3 + ports/mimxrt10xx/common-hal/busio/SPI.c | 255 ++++++++++++++---------- ports/mimxrt10xx/common-hal/busio/SPI.h | 8 +- ports/mimxrt10xx/supervisor/port.c | 3 +- 4 files changed, 156 insertions(+), 113 deletions(-) diff --git a/ports/mimxrt10xx/Makefile b/ports/mimxrt10xx/Makefile index 80d1da1aac..cc2ec8f2b2 100644 --- a/ports/mimxrt10xx/Makefile +++ b/ports/mimxrt10xx/Makefile @@ -93,6 +93,9 @@ endif CFLAGS += $(INC) -Wall -Wno-cast-align -std=gnu11 -nostdlib $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT) +# Disable some warnings, as do most ports. NXP SDK causes undef, tinyusb causes cast-align +CFLAGS += -Wno-undef -Wno-cast-align + CFLAGS += \ -mthumb \ -mapcs \ diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.c b/ports/mimxrt10xx/common-hal/busio/SPI.c index 24a6dbff6d..be5f1a6fc8 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.c +++ b/ports/mimxrt10xx/common-hal/busio/SPI.c @@ -25,7 +25,6 @@ * THE SOFTWARE. */ -//TODO #include "shared-bindings/busio/SPI.h" #include "py/mperrno.h" #include "py/runtime.h" @@ -35,46 +34,10 @@ #include -//bool never_reset_sercoms[SERCOM_INST_NUM]; -// -//void never_reset_sercom(Sercom* sercom) { -// // Reset all SERCOMs except the ones being used by on-board devices. -// Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; -// for (int i = 0; i < SERCOM_INST_NUM; i++) { -// if (sercom_instances[i] == sercom) { -// never_reset_sercoms[i] = true; -// break; -// } -// } -//} -// -//void allow_reset_sercom(Sercom* sercom) { -// // Reset all SERCOMs except the ones being used by on-board devices. -// Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; -// for (int i = 0; i < SERCOM_INST_NUM; i++) { -// if (sercom_instances[i] == sercom) { -// never_reset_sercoms[i] = false; -// break; -// } -// } -//} -// -//void reset_sercoms(void) { -// // Reset all SERCOMs except the ones being used by on-board devices. -// Sercom *sercom_instances[SERCOM_INST_NUM] = SERCOM_INSTS; -// for (int i = 0; i < SERCOM_INST_NUM; i++) { -// if (never_reset_sercoms[i]) { -// continue; -// } -// #ifdef MICROPY_HW_APA102_SERCOM -// if (sercom_instances[i] == MICROPY_HW_APA102_SERCOM) { -// continue; -// } -// #endif -// // SWRST is same for all modes of SERCOMs. -// sercom_instances[i]->SPI.CTRLA.bit.SWRST = 1; -// } -//} +//arrays use 0 based numbering: SPI1 is stored at index 0 +#define MAX_SPI 4 +STATIC bool reserved_spi[MAX_SPI]; +STATIC bool never_reset_spi[MAX_SPI]; static void config_periph_pin(const mcu_periph_obj_t *periph) { IOMUXC_SetPinMux( @@ -97,52 +60,144 @@ static void config_periph_pin(const mcu_periph_obj_t *periph) { #define LPSPI_MASTER_CLK_FREQ (CLOCK_GetFreq(kCLOCK_Usb1PllPfd0Clk) / (CLOCK_GetDiv(kCLOCK_LpspiDiv))) +void spi_reset(void) { + for (int i = 0; i < MAX_SPI; i++) { + reserved_spi[i] = false; + } +} + 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) { - // TODO: Allow none mosi or miso + const uint32_t sck_count = MP_ARRAY_SIZE(mcu_spi_sck_list); + const uint32_t miso_count = MP_ARRAY_SIZE(mcu_spi_miso_list); + const uint32_t mosi_count = MP_ARRAY_SIZE(mcu_spi_mosi_list); + bool spi_taken = false; - const uint32_t sck_count = sizeof(mcu_spi_sck_list) / sizeof(mcu_periph_obj_t); - const uint32_t miso_count = sizeof(mcu_spi_miso_list) / sizeof(mcu_periph_obj_t); - const uint32_t mosi_count = sizeof(mcu_spi_mosi_list) / sizeof(mcu_periph_obj_t); - - for (uint32_t i = 0; i < sck_count; ++i) { - if (mcu_spi_sck_list[i].pin != clock) + for (uint i = 0; i < sck_count; i++) { + if (mcu_spi_sck_list[i].pin != clock) { continue; - - for (uint32_t j = 0; j < miso_count; ++j) { - if (mcu_spi_miso_list[j].pin != miso) - continue; - - if (mcu_spi_miso_list[j].bank_idx != mcu_spi_sck_list[i].bank_idx) - continue; - - for (uint32_t k = 0; k < mosi_count; ++k) { - if (mcu_spi_mosi_list[k].pin != mosi) + } + //if both MOSI and MISO exist, loop search normally + if ((mosi != NULL) && (miso != NULL)) { + for (uint j = 0; j < mosi_count; j++) { + if ((mcu_spi_mosi_list[i].pin != mosi) + || (mcu_spi_sck_list[i].bank_idx != mcu_spi_mosi_list[j].bank_idx)){ continue; - - if (mcu_spi_mosi_list[k].bank_idx != mcu_spi_miso_list[j].bank_idx) - continue; - - self->clock_pin = &mcu_spi_sck_list[i]; - self->miso_pin = &mcu_spi_miso_list[j]; - self->mosi_pin = &mcu_spi_mosi_list[k]; - + } + for (uint k = 0; k < miso_count; k++) { + if ((mcu_spi_miso_list[k].pin != miso) //everything needs the same index + || (mcu_spi_sck_list[i].bank_idx != mcu_spi_miso_list[k].bank_idx)) { + continue; + } + //keep looking if the SPI is taken, edge case + if (reserved_spi[mcu_spi_sck_list[i].bank_idx - 1]) { + spi_taken = true; + continue; + } + //store pins if not + self->clock = &mcu_spi_sck_list[i]; + self->mosi = &mcu_spi_mosi_list[j]; + self->miso = &mcu_spi_miso_list[k]; + break; + } + if (self->clock != NULL) { + break; // Multi-level break to pick lowest peripheral + } + } + if (self->clock != NULL) { break; } + // if just MISO, reduce search + } else if (miso != NULL) { + for (uint j = 0; j < miso_count; j++) { + if ((mcu_spi_miso_list[j].pin != miso) //only SCK and MISO need the same index + || (mcu_spi_sck_list[i].bank_idx != mcu_spi_miso_list[j].bank_idx)) { + continue; + } + if (reserved_spi[mcu_spi_sck_list[i].bank_idx - 1]) { + spi_taken = true; + continue; + } + self->clock = &mcu_spi_sck_list[i]; + self->mosi = NULL; + self->miso = &mcu_spi_miso_list[j]; + break; + } + if (self->clock != NULL) { + break; + } + // if just MOSI, reduce search + } else if (mosi != NULL) { + for (uint j = 0; j < mosi_count; j++) { + if ((mcu_spi_mosi_list[j].pin != mosi) //only SCK and MOSI need the same index + || (mcu_spi_sck_list[i].bank_idx != mcu_spi_mosi_list[j].bank_idx)) { + continue; + } + if (reserved_spi[mcu_spi_sck_list[i].bank_idx - 1]) { + spi_taken = true; + continue; + } + self->clock = &mcu_spi_sck_list[i]; + self->mosi = &mcu_spi_mosi_list[j]; + self->miso = NULL; + break; + } + if (self->clock != NULL) { + break; + } + } else { + //throw an error immediately + mp_raise_ValueError(translate("Must provide MISO or MOSI pin")); } } - if(self->clock_pin == NULL || self->mosi_pin == NULL || self->miso_pin == NULL) { - mp_raise_RuntimeError(translate("Invalid SPI pin selection")); + // for (uint32_t i = 0; i < sck_count; ++i) { + // if (mcu_spi_sck_list[i].pin != clock) + // continue; + + // for (uint32_t j = 0; j < miso_count; ++j) { + // if (mcu_spi_miso_list[j].pin != miso) + // continue; + + // if (mcu_spi_miso_list[j].bank_idx != mcu_spi_sck_list[i].bank_idx) + // continue; + + // for (uint32_t k = 0; k < mosi_count; ++k) { + // if (mcu_spi_mosi_list[k].pin != mosi) + // continue; + + // if (mcu_spi_mosi_list[k].bank_idx != mcu_spi_miso_list[j].bank_idx) + // continue; + + // self->clock = &mcu_spi_sck_list[i]; + // self->miso_pin = &mcu_spi_miso_list[j]; + // self->mosi_pin = &mcu_spi_mosi_list[k]; + + // break; + // } + // } + // } + + if (self->clock != NULL && (self->mosi != NULL || self->miso != NULL)) { + self->spi = mcu_spi_banks[self->clock->bank_idx - 1]; } else { - self->spi = mcu_spi_banks[self->clock_pin->bank_idx - 1]; + if (spi_taken) { + mp_raise_ValueError(translate("Hardware busy, try alternative pins")); + } else { + mp_raise_ValueError(translate("Invalid SPI pin selection")); + } } - config_periph_pin(self->mosi_pin); - config_periph_pin(self->miso_pin); - config_periph_pin(self->clock_pin); + config_periph_pin(self->clock); + if (self->mosi != NULL) { + config_periph_pin(self->mosi); + } + if (self->miso != NULL) { + config_periph_pin(self->miso); + } + reserved_spi[self->clock->bank_idx - 1] = true; lpspi_master_config_t config = { 0 }; LPSPI_MasterGetDefaultConfig(&config); @@ -150,47 +205,27 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, // Always start at 250khz which is what SD cards need. They are sensitive to // SPI bus noise before they are put into SPI mode. config.baudRate = 250000; - LPSPI_MasterInit(self->spi, &config, LPSPI_MASTER_CLK_FREQ); - LPSPI_Enable(self->spi, false); uint32_t tcrPrescaleValue; self->baudrate = LPSPI_MasterSetBaudRate(self->spi, config.baudRate, LPSPI_MASTER_CLK_FREQ, &tcrPrescaleValue); LPSPI_Enable(self->spi, true); - claim_pin(self->clock_pin->pin); - -// 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); -// self->MOSI_pin = mosi->number; - claim_pin(self->mosi_pin->pin); -// } - -// 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); -// self->MISO_pin = miso->number; - claim_pin(self->miso_pin->pin); -// } + claim_pin(self->clock->pin); + if (self->mosi != NULL) { + claim_pin(self->mosi->pin); + } + if (self->miso != NULL) { + claim_pin(self->miso->pin); + } } void common_hal_busio_spi_never_reset(busio_spi_obj_t *self) { -// never_reset_sercom(self->spi_desc.dev.prvt); - -// never_reset_pin_number(self->clock_pin); -// never_reset_pin_number(self->MOSI_pin); -// never_reset_pin_number(self->MISO_pin); + // TODO } bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) { - return self->clock_pin == NULL; + return self->clock == NULL; } void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { @@ -198,14 +233,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *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); - self->clock_pin = NULL; + self->clock = NULL; } bool common_hal_busio_spi_configure(busio_spi_obj_t *self, @@ -260,6 +288,9 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, if (len == 0) { return true; } + if (self->mosi == NULL) { + mp_raise_ValueError(translate("No MOSI Pin")); + } lpspi_transfer_t xfer = { 0 }; xfer.txData = (uint8_t*)data; @@ -278,6 +309,9 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, if (len == 0) { return true; } + if (self->miso == NULL) { + mp_raise_ValueError(translate("No MISO Pin")); + } LPSPI_SetDummyData(self->spi, write_value); @@ -296,6 +330,9 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin if (len == 0) { return true; } + if (self->miso == NULL || self->mosi == NULL) { + mp_raise_ValueError(translate("Missing MISO or MOSI Pin")); + } LPSPI_SetDummyData(self->spi, 0xFF); diff --git a/ports/mimxrt10xx/common-hal/busio/SPI.h b/ports/mimxrt10xx/common-hal/busio/SPI.h index 0895e1ddbc..f699cd7adf 100644 --- a/ports/mimxrt10xx/common-hal/busio/SPI.h +++ b/ports/mimxrt10xx/common-hal/busio/SPI.h @@ -38,9 +38,11 @@ typedef struct { LPSPI_Type *spi; bool has_lock; uint32_t baudrate; - const mcu_periph_obj_t *clock_pin; - const mcu_periph_obj_t *mosi_pin; - const mcu_periph_obj_t *miso_pin; + const mcu_periph_obj_t *clock; + const mcu_periph_obj_t *mosi; + const mcu_periph_obj_t *miso; } busio_spi_obj_t; +void spi_reset(void); + #endif // MICROPY_INCLUDED_MIMXRT10XX_COMMON_HAL_BUSIO_SPI_H diff --git a/ports/mimxrt10xx/supervisor/port.c b/ports/mimxrt10xx/supervisor/port.c index 7ba7a77011..527029951e 100644 --- a/ports/mimxrt10xx/supervisor/port.c +++ b/ports/mimxrt10xx/supervisor/port.c @@ -41,6 +41,7 @@ #include "common-hal/pulseio/PulseOut.h" #include "common-hal/pulseio/PWMOut.h" #include "common-hal/rtc/RTC.h" +#include "common-hal/busio/SPI.h" #include "reset.h" #include "tick.h" @@ -264,7 +265,7 @@ safe_mode_t port_init(void) { } void reset_port(void) { - //reset_sercoms(); + spi_reset(); #if CIRCUITPY_AUDIOIO audio_dma_reset();