30
30
#include "shared-bindings/busio/I2C.h"
31
31
#include "shared-bindings/microcontroller/__init__.h"
32
32
#include "shared-bindings/microcontroller/Pin.h"
33
+ #include "supervisor/shared/tick.h"
33
34
#include "py/mperrno.h"
34
35
#include "py/runtime.h"
35
36
39
40
40
41
// all TWI instances have the same max size
41
42
// 16 bits for 840, 10 bits for 810, 8 bits for 832
42
- #define I2C_MAX_XFER_LEN ((1UL << TWIM0_EASYDMA_MAXCNT_SIZE) - 1)
43
+ #define I2C_MAX_XFER_LEN MIN(((1UL << TWIM0_EASYDMA_MAXCNT_SIZE) - 1), 1024)
44
+ #define I2C_TIMEOUT 1000 // 1 second timeout
43
45
44
46
STATIC twim_peripheral_t twim_peripherals [] = {
45
47
#if NRFX_CHECK (NRFX_TWIM0_ENABLED )
46
48
// SPIM0 and TWIM0 share an address.
47
49
{ .twim = NRFX_TWIM_INSTANCE (0 ),
48
- .in_use = false},
50
+ .in_use = false,
51
+ .transferring = false,
52
+ .last_event_type = NRFX_TWIM_EVT_DONE },
49
53
#endif
50
54
#if NRFX_CHECK (NRFX_TWIM1_ENABLED )
51
55
// SPIM1 and TWIM1 share an address.
52
56
{ .twim = NRFX_TWIM_INSTANCE (1 ),
53
- .in_use = false},
57
+ .in_use = false,
58
+ .transferring = false,
59
+ .last_event_type = NRFX_TWIM_EVT_DONE },
54
60
#endif
55
61
};
56
62
@@ -84,16 +90,26 @@ static uint8_t twi_error_to_mp(const nrfx_err_t err) {
84
90
return MP_ENODEV ;
85
91
case NRFX_ERROR_BUSY :
86
92
return MP_EBUSY ;
87
- case NRFX_ERROR_DRV_TWI_ERR_DNACK :
88
93
case NRFX_ERROR_INVALID_ADDR :
94
+ case NRFX_ERROR_DRV_TWI_ERR_DNACK :
95
+ case NRFX_ERROR_DRV_TWI_ERR_OVERRUN :
89
96
return MP_EIO ;
97
+ case NRFX_ERROR_TIMEOUT :
98
+ return MP_ETIMEDOUT ;
90
99
default :
91
100
break ;
92
101
}
93
102
94
103
return 0 ;
95
104
}
96
105
106
+ static void twim_event_handler (nrfx_twim_evt_t const * p_event , void * p_context ) {
107
+ // this is the callback handler - sets transferring to false and records the most recent event.
108
+ twim_peripheral_t * peripheral = (twim_peripheral_t * )p_context ;
109
+ peripheral -> last_event_type = p_event -> type ;
110
+ peripheral -> transferring = false;
111
+ }
112
+
97
113
void common_hal_busio_i2c_construct (busio_i2c_obj_t * self , const mcu_pin_obj_t * scl , const mcu_pin_obj_t * sda , uint32_t frequency , uint32_t timeout ) {
98
114
if (scl -> number == sda -> number ) {
99
115
raise_ValueError_invalid_pins ();
@@ -155,7 +171,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *
155
171
156
172
// About to init. If we fail after this point, common_hal_busio_i2c_deinit() will set in_use to false.
157
173
self -> twim_peripheral -> in_use = true;
158
- nrfx_err_t err = nrfx_twim_init (& self -> twim_peripheral -> twim , & config , NULL , NULL );
174
+ nrfx_err_t err = nrfx_twim_init (& self -> twim_peripheral -> twim , & config , twim_event_handler , self -> twim_peripheral );
159
175
if (err != NRFX_SUCCESS ) {
160
176
common_hal_busio_i2c_deinit (self );
161
177
mp_raise_OSError (MP_EIO );
@@ -238,6 +254,37 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) {
238
254
self -> has_lock = false;
239
255
}
240
256
257
+ STATIC nrfx_err_t _twim_xfer_with_timeout (busio_i2c_obj_t * self , nrfx_twim_xfer_desc_t const * p_xfer_desc , uint32_t flags ) {
258
+ // does non-blocking transfer and raises and exception if it takes longer than I2C_TIMEOUT ms to complete
259
+ uint64_t deadline = supervisor_ticks_ms64 () + I2C_TIMEOUT ;
260
+ nrfx_err_t err = NRFX_SUCCESS ;
261
+ self -> twim_peripheral -> transferring = true;
262
+ err = nrfx_twim_xfer (& self -> twim_peripheral -> twim , p_xfer_desc , flags );
263
+ if (err != NRFX_SUCCESS ) {
264
+ self -> twim_peripheral -> transferring = false;
265
+ return err ;
266
+ }
267
+ while (self -> twim_peripheral -> transferring ) {
268
+ if (supervisor_ticks_ms64 () > deadline ) {
269
+ self -> twim_peripheral -> transferring = false;
270
+ return NRFX_ERROR_TIMEOUT ;
271
+ }
272
+ }
273
+ switch (self -> twim_peripheral -> last_event_type ) {
274
+ case NRFX_TWIM_EVT_DONE : ///< Transfer completed event.
275
+ return NRFX_SUCCESS ;
276
+ case NRFX_TWIM_EVT_ADDRESS_NACK : ///< Error event: NACK received after sending the address.
277
+ return NRFX_ERROR_DRV_TWI_ERR_ANACK ;
278
+ case NRFX_TWIM_EVT_BUS_ERROR : ///< Error event: An unexpected transition occurred on the bus.
279
+ case NRFX_TWIM_EVT_DATA_NACK : ///< Error event: NACK received after sending a data byte.
280
+ return NRFX_ERROR_DRV_TWI_ERR_DNACK ;
281
+ case NRFX_TWIM_EVT_OVERRUN : ///< Error event: The unread data is replaced by new data.
282
+ return NRFX_ERROR_DRV_TWI_ERR_OVERRUN ;
283
+ default : /// unknown error...
284
+ return NRFX_ERROR_INTERNAL ;
285
+ }
286
+ }
287
+
241
288
STATIC uint8_t _common_hal_busio_i2c_write (busio_i2c_obj_t * self , uint16_t addr , const uint8_t * data , size_t len , bool stopBit ) {
242
289
if (len == 0 ) {
243
290
return common_hal_busio_i2c_probe (self , addr ) ? 0 : MP_ENODEV ;
@@ -253,7 +300,7 @@ STATIC uint8_t _common_hal_busio_i2c_write(busio_i2c_obj_t *self, uint16_t addr,
253
300
nrfx_twim_xfer_desc_t xfer_desc = NRFX_TWIM_XFER_DESC_TX (addr , (uint8_t * )data , xact_len );
254
301
uint32_t const flags = (stopBit ? 0 : NRFX_TWIM_FLAG_TX_NO_STOP );
255
302
256
- if (NRFX_SUCCESS != (err = nrfx_twim_xfer ( & self -> twim_peripheral -> twim , & xfer_desc , flags ))) {
303
+ if (NRFX_SUCCESS != (err = _twim_xfer_with_timeout ( self , & xfer_desc , flags ))) {
257
304
break ;
258
305
}
259
306
@@ -284,7 +331,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t
284
331
const size_t xact_len = MIN (len , I2C_MAX_XFER_LEN );
285
332
nrfx_twim_xfer_desc_t xfer_desc = NRFX_TWIM_XFER_DESC_RX (addr , data , xact_len );
286
333
287
- if (NRFX_SUCCESS != (err = nrfx_twim_xfer ( & self -> twim_peripheral -> twim , & xfer_desc , 0 ))) {
334
+ if (NRFX_SUCCESS != (err = _twim_xfer_with_timeout ( self , & xfer_desc , 0 ))) {
288
335
break ;
289
336
}
290
337
0 commit comments