Platform: Keil, SDK13.1, nRF52832
I'm investigating series of seemingly random hangs when app_twi gets permanently stuck in app_twi.c
following code snippet:
while (p_app_twi->p_app_twi_cb->internal_transaction_in_progress) { if (user_function) { user_function(); } }
When this happens SCL line is permanently pulled low. I thought that it may be due to clock stretching and checked if one of slave devices is misbehaving. I wasn't able to to find anything on slave side.
One of my slave devices (Atmel Tiny MCU) has a way to tell if it's holding SCL line. While similar lock happened I was able to check that SCL was held by master (as far as you can trust ATTiny register values). I was also able to reset the slave and this haven't released SCL. However resetting nRF52 (master) caused SCL release.
So I think that's something wrong with app_twi master implemetation.
This code snippet can reliably cause symptoms I've described above:
#include "nrf_log.h" #include "app_twi.h" #include "sm_pin_mapper.h" //TWI instance handle APP_TWI_DEF(m_app_twi, APP_TWI_QUEUE_SIZE, 0); //TWI slave address #define TWI_SLAVE_ADDR 0x1D //how many bytes to read from slave #define TWI_SLAVE_REG_LEN 7 static ret_code_t twi_init(void) { ret_code_t err_code; nrf_drv_twi_config_t twi_config=NRF_DRV_TWI_DEFAULT_CONFIG; twi_config.sda=SM_PIN_TWI_SDA; twi_config.scl=SM_PIN_TWI_SCL; err_code=app_twi_init(&m_app_twi, &twi_config); APP_ERROR_CHECK(err_code); return err_code; } static void read_reg(const uint8_t reg_addr, uint8_t* const p_buff, const uint8_t len) { ret_code_t err_code; static uint8_t tx_buff[1]; tx_buff[0]=reg_addr; app_twi_transfer_t const twi_transfers[] = { APP_TWI_WRITE(TWI_SLAVE_ADDR, tx_buff, sizeof(tx_buff), APP_TWI_NO_STOP), APP_TWI_READ(TWI_SLAVE_ADDR, p_buff, len, 0) }; err_code = app_twi_perform(&m_app_twi, twi_transfers, sizeof(twi_transfers) / sizeof(twi_transfers[0]), 0); APP_ERROR_CHECK(err_code); } static void write_reg(const uint8_t reg_addr, uint8_t* const p_buff, const uint8_t len, const uint8_t stop) { ret_code_t err_code; uint8_t tx_buff[TWI_SLAVE_REG_LEN+1]={0}; tx_buff[0] = reg_addr; memcpy(&tx_buff[1], p_buff, len); app_twi_transfer_t const twi_transfers[] = { APP_TWI_WRITE(TWI_SLAVE_ADDR, tx_buff, len + 1, (stop == 1) ? 0 : APP_TWI_NO_STOP) }; err_code = app_twi_perform(&m_app_twi, twi_transfers, sizeof(twi_transfers) / sizeof(twi_transfers[0]), 0); APP_ERROR_CHECK(err_code); } static void test_case(uint8_t tx_stop) { uint8_t rx_buff[TWI_SLAVE_REG_LEN] = { 0 }; uint8_t tx_buff[] = { 0 }; write_reg(0, tx_buff, sizeof(tx_buff), tx_stop); read_reg(0, rx_buff, sizeof(rx_buff)); NRF_LOG_RAW_HEXDUMP_DEBUG(rx_buff, sizeof(rx_buff)); } void twi_slave_tiny_main_unwrap(void) { APP_ERROR_CHECK(twi_init()); //this will complete just fine test_case(1); //this will pull SCL low and get stuck forever test_case(0); }
test_case(1)
works as expected while test_case(0)
reliably causes app_twi
to get stuck as on attached Saleae trace /cfs-file/__key/support-attachments/beef5d1b77644c448dabff31668f3a47-010a9164018145d884c8f96862005e33/twi_5F00_hang.logicdata and register view screenshot
While this happens SCL is permanently pulled low. Resetting nRF52 gets communication working again.
This is just an example. Hangs I'm experiencing happen in various configurations of TWI read/write operations.
Am I doing something wrong?
What can be done to debug this?
I'm observing similar problems in devices already deployed in the field and I'd appreciate pointer towards solving this.