Skip to content

mimxrt10xx: add one-directional SPI #2841

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions ports/mimxrt10xx/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ endif

CFLAGS += $(INC) -Wall -Wno-cast-align -std=gnu11 -nostdlib $(BASE_CFLAGS) $(CFLAGS_MOD) $(COPT)

# TODO: add these when -Werror is applied
# Disable some warnings, as do most ports. NXP SDK causes undef, tinyusb causes cast-align
# CFLAGS += -Wno-undef -Wno-cast-align

CFLAGS += \
-mthumb \
-mapcs \
Expand Down
230 changes: 120 additions & 110 deletions ports/mimxrt10xx/common-hal/busio/SPI.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
* THE SOFTWARE.
*/

//TODO
#include "shared-bindings/busio/SPI.h"
#include "py/mperrno.h"
#include "py/runtime.h"
Expand All @@ -35,48 +34,12 @@

#include <stdio.h>

//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;
// }
//}

static void config_periph_pin(const mcu_periph_obj_t *periph) {
//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(
periph->pin->mux_reg, periph->mux_mode,
periph->input_reg, periph->input_idx,
Expand All @@ -97,115 +60,153 @@ 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 = 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);
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;

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)
}
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;

self->clock_pin = &mcu_spi_sck_list[i];
self->miso_pin = &mcu_spi_miso_list[j];
self->mosi_pin = &mcu_spi_mosi_list[k];

}
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"));
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);

// 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) {
if (common_hal_busio_spi_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);
self->clock_pin = NULL;
self->clock = NULL;
}

bool common_hal_busio_spi_configure(busio_spi_obj_t *self,
Expand Down Expand Up @@ -260,6 +261,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;
Expand All @@ -278,6 +282,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);

Expand All @@ -296,6 +303,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);

Expand Down
8 changes: 5 additions & 3 deletions ports/mimxrt10xx/common-hal/busio/SPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
3 changes: 2 additions & 1 deletion ports/mimxrt10xx/supervisor/port.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -264,7 +265,7 @@ safe_mode_t port_init(void) {
}

void reset_port(void) {
//reset_sercoms();
spi_reset();

#if CIRCUITPY_AUDIOIO
audio_dma_reset();
Expand Down