Skip to content

Commit e00b326

Browse files
committed
use properly-sized SPI transactions
1 parent cde9b63 commit e00b326

File tree

5 files changed

+51
-79
lines changed

5 files changed

+51
-79
lines changed

ports/nrf/boards/common.template.ld

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ MEMORY
2222
/* SoftDevice 6.1.0 with 5 connections and various increases takes just under 64kiB.
2323
/* To measure the minimum required amount of memory for given configuration, set this number
2424
high enough to work and then check the mutation of the value done by sd_ble_enable. */
25-
SPIM3_RAM (rw) : ORIGIN = 0x20000000 + 64K, LENGTH = 8K
26-
RAM (xrw) : ORIGIN = 0x20000000 + 64K + 8K, LENGTH = 256K - 64K -8K
25+
SPIM3_RAM (rw) : ORIGIN = 0x20000000 + ${SOFTDEVICE_RAM_SIZE}, LENGTH = ${SPIM3_BUFFER_SIZE}
26+
RAM (xrw) : ORIGIN = 0x20000000 + ${SOFTDEVICE_RAM_SIZE} + ${SPIM3_BUFFER_SIZE}, LENGTH = 256K - ${SOFTDEVICE_RAM_SIZE} -${SPIM3_BUFFER_SIZE}
2727

2828
}
2929

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

Lines changed: 38 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -31,35 +31,35 @@
3131
#include "nrfx_spim.h"
3232
#include "nrf_gpio.h"
3333

34-
// These are in order from ighest available frequency to lowest (32MHz first, then 8MHz).
34+
// These are in order from highest available frequency to lowest (32MHz first, then 8MHz).
3535
STATIC spim_peripheral_t spim_peripherals[] = {
3636
#if NRFX_CHECK(NRFX_SPIM3_ENABLED)
3737
// SPIM3 exists only on nRF52840 and supports 32MHz max. All other SPIM's are only 8MHz max.
3838
// Allocate SPIM3 first.
3939
{ .spim = NRFX_SPIM_INSTANCE(3),
4040
.max_frequency = 32000000,
41-
.max_xfer_size = SPIM3_EASYDMA_MAXCNT_SIZE,
41+
.max_xfer_size = MIN(SPIM3_BUFFER_SIZE, (1UL << SPIM3_EASYDMA_MAXCNT_SIZE) - 1)
4242
},
4343
#endif
4444
#if NRFX_CHECK(NRFX_SPIM2_ENABLED)
4545
// SPIM2 is not shared with a TWIM, so allocate before the shared ones.
4646
{ .spim = NRFX_SPIM_INSTANCE(2),
4747
.max_frequency = 8000000,
48-
.max_xfer_size = SPIM2_EASYDMA_MAXCNT_SIZE,
48+
.max_xfer_size = (1UL << SPIM2_EASYDMA_MAXCNT_SIZE) - 1
4949
},
5050
#endif
5151
#if NRFX_CHECK(NRFX_SPIM1_ENABLED)
5252
// SPIM1 and TWIM1 share an address.
5353
{ .spim = NRFX_SPIM_INSTANCE(1),
5454
.max_frequency = 8000000,
55-
.max_xfer_size = SPIM1_EASYDMA_MAXCNT_SIZE,
55+
.max_xfer_size = (1UL << SPIM1_EASYDMA_MAXCNT_SIZE) - 1
5656
},
5757
#endif
5858
#if NRFX_CHECK(NRFX_SPIM0_ENABLED)
5959
// SPIM0 and TWIM0 share an address.
6060
{ .spim = NRFX_SPIM_INSTANCE(0),
6161
.max_frequency = 8000000,
62-
.max_xfer_size = SPIM0_EASYDMA_MAXCNT_SIZE,
62+
.max_xfer_size = (1UL << SPIM0_EASYDMA_MAXCNT_SIZE) - 1
6363
},
6464
#endif
6565
};
@@ -232,104 +232,66 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
232232
}
233233

234234
bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size_t len) {
235-
if (len == 0) {
236-
return true;
237-
}
238-
239235
const bool is_spim3 = self->spim_peripheral->spim.p_reg == NRF_SPIM3;
236+
uint8_t *next_chunk = (uint8_t *) data;
240237

241-
const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size;
242-
const uint32_t parts = len / max_xfer_size;
243-
const uint32_t remainder = len % max_xfer_size;
244-
245-
for (uint32_t i = 0; i < parts; ++i) {
246-
uint8_t *start = (uint8_t *) (data + i * max_xfer_size);
238+
while (len > 0) {
239+
size_t chunk_size = MIN(len, self->spim_peripheral->max_xfer_size);
240+
uint8_t *chunk = next_chunk;
247241
if (is_spim3) {
248242
// If SPIM3, copy into unused RAM block, and do DMA from there.
249-
memcpy(spim3_transmit_buffer, start, max_xfer_size);
250-
start = spim3_transmit_buffer;
243+
memcpy(spim3_transmit_buffer, chunk, chunk_size);
244+
chunk = spim3_transmit_buffer;
251245
}
252-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(start, max_xfer_size);
253-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
246+
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(chunk, chunk_size);
247+
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) {
254248
return false;
255-
}
256-
257-
if (remainder > 0) {
258-
uint8_t *start = (uint8_t *) (data + parts * max_xfer_size);
259-
if (is_spim3) {
260-
// If SPIM3, copy into unused RAM block, and do DMA from there.
261-
memcpy(spim3_transmit_buffer, start, remainder);
262-
start = spim3_transmit_buffer;
263249
}
264-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX(start, remainder);
265-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
266-
return false;
250+
next_chunk += chunk_size;
251+
len -= chunk_size;
267252
}
268-
269253
return true;
270254
}
271255

272256
bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len, uint8_t write_value) {
273-
if (len == 0) {
274-
return true;
275-
}
276-
277-
const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size;
278-
const uint32_t parts = len / max_xfer_size;
279-
const uint32_t remainder = len % max_xfer_size;
280-
281-
for (uint32_t i = 0; i < parts; ++i) {
282-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + i * max_xfer_size, max_xfer_size);
283-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
284-
return false;
285-
}
257+
uint8_t *next_chunk = data;
286258

287-
if (remainder > 0) {
288-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(data + parts * max_xfer_size, remainder);
289-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
259+
while (len > 0) {
260+
size_t chunk_size = MIN(len, self->spim_peripheral->max_xfer_size);
261+
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_RX(next_chunk, chunk_size);
262+
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) {
290263
return false;
264+
}
265+
next_chunk += chunk_size;
266+
len -= chunk_size;
291267
}
292-
293268
return true;
294269
}
295270

296271
bool common_hal_busio_spi_transfer(busio_spi_obj_t *self, uint8_t *data_out, uint8_t *data_in, size_t len) {
297-
if (len == 0) {
298-
return true;
299-
}
300-
301272
const bool is_spim3 = self->spim_peripheral->spim.p_reg == NRF_SPIM3;
273+
uint8_t *next_chunk_out = data_out;
274+
uint8_t *next_chunk_in = data_in;
302275

303-
const uint32_t max_xfer_size = self->spim_peripheral->max_xfer_size;
304-
const uint32_t parts = len / max_xfer_size;
305-
const uint32_t remainder = len % max_xfer_size;
306-
307-
for (uint32_t i = 0; i < parts; ++i) {
308-
uint8_t *out_start = (uint8_t *) (data_out + i * max_xfer_size);
276+
while (len > 0) {
277+
uint8_t *chunk_out = next_chunk_out;
278+
size_t chunk_size = MIN(len, self->spim_peripheral->max_xfer_size);
309279
if (is_spim3) {
310280
// If SPIM3, copy into unused RAM block, and do DMA from there.
311-
memcpy(spim3_transmit_buffer, out_start, max_xfer_size);
312-
out_start = spim3_transmit_buffer;
281+
memcpy(spim3_transmit_buffer, chunk_out, chunk_size);
282+
chunk_out = spim3_transmit_buffer;
313283
}
314-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(out_start, max_xfer_size,
315-
data_in + i * max_xfer_size, max_xfer_size);
316-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
284+
const nrfx_spim_xfer_desc_t xfer =
285+
NRFX_SPIM_SINGLE_XFER(next_chunk_out, chunk_size,
286+
next_chunk_in, chunk_size);
287+
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS) {
317288
return false;
318-
}
319-
320-
if (remainder > 0) {
321-
uint8_t *out_start = (uint8_t *) (data_out + parts * max_xfer_size);
322-
if (is_spim3) {
323-
// If SPIM3, copy into unused RAM block, and do DMA from there.
324-
memcpy(spim3_transmit_buffer, out_start, remainder);
325-
out_start = spim3_transmit_buffer;
326289
}
327-
const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(out_start, remainder,
328-
data_in + parts * max_xfer_size, remainder);
329-
if (nrfx_spim_xfer(&self->spim_peripheral->spim, &xfer, 0) != NRFX_SUCCESS)
330-
return false;
331-
}
332290

291+
next_chunk_out += chunk_size;
292+
next_chunk_in += chunk_size;
293+
len -= chunk_size;
294+
}
333295
return true;
334296
}
335297

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
typedef struct {
3434
nrfx_spim_t spim;
3535
uint32_t max_frequency;
36-
uint8_t max_xfer_size;
36+
uint32_t max_xfer_size;
3737
} spim_peripheral_t;
3838

3939
typedef struct {

ports/nrf/ld_defines.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,6 @@
3737

3838
/*BOOTLOADER_SETTINGS_START_ADDR=*/ BOOTLOADER_SETTINGS_START_ADDR;
3939
/*BOOTLOADER_SETTINGS_SIZE=*/ BOOTLOADER_SETTINGS_SIZE;
40+
41+
/*SOFTDEVICE_RAM_SIZE=*/ SOFTDEVICE_RAM_SIZE;
42+
/*SPIM3_BUFFER_SIZE=*/ SPIM3_BUFFER_SIZE;

ports/nrf/mpconfigport.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,16 @@
3434
#include "nrf_sdm.h" // for SD_FLASH_SIZE
3535
#include "peripherals/nrf/nvm.h" // for FLASH_PAGE_SIZE
3636

37+
// Max RAM used by SoftDevice. Can be changed when SoftDevice parameters are changed.
38+
// See common.template.ld.
39+
#define SOFTDEVICE_RAM_SIZE (64*1024)
40+
3741
#ifdef NRF52840
3842
#define MICROPY_PY_SYS_PLATFORM "nRF52840"
3943
#define FLASH_SIZE (0x100000) // 1MiB
44+
// Special RAM area for SPIM3 transmit buffer, to work around hardware bug.
45+
// See common.template.ld.
46+
#define SPIM3_BUFFER_SIZE (8192)
4047
#endif
4148

4249
#define MICROPY_PY_COLLECTIONS_ORDEREDDICT (1)

0 commit comments

Comments
 (0)