Skip to content

Commit 4b21157

Browse files
authored
Merge pull request #11739 from maciejbocianski/nrf52_i2c_byte_rw_fix
Nrf52 i2c byte rw fix
2 parents 6f7c1c9 + 703348a commit 4b21157

File tree

1 file changed

+81
-61
lines changed
  • targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52

1 file changed

+81
-61
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/i2c_api.c

Lines changed: 81 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@
6565
#define DEBUG_PRINTF(...)
6666
#endif
6767

68-
#define DEFAULT_TIMEOUT_US (1000) // timeout for waiting for address NACK
69-
#define MAXIMUM_TIMEOUT_US (10000) // timeout for waiting for RX
68+
#define MAXIMUM_TIMEOUT_US (10000) // timeout for waiting for RX/TX
7069
#define I2C_READ_BIT 0x01 // read bit
7170

71+
static uint32_t tick2us = 1;
72+
7273
/* Keep track of what mode the peripheral is in. On NRF52, Driver mode can use TWIM. */
7374
typedef enum {
7475
NORDIC_I2C_MODE_NONE,
@@ -106,6 +107,9 @@ void i2c_init(i2c_t *obj, PinName sda, PinName scl)
106107
struct i2c_s *config = obj;
107108
#endif
108109

110+
const ticker_info_t *ti = lp_ticker_get_info();
111+
tick2us = 1000000 / ti->frequency;
112+
109113
/* Get instance from pin configuration. */
110114
int instance = pin_instance_i2c(sda, scl);
111115
MBED_ASSERT(instance < NRFX_TWI_ENABLED_COUNT);
@@ -169,6 +173,21 @@ void i2c_frequency(i2c_t *obj, int hz)
169173
config->update = true;
170174
}
171175

176+
static uint32_t byte_timeout(nrf_twi_frequency_t frequency)
177+
{
178+
uint32_t timeout = 0;
179+
// set timeout in [us] as: 10 [bits] * 1000000 / frequency
180+
if (frequency == NRF_TWI_FREQ_100K) {
181+
timeout = 100; // 10 * 10us
182+
} else if (frequency == NRF_TWI_FREQ_250K) {
183+
timeout = 40; // 10 * 4us
184+
} else if (frequency == NRF_TWI_FREQ_400K) {
185+
timeout = 25; // 10 * 2.5us
186+
}
187+
188+
return timeout;
189+
}
190+
172191
const PinMap *i2c_master_sda_pinmap()
173192
{
174193
return PinMap_I2C_testing;
@@ -354,69 +373,71 @@ int i2c_byte_write(i2c_t *obj, int data)
354373
struct i2c_s *config = obj;
355374
#endif
356375

357-
int instance = config->instance;
376+
NRF_TWI_Type *p_twi = nordic_nrf5_twi_register[config->instance];
358377
int result = 1; // default to ACK
378+
uint32_t start_us, now_us, timeout;
359379

360-
/* Check if this is the first byte to be transferred. If it is, then send start signal and address. */
361380
if (config->state == NORDIC_TWI_STATE_START) {
362381
config->state = NORDIC_TWI_STATE_BUSY;
363382

364-
/* Beginning of new transaction, configure peripheral if necessary. */
383+
config->update = true;
365384
i2c_configure_twi_instance(obj);
366385

367-
/* Set I2C device address. NOTE: due to hardware limitations only 7-bit addresses are supported. */
368-
nrf_twi_address_set(nordic_nrf5_twi_register[instance], data >> 1);
369-
370-
/* If read bit is set, trigger read task otherwise trigger write task. */
371386
if (data & I2C_READ_BIT) {
372-
/* For timing reasons, reading bytes requires shorts to suspend peripheral after each byte. */
373-
nrf_twi_shorts_set(nordic_nrf5_twi_register[instance], NRF_TWI_SHORT_BB_SUSPEND_MASK);
374-
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_STARTRX);
387+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
388+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_RXDREADY);
389+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
390+
(void)nrf_twi_errorsrc_get_and_clear(p_twi);
391+
392+
nrf_twi_shorts_set(p_twi, NRF_TWI_SHORT_BB_SUSPEND_MASK);
393+
394+
nrf_twi_address_set(p_twi, data >> 1);
395+
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
396+
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTRX);
375397
} else {
376-
/* Reset shorts register. */
377-
nrf_twi_shorts_set(nordic_nrf5_twi_register[instance], 0);
378-
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_STARTTX);
379-
}
398+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_STOPPED);
399+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
400+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
401+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_BB);
402+
(void)nrf_twi_errorsrc_get_and_clear(p_twi);
380403

381-
/* Setup stop watch for timeout. */
382-
uint32_t start_us = lp_ticker_read();
383-
uint32_t now_us = start_us;
404+
nrf_twi_shorts_set(p_twi, 0);
384405

385-
/* Block until timeout or an address error has been detected. */
386-
while (((now_us - start_us) < DEFAULT_TIMEOUT_US) &&
387-
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_ERROR))) {
388-
now_us = lp_ticker_read();
406+
nrf_twi_address_set(p_twi, data >> 1);
407+
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
408+
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_STARTTX);
389409
}
410+
/* Wait two byte duration for address ACK */
411+
timeout = 2 * byte_timeout(config->frequency);
412+
} else {
413+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_TXDSENT);
414+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_ERROR);
415+
nrf_twi_event_clear(p_twi, NRF_TWI_EVENT_BB);
416+
(void)nrf_twi_errorsrc_get_and_clear(p_twi);
417+
418+
nrf_twi_task_trigger(p_twi, NRF_TWI_TASK_RESUME);
419+
nrf_twi_txd_set(p_twi, data);
420+
/* Wait ten byte duration for data ACK */
421+
timeout = 10 * byte_timeout(config->frequency);
422+
}
390423

391-
/* Check error register and update return value if an address NACK was detected. */
392-
uint32_t error = nrf_twi_errorsrc_get_and_clear(nordic_nrf5_twi_register[instance]);
424+
start_us = tick2us * lp_ticker_read();
425+
now_us = start_us;
393426

394-
if (error & NRF_TWI_ERROR_ADDRESS_NACK) {
395-
result = 0; // set NACK
396-
} else {
397-
/* Normal write. Send next byte after clearing event flag. */
398-
nrf_twi_event_clear(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_TXDSENT);
399-
nrf_twi_txd_set(nordic_nrf5_twi_register[instance], data);
400-
401-
/* Setup stop watch for timeout. */
402-
uint32_t start_us = lp_ticker_read();
403-
uint32_t now_us = start_us;
404-
405-
/* Block until timeout or the byte has been sent. */
406-
while (((now_us - start_us) < MAXIMUM_TIMEOUT_US) &&
407-
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_TXDSENT))) {
408-
now_us = lp_ticker_read();
409-
}
410-
411-
/* Check the error code to see if the byte was acknowledged. */
412-
uint32_t error = nrf_twi_errorsrc_get_and_clear(nordic_nrf5_twi_register[instance]);
413-
414-
if (error & NRF_TWI_ERROR_DATA_NACK) {
415-
result = 0; // set NACK
416-
} else if (now_us - start_us >= MAXIMUM_TIMEOUT_US) {
417-
result = 2; // set timeout
418-
}
419-
}
427+
/* Block until timeout or an address/data error has been detected. */
428+
while (((now_us - start_us) < timeout) &&
429+
!nrf_twi_event_check(p_twi, NRF_TWI_EVENT_TXDSENT) &&
430+
!nrf_twi_event_check(p_twi, NRF_TWI_EVENT_ERROR)) {
431+
now_us = tick2us * lp_ticker_read();
432+
}
433+
434+
/* Check error register and update return value if an address/data NACK was detected. */
435+
uint32_t error = nrf_twi_errorsrc_get_and_clear(p_twi);
436+
437+
if ((error & NRF_TWI_ERROR_ADDRESS_NACK) || (error & NRF_TWI_ERROR_DATA_NACK)) {
438+
result = 0; // NACK
439+
} else if (now_us - start_us >= timeout) {
440+
result = 2; // timeout
420441
}
421442

422443
return result;
@@ -441,9 +462,6 @@ int i2c_byte_read(i2c_t *obj, int last)
441462
int instance = config->instance;
442463
int retval = I2C_ERROR_NO_SLAVE;
443464

444-
uint32_t start_us = 0;
445-
uint32_t now_us = 0;
446-
447465
/* Due to hardware limitations, the stop condition must triggered through a short before
448466
* reading the last byte.
449467
*/
@@ -465,18 +483,20 @@ int i2c_byte_read(i2c_t *obj, int last)
465483
/* No data available, resume reception. */
466484
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_RESUME);
467485

486+
/* Wait ten byte duration for data */
487+
uint32_t timeout = 10 * byte_timeout(config->frequency);
468488
/* Setup timeout */
469-
start_us = lp_ticker_read();
470-
now_us = start_us;
489+
uint32_t start_us = tick2us * lp_ticker_read();
490+
uint32_t now_us = start_us;
471491

472492
/* Block until timeout or data ready event has been signaled. */
473-
while (((now_us - start_us) < MAXIMUM_TIMEOUT_US) &&
493+
while (((now_us - start_us) < timeout) &&
474494
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_RXDREADY))) {
475-
now_us = lp_ticker_read();
495+
now_us = tick2us * lp_ticker_read();
476496
}
477497

478498
/* Retrieve data from buffer. */
479-
if ((now_us - start_us) < MAXIMUM_TIMEOUT_US) {
499+
if ((now_us - start_us) < timeout) {
480500
retval = nrf_twi_rxd_get(nordic_nrf5_twi_register[instance]);
481501
nrf_twi_event_clear(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_RXDREADY);
482502
}
@@ -506,12 +526,12 @@ int i2c_stop(i2c_t *obj)
506526
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_STOP);
507527

508528
/* Block until stop signal has been generated. */
509-
uint32_t start_us = lp_ticker_read();
529+
uint32_t start_us = tick2us * lp_ticker_read();
510530
uint32_t now_us = start_us;
511531

512532
while (((now_us - start_us) < MAXIMUM_TIMEOUT_US) &&
513533
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_STOPPED))) {
514-
now_us = lp_ticker_read();
534+
now_us = tick2us * lp_ticker_read();
515535
}
516536

517537
/* Reset state. */

0 commit comments

Comments
 (0)