22
22
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
23
*/
24
24
25
+ #include <string.h>
26
+
25
27
#include "shared-bindings/busio/SPI.h"
26
28
#include "py/mperrno.h"
27
29
#include "py/runtime.h"
28
30
29
31
#include "nrfx_spim.h"
30
32
#include "nrf_gpio.h"
31
33
34
+ // These are in order from ighest available frequency to lowest (32MHz first, then 8MHz).
32
35
STATIC spim_peripheral_t spim_peripherals [] = {
33
36
#if NRFX_CHECK (NRFX_SPIM3_ENABLED )
34
37
// SPIM3 exists only on nRF52840 and supports 32MHz max. All other SPIM's are only 8MHz max.
35
38
// Allocate SPIM3 first.
36
39
{ .spim = NRFX_SPIM_INSTANCE (3 ),
37
- .max_frequency_MHz = 32 ,
40
+ .max_frequency = 32000000 ,
38
41
.max_xfer_size = SPIM3_EASYDMA_MAXCNT_SIZE ,
39
42
},
40
43
#endif
41
44
#if NRFX_CHECK (NRFX_SPIM2_ENABLED )
42
45
// SPIM2 is not shared with a TWIM, so allocate before the shared ones.
43
46
{ .spim = NRFX_SPIM_INSTANCE (2 ),
44
- .max_frequency_MHz = 8 ,
47
+ .max_frequency = 8000000 ,
45
48
.max_xfer_size = SPIM2_EASYDMA_MAXCNT_SIZE ,
46
49
},
47
50
#endif
48
51
#if NRFX_CHECK (NRFX_SPIM1_ENABLED )
49
52
// SPIM1 and TWIM1 share an address.
50
53
{ .spim = NRFX_SPIM_INSTANCE (1 ),
51
- .max_frequency_MHz = 8 ,
54
+ .max_frequency = 8000000 ,
52
55
.max_xfer_size = SPIM1_EASYDMA_MAXCNT_SIZE ,
53
56
},
54
57
#endif
55
58
#if NRFX_CHECK (NRFX_SPIM0_ENABLED )
56
59
// SPIM0 and TWIM0 share an address.
57
60
{ .spim = NRFX_SPIM_INSTANCE (0 ),
58
- .max_frequency_MHz = 8 ,
61
+ .max_frequency = 8000000 ,
59
62
.max_xfer_size = SPIM0_EASYDMA_MAXCNT_SIZE ,
60
63
},
61
64
#endif
62
65
};
63
66
64
67
STATIC bool never_reset [MP_ARRAY_SIZE (spim_peripherals )];
65
68
69
+ // Separate RAM area for SPIM3 transmit buffer to avoid SPIM3 hardware errata.
70
+ // https://infocenter.nordicsemi.com/index.jsp?topic=%2Ferrata_nRF52840_Rev2%2FERR%2FnRF52840%2FRev2%2Flatest%2Fanomaly_840_198.html
71
+ extern uint32_t _spim3_ram ;
72
+ STATIC uint8_t * spim3_transmit_buffer = (uint8_t * ) & _spim3_ram ;
73
+
66
74
void spi_reset (void ) {
67
75
for (size_t i = 0 ; i < MP_ARRAY_SIZE (spim_peripherals ); i ++ ) {
68
76
if (never_reset [i ]) {
@@ -122,7 +130,7 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate)
122
130
}
123
131
124
132
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 ) {
125
- // Find a free instance.
133
+ // Find a free instance, with most desirable (highest freq and not shared) allocated first .
126
134
self -> spim_peripheral = NULL ;
127
135
for (size_t i = 0 ; i < MP_ARRAY_SIZE (spim_peripherals ); i ++ ) {
128
136
if ((spim_peripherals [i ].spim .p_reg -> ENABLE & SPIM_ENABLE_ENABLE_Msk ) == 0 ) {
@@ -137,7 +145,8 @@ void common_hal_busio_spi_construct(busio_spi_obj_t *self, const mcu_pin_obj_t *
137
145
138
146
nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG (NRFX_SPIM_PIN_NOT_USED , NRFX_SPIM_PIN_NOT_USED ,
139
147
NRFX_SPIM_PIN_NOT_USED , NRFX_SPIM_PIN_NOT_USED );
140
- config .frequency = NRF_SPIM_FREQ_8M ;
148
+
149
+ config .frequency = baudrate_to_spim_frequency (self -> spim_peripheral -> max_frequency );
141
150
142
151
config .sck_pin = clock -> number ;
143
152
self -> clock_pin_number = clock -> number ;
@@ -189,8 +198,7 @@ bool common_hal_busio_spi_configure(busio_spi_obj_t *self, uint32_t baudrate, ui
189
198
190
199
// Set desired frequency, rounding down, and don't go above available frequency for this SPIM.
191
200
nrf_spim_frequency_set (self -> spim_peripheral -> spim .p_reg ,
192
- baudrate_to_spim_frequency (MIN (baudrate ,
193
- self -> spim_peripheral -> max_frequency_MHz * 1000000 )));
201
+ baudrate_to_spim_frequency (MIN (baudrate , self -> spim_peripheral -> max_frequency )));
194
202
195
203
nrf_spim_mode_t mode = NRF_SPIM_MODE_0 ;
196
204
if (polarity ) {
@@ -224,21 +232,36 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
224
232
}
225
233
226
234
bool common_hal_busio_spi_write (busio_spi_obj_t * self , const uint8_t * data , size_t len ) {
227
- if (len == 0 )
235
+ if (len == 0 ) {
228
236
return true;
237
+ }
238
+
239
+ const bool is_spim3 = self -> spim_peripheral -> spim .p_reg == NRF_SPIM3 ;
229
240
230
241
const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
231
242
const uint32_t parts = len / max_xfer_size ;
232
243
const uint32_t remainder = len % max_xfer_size ;
233
244
234
245
for (uint32_t i = 0 ; i < parts ; ++ i ) {
235
- const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX (data + i * max_xfer_size , max_xfer_size );
246
+ uint8_t * start = (uint8_t * ) (data + i * max_xfer_size );
247
+ if (is_spim3 ) {
248
+ // 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 ;
251
+ }
252
+ const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX (start , max_xfer_size );
236
253
if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
237
254
return false;
238
255
}
239
256
240
257
if (remainder > 0 ) {
241
- const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX (data + parts * max_xfer_size , remainder );
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 ;
263
+ }
264
+ const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_XFER_TX (start , remainder );
242
265
if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
243
266
return false;
244
267
}
@@ -247,8 +270,9 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size
247
270
}
248
271
249
272
bool common_hal_busio_spi_read (busio_spi_obj_t * self , uint8_t * data , size_t len , uint8_t write_value ) {
250
- if (len == 0 )
273
+ if (len == 0 ) {
251
274
return true;
275
+ }
252
276
253
277
const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
254
278
const uint32_t parts = len / max_xfer_size ;
@@ -270,23 +294,37 @@ bool common_hal_busio_spi_read(busio_spi_obj_t *self, uint8_t *data, size_t len,
270
294
}
271
295
272
296
bool common_hal_busio_spi_transfer (busio_spi_obj_t * self , uint8_t * data_out , uint8_t * data_in , size_t len ) {
273
- if (len == 0 )
297
+ if (len == 0 ) {
274
298
return true;
299
+ }
275
300
301
+ const bool is_spim3 = self -> spim_peripheral -> spim .p_reg == NRF_SPIM3 ;
276
302
277
303
const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
278
304
const uint32_t parts = len / max_xfer_size ;
279
305
const uint32_t remainder = len % max_xfer_size ;
280
306
281
307
for (uint32_t i = 0 ; i < parts ; ++ i ) {
282
- const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER (data_out + i * max_xfer_size , max_xfer_size ,
308
+ uint8_t * out_start = (uint8_t * ) (data_out + i * max_xfer_size );
309
+ if (is_spim3 ) {
310
+ // 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 ;
313
+ }
314
+ const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER (out_start , max_xfer_size ,
283
315
data_in + i * max_xfer_size , max_xfer_size );
284
316
if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
285
317
return false;
286
318
}
287
319
288
320
if (remainder > 0 ) {
289
- const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER (data_out + parts * max_xfer_size , remainder ,
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 ;
326
+ }
327
+ const nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER (out_start , remainder ,
290
328
data_in + parts * max_xfer_size , remainder );
291
329
if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
292
330
return false;
@@ -325,9 +363,9 @@ uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) {
325
363
}
326
364
327
365
uint8_t common_hal_busio_spi_get_phase (busio_spi_obj_t * self ) {
328
- return 0 ;
366
+ return ( self -> spim_peripheral -> spim . p_reg -> CONFIG & SPIM_CONFIG_CPHA_Msk ) >> SPIM_CONFIG_CPHA_Pos ;
329
367
}
330
368
331
369
uint8_t common_hal_busio_spi_get_polarity (busio_spi_obj_t * self ) {
332
- return 0 ;
370
+ return ( self -> spim_peripheral -> spim . p_reg -> CONFIG & SPIM_CONFIG_CPOL_Msk ) >> SPIM_CONFIG_CPOL_Pos ;
333
371
}
0 commit comments