Hi all,
I have problem with interfacing eeprom via I2C.
I used MSP430f6638 and eeprom 24LC512.
I tried to do as document Sla208a (MSP430F2xx and external EEPROM 24xx128), but when I read data from eeprom, it always receives 0xFF.
#include "msp430.h"
#include "common.h"
#include "i2c_eeprom.h"
#include "hal.h"
#define MAXPAGEWRITE 64
int PtrTransmit;
unsigned char I2CBufferArray[66];
unsigned char I2CBuffer;
/*----------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module
/*----------------------------------------------------------------------------*/
void InitI2C(unsigned char eeprom_i2c_address)
{
I2C_PORT_SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
// Recommended initialization steps of I2C module as shown in User Guide:
UCB1CTL1 |= UCSWRST; // Enable SW reset
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB1CTL1 = UCSSEL_2 + UCTR + UCSWRST; // Use SMCLK, TX mode, keep SW reset
UCB1BR0 = SCL_CLOCK_DIV; // fSCL = SMCLK/12 = ~100kHz
UCB1BR1 = 0;
UCB1I2CSA = eeprom_i2c_address; // define Slave Address
// In this case the Slave Address
// defines the control byte that is
// sent to the EEPROM.
UCB1I2COA = 0x48; // own address.
UCB1CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
if (UCB1STAT & UCBBUSY) // test if bus to be free
{ // otherwise a manual Clock on is
// generated
I2C_PORT_SEL &= ~SCL_PIN; // Select Port function for SCL
I2C_PORT_OUT &= ~SCL_PIN; //
I2C_PORT_DIR |= SCL_PIN; // drive SCL low
I2C_PORT_SEL |= SDA_PIN + SCL_PIN; // select module function for the
// used I2C pins
};
}
/*---------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Write operation.
/*---------------------------------------------------------------------------*/
void I2CWriteInit(void)
{
UCB1CTL1 |= UCTR; // UCTR=1 => Transmit Mode (R/W bit = 0)
UCB1IFG &= UCTXIFG;
UCB1IE &= ~UCRXIE; // disable Receive ready interrupt
UCB1IE |= UCTXIE; // enable Transmit ready interrupt
}
/*----------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Read operation.
/*----------------------------------------------------------------------------*/
void I2CReadInit(void)
{
UCB1CTL1 &= ~UCTR; // UCTR=0 => Receive Mode (R/W bit = 1)
UCB1IFG &= ~UCRXIFG;
UCB1IE &= ~UCTXIE; // disable Transmit ready interrupt
UCB1IE |= UCRXIE; // enable Receive ready interrupt
}
/*----------------------------------------------------------------------------*/
// Description:
// Byte Write Operation. The communication via the I2C bus with an EEPROM
// (2465) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_ByteWrite(unsigned int Address, unsigned char Data)
{
unsigned char adr_hi;
unsigned char adr_lo;
while (UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations.
adr_hi = Address >> 8; // calculate high byte
adr_lo = Address & 0xFF; // and low byte of address
I2CBufferArray[2] = adr_hi; // Low byte address.
I2CBufferArray[1] = adr_lo; // High byte address.
I2CBufferArray[0] = Data;
PtrTransmit = 2; // set I2CBufferArray Pointer
I2CWriteInit();
UCB1CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
UCB1CTL1 |= UCTXSTP; // I2C stop condition
while(UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
}
/*----------------------------------------------------------------------------*/
// Description:
// Page Write Operation. The communication via the I2C bus with an EEPROM
// (24xx65) is realized. A data byte is written into a user defined address.
/*----------------------------------------------------------------------------*/
void EEPROM_PageWrite(unsigned int StartAddress, unsigned char * Data, unsigned int Size)
{
volatile unsigned int i = 0;
volatile unsigned char counterI2cBuffer;
unsigned char adr_hi;
unsigned char adr_lo;
unsigned int currentAddress = StartAddress;
unsigned int currentSize = Size;
unsigned int bufferPtr = 0;
unsigned char moreDataToRead = 1;
while (UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations.
// Execute until no more data in Data buffer
while(moreDataToRead)
{
adr_hi = currentAddress >> 8; // calculate high byte
adr_lo = currentAddress & 0xFF; // and low byte of address
// Chop data down to 64-byte packets to be transmitted at a time
// Maintain pointer of current startaddress
if(currentSize > MAXPAGEWRITE)
{
bufferPtr = bufferPtr + MAXPAGEWRITE;
counterI2cBuffer = MAXPAGEWRITE - 1;
PtrTransmit = MAXPAGEWRITE + 1; // set I2CBufferArray Pointer
currentSize = currentSize - MAXPAGEWRITE;
currentAddress = currentAddress + MAXPAGEWRITE;
// Get start address
I2CBufferArray[MAXPAGEWRITE + 1] = adr_hi; // High byte address.
I2CBufferArray[MAXPAGEWRITE] = adr_lo; // Low byte address.
}
else
{
bufferPtr = bufferPtr + currentSize;
counterI2cBuffer = currentSize - 1;
PtrTransmit = currentSize + 1; // set I2CBufferArray Pointer.
moreDataToRead = 0;
currentAddress = currentAddress + currentSize;
// Get start address
I2CBufferArray[currentSize + 1] = adr_hi; // High byte address.
I2CBufferArray[currentSize] = adr_lo; // Low byte address.
}
// Copy data to I2CBufferArray
unsigned char temp;
for(i ; i < bufferPtr ; i++)
{
temp = Data[i]; // Required or else IAR throws a
// warning [Pa082]
I2CBufferArray[counterI2cBuffer] = temp;
counterI2cBuffer--;
}
I2CWriteInit();
UCB1CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
UCB1CTL1 |= UCTXSTP; // I2C stop condition
while(UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
EEPROM_AckPolling(); // Ensure data is written in EEPROM
}
}
/*----------------------------------------------------------------------------*/
// Description:
// Current Address Read Operation. Data is read from the EEPROM. The current
// address from the EEPROM is used.
/*----------------------------------------------------------------------------*/
unsigned char EEPROM_CurrentAddressRead(void)
{
while(UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations
I2CReadInit();
UCB1CTL1 |= UCTXSTT; // I2C start condition
while(UCB1CTL1 & UCTXSTT); // Start condition sent?
UCB1CTL1 |= UCTXSTP; // I2C stop condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
return I2CBuffer;
}
/*----------------------------------------------------------------------------*/
// Description:
// Random Read Operation. Data is read from the EEPROM. The EEPROM
// address is defined with the parameter Address.
/*----------------------------------------------------------------------------*/
unsigned char EEPROM_RandomRead(unsigned int Address)
{
unsigned char adr_hi;
unsigned char adr_lo;
while (UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations
adr_hi = Address >> 8; // calculate high byte
adr_lo = Address & 0xFF; // and low byte of address
I2CBufferArray[1] = adr_hi; // store single bytes that have to
I2CBufferArray[0] = adr_lo; // be sent in the I2CBuffer.
PtrTransmit = 1; // set I2CBufferArray Pointer
// Write Address first
I2CWriteInit();
UCB1CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
// Read Data byte
I2CReadInit();
UCB1CTL1 |= UCTXSTT; // I2C start condition
while(UCB1CTL1 & UCTXSTT); // Start condition sent?
UCB1CTL1 |= UCTXSTP; // I2C stop condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
return I2CBuffer;
}
/*----------------------------------------------------------------------------*/
// Description:
// Sequential Read Operation. Data is read from the EEPROM in a sequential
// form from the parameter address as a starting point. Specify the size to
// be read and populate to a Data buffer.
/*----------------------------------------------------------------------------*/
void EEPROM_SequentialRead(unsigned int Address , unsigned char * Data , unsigned int Size)
{
unsigned char adr_hi;
unsigned char adr_lo;
unsigned int counterSize;
while (UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations
adr_hi = Address >> 8; // calculate high byte
adr_lo = Address & 0xFF; // and low byte of address
I2CBufferArray[1] = adr_hi; // store single bytes that have to
I2CBufferArray[0] = adr_lo; // be sent in the I2CBuffer.
PtrTransmit = 1; // set I2CBufferArray Pointer
// Write Address first
I2CWriteInit();
UCB1CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
// Read Data byte
I2CReadInit();
UCB1CTL1 |= UCTXSTT; // I2C start condition
while(UCB1CTL1 & UCTXSTT); // Start condition sent?
for(counterSize = 0 ; counterSize < Size ; counterSize++)
{
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
Data[counterSize] = I2CBuffer;
}
UCB1CTL1 |= UCTXSTP; // I2C stop condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB1CTL1 & UCTXSTP); // Ensure stop condition got sent
}
/*----------------------------------------------------------------------------*/
// Description:
// Acknowledge Polling. The EEPROM will not acknowledge if a write cycle is
// in progress. It can be used to determine when a write cycle is completed.
/*----------------------------------------------------------------------------*/
void EEPROM_AckPolling(void)
{
while (UCB1STAT & UCBUSY); // wait until I2C module has
// finished all operations
do
{
UCB1STAT = 0x00; // clear I2C interrupt flags
UCB1CTL1 |= UCTR; // I2CTRX=1 => Transmit Mode (R/W bit = 0)
UCB1CTL1 &= ~UCTXSTT;
UCB1CTL1 |= UCTXSTT; // start condition is generated
while(UCB1CTL1 & UCTXSTT) // wait till I2CSTT bit was cleared
{
if(!(UCB1STAT & UCNACKIFG)) // Break out if ACK received
break;
}
UCB1CTL1 |= UCTXSTP; // stop condition is generated after
// slave address was sent => I2C communication is started
while (UCB1CTL1 & UCTXSTP); // wait till stop bit is reset
__delay_cycles(500); // Software delay
}while(UCB1STAT & UCNACKIFG);
}
/*---------------------------------------------------------------------------*/
/* Interrupt Service Routines */
/* Note that the Compiler version is checked in the following code and */
/* depending of the Compiler Version the correct Interrupt Service */
/* Routine definition is used. */
#if __VER__ < 200
interrupt [USCI_B1_VECTOR] void TX_ISR_I2C(void)
#else
#pragma vector=USCI_B1_VECTOR
__interrupt void TX_ISR_I2C(void)
#endif
{
if(UCB1IFG & UCTXIFG)
{
handleLed(LED0, LED_TOGGLE);
UCB1TXBUF = I2CBufferArray[PtrTransmit];// Load TX buffer
PtrTransmit--; // Decrement TX byte counter
if(PtrTransmit < 0)
{
while(!(UCB1IFG & UCTXIFG));
UCB1IE &= ~UCTXIE; // disable interrupts.
UCB1IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}
else if(UCB1IFG & UCRXIFG)
{
handleLed(LED1, LED_TOGGLE);
I2CBuffer = UCB1RXBUF; // store received data in buffer
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}