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'm using code composer studio (version: 9.3.0.00012) and the msp430 driverlib library to have the msp-expFR5994 communicate with an off-board I2C EEPROM. I have verified that I2C is communicating with the EEPROM by writing to the first page of the EEPROM (128 bytes). However, I run into problems when I try to write to subsequent pages. I based the code off the eusci_b_i2c_ex3_masterTxMultiple example in driverlib, but this uses interrupts, and I rather stick to polling for now. Here is my implementation:
void SYS_I2C_init(void){ EUSCI_B_I2C_initMasterParam defaultParam = {0}; defaultParam.selectClockSource = EUSCI_B_I2C_CLOCKSOURCE_SMCLK; defaultParam.i2cClk = CS_getSMCLK(); defaultParam.dataRate = EUSCI_B_I2C_SET_DATA_RATE_100KBPS; defaultParam.byteCounterThreshold = 0; // 0 disables the counter defaultParam.autoSTOPGeneration = EUSCI_B_I2C_NO_AUTO_STOP; EUSCI_B_I2C_initMaster(EUSCI_B2_BASE, &defaultParam); //Specify slave address EUSCI_B_I2C_setSlaveAddress(EUSCI_B2_BASE, 0x50); //Set Master in transmit mode EUSCI_B_I2C_setMode(EUSCI_B2_BASE, EUSCI_B_I2C_TRANSMIT_MODE); //Enable I2C Module to start operations EUSCI_B_I2C_enable(EUSCI_B2_BASE); // EUSCI_B_I2C_clearInterrupt(EUSCI_B2_BASE, // EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + // EUSCI_B_I2C_NAK_INTERRUPT // ); // // //Enable master transmit interrupt // EUSCI_B_I2C_enableInterrupt(EUSCI_B2_BASE, // EUSCI_B_I2C_TRANSMIT_INTERRUPT0 + // EUSCI_B_I2C_NAK_INTERRUPT // ); }
#define EEPROM_PAGE_SIZE 128 uint16_t currAddr16_t = 0; uint16_t currPage = 0; uint8_t currAddr8_msb = 0; uint8_t currAddr8_lsb = 0; uint8_t byteCtr = 0; for (currPage = 0; currPage < 3; currPage++) { currAddr8_msb = (currAddr16_t >> 8) & 0xFF; currAddr8_lsb = currAddr16_t & 0xFF; EUSCI_B_I2C_masterSendMultiByteStart(EUSCI_B2_BASE, currAddr8_msb); EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B2_BASE, currAddr8_lsb); for (byteCtr = 0; byteCtr < EEPROM_PAGE_SIZE; byteCtr++){ EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B2_BASE, 0xFF); } EUSCI_B_I2C_masterSendMultiByteStop(EUSCI_B2_BASE); while (EUSCI_B_I2C_SENDING_STOP == EUSCI_B_I2C_masterIsStopSent (EUSCI_B2_BASE)); HWREG16(EUSCI_B2_BASE + OFS_UCBxIFG) &= ~(UCTXIFG); // ADDED TO FIX ISSUE #2 __delay_cycles(15000); // ADDED TO FIX ISSUE #1 currAddr16_t += EEPROM_PAGE_SIZE; } byteCtr = 0;
There were two problems I was encountering:
ISSUE #1) When currPage = 0, the EEPROM first page (128 bytes) would successfully be written to 0xFF. However, when currPage = 1, the processor would enter EUSCI_B_I2C_masterSendMultiByteNext(EUSCI_B2_BASE, currAddr8_lsb); and get stuck in in the infinite loop:
void EUSCI_B_I2C_masterSendMultiByteNext(uint16_t baseAddress, uint8_t txData) { //If interrupts are not used, poll for flags if(!(HWREG16(baseAddress + OFS_UCBxIE) & UCTXIE)) { //Poll for transmit interrupt flag. while(!(HWREG16(baseAddress + OFS_UCBxIFG) & UCTXIFG)) { ; } } //Send single byte data. HWREG16(baseAddress + OFS_UCBxTXBUF) = txData; }
UCTXIFG was never getting set and therefore the processor was stuck inside this loop. After trial and error, I found that adding the following fixed this issue:
__delay_cycles(15000); // ADDED TO FIX ISSUE #1
The processor now completes the for (currPage = 0; currPage < 3; currPage++) nested loop in my implementation, and exits the loop. However, another problem occurred:
ISSUE #2) Even though the program executes the nested loop, only the first page of the EEPROM was getting written to. In other words, the currPage = 0 iteration was successful in writing to the EEPROM, but currPage = 2 and currPage = 3 did NOT write to the EEPROM. The nested loops completes successfully, but the write fails. I was able to fix this issue by adding the following:
HWREG16(EUSCI_B2_BASE + OFS_UCBxIFG) &= ~(UCTXIFG); // ADDED TO FIX ISSUE #2
So I seem to have solved issue #1 and #2 now by adding these two lines of code:
HWREG16(EUSCI_B2_BASE + OFS_UCBxIFG) &= ~(UCTXIFG); // ADDED TO FIX ISSUE #2 __delay_cycles(15000); // ADDED TO FIX ISSUE #1
I have no idea what was causing the issues and I'm not sure how the solution for issue #1 and #2 fixed the problem.
What do you think was causing issue #1 and issue #2? How did the two lines of code above solve these issues?
I would like for this to become a learning opportunity so I would appreciate any insight, thanks!
On #1: The I2C EEPROM I'm familiar with (M24256) indicates "busy" using a NACK on the next request. This would show up as a UCNACKIFG along with the absence of a TXIFG in SendMultiByteNext (viz. program hang).
Driverlib doesn't really help much with UCNACKIFG, but you could check it explicitly (and loop). As I recall, I decided this was Too Much Like Work and put in a write-timer (5ms per the M24256 datasheet), which is what you did.
Unsolicited: The M24256 comes initialized with 0xFF-s. I suggest you use some other value(s) as a test pattern. For best results, arrange for the pattern to be different for each page.
The EEPROM I'm using is Microchip's AT24C512C, in case anyone finds this thread useful.
Regarding Issue #1:
What you say makes sense. I've never been very good at following the I2C timing specs of slaves - don't tell my boss - so it makes sense that I should either check for the slave's ACK/NACK or wait a bit before sending the next byte of data. Like the M24256, the AT24C512C seems to also have a write cycle time of 5ms.
However, I'm still not sure if this is the root cause of issue #1. The first page of the EEPROM was always successfully written to without any delays between byte writes. The problem was that after the first STOP condition (currPage = 0), the CPU would hang in masterSendMultiByteNext(EUSCI_B2_BASE, currAddr8_lsb) of currPage = 1. So a whole page is successfully written to before this issue even occurs.
To solve issue #1, I had to insert __delay_cycles(15000) between the STOP condition of the previous page write and the START condition of the next page write. The delay was not inserted between byte writes.
Perhaps the issue has more to do with not following timing specs between STOP and START conditions?
Regarding Issue #2:
From what I understand, after UCTXIFG is set it can be cleared automatically by writing to UCBxTXBUF or by explicitly clearing UCTXIFG. It seems masterSendMultiByteStop() polls for UCTXIFG but never clears it. So when masterSendMultiByteStart() is called, it also polls for UCTXIFG, but UCTXIFG was never cleared.
Could this be what was causing issue #2? Is the user responsible for clearing UCTXIFG after masterSendMultiByteStop() is called? I followed the eusci_b_i2c_ex3_masterTxMultiple example in driverlib and the example never explicitly had to clear UCTXIFG, so that's why I'm a bit confused.
#1: The write cycle begins when you send the Stop. Thus you need a time span of Twrite=5ms between the Stop and the next Start. The first page always succeeds since there's no preceding Stop.
#2: Looking at User Guide (SLAU367O) Fig 32-12, it looks like sending a Stop doesn't set TXIFG=0, so there's a race here depending on how soon after the last byte you send the Stop. (I always use interrupts, and so I always clear the stale status (including TXIFG) before enabling -- in other words, I never looked, so maybe that's what happens.)
**Attention** This is a public forum