From 2309e60c0d9867c99ac2635f7ff698e7114e314d Mon Sep 17 00:00:00 2001 From: Dan Halbert Date: Wed, 19 Sep 2018 21:59:04 -0400 Subject: [PATCH] WIP; problem with staticly allocated IRQ handlers --- ports/nrf/common-hal/busio/SPI.c | 143 ++++++++++++++++++++----------- ports/nrf/common-hal/busio/SPI.h | 8 +- ports/nrf/nrfx_config.h | 9 +- 3 files changed, 106 insertions(+), 54 deletions(-) diff --git a/ports/nrf/common-hal/busio/SPI.c b/ports/nrf/common-hal/busio/SPI.c index e2d6a0daa1..21f80ff101 100644 --- a/ports/nrf/common-hal/busio/SPI.c +++ b/ports/nrf/common-hal/busio/SPI.c @@ -27,40 +27,65 @@ #include "nrfx_spim.h" #include "nrf_gpio.h" -#if NRFX_SPIM3_ENABLED - #define INST_NO 3 -#else - #define INST_NO 2 +STATIC spim_peripheral_t spim_peripherals[] = { +#if NRFX_CHECK(NRFX_SPIM3_ENABLED) + // SPIM3 exists only on nRF52840 and supports 32MHz max. All other SPIM's are only 8MHz max. + // Allocate SPIM3 first. + { .spim = NRFX_SPIM_INSTANCE(3), + .max_frequency_MHz = 32, + .max_xfer_size = SPIM3_EASYDMA_MAXCNT_SIZE, + }, #endif - -#define MAX_XFER_SIZE ((1U << NRFX_CONCAT_3(SPIM, INST_NO, _EASYDMA_MAXCNT_SIZE)) - 1) +#if NRFX_CHECK(NRFX_SPIM2_ENABLED) + // SPIM2 is not shared with a TWIM, so allocate before the shared ones. + { .spim = NRFX_SPIM_INSTANCE(2), + .max_frequency_MHz = 8, + .max_xfer_size = SPIM2_EASYDMA_MAXCNT_SIZE, + }, +#endif +#if NRFX_CHECK(NRFX_SPIM1_ENABLED) + // SPIM1 and TWIM1 share an address. + { .spim = NRFX_SPIM_INSTANCE(1), + .max_frequency_MHz = 8, + .max_xfer_size = SPIM1_EASYDMA_MAXCNT_SIZE, + }, +#endif +#if NRFX_CHECK(NRFX_SPIM0_ENABLED) + // SPIM0 and TWIM0 share an address. + { .spim = NRFX_SPIM_INSTANCE(0), + .max_frequency_MHz = 8, + .max_xfer_size = SPIM0_EASYDMA_MAXCNT_SIZE, + }, +#endif +}; // Convert frequency to clock-speed-dependent value static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) { - if (baudrate <= 125000) + if (baudrate <= 125000) { return NRF_SPIM_FREQ_125K; - - if (baudrate <= 250000) + } + if (baudrate <= 250000) { return NRF_SPIM_FREQ_250K; - - if (baudrate <= 500000) + } + if (baudrate <= 500000) { return NRF_SPIM_FREQ_500K; - - if (baudrate <= 1000000) + } + if (baudrate <= 1000000) { return NRF_SPIM_FREQ_1M; - - if (baudrate <= 2000000) + } + if (baudrate <= 2000000) { return NRF_SPIM_FREQ_2M; - - if (baudrate <= 4000000) + } + if (baudrate <= 4000000) { return NRF_SPIM_FREQ_4M; - - if (baudrate <= 8000000) + } + if (baudrate <= 8000000) { return NRF_SPIM_FREQ_8M; - + } #ifdef SPIM_FREQUENCY_FREQUENCY_M16 - if (baudrate <= 16000000) + if (baudrate <= 16000000) { return NRF_SPIM_FREQ_16M; + } #endif #ifdef SPIM_FREQUENCY_FREQUENCY_M32 @@ -71,8 +96,18 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) } 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 nrfx_spim_t instance = NRFX_SPIM_INSTANCE(INST_NO); - self->spim = instance; + // Find a free instance. + self->spim_peripheral = NULL; + for (size_t i = 0 ; i < MP_ARRAY_SIZE(spim_peripherals); i++) { + if ((spim_peripherals[i].spim.p_reg->ENABLE & SPIM_ENABLE_ENABLE_Msk) == 0) { + self->spim_peripheral = &spim_peripherals[i]; + break; + } + } + + if (self->spim_peripheral == NULL) { + mp_raise_ValueError(translate("All SPI peripherals are in use")); + } nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG; config.frequency = NRF_SPIM_FREQ_8M; @@ -97,12 +132,12 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t * self->MISO_pin_number = NO_PIN; } - nrfx_err_t err = nrfx_spim_init(&self->spim, &config, NULL, NULL); + nrfx_err_t err = nrfx_spim_init(&self->spim_peripheral->spim, &config, NULL, NULL); // A soft reset doesn't uninit the driver so we might end up with a invalid state if (err == NRFX_ERROR_INVALID_STATE) { - nrfx_spim_uninit(&self->spim); - err = nrfx_spim_init(&self->spim, &config, NULL, NULL); + nrfx_spim_uninit(&self->spim_peripheral->spim); + err = nrfx_spim_init(&self->spim_peripheral->spim, &config, NULL, NULL); } if (err != NRFX_SUCCESS) { @@ -119,7 +154,7 @@ void common_hal_busio_spi_deinit(busio_spi_obj_t *self) { if (common_hal_busio_spi_deinited(self)) return; - nrfx_spim_uninit(&self->spim); + nrfx_spim_uninit(&self->spim_peripheral->spim); reset_pin_number(self->clock_pin_number); reset_pin_number(self->MOSI_pin_number); @@ -131,7 +166,11 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, ui if (bits != 8) return false; - nrf_spim_frequency_set(self->spim.p_reg, baudrate_to_spim_frequency(baudrate)); + if (baudrate > self->spim_peripheral->max_frequency_MHz * 1000000) { + mp_raise_ValueError(translate("Baud rate too high for this SPI peripheral")); + return false; + } + nrf_spim_frequency_set(self->spim_peripheral->spim.p_reg, baudrate_to_spim_frequency(baudrate)); nrf_spim_mode_t mode = NRF_SPIM_MODE_0; if (polarity) { @@ -140,7 +179,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, ui mode = (phase) ? NRF_SPIM_MODE_1 : NRF_SPIM_MODE_0; } - nrf_spim_configure(self->spim.p_reg, mode, NRF_SPIM_BIT_ORDER_MSB_FIRST); + nrf_spim_configure(self->spim_peripheral->spim.p_reg, mode, NRF_SPIM_BIT_ORDER_MSB_FIRST); return true; } @@ -168,18 +207,19 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size if (len == 0) return true; - const uint32_t parts = len / MAX_XFER_SIZE; - const uint32_t remainder = len % MAX_XFER_SIZE; + const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size; + const uint32_t parts = len / max_xfer_size; + const uint32_t remainder = len % max_xfer_size; for (uint32_t i = 0; i < parts; ++i) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(data + i * MAX_XFER_SIZE, MAX_XFER_SIZE); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(data + i * max_xfer_size, max_xfer_size); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } if (remainder > 0) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(data + parts * MAX_XFER_SIZE, remainder); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(data + parts * max_xfer_size, remainder); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } @@ -190,18 +230,19 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, if (len == 0) return true; - const uint32_t parts = len / MAX_XFER_SIZE; - const uint32_t remainder = len % MAX_XFER_SIZE; + const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size; + const uint32_t parts = len / max_xfer_size; + const uint32_t remainder = len % max_xfer_size; for (uint32_t i = 0; i < parts; ++i) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + i * MAX_XFER_SIZE, MAX_XFER_SIZE); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + i * max_xfer_size, max_xfer_size); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } if (remainder > 0) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + parts * MAX_XFER_SIZE, remainder); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + parts * max_xfer_size, remainder); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } @@ -212,20 +253,22 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin if (len == 0) return true; - const uint32_t parts = len / MAX_XFER_SIZE; - const uint32_t remainder = len % MAX_XFER_SIZE; + + const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size; + const uint32_t parts = len / max_xfer_size; + const uint32_t remainder = len % max_xfer_size; for (uint32_t i = 0; i < parts; ++i) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(data_out + i * MAX_XFER_SIZE, MAX_XFER_SIZE, - data_in + i * MAX_XFER_SIZE, MAX_XFER_SIZE); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(data_out + i * max_xfer_size, max_xfer_size, + data_in + i * max_xfer_size, max_xfer_size); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } if (remainder > 0) { - const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(data_out + parts * MAX_XFER_SIZE, remainder, - data_in + parts * MAX_XFER_SIZE, remainder); - if (nrfx_spim_xfer(&self->spim, &xfer, 0) != NRFX_SUCCESS) + const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(data_out + parts * max_xfer_size, remainder, + data_in + parts * max_xfer_size, remainder); + if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) return false; } @@ -233,7 +276,7 @@ bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uin } uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) { - switch (self->spim.p_reg->FREQUENCY) { + switch (self->spim_peripheral->spim.p_reg->FREQUENCY) { case NRF_SPIM_FREQ_125K: return 125000; case NRF_SPIM_FREQ_250K: diff --git a/ports/nrf/common-hal/busio/SPI.h b/ports/nrf/common-hal/busio/SPI.h index 8b637b4a5e..c05fb1e18f 100644 --- a/ports/nrf/common-hal/busio/SPI.h +++ b/ports/nrf/common-hal/busio/SPI.h @@ -31,8 +31,14 @@ #include "py/obj.h" typedef struct { - mp_obj_base_t base; nrfx_spim_t spim; + uint8_t max_frequency_MHz; + uint8_t max_xfer_size; +} spim_peripheral_t; + +typedef struct { + mp_obj_base_t base; + spim_peripheral_t* spim_peripheral; bool has_lock; uint8_t clock_pin_number; uint8_t MOSI_pin_number; diff --git a/ports/nrf/nrfx_config.h b/ports/nrf/nrfx_config.h index fb603a896d..36f2665a51 100644 --- a/ports/nrf/nrfx_config.h +++ b/ports/nrf/nrfx_config.h @@ -8,18 +8,21 @@ // SPI #define NRFX_SPIM_ENABLED 1 +#define NRFX_SPIM0_ENABLED 1 +#define NRFX_SPIM1_ENABLED 1 +#define NRFX_SPIM2_ENABLED 1 #ifdef NRF52840_XXAA #define NRFX_SPIM3_ENABLED 1 -#else - #define NRFX_SPIM2_ENABLED 1 #endif + #define NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY 7 #define NRFX_SPIM_MISO_PULL_CFG 1 // TWI aka. I2C #define NRFX_TWIM_ENABLED 1 #define NRFX_TWIM0_ENABLED 1 +#define NRFX_TWIM1_ENABLED 1 #define NRFX_TWIM_DEFAULT_CONFIG_IRQ_PRIORITY 7 #define NRFX_TWIM_DEFAULT_CONFIG_FREQUENCY NRF_TWIM_FREQ_400K @@ -45,4 +48,4 @@ #define NRFX_PWM3_ENABLED 0 #endif -#endif +#endif // NRFX_CONFIG_H__