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.

Always get NACK from I2C slave after sending the slave address from Concerto C28x core

Other Parts Discussed in Thread: F28M35H52C

Hello there,

I have  a really annoy problem in using the I2C module in C28x core of a F28M35H52C device. After sending a start condition and the 7 bit slave address, and R/W bit, I always get a NACK signal from the slave. No matter how hard I tried. The I2C slave I am trying to use is a 3-axis accelerometer on an IMU board. I have proofed the I2C slave is working properly using another microcontroller. Thus, the problem must in the Concerto side, either code or hardware, or both.

The pin 104 (GPIO32) for SDA, and pin 103 (GPIO33) for SCL, pull up both internally and externally.  Pullup condition has been checked by measuring the pin voltage right before running the C28x code. In addition, the waveform from a scope confirmed the SDA is high during the 9th SCL pulse. 

I am very frustrated now. The following is my code based on the sample code with F28335. Any comments and advise will be highly appreciated. Thanks all.



#include "F28M35x_Device.h"     // F28M35x Headerfile Include File
#include "F28M35x_Examples.h"   // F28M35x Examples Include File
#include "F28M35x_I2C.h"
#include "C28x_FPU_FastRTS.h"
#include "math.h"


#define C28_FREQ    150         //CPU frequency in MHz
#define ADXL345ADDR    0x53        //as designed for sparkfun 6dom imu

struct I2CMSG *CurrentMsgPtr;                // Used in interrupts


void   I2CA_Init(void)
{

    EALLOW;

    GpioCtrlRegs.GPBMUX1.bit.GPIO32 = 1;   // Configure GPIO32 for SDAA operation pin 104
    GpioCtrlRegs.GPBMUX1.bit.GPIO33 = 1;   // Configure GPIO33 for SCLA operation pin 103

    EDIS;

    I2caRegs.I2CSAR = 0x0053;        // Slave address - ADXL345

    I2caRegs.I2CPSC.all = 14;            // Prescaler - need 7-12 Mhz on module clk  150Mhz/15=  10Mhz
    I2caRegs.I2CCLKL = 10;            // NOTE: must be non zero
    I2caRegs.I2CCLKH = 5;            // NOTE: must be non zero
    I2caRegs.I2CIER.all = 0x24;        // Enable SCD & ARDY interrupts

    I2caRegs.I2CMDR.all = 0x0020;    // Take I2C out of reset
                                    // Stop I2C when suspended

    I2caRegs.I2CFFTX.all = 0x6000;    // Enable FIFO mode and TXFIFO
    I2caRegs.I2CFFRX.all = 0x2040;    // Enable RXFIFO, clear RXFFINT,
   return;

}
Uint16 I2CA_WriteData(struct I2CMSG *msg)
{
   Uint16 i;

   // Wait until the STP bit is cleared from any previous master communication.
   // Clearing of this bit by the module is delayed until after the SCD bit is
   // set. If this bit is not checked prior to initiating a new message, the
   // I2C could get confused.
   if (I2caRegs.I2CMDR.bit.STP == 1)
   {
      return I2C_STP_NOT_READY_ERROR;
   }

   // Setup slave address
   I2caRegs.I2CSAR = msg->SlaveAddress;

   // Check if bus busy
   if (I2caRegs.I2CSTR.bit.BB == 1)
   {
      return I2C_BUS_BUSY_ERROR;
   }

   // Setup number of bytes to send
   // MsgBuffer + Address
   I2caRegs.I2CCNT = msg->NumOfBytes+1;

   // Setup data to send
   I2caRegs.I2CDXR = msg->MemoryLowAddr;
   for (i=0; i<msg->NumOfBytes; i++)
   {
      I2caRegs.I2CDXR = *(msg->MsgBuffer+i);
   }

   // Send start as master transmitter
   I2caRegs.I2CMDR.all = 0x6E20;

   return I2C_SUCCESS;
}

interrupt void i2c_int1a_isr(void)     // I2C-A
{
   Uint16 IntSource, i;

   // Read interrupt source
   IntSource = I2caRegs.I2CISRC.all;

   // Interrupt source = stop condition detected
   if(IntSource == I2C_SCD_ISRC)
   {
      // If completed message was writing data, reset msg to inactive state
      if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_WRITE_BUSY)
      {
         CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
      }
      else
      {
         if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
         {
            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_SEND_NOSTOP;
         }
         // If completed message was reading EEPROM data, reset msg to inactive state
         // and read data from FIFO.
         else if (CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_READ_BUSY)
         {
            CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_INACTIVE;
            for(i=0; i < 1; i++)
            {
              CurrentMsgPtr->MsgBuffer[i] = I2caRegs.I2CDRR;
            }
         }
      }
   }  // end of stop condition detected

   else if(IntSource == I2C_ARDY_ISRC)
   {
      if(I2caRegs.I2CSTR.bit.NACK == 1)
      {
         I2caRegs.I2CMDR.bit.STP = 1;
         I2caRegs.I2CSTR.all = I2C_CLR_NACK_BIT;
      }
      else if(CurrentMsgPtr->MsgStatus == I2C_MSGSTAT_SEND_NOSTOP_BUSY)
      {
         CurrentMsgPtr->MsgStatus = I2C_MSGSTAT_RESTART;
      }
   }  // end of register access ready

   else
   {
      // Generate some error due to invalid interrupt source
      asm("   ESTOP0");
   }

   // Enable future I2C (PIE Group 8) interrupts
   PieCtrlRegs.PIEACK.bit.ACK8 = 1;
}

struct I2CMSG ADXL345In;
struct I2CMSG ADXL345Out;


void main(void)
{

// Step 1. Initialize System Control:
// PLL, WatchDog, enable Peripheral Clocks
// This example function is found in the F28M35x_SysCtrl.c file.
    InitSysCtrl();

// Step 2. Initialize GPIO:
// This example function is found in the F28M35x_Gpio.c file and
// illustrates how to set the GPIO to it's default state.
//    InitGpio(); // Skipped for this example
// Step 3. Clear all interrupts and initialize PIE vector table:
// Disable CPU interrupts
    DINT;

// Initialize the PIE control registers to their default state.
// The default state is all PIE interrupts disabled and flags
// are cleared.
// This function is found in the F28M35x_PieCtrl.c file.
    InitPieCtrl();

// Disable CPU interrupts and clear all CPU interrupt flags:
    IER = 0x0000;
    IFR = 0x0000;

// Initialize the PIE vector table with pointers to the shell Interrupt
// Service Routines (ISR).
    InitPieVectTable();

// Reassign ISRs.

    EALLOW;    // This is needed to write to EALLOW protected registers
    PieVectTable.I2CINT1A = &i2c_int1a_isr;
    EDIS;

    CurrentMsgPtr = &ADXL345In;

    ADXL345Out.MsgStatus = I2C_MSGSTAT_SEND_WITHSTOP;
    ADXL345Out.MemoryLowAddr = 0x2c;
    ADXL345Out.NumOfBytes = 1;
    ADXL345Out.MsgBuffer[0] = 0x04;
    ADXL345Out.SlaveAddress = 0x53;

    I2CA_Init();

    PieCtrlRegs.PIEIER8.bit.INTx1 = 1;    //// Enable I2C interrupt 1 in the PIE: Group 8 interrupt 1

    IER |= M_INT8;

// Enable global Interrupts and higher priority real-time debug events:
    EINT;  // Enable Global interrupt INTM
    ERTM;  // Enable Global realtime interrupt DBGM

    Uint16 Error;
// Step 6. IDLE loop. Just sit and loop forever (optional):
    do
    {
        if(ADXL345Out.MsgStatus == I2C_MSGSTAT_SEND_WITHSTOP)
        {
           Error = I2CA_WriteData(&ADXL345Out);
           // If communication is correctly initiated, set msg status to busy
           // and update CurrentMsgPtr for the interrupt service routine.
           // Otherwise, do nothing and try again next loop. Once message is
           // initiated, the I2C interrupts will handle the rest. Search for
           // i2c_int1a_isr in this file.
           if (Error == I2C_SUCCESS)
           {
              CurrentMsgPtr = &ADXL345Out;
              ADXL345Out.MsgStatus = I2C_MSGSTAT_WRITE_BUSY;
           }
        }  // end of write section
    }while (ADXL345Out.MsgStatus!=I2C_MSGSTAT_INACTIVE);

    for(;;)
    {
        //
        // TO DO
        //

    }

}

  • Hi Yuncheng

    Based on what I read from the ADXL datasheet pin 12(ALT_ADDRESS) needs to be grounded to use the alternate address 0x53. Can you check that pin on the breakout to make sure its properly grounded at the board and at pin12 of the accelerometer?

    Yuncheng Song said:
    #define ADXL345ADDR    0x53        //as designed for sparkfun 6dom imu

    If not looks like you can revert to the primary address 0x1D

  • hello Vishal,

    Thanks for you advise, I've checked the salve hardware by using another known working microcontroller and software, they worked perfectly.

    The problem has been solved by itself, sort of...

    I changed the I2C module to loop-back mode once, then it started working perfectly ever since, with the exactly the same piece of code.

    best,

  • Hi Ning,

    I faced the same problem. I always read a constant number.

    Could you please specify what changes did you applied to change the I2C module to loop-back mode?

    Thanks,

    Naeim

  • Hi,

    I do not recall what happened exactly because such a long time... 

    I think I just set the I2C module to loop back mode by setting a bit in a register. Frankly speaking, I do not think the loop back mode actually changed anything. I highly suspect the connection to the external module somehow improved. 

    best,