Tool/software: Code Composer Studio
Hello,
I am simply trying to write a single byte to the 24AA32AF EEPROM and then read the byte back but when I attempt this simple operation I am unable to read and write correctly. I have downloaded the I2Croutines.c and I2Croutines.h files from TI which includes EEPROM read, write, and acknowledge functions. I changed the SDA to P3.0 and SCL to P3.1. I also set the slave address to 0xA0 to agree with the control byte of b10100000. Now I am attempting to run a simple main program which should write and read a byte but I am not getting the correct result.
#include <msp430f5529.h>
#include "I2Croutines.h"
int main(void)
{
unsigned int i;
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
InitI2C(0xA0);
EEPROM_ByteWrite(0x0000,0x12);
EEPROM_AckPolling();
unsigned char read_val = EEPROM_RandomRead(0x0000);
while(1);
return 0;
}
I am confused why this does not correctly write to and read from the EEPROM. The code that I got from TI for I2Croutines can be seen below.
I2CRoutines.c:
#include "msp430f5418a.h"
#include "I2Croutines.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 address = 0xA0 for 10100000?
{
I2C_PORT_DIR |= SDA_PIN + SCL_PIN;
I2C_PORT_SEL |= SDA_PIN + SCL_PIN; // Assign I2C pins to USCI_B0
// Recommended initialisation steps of I2C module as shown in User Guide:
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCTR + UCSWRST; // Use SMCLK, TX mode, keep SW reset
UCB0BR0 = SCL_CLOCK_DIV; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = eeprom_i2c_address; // define Slave Address
// In this case the Slave Address
// defines the control byte that is
// sent to the EEPROM.
//UCB0I2COA = 0x01A5; // own address.
// UCB0IE|=UCTXIE+UCRXIE;
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
if (UCB0STAT & 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
};
__enable_interrupt();
}
/*---------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Write operation.
/*---------------------------------------------------------------------------*/
void I2CWriteInit(void)
{
UCB0CTL1 |= UCTR; // UCTR=1 => Transmit Mode (R/W bit = 0)
UCB0IFG &= ~UCTXIFG;
UCB0IE &= ~UCRXIE; // disable Receive ready interrupt
UCB0IE|= UCTXIE; // enable Transmit ready interrupt
}
/*----------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Read operation.
/*----------------------------------------------------------------------------*/
void I2CReadInit(void)
{
UCB0CTL1 &= ~UCTR; // UCTR=0 => Receive Mode (R/W bit = 1)
UCB0IFG &= ~UCRXIFG;
UCB0IE &= ~UCTXIE; // disable Transmit ready interrupt
UCB0IE |= 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 (UCB0STAT & 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();
UCB0CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
// __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & 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 char Size)
{
volatile unsigned int i = 0;
volatile unsigned char counterI2cBuffer;
unsigned char adr_hi;
unsigned char adr_lo;
unsigned int currentAddress = StartAddress;
unsigned char currentSize = Size;
unsigned char bufferPtr = 0;
unsigned char moreDataToRead = 1;
while (UCB0STAT & 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();
UCB0CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
// __bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & 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(UCB0STAT & UCBUSY); // wait until I2C module has
// finished all operations
I2CReadInit();
UCB0CTL1 |= UCTXSTT; // I2C start condition
while(UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & 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 (UCB0STAT & 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();
UCB0CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
// Read Data byte
I2CReadInit();
UCB0CTL1 |= UCTXSTT; // I2C start condition
while(UCB0CTL1 & UCTXSTT); // Start condition sent?
UCB0CTL1 |= UCTXSTP; // I2C stop condition
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & 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 (UCB0STAT & 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();
UCB0CTL1 |= UCTXSTT; // start condition generation
// => I2C communication is started
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
// Read Data byte
UCB0CTL1 &= ~UCTR; // UCTR=0 => Receive Mode (R/W bit = 1)
UCB0IFG &= ~UCRXIFG;
UCB0IE &= ~UCTXIE; // disable Transmit ready interrupt
UCB0IE |= UCRXIE; // enable Receive ready interrupt
UCB0CTL1 |= UCTXSTT; // I2C start condition
while(UCB0CTL1 & UCTXSTT); // Start condition sent?
for(counterSize = 0 ; counterSize < Size ; counterSize++)
{
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
Data[counterSize] = I2CBuffer;
}
UCB0CTL1 |= UCTXSTP; // I2C stop condition
//__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTL1 & 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 (UCB0STAT & UCBUSY); // wait until I2C module has
// finished all operations
do
{
UCB0STAT = 0x00; // clear I2C interrupt flags
UCB0CTL1 |= UCTR; // I2CTRX=1 => Transmit Mode (R/W bit = 0)
UCB0CTL1 &= ~UCTXSTT;
UCB0CTL1 |= UCTXSTT; // start condition is generated
while(UCB0CTL1 & UCTXSTT) // wait till I2CSTT bit was cleared
{
if(!(UCNACKIFG & UCB0STAT)) // Break out if ACK received
break;
}
UCB0CTL1 |= UCTXSTP; // stop condition is generated after
// slave address was sent => I2C communication is started
while (UCB0CTL1 & UCTXSTP); // wait till stop bit is reset
__delay_cycles(500); // Software delay
}while(UCNACKIFG & UCB0STAT);
}
/*---------------------------------------------------------------------------*/
/* 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 [USCIAB0TX_VECTOR] void TX_ISR_I2C(void)
//#else
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
//#endif
{
if(UCTXIFG & UCB0IFG)
{
UCB0TXBUF = I2CBufferArray[PtrTransmit];// Load TX buffer
PtrTransmit--; // Decrement TX byte counter
if(PtrTransmit < 0)
{
while(!(UCB0IFG & UCTXIFG));
UCB0CTL1 |= UCTXSTP; // I2C stop condition
UCB0IE &= ~UCTXIE; // disable interrupts.
UCB0IFG &= ~UCTXIFG; // Clear USCI_B0 TX int flag
// __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}
else if(UCRXIFG & UCB0IFG)
{
I2CBuffer = UCB0RXBUF; // store received data in buffer
//__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
}
I2CRoutines.h:
#define I2C_PORT_SEL P3SEL #define I2C_PORT_OUT P3OUT #define I2C_PORT_REN P3REN #define I2C_PORT_DIR P3DIR #define SDA_PIN BIT0 // UCB0SDA pin #define SCL_PIN BIT1 // UCB0SCL pin #define SCL_CLOCK_DIV 0x12 // SCL clock devider void InitI2C(unsigned char eeprom_i2c_address); void EEPROM_ByteWrite(unsigned int Address , unsigned char Data); void EEPROM_PageWrite(unsigned int StartAddress , unsigned char * Data , unsigned char Size); unsigned char EEPROM_RandomRead(unsigned int Address); unsigned char EEPROM_CurrentAddressRead(void); void EEPROM_SequentialRead(unsigned int Address , unsigned char * Data , unsigned int Size); void EEPROM_AckPolling(void);
