Reply
Posts: 51
Registered: ‎06-04-2017

SMBus/I2C: C8051F990 as Master and BGM121 as slave

Hi,

 

I am trying to send data between C8051F990 (Master, SMBus) and BGM121/EFR32BG1 (Slave, I2C). The SMBus code for Master works fine with SDA line voltages and interrupts as expected. However, the slave code on BGM121 does not receive any interrupts when the Master sends slave address. I have used two pins PC10 and PC11 of the slave for SCL and SDA respectively. Here is the 'main' and 'interrupt' part of slave code:

void main(void)
{
  /* Initialize peripherals */

  enter_DefaultMode_from_RESET();


   /* Setting up i2c */
  setupI2C();
 

  while (1)
  {
    


if (i2c_rxInProgress)
    {
    	receiveI2CData();
    }
  
   }
 }


void I2C0_IRQHandler(void)
{
  int status;

  status = I2C0->IF;

  if (status & I2C_IF_ADDR){      //IF reg has 3rd bit (2nd position) as ADDR bit; set to 1 if addr matches
    /* Address Match */
    /* Indicating that reception is started */
	i2c_rxInProgress = true;
    I2C0->RXDATA;    //Reads once to clear RXDATA buffer which currently contains start bit, slave address and 'write' bit

    I2C_IntClear(I2C0, I2C_IFC_ADDR); //clears address

  }
  else if (status & I2C_IF_RXDATAV)
  {
    /* Data received */
     
	i2c_rxBuffer[i2c_rxBufferIndex] = I2C0->RXDATA;
    i2c_rxBufferIndex++;
  }

  if(status & I2C_IEN_SSTOP){
    /* Stop received, reception is ended */
    I2C_IntClear(I2C0, I2C_IEN_SSTOP);
    i2c_rxInProgress = false;
    i2c_rxBufferIndex = 0;
  }
}

Other functions:

 

 

extern void enter_DefaultMode_from_RESET(void) {
	// $[Config Calls]
	CHIP_Init();

	EMU_enter_DefaultMode_from_RESET();
	LFXO_enter_DefaultMode_from_RESET();
	CMU_enter_DefaultMode_from_RESET();
	RTCC_enter_DefaultMode_from_RESET();
	I2C0_enter_DefaultMode_from_RESET();
	GPCRC_enter_DefaultMode_from_RESET();
	LDMA_enter_DefaultMode_from_RESET();
	PRS_enter_DefaultMode_from_RESET();
	PORTIO_enter_DefaultMode_from_RESET();
	// [Config Calls]$

}
void setupI2C(void)
{
 

  /* Using PC10 (SCL) and PC11 (SDA) */
  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUpFilter, 1);
  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUpFilter, 1);


  /* Setting the status flags and index */
  i2c_rxInProgress = false;
  i2c_startTx = false;
  i2c_rxBufferIndex = 0;

  /* Setting up to enable slave mode */
  I2C0->SADDR = I2C_ADDRESS;
  I2C0->CTRL |= I2C_CTRL_SLAVE | I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;

  enableI2cSlaveInterrupts();
}
void enableI2cSlaveInterrupts(void){
  I2C_IntClear(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
  I2C_IntEnable(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
  NVIC_EnableIRQ(I2C0_IRQn);
  I2C_Enable(I2C0,true);
}
extern void I2C0_enter_DefaultMode_from_RESET(void) {

	// $[I2C0 I/O setup]
	/* Set up SCL */
	I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SCLPEN;
	I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK))
			| I2C_ROUTELOC0_SCLLOC_LOC14;
	/* Set up SDA */
	I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SDAPEN;
	I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK))
			| _I2C_ROUTELOC0_SCLLOC_LOC16;
	// [I2C0 I/O setup]$

	// $[I2C0 initialization]
	I2C_Init_TypeDef init = I2C_INIT_DEFAULT;

	init.enable = 1;
	//init.master = 1;
	init.master = 0;
	init.freq = I2C_FREQ_STANDARD_MAX;
	init.clhr = i2cClockHLRStandard;
	I2C_Init(I2C0, &init);

	I2C_SlaveAddressSet(I2C0,0xE2);
	// [I2C0 initialization]$


}

 

I am not sure if it is due to the compatibility problem between SMBus and I2C, clock frequency mismatch between master and slave or due to GPIO pins.

 

Please let me know if there is any way to solve this issue. 

 

Thanks a lot.

 

 

 

Posts: 51
Registered: ‎06-04-2017

Re: SMBus/I2C: C8051F990 as Master and BGM121 as slave

Hi,

 

I figured that there was an issue with the connection pins of BGM121. I am facing a different problem now: I can see that the data is being received by the slave (BGM121) by accessing the 'Receive data buffer' register in the slave. However, the I2C interrupt handler is not being called. Instead, the default handler present in startup_efr32bg1b.c is being used. I have attached the entire 'main' code here. Please 

Please let me know in which scenarios the 'default handler' might be called. Is it due to an unknown interrupt occurring prior to I2C?

 

Thank you. 

 

/***********************************************************************************************//**
 * \file   main.c
 * \brief  Silicon Labs Thermometer Example Application
 *
 * This Thermometer and OTA example allows the user to measure temperature
 * using the temperature sensor on the WSTK. The values can be read with the
 * Health Thermometer reader on the Blue Gecko smartphone app.
 ***************************************************************************************************
 * <b> (C) Copyright 2016 Silicon Labs, http://www.silabs.com</b>
 ***************************************************************************************************
 * This file is licensed under the Silicon Labs License Agreement. See the file
 * "Silabs_License_Agreement.txt" for details. Before using this software for
 * any purpose, you must agree to the terms of that agreement.
 **************************************************************************************************/

#ifndef GENERATION_DONE
#error You must run generate first!
#endif

#define CORE_FREQUENCY              14000000
#define RTC_MIN_TIMEOUT                32000
#define I2C_ADDRESS                     0xE2
#define I2C_RXBUFFER_SIZE                20
#define I2C_TXBUFFER_SIZE                5
/* Board Headers */
#include "boards.h"
#include "ble-configuration.h"
#include "board_features.h"

/* Bluetooth stack headers */
#include "bg_types.h"
#include "native_gecko.h"
#include "aat.h"
#include "infrastructure.h"

/* GATT database */
#include "gatt_db.h"

/* EM library (EMlib) */
#include "em_system.h"

/* Libraries containing default Gecko configuration values */
#include "em_emu.h"
#include "em_cmu.h"
#include "em_chip.h"
#ifdef FEATURE_BOARD_DETECTED
#include "bspconfig.h"
#include "pti.h"
#else
#error This sample app only works with a Silicon Labs Board
#endif

#ifdef FEATURE_IOEXPANDER
#include "bsp.h"
#include "bsp_stk_ioexp.h"
#endif /* FEATURE_IOEXPANDER */ 


/* Device initialization header */
#include "InitDevice.h"

/* Temperature sensor and I2c*/
#include "i2cspmconfig.h"
#include "i2cspm.h"
#include "si7013.h"
#include "tempsens.h"

#ifdef FEATURE_SPI_FLASH
#include "em_usart.h"
#include "mx25flash_spi.h"
#endif /* FEATURE_SPI_FLASH */


/***********************************************************************************************//**
 * @addtogroup Application
 * @{
 **************************************************************************************************/

/***********************************************************************************************//**
 * @addtogroup app
 * @{
 **************************************************************************************************/

/* Gecko configuration parameters (see gecko_configuration.h) */
#ifndef MAX_CONNECTIONS
#define MAX_CONNECTIONS 4
#endif
uint8_t bluetooth_stack_heap[DEFAULT_BLUETOOTH_HEAP(MAX_CONNECTIONS)];

#ifdef FEATURE_PTI_SUPPORT
static const RADIO_PTIInit_t ptiInit = RADIO_PTI_INIT;
#endif

static const gecko_configuration_t config = {
  .config_flags=0,
  .sleep.flags=SLEEP_FLAGS_DEEP_SLEEP_ENABLE,
  .bluetooth.max_connections=MAX_CONNECTIONS,
  .bluetooth.heap=bluetooth_stack_heap,
  .bluetooth.heap_size=sizeof(bluetooth_stack_heap),
  .bluetooth.sleep_clock_accuracy = 100, // ppm
  .gattdb=&bg_gattdb_data,
  .ota.flags=0,
  .ota.device_name_len=3,
  .ota.device_name_ptr="OTA",
  #ifdef FEATURE_PTI_SUPPORT
  .pti = &ptiInit,
  #endif
};

uint8_t i2c_txBuffer[I2C_TXBUFFER_SIZE];
uint8_t i2c_rxBuffer[I2C_RXBUFFER_SIZE];
uint8_t i2c_rxBufferIndex;

// Transmission flags
volatile bool i2c_rxInProgress;
volatile bool i2c_startTx;


uint8_t cur_crc = 0;

void setupOscillators(void)
{
  /* Enabling clock to the I2C, GPIO, LE */
  CMU_ClockEnable(cmuClock_I2C0, true);
  CMU_ClockEnable(cmuClock_GPIO, true);
  CMU_ClockEnable(cmuClock_CORELE, true);

  // Enabling USART0 (see errata)
 // CMU_ClockEnable(cmuClock_USART0, true);

  /* Starting LFXO and waiting until it is stable */
  CMU_OscillatorEnable(cmuOsc_LFXO, true, true);

  /* Routing the LFXO clock to the RTC */
  CMU_ClockSelectSet(cmuClock_LFA,cmuSelect_LFXO);
  CMU_ClockEnable(1050208, true);
}



/**************************************************************************//**
 * @brief  enables I2C slave interrupts
 *****************************************************************************/
void enableI2cSlaveInterrupts(void){
  I2C_IntClear(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
  I2C_IntEnable(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
  NVIC_EnableIRQ(I2C0_IRQn);
 }

/**************************************************************************//**
 * @brief  disables I2C interrupts
 *****************************************************************************/
void disableI2cInterrupts(void){
  NVIC_DisableIRQ(I2C0_IRQn);
  I2C_IntDisable(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
  I2C_IntClear(I2C0, I2C_IEN_ADDR | I2C_IEN_RXDATAV | I2C_IEN_SSTOP);
}



/**************************************************************************//**
 * @brief  Setup I2C
 *****************************************************************************/
 #define I2C_ROUTEPEN_MASK
void setupI2C(void)
{
  // Using default settings
//  I2C_Init_TypeDef i2cInit = I2C_INIT_DEFAULT;

  /* Using PC10 (SCL) and PC11 (SDA) */
  GPIO_PinModeSet(gpioPortC, 10, gpioModeWiredAndPullUpFilter, 1);//i2c0_SCL#14
  GPIO_PinModeSet(gpioPortC, 11, gpioModeWiredAndPullUpFilter, 1);//i2c0_SDA#16

  I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SCLPEN;
  	I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SCLLOC_MASK))
  			| I2C_ROUTELOC0_SCLLOC_LOC14;
  	/* Set up SDA */
  	I2C0->ROUTEPEN = I2C0->ROUTEPEN | I2C_ROUTEPEN_SDAPEN;
  	I2C0->ROUTELOC0 = (I2C0->ROUTELOC0 & (~_I2C_ROUTELOC0_SDALOC_MASK))
  			| I2C_ROUTELOC0_SDALOC_LOC16;
  	// [I2C0 I/O setup]$

  	// $[I2C0 initialization]
  	I2C_Init_TypeDef init = I2C_INIT_DEFAULT;

  	init.enable = 1;
  	//init.master = 1;
  	init.master = 0;
  	init.freq = I2C_FREQ_STANDARD_MAX;
  	init.clhr = i2cClockHLRStandard;
  	I2C_Init(I2C0, &init);

  	I2C_SlaveAddressSet(I2C0,0xE2);

  /* Setting the status flags and index */
  i2c_rxInProgress = false;
  i2c_startTx = false;
  i2c_rxBufferIndex = 0;

  /* Setting up to enable slave mode */
  I2C0->SADDR = I2C_ADDRESS;
  I2C0->CTRL |= I2C_CTRL_SLAVE | I2C_CTRL_AUTOACK | I2C_CTRL_AUTOSN;

  enableI2cSlaveInterrupts();
}



/**************************************************************************//**
 * @brief  Receiving I2C data. Along with the I2C interrupt, it will keep the
  EFM32 in EM1 while the data is received.
 *****************************************************************************/
void receiveI2CData(void){
  while(i2c_rxInProgress){
   EMU_EnterEM1();
  }
}



/**************************************************************************//**
 * @brief  Transmitting I2C data. Will busy-wait until the transfer is complete.
 *****************************************************************************/
void performI2CTransfer(uint8_t data, uint8_t data_len)
{
  /* Transfer structure */
  I2C_TransferSeq_TypeDef i2cTransfer;

   /* Initializing I2C transfer */
  i2cTransfer.addr          = I2C_ADDRESS;
  i2cTransfer.flags         = I2C_FLAG_WRITE;
  i2cTransfer.buf[0].data   = data;
  i2cTransfer.buf[0].len    = data_len;
  i2cTransfer.buf[1].data   = i2c_rxBuffer;
  i2cTransfer.buf[1].len    = I2C_RXBUFFER_SIZE;
  I2C_TransferInit(I2C0, &i2cTransfer);

  /* Sending data */
  while (I2C_Transfer(I2C0) == i2cTransferInProgress){;}

   enableI2cSlaveInterrupts(); //after line number 186, the device returns back to slave
}


/* Flag for indicating DFU Reset must be performed */
uint8_t boot_to_dfu = 0;


/**
 * @brief Function for taking a single temperature measurement with the WSTK Relative Humidity and Temperature (RHT) sensor.
 */
void temperatureMeasure()
{

  uint8_t htmTempBuffer[5]; /* Stores the temperature data in the Health Thermometer (HTM) format. */
  uint8_t flags = 0x00;   /* HTM flags set as 0 for Celsius, no time stamp and no temperature type. */
  int32_t tempData;     /* Stores the Temperature data read from the RHT sensor. */
  uint32_t rhData = 0;    /* Dummy needed for storing Relative Humidity data. */
  uint32_t temperature;   /* Stores the temperature data read from the sensor in the correct format */
  uint8_t *p = htmTempBuffer; /* Pointer to HTM temperature buffer needed for converting values to bitstream. */

  /* Convert flags to bitstream and append them in the HTM temperature data buffer (htmTempBuffer) */
  UINT8_TO_BITSTREAM(p, flags);

  /* Sensor relative humidity and temperature measurement returns 0 on success, nonzero otherwise */
  if (Si7013_MeasureRHAndTemp(I2C0, SI7021_ADDR, &rhData, &tempData) == 0) {
    /* Convert sensor data to correct temperature format */
    temperature = FLT_TO_UINT32(tempData, -3);
    /* Convert temperature to bitstream and place it in the HTM temperature data buffer (htmTempBuffer) */
    UINT32_TO_BITSTREAM(p, temperature);
    /* Send indication of the temperature in htmTempBuffer to all "listening" clients.
     * This enables the Health Thermometer in the Blue Gecko app to display the temperature.
     *  0xFF as connection ID will send indications to all connections. */
    gecko_cmd_gatt_server_send_characteristic_notification(
      0xFF, gattdb_temp_measurement, 5, htmTempBuffer);
  }
}

/**
 * @brief  Main function
 */
void main(void)
{
  /* Initialize peripherals */
  CHIP_Init();

  setupOscillators();
 // enter_DefaultMode_from_RESET();


   /* Setting up i2c */
  setupI2C();
  EMU_DCDCInit_TypeDef dcdcInit = EMU_DCDCINIT_DEFAULT;
  EMU_DCDCInit(&dcdcInit); // Check; related to POR?


  /* Initialize the Temperature Sensor */
 // Si7013_Detect(I2C0, SI7021_ADDR, NULL);

  while (1)
  {
    /* Event pointer for handling events */
   // struct gecko_cmd_packet* evt;


if (i2c_rxInProgress)
    {
    	receiveI2CData();
    }
   else if (cur_crc)
   {
    	performI2CTransfer (cur_crc, sizeof(cur_crc));
	}
   }
}


void I2C0_IRQHandler(void)
{
  int status;

  status = I2C0->IF;

  if (status & I2C_IF_ADDR){      //IF reg has 3rd bit (2nd position) as ADDR bit; set to 1 if addr matches
    /* Address Match */
    /* Indicating that reception is started */
	i2c_rxInProgress = true;
    I2C0->RXDATA;    //Reads once to clear RXDATA buffer which currently contains start bit, slave address and 'write' bit

    I2C_IntClear(I2C0, I2C_IFC_ADDR); //clears address

  }
  else if (status & I2C_IF_RXDATAV)
  {
    /* Data received */
   //if (i2c_rxBufferIndex >= I2C_RXBUFFER_SIZE)
  // {
	   //write to flash
	 //  i2c_rxBufferIndex = 0;
   //}
	i2c_rxBuffer[i2c_rxBufferIndex] = I2C0->RXDATA;
    i2c_rxBufferIndex++;
    cur_crc= i2c_rxBuffer[i2c_rxBufferIndex-1];


    //if (i2c_rxBuffer[i2c_rxBufferIndex-1]==0xFF && i2c_rxBufferIndex >=2)
   // {
    	//cur_crc= i2c_rxBuffer[i2c_rxBufferIndex-2];
   // }
  }

  if(status & I2C_IEN_SSTOP){
    /* Stop received, reception is ended */
    I2C_IntClear(I2C0, I2C_IEN_SSTOP);
    i2c_rxInProgress = false;
    i2c_rxBufferIndex = 0;
  }
}

/** @} (end addtogroup app) */
/** @} (end addtogroup Application) */

 

Posts: 381
Registered: ‎09-04-2013

Re: SMBus/I2C: C8051F990 as Master and BGM121 as slave

@vneehu Ensure the I2C interrupt is enable by checking related registers setting. And try to add a breakpoint at the beginning of your I2C ISR handler to see if it was fired or not after receiving data from master.

Posts: 381
Registered: ‎09-04-2013

Re: SMBus/I2C: C8051F990 as Master and BGM121 as slave

All interrupts' handler are set to the Default_Handler in the startup file.

You may need to check all interrupts that are enabled and add corresponding handler in your project so that it will not jump into the Default_Handler when associated interrupt fires.