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.
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,