Skip to content

Commit 2f1e678

Browse files
committed
nrf: Rewrite the SPI common-hal using nrfx
Use SPIM2 on nRF52832 and SPIM3 on nRF52840. SPIM3 is able to go up to 32MHz!
1 parent c1924f3 commit 2f1e678

23 files changed

+515
-34836
lines changed

ports/nrf/Makefile

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,14 @@ INC += -I$(BUILD)
4343
INC += -I$(BUILD)/genhdr
4444
INC += -I./../../lib/cmsis/inc
4545
INC += -I./boards/$(BOARD)
46-
INC += -I./device
47-
INC += -I./device/$(MCU_VARIANT)
4846
INC += -I./hal
49-
INC += -I./hal/$(MCU_VARIANT)
5047
INC += -I./modules/ubluepy
5148
INC += -I./modules/random
5249
INC += -I./modules/ble
50+
INC += -I./nrfx
51+
INC += -I./nrfx/hal
52+
INC += -I./nrfx/mdk
53+
INC += -I./nrfx/drivers/include
5354
INC += -I../../lib/mp-readline
5455
INC += -I./drivers/bluetooth
5556
INC += -I./drivers
@@ -91,8 +92,6 @@ LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lgcc
9192
SRC_HAL = $(addprefix hal/,\
9293
hal_uart.c \
9394
hal_uarte.c \
94-
hal_spi.c \
95-
hal_spie.c \
9695
hal_time.c \
9796
hal_timer.c \
9897
hal_twi.c \
@@ -104,6 +103,10 @@ SRC_HAL = $(addprefix hal/,\
104103
hal_pwm.c \
105104
)
106105

106+
SRC_NRFX = $(addprefix nrfx/,\
107+
drivers/src/nrfx_spim.c \
108+
)
109+
107110
SRC_C += \
108111
mphalport.c \
109112
help.c \
@@ -219,6 +222,7 @@ FROZEN_MPY_MPY_FILES := $(addprefix $(BUILD)/,$(FROZEN_MPY_PY_FILES:.py=.mpy))
219222
OBJ += $(PY_O) $(SUPERVISOR_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
220223
OBJ += $(BUILD)/pins_gen.o
221224
OBJ += $(addprefix $(BUILD)/, $(SRC_HAL:.c=.o))
225+
OBJ += $(addprefix $(BUILD)/, $(SRC_NRFX:.c=.o))
222226
OBJ += $(addprefix $(BUILD)/, $(DRIVERS_SRC_C:.c=.o))
223227
OBJ += $(addprefix $(BUILD)/, $(SRC_COMMON_HAL_EXPANDED:.c=.o))
224228
OBJ += $(addprefix $(BUILD)/, $(SRC_SHARED_MODULE_EXPANDED:.c=.o))

ports/nrf/common-hal/busio/SPI.c

Lines changed: 110 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Copyright (c) 2015 Arduino LLC
44
* Copyright (c) 2016 Sandeep Mistry All right reserved.
55
* Copyright (c) 2017 hathach
6+
* Copyright (c) 2018 Artur Pacholec
67
*
78
* This library is free software; you can redistribute it and/or
89
* modify it under the terms of the GNU Lesser General Public
@@ -19,94 +20,111 @@
1920
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2021
*/
2122

22-
2323
#include "shared-bindings/busio/SPI.h"
2424
#include "py/mperrno.h"
2525
#include "py/runtime.h"
2626

27-
#include "nrf.h"
28-
#include "pins.h"
29-
30-
// Convert frequency to clock-speed-dependent value. Return 0 if out of range.
31-
static uint32_t baudrate_to_reg(const uint32_t baudrate) {
32-
uint32_t value;
33-
34-
if (baudrate <= 125000) {
35-
value = SPI_FREQUENCY_FREQUENCY_K125;
36-
} else if (baudrate <= 250000) {
37-
value = SPI_FREQUENCY_FREQUENCY_K250;
38-
} else if (baudrate <= 500000) {
39-
value = SPI_FREQUENCY_FREQUENCY_K500;
40-
} else if (baudrate <= 1000000) {
41-
value = SPI_FREQUENCY_FREQUENCY_M1;
42-
} else if (baudrate <= 2000000) {
43-
value = SPI_FREQUENCY_FREQUENCY_M2;
44-
} else if (baudrate <= 4000000) {
45-
value = SPI_FREQUENCY_FREQUENCY_M4;
46-
} else {
47-
value = SPI_FREQUENCY_FREQUENCY_M8;
48-
}
27+
#include "nrfx_spim.h"
28+
#include "nrf_gpio.h"
29+
30+
#if NRFX_SPIM3_ENABLED
31+
#define INST_NO 3
32+
#else
33+
#define INST_NO 2
34+
#endif
35+
36+
// Convert frequency to clock-speed-dependent value
37+
static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate) {
38+
if (baudrate <= 125000)
39+
return NRF_SPIM_FREQ_125K;
40+
41+
if (baudrate <= 250000)
42+
return NRF_SPIM_FREQ_250K;
43+
44+
if (baudrate <= 500000)
45+
return NRF_SPIM_FREQ_500K;
46+
47+
if (baudrate <= 1000000)
48+
return NRF_SPIM_FREQ_1M;
49+
50+
if (baudrate <= 2000000)
51+
return NRF_SPIM_FREQ_2M;
52+
53+
if (baudrate <= 4000000)
54+
return NRF_SPIM_FREQ_4M;
55+
56+
if (baudrate <= 8000000)
57+
return NRF_SPIM_FREQ_8M;
58+
59+
#ifdef SPIM_FREQUENCY_FREQUENCY_M16
60+
if (baudrate <= 16000000)
61+
return NRF_SPIM_FREQ_16M;
62+
#endif
4963

50-
return value;
64+
#ifdef SPIM_FREQUENCY_FREQUENCY_M32
65+
return NRF_SPIM_FREQ_32M;
66+
#else
67+
return NRF_SPIM_FREQ_8M;
68+
#endif
5169
}
5270

5371
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) {
72+
const nrfx_spim_t instance = NRFX_SPIM_INSTANCE(INST_NO);
73+
self->spim = instance;
5474

55-
// 1 for I2C, 0 for SPI
56-
self->spi = NRF_SPI0;
75+
nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG;
76+
config.frequency = NRF_SPIM_FREQ_8M;
5777

58-
self->spi->PSELSCK = clock->pin;
59-
self->spi->PSELMOSI = mosi->pin;
60-
self->spi->PSELMISO = miso->pin;
78+
config.sck_pin = NRF_GPIO_PIN_MAP(clock->port, clock->pin);
6179

80+
if (mosi != (mcu_pin_obj_t*)&mp_const_none_obj)
81+
config.mosi_pin = NRF_GPIO_PIN_MAP(mosi->port, mosi->pin);
6282

63-
#if NRF52840_XXAA
64-
self->spi->PSELSCK |= (clock->port << SPI_PSEL_SCK_PORT_Pos);
65-
self->spi->PSELMOSI |= (mosi->port << SPI_PSEL_MOSI_PORT_Pos);
66-
self->spi->PSELMISO |= (miso->port << SPI_PSEL_MISO_PORT_Pos);
67-
#endif
83+
if (miso != (mcu_pin_obj_t*)&mp_const_none_obj)
84+
config.miso_pin = NRF_GPIO_PIN_MAP(miso->port, miso->pin);
85+
86+
nrfx_err_t err = nrfx_spim_init(&self->spim, &config, NULL, NULL);
87+
88+
// A soft reset doesn't uninit the driver so we might end up with a invalid state
89+
if (err == NRFX_ERROR_INVALID_STATE) {
90+
nrfx_spim_uninit(&self->spim);
91+
err = nrfx_spim_init(&self->spim, &config, NULL, NULL);
92+
}
93+
94+
if (err != NRFX_SUCCESS)
95+
mp_raise_OSError(MP_EIO);
96+
97+
self->inited = true;
6898
}
6999

70100
bool common_hal_busio_spi_deinited(busio_spi_obj_t *self) {
71-
return self->spi == NULL;
101+
return !self->inited;
72102
}
73103

74104
void common_hal_busio_spi_deinit(busio_spi_obj_t *self) {
75-
if (common_hal_busio_spi_deinited(self)) {
105+
if (common_hal_busio_spi_deinited(self))
76106
return;
77-
}
78107

79-
#ifdef NRF52840_XXAA
80-
self->spi->PSEL.SCK = SPI_PSEL_SCK_CONNECT_Disconnected;
81-
self->spi->PSEL.MOSI = SPI_PSEL_MOSI_CONNECT_Disconnected;
82-
self->spi->PSEL.MISO = SPI_PSEL_MISO_CONNECT_Disconnected;
83-
#else
84-
self->spi->PSELSCK = SPI_PSEL_SCK_PSELSCK_Disconnected;
85-
self->spi->PSELMOSI = SPI_PSEL_MOSI_PSELMOSI_Disconnected;
86-
self->spi->PSELMISO = SPI_PSEL_MISO_PSELMISO_Disconnected;
87-
#endif
88-
// reset_pin(self->clock_pin);
89-
// reset_pin(self->MOSI_pin);
90-
// reset_pin(self->MISO_pin);
108+
nrfx_spim_uninit(&self->spim);
91109

92-
self->spi = NULL;
110+
self->inited = false;
93111
}
94112

95113
bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, uint8_t polarity, uint8_t phase, uint8_t bits) {
96114
// nrf52 does not support 16 bit
97-
if ( bits != 8 ) return false;
98-
99-
self->spi->ENABLE = (SPI_ENABLE_ENABLE_Disabled << SPI_ENABLE_ENABLE_Pos);
115+
if (bits != 8)
116+
return false;
100117

101-
uint32_t config = (SPI_CONFIG_ORDER_MsbFirst << SPI_CONFIG_ORDER_Pos);
118+
nrf_spim_frequency_set(self->spim.p_reg, baudrate_to_spim_frequency(baudrate));
102119

103-
config |= ((polarity ? SPI_CONFIG_CPOL_ActiveLow : SPI_CONFIG_CPOL_ActiveHigh) << SPI_CONFIG_CPOL_Pos);
104-
config |= ((phase ? SPI_CONFIG_CPHA_Trailing : SPI_CONFIG_CPHA_Leading ) << SPI_CONFIG_CPHA_Pos);
105-
106-
self->spi->CONFIG = config;
107-
self->spi->FREQUENCY = baudrate_to_reg(baudrate);
120+
nrf_spim_mode_t mode = NRF_SPIM_MODE_0;
121+
if (polarity) {
122+
mode = (phase) ? NRF_SPIM_MODE_3 : NRF_SPIM_MODE_2;
123+
} else {
124+
mode = (phase) ? NRF_SPIM_MODE_1 : NRF_SPIM_MODE_0;
125+
}
108126

109-
self->spi->ENABLE = (SPI_ENABLE_ENABLE_Enabled << SPI_ENABLE_ENABLE_Pos);
127+
nrf_spim_configure(self->spim.p_reg, mode, NRF_SPIM_BIT_ORDER_MSB_FIRST);
110128

111129
return true;
112130
}
@@ -131,87 +149,59 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
131149
}
132150

133151
bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) {
134-
if (len == 0) {
135-
return true;
136-
}
137-
138-
while (len)
139-
{
140-
self->spi->TXD = *data;
152+
if (len == 0)
153+
return true;
141154

142-
while(!self->spi->EVENTS_READY);
143-
144-
(void) self->spi->RXD;
145-
data++;
146-
len--;
147-
148-
self->spi->EVENTS_READY = 0x0UL;
149-
}
155+
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(data, len);
156+
const nrfx_err_t err = nrfx_spim_xfer(&self->spim, &xfer, 0);
150157

151-
return true;
158+
return (err == NRFX_SUCCESS);
152159
}
153160

154161
bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) {
155-
if (len == 0) {
156-
return true;
157-
}
158-
159-
while (len)
160-
{
161-
self->spi->TXD = write_value;
162+
if (len == 0)
163+
return true;
162164

163-
while(!self->spi->EVENTS_READY);
165+
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data, len);
166+
const nrfx_err_t err = nrfx_spim_xfer(&self->spim, &xfer, 0);
164167

165-
*data = self->spi->RXD;
166-
167-
data++;
168-
len--;
169-
170-
self->spi->EVENTS_READY = 0x0UL;
171-
}
172-
173-
return true;
168+
return (err == NRFX_SUCCESS);
174169
}
175170

176171
bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) {
177-
if (len == 0) {
178-
return true;
179-
}
180-
181-
while (len)
182-
{
183-
self->spi->TXD = *data_out;
184-
185-
while(!self->spi->EVENTS_READY);
186-
187-
*data_in = self->spi->RXD;
172+
if (len == 0)
173+
return true;
188174

189-
data_out++;
190-
data_in++;
191-
len--;
175+
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(data_out, len, data_in, len);
176+
const nrfx_err_t err = nrfx_spim_xfer(&self->spim, &xfer, 0);
192177

193-
self->spi->EVENTS_READY = 0x0UL;
194-
}
195-
196-
return true;
178+
return (err == NRFX_SUCCESS);
197179
}
198-
180+
199181
uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) {
200-
switch (self->spi->FREQUENCY) {
201-
case SPI_FREQUENCY_FREQUENCY_K125:
182+
switch (self->spim.p_reg->FREQUENCY) {
183+
case NRF_SPIM_FREQ_125K:
202184
return 125000;
203-
case SPI_FREQUENCY_FREQUENCY_K250:
185+
case NRF_SPIM_FREQ_250K:
204186
return 250000;
205-
case SPI_FREQUENCY_FREQUENCY_K500:
187+
case NRF_SPIM_FREQ_500K:
206188
return 500000;
207-
case SPI_FREQUENCY_FREQUENCY_M1:
189+
case NRF_SPIM_FREQ_1M:
208190
return 1000000;
209-
case SPI_FREQUENCY_FREQUENCY_M2:
191+
case NRF_SPIM_FREQ_2M:
210192
return 2000000;
211-
case SPI_FREQUENCY_FREQUENCY_M4:
193+
case NRF_SPIM_FREQ_4M:
212194
return 4000000;
213-
case SPI_FREQUENCY_FREQUENCY_M8:
195+
case NRF_SPIM_FREQ_8M:
214196
return 8000000;
197+
#ifdef SPIM_FREQUENCY_FREQUENCY_M16
198+
case NRF_SPIM_FREQ_16M:
199+
return 16000000;
200+
#endif
201+
#ifdef SPIM_FREQUENCY_FREQUENCY_M32
202+
case NRF_SPIM_FREQ_32M:
203+
return 32000000;
204+
#endif
215205
default:
216206
return 0;
217207
}

ports/nrf/common-hal/busio/SPI.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,13 @@
2727
#ifndef MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H
2828
#define MICROPY_INCLUDED_NRF_COMMON_HAL_BUSIO_SPI_H
2929

30-
#include "common-hal/microcontroller/Pin.h"
31-
32-
//#include "hal/include/hal_spi_m_sync.h"
33-
30+
#include "nrfx_spim.h"
3431
#include "py/obj.h"
3532

3633
typedef struct {
3734
mp_obj_base_t base;
38-
NRF_SPI_Type *spi;
35+
nrfx_spim_t spim;
36+
bool inited;
3937
bool has_lock;
4038
} busio_spi_obj_t;
4139

0 commit comments

Comments
 (0)