2222 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2323 */
2424
25+ #include <string.h>
26+
2527#include "shared-bindings/busio/SPI.h"
2628#include "py/mperrno.h"
2729#include "py/runtime.h"
2830
2931#include "nrfx_spim.h"
3032#include "nrf_gpio.h"
3133
34+ // These are in order from ighest available frequency to lowest (32MHz first, then 8MHz).
3235STATIC spim_peripheral_t spim_peripherals [] = {
3336#if NRFX_CHECK (NRFX_SPIM3_ENABLED )
3437 // SPIM3 exists only on nRF52840 and supports 32MHz max. All other SPIM's are only 8MHz max.
3538 // Allocate SPIM3 first.
3639 { .spim = NRFX_SPIM_INSTANCE (3 ),
37- .max_frequency_MHz = 32 ,
40+ .max_frequency = 32000000 ,
3841 .max_xfer_size = SPIM3_EASYDMA_MAXCNT_SIZE ,
3942 },
4043#endif
4144#if NRFX_CHECK (NRFX_SPIM2_ENABLED )
4245 // SPIM2 is not shared with a TWIM, so allocate before the shared ones.
4346 { .spim = NRFX_SPIM_INSTANCE (2 ),
44- .max_frequency_MHz = 8 ,
47+ .max_frequency = 8000000 ,
4548 .max_xfer_size = SPIM2_EASYDMA_MAXCNT_SIZE ,
4649 },
4750#endif
4851#if NRFX_CHECK (NRFX_SPIM1_ENABLED )
4952 // SPIM1 and TWIM1 share an address.
5053 { .spim = NRFX_SPIM_INSTANCE (1 ),
51- .max_frequency_MHz = 8 ,
54+ .max_frequency = 8000000 ,
5255 .max_xfer_size = SPIM1_EASYDMA_MAXCNT_SIZE ,
5356 },
5457#endif
5558#if NRFX_CHECK (NRFX_SPIM0_ENABLED )
5659 // SPIM0 and TWIM0 share an address.
5760 { .spim = NRFX_SPIM_INSTANCE (0 ),
58- .max_frequency_MHz = 8 ,
61+ .max_frequency = 8000000 ,
5962 .max_xfer_size = SPIM0_EASYDMA_MAXCNT_SIZE ,
6063 },
6164#endif
6265};
6366
6467STATIC bool never_reset [MP_ARRAY_SIZE (spim_peripherals )];
6568
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+
6674void spi_reset (void ) {
6775 for (size_t i = 0 ; i < MP_ARRAY_SIZE (spim_peripherals ); i ++ ) {
6876 if (never_reset [i ]) {
@@ -122,7 +130,7 @@ static nrf_spim_frequency_t baudrate_to_spim_frequency(const uint32_t baudrate)
122130}
123131
124132void 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 .
126134 self -> spim_peripheral = NULL ;
127135 for (size_t i = 0 ; i < MP_ARRAY_SIZE (spim_peripherals ); i ++ ) {
128136 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 *
137145
138146 nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG (NRFX_SPIM_PIN_NOT_USED , NRFX_SPIM_PIN_NOT_USED ,
139147 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 );
141150
142151 config .sck_pin = clock -> number ;
143152 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
189198
190199 // Set desired frequency, rounding down, and don't go above available frequency for this SPIM.
191200 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 )));
194202
195203 nrf_spim_mode_t mode = NRF_SPIM_MODE_0 ;
196204 if (polarity ) {
@@ -224,21 +232,36 @@ void common_hal_busio_spi_unlock(busio_spi_obj_t *self) {
224232}
225233
226234bool 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 ) {
228236 return true;
237+ }
238+
239+ const bool is_spim3 = self -> spim_peripheral -> spim .p_reg == NRF_SPIM3 ;
229240
230241 const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
231242 const uint32_t parts = len / max_xfer_size ;
232243 const uint32_t remainder = len % max_xfer_size ;
233244
234245 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 );
236253 if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
237254 return false;
238255 }
239256
240257 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 );
242265 if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
243266 return false;
244267 }
@@ -247,8 +270,9 @@ bool common_hal_busio_spi_write(busio_spi_obj_t *self, const uint8_t *data, size
247270}
248271
249272bool 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 ) {
251274 return true;
275+ }
252276
253277 const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
254278 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,
270294}
271295
272296bool 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 ) {
274298 return true;
299+ }
275300
301+ const bool is_spim3 = self -> spim_peripheral -> spim .p_reg == NRF_SPIM3 ;
276302
277303 const uint32_t max_xfer_size = self -> spim_peripheral -> max_xfer_size ;
278304 const uint32_t parts = len / max_xfer_size ;
279305 const uint32_t remainder = len % max_xfer_size ;
280306
281307 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 ,
283315 data_in + i * max_xfer_size , max_xfer_size );
284316 if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
285317 return false;
286318 }
287319
288320 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 ,
290328 data_in + parts * max_xfer_size , remainder );
291329 if (nrfx_spim_xfer (& self -> spim_peripheral -> spim , & xfer , 0 ) != NRFX_SUCCESS )
292330 return false;
@@ -325,9 +363,9 @@ uint32_t common_hal_busio_spi_get_frequency(busio_spi_obj_t* self) {
325363}
326364
327365uint8_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 ;
329367}
330368
331369uint8_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 ;
333371}
0 commit comments