This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

CC2541: Problem disappearing BLE advertisement using I2C

Part Number: CC2541

Dear reader,

Currently I am working on a project where both I2C functionality and BLE functionality is required. These are supported by the CC2541, so that is good.  

The situation

  • I am able to write the registers of the PCA9635 LEDdriver module using I2C protocol. 
  • I am able to connect with the device using BLE, I have a constant stream of incoming data (once every 350ms).

The goal

  • Being able to have a stable (continuous) BLE connection as well as being able to write data to the LEDdriver every now and then (less frequent).

The problem

  • When writing registers using I2C, the device stops advertising its profile (it is not visible in the lightBlue app anymore). So both BLE and I2C work individually, but using them together opposes problems.

Findings

  • Setting the global interrupt enable bit to 0, ruins the BLE connection. After finding this issue, the explanation was quite simple as BLE requires interrupts to work.
  • In the BLE software developers guide I found that processing time of the application (I2C) may maximally take up to 2ms. (sec 7.6.2: Limit Application Processing During BLE Activity). Can I easily measure the time of an event? And since interrupts for BLE have the highest priority (right?), how can the connection break. I would expect I2C communication to break, not the BLE advertising. 
  • When writing 0x00 or 0x01 to the I2CDATA register, the device remains visible in the lightBlue app so BLE seems to work still. When writing 0xAA to I2CDATA (and thus to the LED driver), the device disappears in the lightBlue app. Thinking about that, assuming this is a timing issue: can it be true that writing more 1's to a register like I2CDATA takes longer?

So my question is, what could be the cause of this problem and how can it be fixed? 
The I2C function I use for writing I2C data is:

typedef enum
{
  // HAL_I2C_MASTER mode clk frequencies.
  i2cClock_123KHZ = 0x00,
  i2cClock_144KHZ = 0x01,
  i2cClock_165KHZ = 0x02,
  i2cClock_197KHZ = 0x03,
  i2cClock_33KHZ = 0x80,
  i2cClock_267KHZ = 0x81,
  i2cClock_533KHZ = 0x82
} i2cClock_t;

void HalI2CInit(i2cClock_t clockRate)
{
  // Set pull-up pins.
  I2CWC = 0x0C; // 0000 1100

  // Reset I2C config
  I2CCFG = 0x00; // 0000 0000

  // Set I2C clock rate
  I2C_CLOCK_RATE(clockRate);

  // Enable global interrupts (IEN0.EA = 1)
  IEN0 |= 0x80; // 1000 0000
  // Enable interrupt (P2IE = 1)
  IEN2 |= 0x02; // 0000 0010

  // Enable I2C (ENS1 = 1)
  I2C_ENABLE();
}

void HalI2CDisable(void)
{
  // Stop the communication by removing clock signal
  I2C_STOP();

  // Disable the clock signal
  I2C_DISABLE();

  // Disable interrupt (P2IE = 0)
  IEN2 &= 0xFD; // 1111 1101

  // Don't disable global interrupts, as this will ruin the BLE functionality.
  // Disable global interrupts (IEN0.EA = 0)
  // IEN0 &= 0x7F; // 0111 1111
}

void setLEDOUTPUT0(uint8 registerLEDOUT0)

{
  HalI2CInit(i2cClock_33KHZ);

  //////////////////////////////////////////////////////////////////////////
  // Set LEDOUTPUT 0 - 3
  // Initiate communication by sending start bit (STA = 1)
  // 1: Clear SI bit (to 0) (the interrupt flag)
  I2CCFG &= 0xF7; // 1111 0111
  // 2: Set start bit (to 1)
  I2CCFG |= 0x20; // 0010 0000
  // 3: Wait for SI bit to be set (to 1) (the interrupt flag)
  while ((I2CCFG & 0x08) == 0); // 0000 1000
  // 4: Unset start bit (to 0)
  I2CCFG &= 0xDF; // 1101 1111

  // Send device address and inform to write
  if (I2CSTAT == 0x08 ) // if a start condition has been transmitted (it should)
  {
    // 1: Load device address and R/W into I2C data register
    I2CDATA = ((0x00 << 1) | 0x00); // 0x00 = write
    // 2: Clear SI bit (to 0) (the interrupt flag)
    I2CCFG &= 0xF7; // 1111 0111
    // 3: Wait for SI bit to be set (to 1) (the interrupt flag)
   while ((I2CCFG & 0x08) == 0); // 0000 1000
  }

  // Send data bytes to the device
  // 1: Check whether the device (slave) has acknowledged the request.
  if (I2CSTAT == 0x18) // If the device address and write bit have been transmitted, ACK is received.
  {
    // Send byte
    // 1: Load dataByte into I2C data register
    I2CDATA = 0x14; //dataByte;
    // 2: Clear SI bit (to 0) (the interrupt flag)
    I2CCFG &= 0xF7; // 1111 0111
    // 3: Wait for SI bit to be set (to 1) (the interrupt flag)
   while ((I2CCFG & 0x08) == 0); // 0000 1000
  }

  // Send data bytes to the device
  // 1: Check whether the device (slave) has acknowledged the request.
  if (I2CSTAT == 0x28) // If the device address and write bit have been transmitted, ACK is received.
  {
    // Send byte
    // 1: Load dataByte into I2C data register
    I2CDATA = registerLEDOUT0; //0xAA; //dataByte;
    // 2: Clear SI bit (to 0) (the interrupt flag)
    I2CCFG &= 0xF7; // 1111 0111
    // 3: Wait for SI bit to be set (to 1) (the interrupt flag)
    while ((I2CCFG & 0x08) == 0); // 0000 1000
  }

  // Stop the communication by setting the Stop bit (STO = 1)
  HalI2CDisable();

  return;
}