Dear support team
Please note my sample application code attached, and the trace of the I2C transmission
I am facing the issue that the twi driver does not write more than slave-address + 1 byte of data onto I2C at once, although the application requests to transmit 2 data bytes.
Setup:
HW: nRF52840 DK connected to Sensirion sensor of sgp40 via I2C.
SW:
sdk_config.h:
#define TWI_ENABLED 1
#define TWI_DEFAULT_CONFIG_FREQUENCY 26738688
#define TWI0_ENABLED 1
I2C config:
const nrf_drv_twi_config_t twi_sgp40_config = {
.scl = ARDUINO_SCL_PIN,
.sda = ARDUINO_SDA_PIN,
.frequency = NRF_DRV_TWI_FREQ_100K,
.interrupt_priority = APP_IRQ_PRIORITY_HIGH,
.clear_bus_init = false
};
I2C trace; after address and first byte (0x36) have been transmitted successfully the I2C SCK line remains low. the content of the second data byte does not get sent out.
uint8_t cmd[2u] = { 0x36u, 0x82u } ;
(void)nrf_drv_twi_tx(&m_twi, 0x59u, cmd, 2, false);
main.c:
#include <stdio.h> #include "boards.h" #include "app_util_platform.h" #include "app_error.h" #include "nrf_drv_twi.h" #include "nrf_delay.h" #include "nrf_log.h" #include "nrf_log_ctrl.h" #include "nrf_log_default_backends.h" #define TWI_INSTANCE_ID 0 #define SENSIRION_WORD_SIZE 2 #define SENSIRION_NUM_WORDS(x) (sizeof(x) / SENSIRION_WORD_SIZE) #define SENSIRION_MAX_BUFFER_WORDS 32 #define CRC8_POLYNOMIAL 0x31 #define CRC8_INIT 0xFF #define CRC8_LEN 1 #define SGP40_CMD_MEASURE_RAW_DURATION_US 100000 #define SGP40_SERIAL_ID_NUM_BYTES 6 typedef enum { WAIT, READ, WRITE, PRINT }state_t; static uint8_t serial[6u] = { 0 }; static state_t state = WRITE; static uint32_t tick = 0u; static const nrf_drv_twi_t m_twi = NRF_DRV_TWI_INSTANCE(TWI_INSTANCE_ID); static int8_t sensirion_i2c_read(uint8_t address, uint8_t* data, uint16_t count) { ret_code_t err_code = nrf_drv_twi_rx(&m_twi, address, data, count); if (err_code == 0) { return 0; } return -1; } static uint8_t sensirion_common_generate_crc(const uint8_t* data, uint16_t count) { uint16_t current_byte; uint8_t crc = CRC8_INIT; uint8_t crc_bit; /* calculates 8-Bit checksum with given polynomial */ for (current_byte = 0; current_byte < count; ++current_byte) { crc ^= (data[current_byte]); for (crc_bit = 8; crc_bit > 0; --crc_bit) { if (crc & 0x80) crc = (crc << 1) ^ CRC8_POLYNOMIAL; else crc = (crc << 1); } } return crc; } static int8_t sensirion_common_check_crc(const uint8_t* data, uint16_t count, uint8_t checksum) { if (sensirion_common_generate_crc(data, count) != checksum) return 1; return 0; } static int16_t sensirion_i2c_read_words_as_bytes(uint8_t address, uint8_t* data, uint16_t num_words) { int16_t ret; uint16_t i, j; uint16_t size = num_words * (SENSIRION_WORD_SIZE + CRC8_LEN); uint16_t word_buf[SENSIRION_MAX_BUFFER_WORDS]; uint8_t* const buf8 = (uint8_t*)word_buf; ret = sensirion_i2c_read(address, buf8, size); if (ret != 0) return ret; /* check the CRC for each word */ for (i = 0, j = 0; i < size; i += SENSIRION_WORD_SIZE + CRC8_LEN) { ret = sensirion_common_check_crc(&buf8[i], SENSIRION_WORD_SIZE, buf8[i + SENSIRION_WORD_SIZE]); if (ret != 0) return ret; data[j++] = buf8[i]; data[j++] = buf8[i + 1]; } return 0; } static void twi_handler(nrf_drv_twi_evt_t const * p_event, void * p_context) { switch (p_event->type) { case NRF_DRV_TWI_EVT_DONE: if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_RX) { state = PRINT; } else if (p_event->xfer_desc.type == NRF_DRV_TWI_XFER_TX) { state = READ; } else { } break; default: break; } } static void twi_init (void) { ret_code_t err_code; const nrf_drv_twi_config_t twi_sgp40_config = { .scl = ARDUINO_SCL_PIN, .sda = ARDUINO_SDA_PIN, .frequency = NRF_DRV_TWI_FREQ_100K, .interrupt_priority = APP_IRQ_PRIORITY_HIGH, .clear_bus_init = false }; err_code = nrf_drv_twi_init(&m_twi, &twi_sgp40_config, twi_handler, NULL); APP_ERROR_CHECK(err_code); nrf_drv_twi_enable(&m_twi); } int main(void) { uint8_t cmd[2u] = { 0x36u, 0x82u } ; // command: get serial Id APP_ERROR_CHECK(NRF_LOG_INIT(NULL)); NRF_LOG_DEFAULT_BACKENDS_INIT(); NRF_LOG_INFO("\r\nTWI sensor example started."); NRF_LOG_FLUSH(); twi_init(); while (true) { switch (state) { case WRITE: state = WAIT; // send command and wait for succesful transmission (void)nrf_drv_twi_tx(&m_twi, 0x59u, cmd, 2, false); break; case READ: state = WAIT; nrf_delay_ms(1); // read datat and wait for succesful receiption memset(serial, 0, 6); (void)sensirion_i2c_read_words_as_bytes(0x59u, serial, 3u /* words, not bytes */); break; case PRINT: state = WRITE; NRF_LOG_INFO("\r\nserial Id"); NRF_LOG_HEXDUMP_INFO(serial, 6u); NRF_LOG_FLUSH(); nrf_delay_ms(1000u); break; default: break; } } } /** @} */
Any ideas as to why this happens? Am I using the twi API correctly?
Thanks for your help
Marko