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.

I2c interface to srf02 ultrasonic range finder, several basic problems

Other Parts Discussed in Thread: MSP430G2553, PCA9306

Trying to interface MSP430G2553 with SRF02 ultrasonic ranger finder, nothing is working.

Several problems, appreciate answer to any of them:

  1. On the connection side: the srf02 is a 5V device while the MSP430 is a 3.3V device. On the srf02, datasheet says i2c SDA and SCL should be pulled up to 5V, while the MSP430 warns to not pull up anything above 3.3V.

So what should I do? Right now I’m trying to pull it up to 5V with a 10k resistor, but with an inline resistor of 1k. Will this work? I'm trying to get it to work, and not worrying about performance issues currently.

       2.   On the datasheet it says the Device Address is 0xE0, so for MSP430 is it 0xE0 or 0x70?

       3.   Also, I’ve been trying weeks to do the coding part in CCS. I’m trying to do the following idea (it’s all from the datasheet):

I2c_init();

I2c_write(0x70); (or 0xE0 don’t know which one is right)

I2c_write(0x00);

I2c_write(0x51);

I2c_stop();

 Right now I can’t even implement this properly (i try to write 3 bytes in, but the code won't even get to the second byte(0x00)). The code below (very long) is mostly the same as an example code written by Mr. Dang from TI. I changed some parts:

If anyone can see any glaring errors in the part I changed (indicated in bold below). It would help immensely.

#include <msp430.h>
//1.6
#define NUM_BYTES_TX 3 // How many bytes?
#define NUM_BYTES_RX 1

int RXByteCtr, RPT_Flag = 0; // enables repeated start when 1
volatile unsigned char RxBuffer[128]; // Allocate 128 byte of RAM
unsigned char *PTxData; // Pointer to TX data
unsigned char *PRxData; // Pointer to RX data
unsigned char TXByteCtr, RX = 0;
int txc, rxc = 0;
unsigned char test = 0;
unsigned char TxData[] = {0x70,0x00,0x51}; //data trying to send

void Setup_TX(void);

void Setup_RX(void);

void Transmit(void);
void Receive(void);
int flag = 0;

int main(void)
{


WDTCTL = WDTPW + WDTHOLD; // Stop WDT
P1SEL |= BIT6 + BIT7; // Assign I2C pins to USCI_B0
P1SEL2|= BIT6 + BIT7; // Assign I2C pins to USCI_B0

while(1){
//Transmit process
Setup_TX();
RPT_Flag = 1;
Transmit();
if(flag==1)
{
P1DIR |= BIT0;
P1OUT |= 0x01;
}
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
//Receive process

Setup_RX();
Receive();
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
}
}

//-------------------------------------------------------------------------------
// The USCI_B0 data ISR is used to move received data from the I2C slave
// to the MSP430 memory. It is structured such that it can be used to receive
// any 2+ number of bytes by pre-loading RXByteCtr with the byte count.
//-------------------------------------------------------------------------------
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
{ // does the transmitting & receiving
//Rx = 1 is master receive mode
if(RX == 1){ // Master Receive?
RXByteCtr--; // Decrement RX byte counter
if (RXByteCtr)
{
*PRxData++ = UCB0RXBUF; // Move RX data to address PRxData
}
else
{
if(RPT_Flag == 0)
UCB0CTL1 |= UCTXSTP; // No Repeated Start: stop condition
if(RPT_Flag == 1){ // if Repeated Start: do nothing
RPT_Flag = 0;
}
*PRxData = UCB0RXBUF; // Move final RX data to PRxData
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}

else{ //Rx = 0 master transmitter mode // Master Transmit
if (TXByteCtr) // Check TX byte counter
{ //I changed this part
UCB0TXBUF = TxData[txc]; // Load TX buffer
txc = txc + 1; //until here
flag = 1;
TXByteCtr--; // Decrement TX byte counter
}
else
{

if(RPT_Flag == 1){
RPT_Flag = 0;
PTxData = (unsigned char *)TxData; // TX array start address
TXByteCtr = sizeof TxData; // Load TX byte counter
// PTxData = *MSData; // TX array start address
// TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
__bic_SR_register_on_exit(CPUOFF);
}
else{
UCB0CTL1 |= UCTXSTP; // I2C stop condition
IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
}
}

}

void Setup_TX(void){ //unchanged
_DINT();
RX = 0;
IE2 &= ~UCB0RXIE;
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent// Disable RX interrupt
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x70; // Slave Address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0TXIE; // Enable TX interrupt
}
void Setup_RX(void){ //unchanged
_DINT();
RX = 1;
IE2 &= ~UCB0TXIE;
UCB0CTL1 |= UCSWRST; // Enable SW reset
UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C Master, synchronous mode
UCB0CTL1 = UCSSEL_2 + UCSWRST; // Use SMCLK, keep SW reset
UCB0BR0 = 12; // fSCL = SMCLK/12 = ~100kHz
UCB0BR1 = 0;
UCB0I2CSA = 0x70; // Slave Address
UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation
IE2 |= UCB0RXIE; // Enable RX interrupt
}

void Transmit(void){ //changed first two lines to account for multiple byte sending
PTxData = (unsigned char *)TxData; // TX array start address
TXByteCtr = sizeof TxData; // Load TX byte counter
// PTxData = *MSData; // TX array start address
// TXByteCtr = NUM_BYTES_TX; // Load TX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTR + UCTXSTT; // I2C TX, start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}
void Receive(void){ //changed first two lines
PRxData = (unsigned char *)RxBuffer; // Start of RX buffer
RXByteCtr = NUM_BYTES_RX; // Load RX byte counter
while (UCB0CTL1 & UCTXSTP); // Ensure stop condition got sent
UCB0CTL1 |= UCTXSTT; // I2C start condition
__bis_SR_register(CPUOFF + GIE); // Enter LPM0 w/ interrupts
}

  • Randy Yao said:
    On the srf02, datasheet says i2c SDA and SCL should be pulled up to 5V, while the MSP430 warns to not pull up anything above 3.3V.

    That's right. The two chips use different logic levels which are incompatible.

    There are three possible solutions:

    1) you pull the lines up to 3.3V and pray that this is detected as 'high' by the 5V device. However, you shouldn't use the bus at full speed then - even if the 5V devices accepts 3.3V as high, the signal waveform might prevent proper data transfer at higher speeds then.

    2) You use a dedicated I2C interface chip. There are some available, like the PCA9306.

    3) some time ago I posted a schematics here in the forum where I used standard CMOS logic gates as an I2C line driver, which can be used for level conversion too.

    Randy Yao said:
    Right now I’m trying to pull it up to 5V with a 10k resistor, but with an inline resistor of 1k. Will this work?

    Result is almsot idetical to pulling up to 3.3V. Just that you have the inline resistor in the way when the MSP pulls the line down -> even worse.
    the two resistors will limit the current into the MSP pin, so that the surplus 1.7V are wasted on them. With 11k total, thia means 155µA. But most of the voltage (10/11) will drop on the pullup resistor, which means the series resistor will drop only 155mV an the line voltage will rise to 3.3V+155mV+(~0.2V clamp diode voltage) = ~3.65V. This will maybe increase the chance that this is accepted as high by the 5V device, but also significantly affect the signal waveform.

    Randy Yao said:
    On the datasheet it says the Device Address is 0xE0, so for MSP430 is it 0xE0 or 0x70?

    0x70. Whcih is converted into a 0xe0/0xe1 start byte by the MSP, depeding on transfer direction.

    Randy Yao said:
    I’m trying to do the following idea (it’s all from the datasheet):

    When using the USCI in I2C mode, the address byte is included into the start sequence. You program the slave address (0x70), set the transfer direction (UCTR), then set UCTXSTT and the USCI will send a start condition, the start byte (address and direction bit) and then pull an ACK from the slave.
    If sending, the USCI expects you to put the first data byte into TXBUF before it pulls the slave ACK. Then it either begins sending and flags you (UXTXIFG) that you can put the next byte into TXBUF, or sets UCNACKIFG to tell you that the slave didn't respond (and discards the data byte).

    Randy Yao said:
    If anyone can see any glaring errors in the part I changed

    Not int he part you changed but in the demo code you used.

    I guess it is from msp430g2xx2.uscib0_i2c_12.c
    The code isn't handling any error condition and not suitable for a generic I2C transmission. It is only suitable for the very constellation it demonstrates.
    Changing parts of it to adjust it to your needs is futile. It can be used to understand what's going on in thsi particular case (and it is surprisingly well documented even though the comments do not explain the global concept), but for your own project you should either start over with your own code from scratch (using what you have learned by analyzing this and other smaple codes) or you use the MSP430 drive rlibrary, whose code is not well documented and also has some quirks, but can be used more or less out-of-the-box.

  • Thanks so much for the answer.

    "this transfers to a 0xe0/0xe1 start condition"

    what does this mean?

    does it mean my pseudocode should be like:

    slave address = 0x70;

    write(0xe0 or 0xe1);

    write(followup command);

    Thanks again for the answer

  • Randy Yao said:
    "this transfers to a 0xe0/0xe1 start condition"
    what does this mean?

    "start byte". The start byte consists of a start condition (falling SDA edge while SCL is high), 7 bits device address and one R/W bit. The R/W bit is the LSB of this data byte, so the 7 bits 0x70 ruen into 0xe0 when sent, with teh direciton bit attached as LSB (resulting in 0xe0 or 0xe1 being sent).

    Randy Yao said:
    slave address = 0x70;

    yes.

    Randy Yao said:
    write(0xe0 or 0xe1);

    no. Sending this byte is only required if you have an MSP with an USI module.
    The USCI in the 2553 automatically generates and sends this byte absed on teh slave address register and the UCTR bit.
    When you set the UCTXSTT bit, start condition and start byte are generated. Then the answer of the slave (ACK) is recorded (in TX mode, you'll have to write the first data byte to TXBUF before the ACK is checked!) and the UCTXSTT bit is reset. At this point, either UCNACKIFG is set (slave didn't respond; content of TXBUF is discarded then) or the transfer of the data bytes begins.

    The users guide has a nice sheet which explains how the transfer works. User/software action and hardware (USCI) action, step by step. One diagram for each of the four possible modes (master send or receive, slave send or receive).

**Attention** This is a public forum