Skip to content

Commit bd40d7c

Browse files
NRF52: fix i2c byte read/write implementation
1 parent 7d5f6cf commit bd40d7c

File tree

1 file changed

+73
-58
lines changed
  • targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52

1 file changed

+73
-58
lines changed

targets/TARGET_NORDIC/TARGET_NRF5x/TARGET_NRF52/i2c_api.c

Lines changed: 73 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,7 @@
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

7271
static uint32_t tick2us = 1;
@@ -174,6 +173,21 @@ void i2c_frequency(i2c_t *obj, int hz)
174173
config->update = true;
175174
}
176175

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+
177191
const PinMap *i2c_master_sda_pinmap()
178192
{
179193
return PinMap_I2C_testing;
@@ -359,69 +373,71 @@ int i2c_byte_write(i2c_t *obj, int data)
359373
struct i2c_s *config = obj;
360374
#endif
361375

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

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

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

372-
/* Set I2C device address. NOTE: due to hardware limitations only 7-bit addresses are supported. */
373-
nrf_twi_address_set(nordic_nrf5_twi_register[instance], data >> 1);
374-
375-
/* If read bit is set, trigger read task otherwise trigger write task. */
376386
if (data & I2C_READ_BIT) {
377-
/* For timing reasons, reading bytes requires shorts to suspend peripheral after each byte. */
378-
nrf_twi_shorts_set(nordic_nrf5_twi_register[instance], NRF_TWI_SHORT_BB_SUSPEND_MASK);
379-
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);
380397
} else {
381-
/* Reset shorts register. */
382-
nrf_twi_shorts_set(nordic_nrf5_twi_register[instance], 0);
383-
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_STARTTX);
384-
}
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);
385403

386-
/* Setup stop watch for timeout. */
387-
uint32_t start_us = tick2us * lp_ticker_read();
388-
uint32_t now_us = start_us;
404+
nrf_twi_shorts_set(p_twi, 0);
389405

390-
/* Block until timeout or an address error has been detected. */
391-
while (((now_us - start_us) < DEFAULT_TIMEOUT_US) &&
392-
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_ERROR))) {
393-
now_us = tick2us * 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);
394409
}
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+
}
395423

396-
/* Check error register and update return value if an address NACK was detected. */
397-
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;
398426

399-
if (error & NRF_TWI_ERROR_ADDRESS_NACK) {
400-
result = 0; // set NACK
401-
} else {
402-
/* Normal write. Send next byte after clearing event flag. */
403-
nrf_twi_event_clear(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_TXDSENT);
404-
nrf_twi_txd_set(nordic_nrf5_twi_register[instance], data);
405-
406-
/* Setup stop watch for timeout. */
407-
uint32_t start_us = tick2us * lp_ticker_read();
408-
uint32_t now_us = start_us;
409-
410-
/* Block until timeout or the byte has been sent. */
411-
while (((now_us - start_us) < MAXIMUM_TIMEOUT_US) &&
412-
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_TXDSENT))) {
413-
now_us = tick2us * lp_ticker_read();
414-
}
415-
416-
/* Check the error code to see if the byte was acknowledged. */
417-
uint32_t error = nrf_twi_errorsrc_get_and_clear(nordic_nrf5_twi_register[instance]);
418-
419-
if (error & NRF_TWI_ERROR_DATA_NACK) {
420-
result = 0; // set NACK
421-
} else if (now_us - start_us >= MAXIMUM_TIMEOUT_US) {
422-
result = 2; // set timeout
423-
}
424-
}
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
425441
}
426442

427443
return result;
@@ -446,9 +462,6 @@ int i2c_byte_read(i2c_t *obj, int last)
446462
int instance = config->instance;
447463
int retval = I2C_ERROR_NO_SLAVE;
448464

449-
uint32_t start_us = 0;
450-
uint32_t now_us = 0;
451-
452465
/* Due to hardware limitations, the stop condition must triggered through a short before
453466
* reading the last byte.
454467
*/
@@ -470,18 +483,20 @@ int i2c_byte_read(i2c_t *obj, int last)
470483
/* No data available, resume reception. */
471484
nrf_twi_task_trigger(nordic_nrf5_twi_register[instance], NRF_TWI_TASK_RESUME);
472485

486+
/* Wait ten byte duration for data */
487+
uint32_t timeout = 10 * byte_timeout(config->frequency);
473488
/* Setup timeout */
474-
start_us = tick2us * lp_ticker_read();
475-
now_us = start_us;
489+
uint32_t start_us = tick2us * lp_ticker_read();
490+
uint32_t now_us = start_us;
476491

477492
/* Block until timeout or data ready event has been signaled. */
478-
while (((now_us - start_us) < MAXIMUM_TIMEOUT_US) &&
493+
while (((now_us - start_us) < timeout) &&
479494
!(nrf_twi_event_check(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_RXDREADY))) {
480495
now_us = tick2us * lp_ticker_read();
481496
}
482497

483498
/* Retrieve data from buffer. */
484-
if ((now_us - start_us) < MAXIMUM_TIMEOUT_US) {
499+
if ((now_us - start_us) < timeout) {
485500
retval = nrf_twi_rxd_get(nordic_nrf5_twi_register[instance]);
486501
nrf_twi_event_clear(nordic_nrf5_twi_register[instance], NRF_TWI_EVENT_RXDREADY);
487502
}

0 commit comments

Comments
 (0)