This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
I trailered the following code to use it for MSP430F47197.
www.ti.com/lit/an/slaa208a/slaa208a.zip
Here is my code:
#include "msp430x471x7.h" #define SlaveAddress 0x50 #define MAXPAGEWRITE 32 int PtrTransmit; unsigned char I2CBufferArray[100]; unsigned char I2CBuffer; unsigned char read_val[64]; unsigned char write_val[64]; unsigned int address = 0xC0; #define I2C_PORT_SEL P2SEL #define I2C_PORT_OUT P2OUT #define I2C_PORT_REN P2REN #define I2C_PORT_DIR P2DIR #define SDA_PIN BIT1 // SDA pin #define SCL_PIN BIT2 // SCL pin 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 int 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); int main(void) { unsigned int i; WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer InitI2C(SlaveAddress); // Initialize I2C module EEPROM_ByteWrite(0x0000,0x12); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion EEPROM_ByteWrite(0x0001,0x34); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion EEPROM_ByteWrite(0x0002,0x56); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion EEPROM_ByteWrite(0x0003,0x78); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion EEPROM_ByteWrite(0x0004,0x9A); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion EEPROM_ByteWrite(0x0005,0xBC); EEPROM_AckPolling(); // Wait for EEPROM write cycle // completion read_val[0] = EEPROM_RandomRead(0x0000); // Read from address 0x0000 read_val[1] = EEPROM_CurrentAddressRead();// Read from address 0x0001 read_val[2] = EEPROM_CurrentAddressRead();// Read from address 0x0002 read_val[3] = EEPROM_CurrentAddressRead();// Read from address 0x0003 read_val[4] = EEPROM_CurrentAddressRead();// Read from address 0x0004 read_val[5] = EEPROM_CurrentAddressRead();// Read from address 0x0005 // Fill write_val array with counter values for(i = 0 ; i <= sizeof(write_val) ; i++) { write_val[i] = i; } address = 0x0000; // Set starting address // Write a sequence of data array EEPROM_PageWrite(address , write_val , sizeof(write_val)); //Read out a sequence of data from EEPROM EEPROM_SequentialRead(address, read_val , sizeof(read_val)); __bis_SR_register(LPM4); __no_operation(); } /*----------------------------------------------------------------------------*/ // 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_B1 // Recommended initialisation 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 = 35; // 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 = 0x01A5; // 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) IFG2 &= ~UCB1TXIFG; IE2 &= ~UCB1RXIE; // disable Receive ready interrupt IE2 |= UCB1TXIE; // 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) IFG2 &= ~UCB1RXIFG; IE2 &= ~UCB1TXIE; // disable Transmit ready interrupt IE2 |= UCB1RXIE; // 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(!(UCNACKIFG & UCB1STAT)) // 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(UCNACKIFG & UCB1STAT); } /*---------------------------------------------------------------------------*/ /* 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 [USCIAB1TX_VECTOR] void TX_ISR_I2C(void) #else #pragma vector=USCIAB1TX_VECTOR __interrupt void TX_ISR_I2C(void) #endif { if(UCB1TXIFG & IFG2) { UCB1TXBUF = I2CBufferArray[PtrTransmit];// Load TX buffer PtrTransmit--; // Decrement TX byte counter if(PtrTransmit < 0) { while(!(IFG2 & UCB1TXIFG)); IE2 &= ~UCB1TXIE; // disable interrupts. IFG2 &= ~UCB1TXIFG; // Clear USCI_B1 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } } else if(UCB1RXIFG & IFG2) { I2CBuffer = UCB1RXBUF; // store received data in buffer __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } }
I have no idea why it stops right at
EEPROM_ByteWrite(0x0000,0x12);
Also, "Own Address" I am not too sure!!!
Any idea what the problem is?
Cameron,
Yes this example is part of TI's Code Examples and can be found by the following links. (Documentation + code)
Here are my uncertainties:
1. How can I find out about the "OWN ADDRess"?!
2. I believe the Slave Address is also should not be 0x50!
3. Is this function cause a problem that it does not go through?
4. It stops at Write Byte Function and gets stuck at the following line:
I2CTCTL |= I2CSTP;
Here is the snap shot of the code when it gets stuck in the Write Byte!
Thank you very much for your time.
p.s. As you can see I have changed B0 to B1 and changed the PIN3s to PIN2s.
I have a question for you Cameron. I suppose to use this interrupt at the end of Write Cycle right? But I don't know why the code does not get into the following!
/*---------------------------------------------------------------------------*/ /* 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 [USCIAB1TX_VECTOR] void TX_ISR_I2C(void) #else #pragma vector=USCIAB1TX_VECTOR __interrupt void TX_ISR_I2C(void) #endif { if(UCB1TXIFG & IFG2) { UCB1TXBUF = I2CBufferArray[PtrTransmit];// Load TX buffer PtrTransmit--; // Decrement TX byte counter if(PtrTransmit < 0) { while(!(IFG2 & UCB1TXIFG)); IE2 &= ~UCB1TXIE; // disable interrupts. IFG2 &= ~UCB1TXIFG; // Clear USCI_B1 TX int flag __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } } else if(UCB1RXIFG & IFG2) { I2CBuffer = UCB1RXBUF; // store received data in buffer __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 } }
As for the Own Address. I don't know why they put it there. Because I guess it might be used as Slave mode as well. Regarding the Slave Address, that one also we are not quite sure. The EEPROM is CAT24C01 and it is written in its data-sheet that we need to send 1010 and as we do not have A0, A1, and A3 so we have three zeros and for Read we use 1 and write 0! So, is it 0xA0 then?!
Hi William!
We realized that we had initialized the wrong Interrupt registers and we put those on and now it is working. Having said this, we still have problem of Reading and Writing issue. No matter what address you choose it keeps showing what you have written as follows.
To clear this for you I am going to bring the following example.
When you write this:
EEPROM_ByteWrite(0x0000,0x12);
EEPROM_AckPolling();
And for Read
read_val[0] = EEPROM_RandomRead(0x0010);
I still get 12!!! I was supposed to get FF not 12!
I believe there must be something messed up in the Read function as follows.
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; }
What do you say?
Guys! we made the Byte write and Random Read functions to work! We had the buffers in a reverse orders that's why we had problem to read back and also a weird thing in the read function that I will explain it later on!
Having said these, we still need to know which method works better:
Having the byte write/read method or page write/read? What do you say? which way is more efficient and why?
CaEngineer said:Having the byte write/read method or page write/read? What do you say? which way is more efficient and why?
This depends if you plan to write a large chunk of data at a time. Typically, you would want to use page write/read for a sequence of data. Do keep in mind that most EEPROM has a limited max number of bytes you could write/read at the time before you could start the next transfer. But, EEPROM is also designed in such to write single-byte to a specific address.
Regards,
William
**Attention** This is a public forum