Simple SDK I2C Routine

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Simple SDK I2C Routine

Jump to solution
1,216 Views
philhale
Contributor IV

I am continuing my efforts to learn the Kinetis SDK by now evaluating the I2C routines. I have a simple project where I am trying to communicate with a Analog Devices chip at slave address 0xB0.

Here is my code:  ( I am trying to send two writes to the ADI chip. )

void I2C_WriteRegister(uint32_t instance, uint8_t addr, uint8_t reg, uint8_t data)

{

  uint8_t regBuff[1];

  uint8_t datBuff[1];

  i2c_status_t ret;

  i2c_device_t deviceInfo = {

   .address = addr,

   .baudRate_kbps = I2C_COMM_SPEED,   // 100U

  };

 

  regBuff[0] = reg;

  datBuff[0] = data;

  ret = I2C_DRV_MasterSendDataBlocking(instance, &deviceInfo, regBuff, 1, datBuff, 1, 1000u);

  if (ret != kStatus_I2C_Success)

  {

       unsigned char str[64], n;

       n = sprintf((char *)str,"\n\rI2C Write Error: 0x%02x 0x%02x 0x%02x - Ret = 0x%02x",addr, reg, data, ret);

       UART_DRV_SendDataBlocking(UART0_IDX, str, n, 1000u);

  }

  //PIT_DRV_DelayUs(50);

}

 

/*lint -save  -e970 Disable MISRA rule (6.3) checking. */

int main(void)

/*lint -restore Enable MISRA rule (6.3) checking. */

{

  /* Write your local variable definition here */

 

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/

  PE_low_level_init();

  /*** End of Processor Expert internal initialization.                    ***/

 

  /* Write your code here */

  GPIO_DRV_SetPinOutput(LED_RED);

 

  unsigned char str[] = "\n\rMy Kinetis Design Studio SDK Test Program\n\r";

  UART_DRV_SendDataBlocking(UART0_IDX, str, sizeof(str), 1000u);

 

  I2C_WriteRegister(i2cCom0_IDX, 0xB0, 0xFF, 0xFF);

  I2C_WriteRegister(i2cCom0_IDX, 0xB0, 0xE5, 0x82);

 

  GPIO_DRV_SetPinOutput(LED_BLUE);

 

  for(;;)

  {}

 

  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/

  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/

  #ifdef PEX_RTOS_START

    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */

  #endif

  /*** End of RTOS startup code.  ***/

  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/

  for(;;){}

  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/

} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

 

 

/* END main */

 

I believe I am getting a Nak back from the ADI chip. See below.

121777_121777.jpgScreenHunter_117 Dec. 29 17.58.jpg

Any idea why this code is failing?

 

I know the hardware works fine because I have another application in Keil that works with this hardware.

 

Thank you.

 

Phil

Original Attachment has been moved to: ProjectInfo.zip

Labels (1)
0 Kudos
1 Solution
600 Views
philhale
Contributor IV

Problem solved!

Turns out that when stepping through the SDK routines, the SlaveAddress is shifted to the left 1 bit. Not sure the reason for this but when the address is sent via I2C the address is wrong when analyzed.

So, when I send the address to the SDK routines, I shift the address to the right 1 bit and eveything works perfectly.

i2c_device_t deviceInfo = {

   .address = (addr >> 1U),

   .baudRate_kbps = I2C_COMM_SPEED,   // 100U

  };

Thank you all for your help. One more SDK routine under my belt!

Phil

View solution in original post

0 Kudos
4 Replies
600 Views
philhale
Contributor IV

Rechecked hardware configuration in Kinetis Design Studio. Pins are correct and open drain. I have also compared it to the EEPROM sample and it appears like I am doing everything the way it should.

The device I am talking with is expecting a one byte "register" plus one byte "data". My device address is 0xB0 and I am of the understanding that the I2C_DRV routines do the address shift for me. I will put it on the scope tomorrow to verify.

If anyone has any other things I should check, I would be most appreciative.

Regards,

Phil

0 Kudos
600 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Phil,

Regarding your question, I am not sure whether the K66 has succeeded to write the value to the register of the analog device, as you know that IIC module needs ACK handshaking signal, so i can not test your application code on my board.

From your code, I have not found any problem. when you call the api function:  I2C_WriteRegister(i2cCom0_IDX, 0xB0, 0xFF, 0xFF);, the K66 writes the 0xB0(slave address), 0xFF(I suppose register address) and 0xFF to the IIC slave device in sequence via IIC, in the process, an IIC  interrupt happens, it is normal because you enable the IIC interrupt, in the ISR, the Bit0 RXAK of I2Cx_S is tested, if the RXAK bit is set, the kStatus_I2C_ReceivedNak is assigned to status variable with the code:

  master->status = kStatus_I2C_ReceivedNak;

so the I2C_DRV_MasterSendDataBlocking() return the status value.

Note that I2C_DRV_MasterIRQHandler() is the only function that kStatus_I2C_ReceivedNak is assigned to status variable.

do you have the other alternative on the IIC slave device to confirm whether the data has written or not?

BR

Xiangjun Rong

.

This is the IIC ISR in SDK.

void I2C_DRV_MasterIRQHandler(uint32_t instance)

{

    assert(instance < I2C_INSTANCE_COUNT);

    I2C_Type * base = g_i2cBase[instance];

    /* Clear the interrupt flag*/

    I2C_HAL_ClearInt(base);

    /* Get current runtime structure */

    i2c_master_state_t * master = (i2c_master_state_t *)g_i2cStatePtr[instance];

    /* Get current master transfer direction */

    i2c_direction_t direction = I2C_HAL_GetDirMode(base);

    bool     wasArbLost = I2C_HAL_GetStatusFlag(base, kI2CArbitrationLost);

    if (wasArbLost)

    {

        I2C_HAL_ClearArbitrationLost(base);

        master->status = kStatus_I2C_AribtrationLost;

        /* Disable I2C interrupt in the peripheral.*/

        I2C_HAL_SetIntCmd(base, false);

        if (master->isBlocking)

        {

            OSA_SemaPost(&master->irqSync);

        }

        return;

    }

    /* Exit immediately if there is no transfer in progress OR not in master mode */

    if ((!I2C_HAL_GetStatusFlag(base, kI2CBusBusy)) ||

        (!I2C_HAL_IsMaster(base)))

    {

        return;

    }

    /* Handle send */

    if (direction == kI2CSend)

    {

        /* Check whether we got an ACK or NAK from the former byte we sent */

        if (I2C_HAL_GetStatusFlag(base, kI2CReceivedNak))

        {

            /* Record that we got a NAK */

            master->status = kStatus_I2C_ReceivedNak;

            /* Got a NAK, so we're done with this transfer */

            I2C_DRV_CompleteTransfer(instance);

        }

        else

        {

            /* Continue send if still have data. TxSize/txBuff index need

             * increment first because one byte is already sent in order

             * to trigger interrupt */

            if (--master->txSize > 0)

            {

               /* Transmit next byte and update buffer index */

                I2C_HAL_WriteByte(base, *(++master->txBuff));

            }

            else

            {

                /* Finish send data, send STOP, disable interrupt */

                I2C_DRV_CompleteTransfer(instance);

            }

        }

    }

    else /* Handle receive */

    {

        switch (--master->rxSize)

        {

            case 0x0U:

                /* Finish receive data, send STOP, disable interrupt */

                I2C_DRV_CompleteTransfer(instance);

                break;

            case 0x1U:

                /* For the byte before last, we need to set NAK */

                I2C_HAL_SendNak(base);

                break;

            default :

                I2C_HAL_SendAck(base);

                break;

        }

        /* Read recently received byte into buffer and update buffer index */

        *(master->rxBuff++) = I2C_HAL_ReadByte(base);

    }

}

0 Kudos
600 Views
philhale
Contributor IV

Thank you for your response.

You are correct. I am communicating with a slave of address B0. I am writing to address FF and sending the data FF. This particular register is a reset register but I write to other registers that should be holding a value. When I readback from those addresses the status is also 05 - NAK and the data value returned is 0x00.

I will get the board up on a scope and let you know if I see something interesting.

Thank you again.

Phil

0 Kudos
601 Views
philhale
Contributor IV

Problem solved!

Turns out that when stepping through the SDK routines, the SlaveAddress is shifted to the left 1 bit. Not sure the reason for this but when the address is sent via I2C the address is wrong when analyzed.

So, when I send the address to the SDK routines, I shift the address to the right 1 bit and eveything works perfectly.

i2c_device_t deviceInfo = {

   .address = (addr >> 1U),

   .baudRate_kbps = I2C_COMM_SPEED,   // 100U

  };

Thank you all for your help. One more SDK routine under my belt!

Phil

0 Kudos