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.
HI all I have run into a problem that I have been banging my head against the wall for a couple of week. I have using the MSP430F2274 and the i2c bus and getting mixed results. I have the SDA and SCL lines pulled up to VCC with 10k resistors.
I would say about 30% of the time everything works great and I get good data from the device that I am connecting to. The rest of the time I am getting hung up on the polling loop waiting for the TX Flag to be set in my I2C_write function. It seems that the UCTXSTT bit is not getting cleared out on the first byte TX. I have to power cycle to get things going again. Please provide some guidance if you can. Thank you for your time.
Attached is my code:
void I2C_init()
{
P3SEL |= 0x06; // Assign I2C pins to USCI_B0s P3.2 = SCL; P3.1 = SDA
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = CLK_DIVIDER; // fSCL = SMCLK/3 = ~333kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x68; // Set slave address 0x68
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume
}
void I2C_write(char reg_addr, char parameters)
{
while(UCB0STAT & UCBUSY);
UCB0CTL1 |= UCTXSTT + UCTR; //Start Condition sends address of slave
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = reg_addr; //Load register Address
while (!(IFG2 & UCB0TXIFG)); //<---LOCKS UP HERE
UCB0TXBUF = parameters; //Load register parameters
while (!(IFG2 & UCB0TXIFG));
UCB0CTL1 |= UCTXSTP; //Send stop message
while (UCB0CTL1 & UCTXSTP); //Wait until the stop message is sent
}
signed int I2C_read(char reg_addr)
{
signed int Data = 0;
while(UCB0STAT & UCBUSY); //Make sure bus in not busy
UCB0CTL1 |= UCTXSTT + UCTR; //Start Condition sends address of slave
while (!(IFG2 & UCB0TXIFG)); //Make sure data has been shifted out
UCB0TXBUF = reg_addr; //Load register address to read
while (UCB0CTL1 & UCTXSTT); //Wait until the ACK message has been RX
while(UCB0STAT & UCBUSY); //Make sure bus is not busy
UCB0CTL1 &= ~UCTR //Sets the master as a receiver
UCB0CTL1 |= UCTXSTT; //Start Condition sends address of slave
while ((UCB0CTL1 & UCTXSTT)); //Make sure start has been cleared
UCB0CTL1 |= UCTXSTP; //Send stop message
while (!(IFG2 & UCB0RXIFG)); //Make sure RXIFG is set
Data = UCB0RXBUF; //Save data to memory
while((UCB0CTL1 & UCTXSTP)); //Make sure stop has been sent
return Data;
}
Hi,
From the users manual
" The UCBxTXIFG bit is set when
the START condition is generated and the first data to be transmitted can be
written into UCBxTXBUF. As soon as the slave acknowledges the address the
UCTXSTT bit is cleared.
The data written into UCBxTXBUF is transmitted if arbitration is not lost during
transmission of the slave address."
It sounds like arbitration is being lost and the slave address is not being acknowledged. Perhaps checking for the UCTXSTT bit being cleared and if after a certain amount of time if it isn't, restart the process by resending the START condition.
HTH,
Barry
Thank you for the quick response. I will implement the UCTXSTT check, but with respect to arbitration I only have the one slave device on the i2c bus. Although, I suppose, a loss of arbitration can occur if an interrupt occurs while the i2c bus is busy?
One thing that I would like to mention and get some feedback on is that I have connected the pullup resistors(10K) to a ~2.5 volt source and the SDA line is consistently pulled low, but when I connect the pullups to a 3.3V source the SDA line behaves as it is suppose to(most of the time). My assumption is that the lower voltage combined with the 10k pullups is limited too much current and the slave device is missing a clock pulse(s) (an acknowledge from the slave, relating back to Barry's post). I wonder if this could be the cause of random problems even at 3.3V? The voltage source is a regulated 3.3V and the slave device is also filtered with caps.
Thanks
Arbitration loss and slave NACK are two different things.blb said:It sounds like arbitration is being lost and the slave address is not being acknowledged.
Arbitration is lost if during slave address transmission the master detects a low SDA line when it should be high by its own output. Then the master cancels the start process and the other master (which is assumed to cause SDA low) continues. No harm is done because up to this point, both masters were sending the same signals. (thanks to clock stretching, they were even using the same clock speed implicitely - the slower one was 'dictating' the speed)
If arbitration is lost, this is flagged and you must try again. If you ar ehte only master in the system, an arbitration loss can only happen if there is no pullup ion the data line or the pullup is too weak and the clock frequency is too high.
The other situation is that no slave answers. If the slave is physically there, this has two possible reasons:
first, the slave does not sense the signals because of different VCC, weak pullups (note: on many MSPs the internal pullups are unavailable if the port pin is in output mode - this includes the OC output mdoe for the USCI), too-high clock or high parasitic capacitances which keep the signal low for too long.
The second possibility is a wrong slave address. Keep in mind that the slave address to write into the USCI slave address register is 7 bit. The LSB, that switches between read and write mode, is NOT included into the slave address. So if the slave manual says 0x20/0x21 for write/read, then the 'real' slave address to be used is 0x10.
In both cases, if a NACK is detected or if bus arbitration is lost, the TXIFG bit is reset and/or a previously to TXBUF written content is discarded. At the same time UCSTT is cleared. So once UCSTT is clear, it should be hecked for NACKIFG or arbitration loss before proceeding.
If UCSTT does not clear at all, this usually means that the SCL line doesn't come up. Usually a missing/weak pullup. so the master cannot complete the strt sequence since the clock is hold. The master cannot recover from this situation, since it cannot pull a low line high. And it should never happen normally. Usually, it is a sign of a bad board design or similar problems.
It may also be possible that the master has no clock (e.g. SMCLK is off, the crystal failed, whatever). Of course without a clock, the master cannot continue too.
JMG thanks for the detailed answer, a couple of questions for you..
Jens-Michael Gross said:Keep in mind that the slave address to write into the USCI slave address register is 7 bit. The LSB, that switches between read and write mode, is NOT included into the slave address. So if the slave manual says 0x20/0x21 for write/read, then the 'real' slave address to be used is 0x10.
Should the real slave address be 0x20? I don't understand where 0x10 comes from.
Jens-Michael Gross said:In both cases, if a NACK is detected or if bus arbitration is lost, the TXIFG bit is reset and/or a previously to TXBUF written content is discarded. At the same time UCSTT is cleared. So once UCSTT is clear, it should be hecked for NACKIFG or arbitration loss before proceeding.
So the UCTXSTT flag is cleared when the slave address is ACKD, NAKD or if bus arbitration is lost. Is that correct? If the NACKIFG flag is not set then to check for arbitration loss you would wait for the UCBxTXIFG flag to be set? Is there a better way to check for arbitration loss?
Thanks,
Barry
Hi, I also saw some issues with the MSP430's I2C module. It seems that there are some time critical code sequences. Especially your comment about that most of the time it is working let me think that there is some timing issues here... Is it possible that there are other interrupt sources used in your code and that those from time to time causes some delays in the I2C code?
I made good experience with the I2C code that is offered by TI. Maybe this one helps you too. Here is the link to the app note:
http://focus.ti.com/general/docs/litabsmultiplefilelist.tsp?literatureNumber=slaa382
Regards.
blb said:Should the real slave address be 0x20? I don't understand where 0x10 comes from.
Slave manuals usually give you two 8 bit addresses, one for reading and one for writing. Only the upper 7 bits are really the address while th eLSB is the R/W bit.
The MSP takes only the upper 7 bits, but right-justified (so the datasheet address is divided by 2) and adds the 8th bit later, based on the UCTR bit, when sending the start condition and slave address.
So if the slave address is 00100000/00100001 (0x20/0x21) the address to write into the slave address register is 0010000 (0x10) only. And there is no need to change the slave address when switching from write to read or back. Same slave, same address for both directions.
I agree it would have been way more intuitive if the slave address register would just take the 8 bit value and ignore the LSB.
Thanks for the input. The i2c functionality seems to be running very well now. I have added my code as a reference below. I believe the problem was that I had a timer that caused an interrupt on a regular basis and this was causing the i2c bus to halt and lose communication. I have added code to disable and then re-enable the interrupts while the i2c bus is needed.
The slaa382 application report was helpful in verifying this.
Thanks for the help everyone. I appreciate it very much.
void C_Dgyro_I2C_write(char reg_addr, char parameters)
{
__disable_interrupt();
while(UCB0STAT & UCBUSY);
UCB0CTL1 |= UCTXSTT + UCTR; //Start Condition sends address of slave
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = reg_addr; //Load address of slave register
while (!(IFG2 & UCB0TXIFG));
UCB0TXBUF = parameters; //Load address of slave register
while (!(IFG2 & UCB0TXIFG));
UCB0CTL1 |= UCTXSTP; //Send stop message
while (UCB0CTL1 & UCTXSTP); //Wait until the stop message is sent
__enable_interrupt();
}
signed int C_Dgyro_I2C_read(char reg_addr)
{
signed int gyroData = 0;
__disable_interrupt();
while(UCB0STAT & UCBUSY);
UCB0CTL1 |= UCTXSTT + UCTR; //Start Condition sends address of slave
while (!(IFG2 & UCB0TXIFG)); //Wait until the data has been shifted out
UCB0TXBUF = reg_addr; //Load address of slave register
while (UCB0CTL1 & UCTXSTT); //Wait until the acknowlege message has been received
while(UCB0STAT & UCBUSY);
UCB0CTL1 &= ~UCTR; //Sets the master as a receiver
UCB0CTL1 |= UCTXSTT; //Start Condition sends address of slave
while(UCB0CTL1 & UCTXSTT);
UCB0CTL1 |= UCTXSTP; //Send stop message
while (!(IFG2 & UCB0RXIFG));
gyroData = UCB0RXBUF; //Save data to memory
while((UCB0CTL1 & UCTXSTP));
__enable_interrupt();
return gyroData;
}
Normally, this isn't a problem. If your tiemr ISR keeps the processor busy for some time, the I2C master will simply delay the start of the next byte transfer until you stuffed TXBUF/read RXBUF. And the I2C slave will hold the clock line low until you do, stretchign the clock.cody lohse said:I had a timer that caused an interrupt on a regular basis and this was causing the i2c bus to halt and lose communication.
Your timer ISRs shouldn't be lengthy and time-comsuming anyway.
However, you r code will fail if the slave doesn't respond.
After settign UCSTT, you should wait for UCSTT to clear (you should even implement an emergency timeout, in case the clock vanishes or someone keeps the CLK line low)
Once ICSTTis clear, check for UCNACKIFG. If it is set, the slave didn't answer and you should set UCSTP and bail out.
THEN you can continue waiting for UCTXIFG and stuffing UCTXBUF. Or wait for UCRXIFG.
**Attention** This is a public forum