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