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); }