I2C action from Timer callback

cancel
Showing results for 
Search instead for 
Did you mean: 

I2C action from Timer callback

71 Views
embedded_eng_
Contributor III

Hi all,

I'm using LPC55S16-EVK, and having some trouble reading from I2C within a Ctimer callback.

 

I have CTIEMR2 calling my callback every X seconds which works well.

I have I2C read/write (non blocking) functions working well, based on i2c_interrupt_b2b_transfer_master demo.

 

The problem occurs when I'm trying to read from I2C within the CTIMER callback.

The I2C handle is not been called at all.

 

I guess that this has something to do with IRQ priority.

I figured that the MCU is busy executing the CTIMER callback, so if CTIEMR's IRQ has a higher/equal priority than the I2C's IRQ, the I2C handle will have to wait until CTIMER callback finishes, so I tried to change the I2C priority to a higher one.

I added a NVIC_SetPriority() call in I2C_MasterTransferCreateHandle function with a lower number (higher priority), but the problem still occurs.

 

void I2C_MasterTransferCreateHandle(I2C_Type *base,
                                    i2c_master_handle_t *handle,
                                    i2c_master_transfer_callback_t callback,
                                    void *userData)
{
    assert(handle != NULL);

    uint32_t instance;
    i2c_to_flexcomm_t handler;
    handler.i2c_master_handler = I2C_MasterTransferHandleIRQ;

    /* Clear out the handle. */
    (void)memset(handle, 0, sizeof(*handle));

    /* Look up instance number */
    instance = I2C_GetInstance(base);

    /* Save base and instance. */
    handle->completionCallback = callback;
    handle->userData           = userData;

    FLEXCOMM_SetIRQHandler(base, handler.flexcomm_handler, handle);

    /* Clear internal IRQ enables and enable NVIC IRQ. */
    I2C_DisableInterrupts(base, (uint32_t)kI2C_MasterIrqFlags);

    NVIC_SetPriority(s_i2cIRQ[instance], 1);
    (void)EnableIRQ(s_i2cIRQ[instance]);
}

 

Maybe someone can help with that?

Thanks

0 Kudos
2 Replies

47 Views
Omar_Anguiano
NXP TechSupport
NXP TechSupport

Hello
Hope you are well.
I don´t think that the priorities in the interruption are involved on this since when the callback is executed the IRQ was dispatched.
I suggest you to check the bus communication with an oscilloscope to check how the communication is done. The I2C callback is called when the communication is done.

Additionally, how are you integrating the I2C read function in the Ctimer callback?

I´m looking forward to your reply, if you have more questions do not hesitate to ask me.
Best regards,
Omar

0 Kudos

22 Views
embedded_eng_
Contributor III

Thanks for the answer, and sorry for the delay, I had to work on other stuff.

 

Here is the I2C read function:

 

 

uint8_t *readI2C(uint32_t address, uint32_t size, uint8_t slave)
{
  i2c_master_transfer_t masterXfer = {0};


  /*if size is bigger than buffer, return error*/
  if(size > I2C_DATA_LENGTH)
  {
    return NULL;
  }

  /*lock I2C*/
  if( lockI2C() < 0 )
  {
    //could not lock i2c - return null pointer
    return NULL;
  }

  /* subAddress = 0x01, data = i2cTransfers.receiveBfr - read from slave.
    start + slaveaddress(w) + subAddress + repeated start + slaveaddress(r) + rx data buffer + stop */
  masterXfer.slaveAddress   = slave;
  masterXfer.direction      = kI2C_Read;
  masterXfer.subaddress     = address;
  masterXfer.subaddressSize = 1;
  masterXfer.data           = i2cTransfers.receiveBfr;
  masterXfer.dataSize       = size;
  masterXfer.flags          = kI2C_TransferDefaultFlag;

  /*  Reset master completion flag to false. */
  setNotCompletedI2C();

  if ( I2C_MasterTransferNonBlocking(I2C_MASTER, &g_m_handle, &masterXfer) != kStatus_Success )
  {
      /*free lock and return*/
      freeI2C();
      return NULL;
  }

  /*  Wait for transfer completed. */
  while (!isCompletedI2C()) {};

  /*check for errors*/
  if( isErrorI2C() )
  {
    /*free lock, clean error flag and return*/
    freeI2C();
    resetErrorI2C();
    return NULL;
  }
  //change the completed flag
  setNotCompletedI2C();
  //remove the lock
  freeI2C();

  //return data pointer
  return i2cTransfers.receiveBfr;
}

 

 

 

Example of I2C read from main function:

 

 

    uint8_t *buf = readI2C(0x00, 5, 57);
    for(int i = 0 ; i < 5 ; i ++)
      usb_echo("%02x: %02x\r\n",i, buf[i]);

 

 

Output:

 

 

 0:  0
 1:  0
 2:  1
 3: 20
 4: 71

 

 

Signals:

Screenshot from 2021-10-14 09-40-17.png

Now doing the same from a ctimer callback:

 

 

void callback()
{
  usb_echo("READ START:\r\n");
  uint8_t *buf = readI2C(0x00, 5, 57);
  for(int i = 0 ; i < 5 ; i ++)
    usb_echo("%02x: %02x\r\n",i, buf[i]);

  usb_echo("READ END\r\n");
}

ctimer_callback_t ctimerCallbackTable[] = {
    NULL, callback, callback, NULL, NULL, NULL, NULL, NULL};



/*init ctimer*/
void initCTIMER()
{
  ctimer_config_t config;
  ctimer_match_config_t matchConfig;

  /*init ctimer*/
  CTIMER_GetDefaultConfig(&config);
  CTIMER_Init(CONSUMPTION_ADC_CTIMER_BASE, &config);

  /* set timer configuration */
  matchConfig.enableCounterReset = true;
  matchConfig.enableCounterStop  = false;
  matchConfig.matchValue         = CONSUMPTION_ADC_CTIMER_CLK_FREQ * 5;//5 sec
  matchConfig.outControl         = kCTIMER_Output_Toggle;
  matchConfig.outPinInitState    = false;
  matchConfig.enableInterrupt    = true;

  /*register timer callback*/
  CTIMER_RegisterCallBack(CONSUMPTION_ADC_CTIMER_BASE, &ctimerCallbackTable[0], kCTIMER_MultipleCallback);
  CTIMER_SetupMatch(CONSUMPTION_ADC_CTIMER_BASE, CONSUMPTION_ADC_CTIMER_MAT0_OUT, &matchConfig);
  /*init timer*/
  CTIMER_StartTimer(CONSUMPTION_ADC_CTIMER_BASE);
}

 

 

Output (appears after 5 seconds):

 

 

READ START:

 

 

 

Signals:

Screenshot from 2021-10-14 09-48-07.png

Adding more debug prints:

 

 

uint8_t *readI2C(uint32_t address, uint32_t size, uint8_t slave)
{
  i2c_master_transfer_t masterXfer = {0};


  /*if size is bigger than buffer, return error*/
  if(size > I2C_DATA_LENGTH)
  {
    return NULL;
  }
  usb_echo("1\r\n");
  /*lock I2C*/
  if( lockI2C() < 0 )
  {
    //could not lock i2c - return null pointer
    return NULL;
  }

  usb_echo("2\r\n");

  /* subAddress = 0x01, data = i2cTransfers.receiveBfr - read from slave.
    start + slaveaddress(w) + subAddress + repeated start + slaveaddress(r) + rx data buffer + stop */
  masterXfer.slaveAddress   = slave;
  masterXfer.direction      = kI2C_Read;
  masterXfer.subaddress     = address;
  masterXfer.subaddressSize = 1;
  masterXfer.data           = i2cTransfers.receiveBfr;
  masterXfer.dataSize       = size;
  masterXfer.flags          = kI2C_TransferDefaultFlag;

  /*  Reset master completion flag to false. */
  setNotCompletedI2C();
  usb_echo("3\r\n");
  if ( I2C_MasterTransferNonBlocking(I2C_MASTER, &g_m_handle, &masterXfer) != kStatus_Success )
  {
      /*free lock and return*/
      usb_echo("4\r\n");
      freeI2C();
      return NULL;
  }
  usb_echo("5\r\n");

  /*  Wait for transfer completed. */
  while (!isCompletedI2C()) {};

  usb_echo("6\r\n");
  /*check for errors*/
  if( isErrorI2C() )
  {
    /*free lock, clean error flag and return*/
    freeI2C();
    resetErrorI2C();
    return NULL;
  }
  //change the completed flag
  setNotCompletedI2C();
  //remove the lock
  freeI2C();

  //return data pointer
  return i2cTransfers.receiveBfr;
}

 

 

Output:

 

 

READ START:
1
2
3
5

 

 

So code is stuck in loop

 

 

 while (!isCompletedI2C()) {};

 

 

Which is implemented:

 

 

bool isCompletedI2C()
{
  return i2cTransfers.completed;
}

 

This flag is changed to true from setCompletedI2C function 

 

 

void setCompletedI2C(I2C_Type *base, i2c_master_handle_t *handle, status_t status, void *userData)
{
  i2cTransfers.completed = true;
  /*indicates if an error occured*/
  i2cTransfers.transferError = status != kStatus_Success;
}

 

Which is registered as the I2C handle in initI2C function (initI2C is called from main)

 

void initI2C()
{
  i2c_master_config_t masterConfig;

  /*reset flexcomm*/
  RESET_PeripheralReset(kFC5_RST_SHIFT_RSTn);
  /*init i2c struct parameters*/
  initStructI2C();
  /*get i2c master config*/
  I2C_MasterGetDefaultConfig(&masterConfig);
  /*set baudrate*/
  masterConfig.baudRate_Bps = I2C_BAUDRATE;
  /*init i2c*/
  I2C_MasterInit(I2C_MASTER, &masterConfig, I2C_MASTER_CLOCK_FREQUENCY);
  /* Create the I2C handle for the non-blocking transfer */
  I2C_MasterTransferCreateHandle(I2C_MASTER, &g_m_handle, setCompletedI2C, NULL);
}

 

 

 

 

 

Maybe you know what's wrong?

 

Thanks

 

0 Kudos