3030#include "shared-bindings/busio/I2C.h"
3131#include "shared-bindings/microcontroller/__init__.h"
3232#include "shared-bindings/microcontroller/Pin.h"
33+ #include "supervisor/shared/tick.h"
3334#include "py/mperrno.h"
3435#include "py/runtime.h"
3536
3940
4041// all TWI instances have the same max size
4142// 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
4345
4446STATIC twim_peripheral_t twim_peripherals [] = {
4547 #if NRFX_CHECK (NRFX_TWIM0_ENABLED )
4648 // SPIM0 and TWIM0 share an address.
4749 { .twim = NRFX_TWIM_INSTANCE (0 ),
48- .in_use = false},
50+ .in_use = false,
51+ .transferring = false,
52+ .last_event_type = NRFX_TWIM_EVT_DONE },
4953 #endif
5054 #if NRFX_CHECK (NRFX_TWIM1_ENABLED )
5155 // SPIM1 and TWIM1 share an address.
5256 { .twim = NRFX_TWIM_INSTANCE (1 ),
53- .in_use = false},
57+ .in_use = false,
58+ .transferring = false,
59+ .last_event_type = NRFX_TWIM_EVT_DONE },
5460 #endif
5561};
5662
@@ -84,16 +90,26 @@ static uint8_t twi_error_to_mp(const nrfx_err_t err) {
8490 return MP_ENODEV ;
8591 case NRFX_ERROR_BUSY :
8692 return MP_EBUSY ;
87- case NRFX_ERROR_DRV_TWI_ERR_DNACK :
8893 case NRFX_ERROR_INVALID_ADDR :
94+ case NRFX_ERROR_DRV_TWI_ERR_DNACK :
95+ case NRFX_ERROR_DRV_TWI_ERR_OVERRUN :
8996 return MP_EIO ;
97+ case NRFX_ERROR_TIMEOUT :
98+ return MP_ETIMEDOUT ;
9099 default :
91100 break ;
92101 }
93102
94103 return 0 ;
95104}
96105
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+
97113void 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 ) {
98114 if (scl -> number == sda -> number ) {
99115 raise_ValueError_invalid_pins ();
@@ -155,7 +171,7 @@ void common_hal_busio_i2c_construct(busio_i2c_obj_t *self, const mcu_pin_obj_t *
155171
156172 // About to init. If we fail after this point, common_hal_busio_i2c_deinit() will set in_use to false.
157173 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 );
159175 if (err != NRFX_SUCCESS ) {
160176 common_hal_busio_i2c_deinit (self );
161177 mp_raise_OSError (MP_EIO );
@@ -238,6 +254,37 @@ void common_hal_busio_i2c_unlock(busio_i2c_obj_t *self) {
238254 self -> has_lock = false;
239255}
240256
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+
241288STATIC uint8_t _common_hal_busio_i2c_write (busio_i2c_obj_t * self , uint16_t addr , const uint8_t * data , size_t len , bool stopBit ) {
242289 if (len == 0 ) {
243290 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,
253300 nrfx_twim_xfer_desc_t xfer_desc = NRFX_TWIM_XFER_DESC_TX (addr , (uint8_t * )data , xact_len );
254301 uint32_t const flags = (stopBit ? 0 : NRFX_TWIM_FLAG_TX_NO_STOP );
255302
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 ))) {
257304 break ;
258305 }
259306
@@ -284,7 +331,7 @@ uint8_t common_hal_busio_i2c_read(busio_i2c_obj_t *self, uint16_t addr, uint8_t
284331 const size_t xact_len = MIN (len , I2C_MAX_XFER_LEN );
285332 nrfx_twim_xfer_desc_t xfer_desc = NRFX_TWIM_XFER_DESC_RX (addr , data , xact_len );
286333
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 ))) {
288335 break ;
289336 }
290337
0 commit comments