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'm working on MSP430 to configure I2C. The MSP is master, USCI is repeatedly sending Data for three times after sending SlaveAddress with Read enable.
here is the code
///////////////////////////////////////// Code \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include "msp430f2618.h"
unsigned int d;
void main(void) {
WDTCTL = WDTPW + WDTHOLD;
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 10; // fSCL = SMCLK/10 = >100kHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST;
while (1)
{
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
UCB0I2CSA = 0x64;
UCB0TXBUF = 0x01;
//IFG2 = ~UCB0TXIFG;
UCB0CTL1 &= ~UCTR + UCTXSTT; ////////////////////////////////// here the Master is not changing into Receiver mode \\\\\\\\\\\\\\\\\\\\\\\\
//UCB0CTL1 |= UCTXSTT;
UCB0I2CSA = 0x64;
d = UCB0RXBUF;
//UCB0CTL1 = UCTXSTP;
}
}
here is the screen shot of Logic Analyzer
Also the I2C module is not giving constant output when it is operating more than 1 MHz.
I configured SMCLK for 8 MHz and scale the USCI I2C to operate more than 100kHz.
Please get me out of this.
One thing is the already mentioned programming bug;
(UCB0CTL1 &= ~UCTR + UCTXSTT) ~UCTR is 0xFFEF and 0xFFEF+0x02 is 0xFFF1 which clears UCTXNACK, UCTXSTP, UCTXSTT, but neither clears UCTR nor sets UCTXSTT, which apparently is what you want.
To clear UCTR and set UCTXSTT (for a repeated start in read mode), you cannot use the &= operator. Either use two operations (&= followed by |=) or one assignment.
UCB0CTL1 = (UCB0CTL1 & ~UCTR) |UCTXSTT;
The other thing is that the USCI I2C is not specified for ultra speed I2C mode. Maximum I2C frequency is 400kHz (high-speed mode)
HI Micheal,
thanks alot for the suggestion.
by the step UCB0CTL1 = (UCB0CTL1 & ~UCTR) |UCTXSTT; I'm able to see the change in the register.
but I have problem with receiver mode change from transmitter mode, its not happening even I used the above step.
more over as in the screen shot i attached in the previous message the USCI module is sending the data for three time after sending the start address.
have you experienced this problem before?
Tulasi Dwarakanath said:UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
UCB0I2CSA = 0x64;
You perhaps should set th eslave address before you start the transfer. The slave address needs ot be set while SWRST is low, else funciton is not guaranteed. (Edit: it's the own address in slave mdoe that needs to be set during SWRST set) Likely, your first transfer (not shown on the analyzer) was going to the general call address 0x00.
However, take ing a secodn look at your code, there are several other issues. You don't seem to have noticed that teh USCI hardware is independent of processor function.
You start a transfer and then immediately stop it, start the next and loop. I guess your loop is executed a hundred times before even the start byte has been sent. Your resulting pattern on the logic analyzer is an interference of your patienceless rampaging code and the baudrate-controlled USCI.
Setting the UCTXSTT bit is no library funciton call that returns when things are done. For the CPU, setting this bit is by no mwans different from setting a bit in any global variable: 4 or 5 MCLK cycles and it is done and hte PCU continues.. But the job of the USCI hardware has just started.
When setting UCTYSTT, you have to wait until it clears (which signals that the start byte has been sent). Then you have to check UCNACKIFG for whehter the slave has answered at all. If it is set, set UCTXSTP and bail out.
If UCNACKIFG wasn't set, then you can write your outgoing data to TXBUF, then clear UCTR, set UCTXSTT again. Now wait until UCRXIFG is set, indicating that you have received a byte. then you can read txbuf, set UCTXSTP and wait until it has cleared, at which tim ethe transfer is complete.
For the wait times, you can jsu tdo a while loop or do something else and return later for checking. For the CPU, it is quite some time of waiting. Later, when the transfer is done with interrupts, you may fire the job and all is done in teh background when its tiem has come. And you get notified form the interrupt routine when all is done. And in the meantime, the CPU can do lots of other things.
Hi,
Try this if this works.
///////////////////////////////////////// Code \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include "msp430f2618.h"
unsigned int d;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset, TO CONFIGURE usci MACHINE
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 10; // fSCL = SMCLK/10 = >100kHz
UCB0BR1 = 0;
UCB0CTL1 &= ~UCSWRST; // disable SW reset TO RUN usci MACHINE
while (1)
{
/*****TRANSMITTING***********/
UCB0I2CSA = 0x64; //Slave adress
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
//------------------------------------------------------
UCB0TXBUF = 0x01; //Loading Tx buffer with Data
/* lets check for successful TRANSMISSION. UCB0TXIFG is set
when the TXbuf is empty i.,e data is transmitted */
while(!(IFG2 & UCB0TXIFG));
//Generate stop condition and this is cleared
//automatically once it is successfully generated
UCB0CTL1 |= UCTXSTP;
while(UCB0CTL1 & UCTXSTP)
/*****RECEIVING***********/
UCB0I2CSA = 0x64; //Slave adress
UCB0CTL1 &= ~UCTR
UCB0CTL1 |= UCTXSTT;
//---------------------------------------------------------
/* lets check for successful RECEPTION. UCB0TXIFG is set
when the RXbuf is full i.,e data is loaded(complete character or byte */
while(!(IFG2 & UCB0RXIFG));
UCB0CTL1 |= UCTXSTP; //Always send/generate STOP condifiton befor last
d = UCB0RXBUF;
while( (UCB0CTL1 & UCTXSTP); //Wait till stop condition is sent
}
}
/******Note : STOP condition in Master receive mode is always preceeded by NACK and the explanation for
why to send STOP ccondition before last byte receved data look at michael jens explanation in
one of the I2C forums in here I will post if I find it.
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
{
// Not-acknowledge interrupt. This flag is set when an acknowledge is expected
// but is not received. UCNACKIFG is automatically cleared when a START condition
// is received.
if( UCB0STAT & UCNACKIFG )
{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
UCB0STAT &= ~UCNACKIFG; // Clear interrupt flag
}
}
Hi Sri
I tried the code you have sent. thank you very much in helping me.
but I encounterd a problem while running the code.
///////////////////////////////////////// Code \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
#include "msp430f2618.h"
unsigned int d;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD;
P3SEL |= 0x06; // Assign I2C pins to USCI_B0
UCB0CTL1 |= UCSWRST; // Enable SW reset, TO CONFIGURE usci MACHINE
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 10; // fSCL = SMCLK/10 = >100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x64; //Slave adress
UCB0CTL1 &= ~UCSWRST; // disable SW reset TO RUN usci MACHINE
while (1)
{
/*****TRANSMITTING***********/
UCB0I2CSA = 0x64; //Slave adress
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
//------------------------------------------------------
UCB0TXBUF = 0x01; //Loading Tx buffer with Data
///////////////// I need repeated start condition so I removed the Stop condition generation
/*****RECEIVING***********/ /////////////////// the receiver mode is not setting after the transmitter mode
UCB0CTL1 &= ~UCTR
UCB0CTL1 |= UCTXSTT;
//---------------------------------------------------------
/* lets check for successful RECEPTION. UCB0TXIFG is set
when the RXbuf is full i.,e data is loaded(complete character or byte */
while(!(IFG2 & UCB0RXIFG));
UCB0CTL1 |= UCTXSTP; //Always send/generate STOP condifiton befor last
d = UCB0RXBUF;
while( (UCB0CTL1 & UCTXSTP); //Wait till stop condition is sent
}
}
/******Note : STOP condition in Master receive mode is always preceeded by NACK and the explanation for
why to send STOP ccondition before last byte receved data look at michael jens explanation in
one of the I2C forums in here I will post if I find it.
when I test the receiver mode independently without Transmitter, its working.
again i tested by including the transmitter ( both together are not working i'm not getting the output)
Hi, I am sorry I havent got time to test the code that I have posted would please summary the results that you have got please.So this will make me know what you want and where you or (me) fgoing wrong
Sri
hi Sri,
the MSP430 is not changing the mode from Trnsmitter to Receiver to get the data from the slave.
Once it worked. for the same type of code which I posted in the beginning of the conversation.
Thank You.
Hi,
If you look at the code modifications that you did, You can clearly find these things missing which are critical and are suggested by Michael jens in his post. Repeated start condition which is a RESTART mode, I think you can send/receive n bytes of data sequentially without having to send STOP condition every time after you send/receive a byte. As far as the code that you have posted it sends a byte and reads it back.This is happening forever. I don't think this is what a RESTART does(may be I am wrong). But if your concern is that you were unable to c the machine going in to receive mode after you set the bit UCB0CTL1 &= UTR then you should properly initialize and run I2C machine. You should wait till the data in TXbuff is transmitted completely.[how you know this?? --you should look for TXIFG here] TXIFG says that the TXbuff is empty .
so the piece of code where you wait for the buff to be empty ----------while((IFG2 & UCB0TXIFG) == 0); I think I have coded this as [while(!(IFG2 & UCB0TXIFG));] is being removed in your modifications. Run the code by itself , fix any minor problems and see on the scope this will give you the slave address and your data repeatedly. The problem of reading data 3 times(your problem definition in first post) will get resolved. I think.........
Regards,
Sri.
Hi sri,
I resolved the problem of sending the data three times. :) Thank You,
after that I noticed that the Master is not changing into receiver mode.
from the code
UCB0CTL1 |= UCTR + UCTXSTT; =====>>> setting UCBOTXIFG means the Salve has Acknowledged the first byte(Slave Address) and Data is ready for Transmission
UCB0TXBUF = 0x01; =====>>> after this step the UCB0TXIFG is getting cleared telling that the byte has been put on to the BUS.
after the above step we need to check for NACKIFG to continue with the next steps.
its correct ( from your point of view) to send more Data bytes to the Slave.
here in my Slave case LTC2942 (Battery Monitor), i need to send a repeated start for reading the Data from the Location thwt I sent in the previous Write routine, so I'm setting the repeated Start condition with Read Enable.
UCB0CTL1 &= ~UCTR;
UCB0CTL1 |= UCTXSTT; =====>>> after this it is not setting the UCB0RXIFG which (i think) is similar to the above Condition while transmitting.
even I tried to set that bit forcibly( though it is not correct) so that it can receive the data.
Why i'm telling this is Slave is Putting data on to the bus that I can see in the Logic analyzer, but MSP is not receiving the Data ( this happens only if the RXIFG is set. Am I correct?? ).
Okay now, it mean you want to read multiple bytes from your slave is that right? I mean ,you want to read something(coloumb count or current etc) which is stored in two 8 bit registers, you want to read reg1 with MSB's and REg2 LSB? is that right???
No., RXIFG is set when a byte has been received. It's not a prerequisite. If you have started a transfer with UCTR clear, the master first sends the start byte (addressing the slave) and then begins clockign data in. After 8 bits (no mater whether the slave is sill there), RXIFG is set and a byte is presented on RXBUF. Also, the master will clock out an ACK, then begin to clock in another 8 bytes. If you didn't read RXBUF before the 7th bit is received, the master will hold SDL low and wait.Tulasi Dwarakanath said:MSP is not receiving the Data ( this happens only if the RXIFG is set. Am I correct?? ).
To get an interrupt for icoming dta, you'll have to set the RXIE bit. Fo rpolling, checkign for RXIFG is enough. RXIFG is automatically cleared when you read RXBUF.
Hi sri,
sorry for the late reply. I was in Diwali Vacation.
Yes I need to Read the data from the slave registers.
Hi,
Belated diwali wishes. anyways if that what u want , better have a look here , this what I did to read multiple bytes of data from Accelerometer. Just feel the code and go through the entire thread. Jens michael have explained some portion regards NACK flag and etc. Try it out and update your results r opinions.
just a quick note, if you want to read data continuously from any slave device, you will generate a start every time you read a new byte from slave and thats it, no need of slave adress again.u will c these in the code on this thread. The slave device automatically increments its pointer location and sends the data (depends on that device) sequencially in little Endian format of big endian format.
Regards,
Sri.
**Attention** This is a public forum