Part Number: MSP430F6720
Tool/software: Code Composer Studio
Hi,
I am trying to port slaa208a from MSP430F1/2XXX to MSP430F67XX. I was able to get the code work to some degree but are having some weird problems. Reading from EEPROm seems OK, but writing to EEPROM always has problems:
1) Writing 256 byte one by one takes 10s of seconds.
2) A lot of those bytes are not successfully written into eeprom. When read back from those addresses, many of them are 0xFF, the default value.
My code are attached below. How should I go about troubleshooting?
Thanks in advance.
i2ceeprom.h
#define I2C_PORT_SEL P2SEL #define I2C_PORT_OUT P2OUT #define I2C_PORT_REN P2REN #define I2C_PORT_DIR P2DIR #define SDA_PIN BIT1 // UCB0SDA pin #define SCL_PIN BIT0 // UCB0SCL pin #define SCL_CLOCK_DIV 0x0050 // SCL clock divider void InitI2C(unsigned char eeprom_i2c_address); void EEPROM_ByteWrite(unsigned int Address , unsigned char Data); //void EEPROM_PageWrite(unsigned char StartAddress , unsigned char * Data , unsigned char Size); unsigned char EEPROM_RandomRead(unsigned int Address); unsigned char EEPROM_CurrentAddressRead(void); //void EEPROM_SequentialRead(unsigned char Address , unsigned char * Data , unsigned char Size); void EEPROM_AckPolling(void); void resetI2C(void);
i2ceeprom.c
#include "msp430.h"
#include "i2ceeprom.h"
#define MAXPAGEWRITE 8
int PtrTransmit;
unsigned char I2CBufferArray[16];
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
// Setup eUSCI_B0
UCB0CTLW0 |= UCSWRST; // Enable SW reset
UCB0CTLW0 |= UCMST | UCMODE_3 | UCSSEL__SMCLK | UCSYNC; // I2C Master, use SMCLK
//UCB0BRW = SCL_CLOCK_DIV; // fSCL = SMCLK/40 = ~100kHz
UCB0BRW_L = 40; // fSCL = SMCLK/12 = ~100kHz
UCB0BRW_H = 0;
UCB0I2CSA = eeprom_i2c_address; // Slave Address
UCB0CTLW0 &= ~UCSWRST; // Clear SW reset, resume operation
if (UCB0STATW & 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
};
}
void resetI2C()
{
I2C_PORT_SEL &= ~(SDA_PIN + SCL_PIN); // Assign I2C pins to GPIO
I2C_PORT_DIR &= ~(SDA_PIN + SCL_PIN); // Set I2C pins to input
I2C_PORT_REN &= ~(SDA_PIN + SCL_PIN); // No pull-up or pulldown resistor
}
/*---------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Write operation.
/*---------------------------------------------------------------------------*/
void I2CWriteInit(void)
{
UCB0CTLW0 |= UCTR; // UCTR=1 => Transmit Mode (R/W bit = 0)
UCB0IFG &= ~UCTXIFG0;
UCB0IE &= ~UCRXIE0; // disable Receive ready interrupt
UCB0IE |= UCTXIE0; // enable Transmit ready interrupt
}
/*----------------------------------------------------------------------------*/
// Description:
// Initialization of the I2C Module for Read operation.
/*----------------------------------------------------------------------------*/
void I2CReadInit(void)
{
UCB0CTLW0 &= ~UCTR; // UCTR=0 => Receive Mode (R/W bit = 1)
UCB0IFG &= ~UCRXIFG0;
UCB0IE &= ~UCTXIE0; // disable Transmit ready interrupt
UCB0IE |= UCRXIE0; // 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 (UCB0STATW & 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();
UCB0CTLW0 |= UCTR | UCTXSTT; // start condition generation I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
UCB0CTLW0 |= UCTXSTP; // I2C stop condition
while(UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent
}
/*----------------------------------------------------------------------------*/
// 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(UCB0STATW & UCBUSY); // wait until I2C module has
// finished all operations
I2CReadInit();
UCB0CTLW0 |= UCTXSTT; // I2C start condition
while(UCB0CTLW0 & UCTXSTT); // Start condition sent?
UCB0CTLW0 |= UCTXSTP; // I2C stop condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTLW0 & 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 (UCB0STATW & 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;
// Write Address first
I2CWriteInit();
UCB0CTLW0 |= UCTXSTT; // start condition generation => I2C communication is started
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
// Read Data byte
I2CReadInit();
UCB0CTLW0 |= UCTXSTT; // I2C start condition
while(UCB0CTLW0 & UCTXSTT); // Start condition sent?
UCB0CTLW0 |= UCTXSTP; // I2C stop condition
__bis_SR_register(LPM0_bits + GIE); // Enter LPM0 w/ interrupts
while(UCB0CTLW0 & UCTXSTP); // Ensure stop condition got sent
return I2CBuffer;
}
/*----------------------------------------------------------------------------*/
// 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 (UCB0STATW & UCBUSY); // wait until I2C module has
// finished all operations
do
{
UCB0STATW = 0x00; // clear I2C interrupt flags
UCB0CTLW0 |= UCTR; // I2CTRX=1 => Transmit Mode (R/W bit = 0)
UCB0CTLW0 &= ~UCTXSTT;
UCB0CTLW0 |= UCTXSTT; // start condition is generated
while(UCB0CTLW0 & UCTXSTT) // wait till I2CSTT bit was cleared
{
if(!(UCNACKIFG & UCB0STATW)) // Break out if ACK received
break;
}
UCB0CTLW0 |= UCTXSTP; // stop condition is generated after
// slave address was sent => I2C communication is started
while (UCB0CTLW0 & UCTXSTP); // wait till stop bit is reset
__delay_cycles(500); // Software delay
}while(UCNACKIFG & UCB0STATW);
}
//------------------------------------------------------------------------------
// The USCIAB0_ISR is structured such that it can be used to transmit any
// number of bytes by pre-loading TXByteCtr with the byte count.
//------------------------------------------------------------------------------
// USCI_B0 interrupt service routine
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
switch (__even_in_range(UCB0IV, 30))
{
case USCI_NONE: break; // No interrupts
case USCI_I2C_UCALIFG: break; // ALIFG
case USCI_I2C_UCNACKIFG: break; // NACKIFG
case USCI_I2C_UCSTTIFG: break; // STTIFG
case USCI_I2C_UCSTPIFG: break; // STPIFG
case USCI_I2C_UCRXIFG3: break; // RXIFG3
case USCI_I2C_UCTXIFG3: break; // TXIFG3
case USCI_I2C_UCRXIFG2: break; // RXIFG2
case USCI_I2C_UCTXIFG2: break; // TXIFG2
case USCI_I2C_UCRXIFG1: break; // RXIFG1
case USCI_I2C_UCTXIFG1: break; // TXIFG1
case USCI_I2C_UCRXIFG0: // RXIFG0
I2CBuffer = UCB0RXBUF; // store received data in buffer
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
break;
case USCI_I2C_UCTXIFG0: // TXIFG0
UCB0TXBUF = I2CBufferArray[PtrTransmit]; // Load TX buffer
PtrTransmit--; // Decrement TX byte counter
if(PtrTransmit < 0)
{
while(!(UCB0IFG & UCTXIFG0));
UCB0IE &= ~UCTXIE0; // disable interrupts.
UCB0IFG &= ~UCTXIFG0; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(LPM0_bits); // Exit LPM0
}
break;
case USCI_I2C_UCBCNTIFG: break; // CNTIFG
case USCI_I2C_UCCLTOIFG: break; // LTOIFG
case USCI_I2C_UCBIT9IFG: break; // BIT9IFG
default: break;
}
}
main.c
//WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer sysInit();
WDTCTL = WDTPW | WDTSSEL__ACLK | WDTIS_3; // Enable watchdog timer: ACLK, 4min and 16 seconds
initSystem(); // Init i2c UART and other
int eepromAddr = 0;
char eepromCont = 0;
for(eepromAddr = 0; eepromAddr < 256; eepromAddr++) {
EEPROM_ByteWrite(eepromAddr, ++eepromCont);
EEPROM_AckPolling();
WDTCTL = WDTPW | WDTSSEL__ACLK | WDTIS_3 | WDTCNTCL;
}
eepromAddr = 0;
while (1) {
eepromCont = EEPROM_RandomRead(eepromAddr);
eepromAddr++;
if(eepromAddr > 256) {
eepromAddr = 0;
}
while (!(UCA1IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA1TXBUF = eepromAddr;
while (!(UCA1IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA1TXBUF = eepromCont;
while (!(UCA1IFG&UCTXIFG)); // USCI_A0 TX buffer ready?
UCA1TXBUF = 0x0D;
WDTCTL = WDTPW | WDTSSEL__ACLK | WDTIS_3 | WDTCNTCL;
__bis_SR_register(LPM3_bits | GIE);
}