Jump to content
43oh

I2C Repeat start


Recommended Posts

Hi All,

 

Using the MSP430FR5739 UCSI_B in i2c mode.

 

Just checking ive got this right, as I've never used it before.
I neod to do the following, Ive left out the ack's
 
S= start
E= stop
 
[Address+write][Register][Address+read][Read 6 bytes][E]
 
Setup at beginning of program:


UCB0CTL1 = UCSWRST; // put eUSCI_B in reset state


UCB0CTLW0 = UCMODE_3 | UCMST | UCSSEL__SMCLK; //I2C master mode
UCB0BRW = 0x0008; //clock scaler


UCB0CTL1 &= !UCSWRST; // eUSCI_B in operational state
UCB0IE |= UCTXIE; // Enable interrupts

Program calls the following to get things going:


UCB0CTL1 |= UCSWRST; // put eUSCI_B in reset state


UCB0CTLW1 |= UCASTP_2; // stop after bytes sent
UCB0TBCNT = 6; // automatic stop after bytes

UCB0CTL1 &= !UCSWRST; // eUSCI_B in operational state

UCB0I2CSA = 0x3A; // address of slave
UCB0CTLW0 |= UCTR; //transmitter mode
UCB0CTLW0 |= UCTXSTT; // generate start condition,
Transmit interrupt (should 1 byte and then get ready to send a repeat start once that byte has finished)
case 0x18: // Vector 24: TXIFG0 Ok to accept data into buffer

UCB0TXBUF = 0x32; // send register of first byte of data
//I2C will start sending this data
//Get i2c ready for next bit
UCB0CTLW0 &= !UCTR; //receive mode
UCB0CTLW0 |= UCTXSTT; // generate start condition.
break;
Receive interrupt (accel[] is a char array where I want to store the data, should receive 6 bytes into this array then stop.
The auto stop was setup at the beginning.
case 0x16: // Vector 22: RXIFG0 Ready to take data from buffer

accel[UCB0TBCNT] = UCB0RXBUF; //Get data from buffer
break;

Thanks in advance!

Link to post
Share on other sites

The MSP430FR5739 has the enhanced eUSCI_B module, which is slightly different to the USCI_B on the g2xx series chips. The eUSCI_B doesn't have UCBxCTL0 and UCBxCTL1 registers (they've been merged into UCBxCTLW0). Interestingly the example initialization sequence in section 20.3.1 of the MSP430FR57xx Family User's Guide hasn't been updated to account for the change. Unless the FR57 headers have some backward compatibility support for USCI_B register names the guide needs to be corrected.

 

EDIT: Looking at the User's Guide again I see that UCBxCTL0 and UCBxCTL1 are available on FR57 parts. They just alias the appropriate bytes of UCBxCTLW0. When using UCBxCTL0 or UCBxCTL1 it looks like you need to append _L or _H (respectively) onto the names of any bit constants to get the correct value.

 

I think the initialization sequence needs to look like this:

UCB0CTLW0 = UCSWRST; // put eUSCI_B in reset state
UCB0CTLW0 = UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSWRST; // I2C master mode, SMCLK, retain reset flag state
UCB0BRW = 0x0008; //clock scaler

UCB0CTLW0 &= ~UCSWRST; // eUSCI_B in operational state (clear reset flag)
UCB0IE |= UCTXIE0; // Enable TX interrupt for address 0

The "get things going" block looks ok (apart from a couple more uses of UCB0CTL1). You might have issues due to taking the module out of reset before setting the slave address. I'm not sure on that though, the fact that UCTR is clear at that time might mean it's safe.

 

In the interrupt I think you're clearing UCTR and setting UCTXSTT too early. According to the timeline diagrams in the user guide you should wait for UCTXIFG0 to go high again after you set UCB0TXBUF to the command value.

 
The receive looks ok, though I've not used USCI_B interrupts before so can't be sure.

Link to post
Share on other sites

I think the initialization sequence needs to look like this:

UCB0CTLW0 = UCSWRST; // put eUSCI_B in reset state
UCB0CTLW0 = UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSWRST; // I2C master mode, SMCLK, retain reset flag state
UCB0BRW = 0x0008; //clock scaler

UCB0CTLW0 &= ~UCSWRST; // eUSCI_B in operational state (clear reset flag)
UCB0IE |= UCTXIE0; // Enable TX interrupt for address 0

 

Thanks! Not something someone new to MSP would know too well haha

 

 

The "get things going" block looks ok (apart from a couple more uses of UCB0CTL1). You might have issues due to taking the module out of reset before setting the slave address. I'm not sure on that though, the fact that UCTR is clear at that time might mean it's safe.

 

 

 

Thats the main bit I am confused about. The Family giude says 

 

After initialization, master transmitter mode is initiated by writing the desired slave address to the

UCBxI2CSA register, selecting the size of the slave address with the UCSLA10 bit, setting UCTR for
transmitter mode, and setting UCTXSTT to generate a START condition.

 

None of these registers say the module needs to be in reset mode to access, so I just left them out of it to keep things simple in my code (i.e. only things which must be done in reset are done in reset).

 

The timing diagram says it starts when both UCTXSTT and UCTR = 1, it then generates a start and sends the slave address so I figured as long as I set the slave address before these 2 registers it would be ok.

 

 

In the interrupt I think you're clearing UCTR and setting UCTXSTT too early. According to the timeline diagrams in the user guide you should wait for UCTXIFG0 to go high again after you set UCB0TXBUF to the command value.

 

The receive looks ok, though I've not used USCI_B interrupts before so can't be sure.

 

EDIT:

 

I think you're right, UCTXSTT needs to be set and UCTR clearing during transmission of the last byte (not before). UCTXIFG0 goes high once UCB0TXBUF is being sent.

Link to post
Share on other sites

Revised code. This should take care to avoid resending the data byte over and over...How does this look? 

case 0x16: // Vector 22: RXIFG0 Ready to take data from buffer
   accel[UCB0STATW >> 8] = UCB0RXBUF; //UCB0STATW byte counter starts at bit 8
   break;

case 0x18: // Vector 24: TXIFG0 TXIFG0 is set when TXBUF is empty or when Start condition is generated
/*  The UCTXIFG0 bit is set when the START condition is generated and the first data to
    be transmitted can be written into UCBxTXBUF. The UCTXSTT flag is cleared as soon as the complete
    address is sent.*/
   if (UCB0CTLW0 && UCTXSTT) { // UCTXSTT is still set so this branch will be taken the first time around (i.e. start condition generated)
      UCB0TXBUF = 0x32;// put byte of data into TX buffer.
   } else { // UCTXSTT will be cleared by now and TXBUF will have been transfered to shift register
      UCB0CTLW0 &= !UCTR; 	// Put into receive mode
      UCB0CTLW0 |= UCTXSTT; 	// generate start condition.
   }
   break;
Link to post
Share on other sites

You're right about not needing to hold the USCI module in reset between the initialisation and master transmitter mode initiation. The module will just wait for UCTXSTT to be set before starting to do anything.

 

The updated interrupt looks ok, but you need to use UCB0CTLW0 & UCTXSTT rather than UCB0CTLW0 && UCTXSTT as the condition ("bitwise and" rather than "logical and").

 

There's something else I totally forgot to mention - you'll need to set up the port registers appropriately to connect the USCI to the outside world. The pinouts vary per chip and package, so the information on that is in the datasheet for the MSP430FR5739 rather than the family user guide.

Link to post
Share on other sites

Oops, typo haha thanks.

 

I did this to the port registers. 

P1SELC |= I2C_SDA | I2C_SCK; 	//Configure I2C pins

P1SELC sets P1SEL0 and P1SEL1 simultaneously.

 

I assume USCI is tertiary function, the pin list on the datasheet says there are up to 5 functions on some of the pins, so who knows how i'd use something beyond tertiary :/

Link to post
Share on other sites

Oh thats something I didnt think of.

 

Does the USCI module add the read/write bit to the end of the slave address?

I assume it does, because the address is refered to as 7 bits, not 8. Thought i'd check because I cant change the address before the repeat start without resetting everything...

Link to post
Share on other sites

I don't think you want to select tertiary function for P1.6 and P1.7 - take a look at page 74 of the datasheet.

 

UCB0SDA on P1.6 and UCB0SCL on P1.7 are selected when bits 6 and 7 of P1SEL1 are set to one and the corresponding bits of P1SEL0 are zero.

 

The USCI module will automatically send the R/W bit along with the address. That's something to be wary of, as some I2C peripherals give an 8 bit address which includes the R/W bit already.

Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...