This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

TWI master driver stops sending after successful transfer of 2 bytes

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

Parents Reply Children
No Data
Related