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
//
}
}