2
\$\begingroup\$

I'm working with a MSP430G2553 and a BMP180 sensor. I have the following function in my program

uint16_t leer_temp_des() {
    unsigned char temp[2];
    escribir_com_bmp180(CTRL_MEAS, LEER_TEMP);
    retardo_ms(RET_LEC_TEMP);
    leer_2_bytes_bmp180(OUT_MSB, temp);
    printf("t0 %u\n", (uint16_t) temp[0]);
    printf("t1 %u\n", (uint16_t) temp[1]);
    uint16_t temperatura = ((uint16_t) (temp[0] << 8) | (uint16_t) temp[1]);
    printf("t %u\n", temperatura);
    //temperatura <<= 8;
    //temperatura |= temp[1];
    return temperatura;
}

Which calls this other function

void leer_2_bytes_bmp180(uint8_t reg, uint8_t *v) {
    inicioI2C(DIR_I2C_BMP180);
    envioI2C(reg);
    reinicioI2C(DIR_I2C_BMP180, false);
    *v = recepcionI2C(false);
    *(v + 1) = recepcionI2C(false);
    finI2C();
}

I2C code

void inicializarI2C() {
    UCB0CTL1 |= UCSWRST;
    UCB0CTL0 &= ~(UCA10 | UCSLA10 | UCMM);
    UCB0CTL0 |= (UCMST | UCMODE1 | UCMODE0 | UCSYNC);
    UCB0CTL1 |= UCSSEL1 | UCSSEL0;
    UCB0CTL1 |= UCTR;
    UCB0STAT = 0;
    UCB0BR0 = 160;
    UCB0BR1 = 0;
    UCB0I2COA = 0x1A;
    UCB0I2CSA = 0x77;
    P1DIR |= BIT6;
    P1SEL |= BIT6;
    P1SEL2 |= BIT6;
    P1SEL |= BIT7;
    P1SEL2 |= BIT7;
    UCB0CTL1 &= ~UCSWRST;
}

void inicioI2C(uint8_t dir) {
    UCB0I2CSA = dir;
    UCB0CTL1 |= UCTR;
    UCB0CTL1 |= UCTXSTT;
    while((IFG2 & UCB0TXIFG) == 0) {}

    //while((UCB0STAT & UCNACKIFG) == 0) {}
}

void reinicioI2C(uint8_t dir, bool rw) {
    UCB0I2CSA = dir;
    if(rw) {
        UCB0CTL1 |= UCTR;
    }
    else {
        UCB0CTL1 &= ~UCTR;
    }
    //UCB0CTL1 |= UCTR;
    UCB0CTL1 |= UCTXSTT;
    while((UCB0CTL1 & UCTXSTT) != 0) {
        if((UCB0STAT & UCNACKIFG) != 0) {
            break;
            /*UCB0STAT &= ~UCNACKIFG;
            UCB0CTL1 |= UCTXSTP;
            while((UCB0CTL1 & UCTXSTP) != 0) {}*/
        }
    }
}

uint8_t envioI2C(uint8_t dato) {
    //UCB0CTL1 |= UCTR;
    //UCB0I2CSA = dir;
    //UCB0CTL1 |= UCTXSTT;
    UCB0TXBUF = dato;
    while((UCB0CTL1 & UCTXSTT) != 0) {}
    if((UCB0STAT & UCNACKIFG) != 0) {
        UCB0STAT &= ~UCNACKIFG;
        UCB0CTL1 |= UCTXSTP;
        //while((UCB0CTL1 & UCTXSTP) != 0);
        return 0;
    }
    while((IFG2 & UCB0TXIFG) == 0);
    return 1;
    //retardo_ms(1);
}

uint8_t recepcionI2C(bool parar) {
    //UCB0CTL1 =& ~UCTR;
    //UCB0I2CSA = dir;
    //UCB0CTL1 |= UCTXSTT;
    if(parar) {
        if((UCB0STAT & UCNACKIFG) != 0) {
            UCB0STAT &= ~UCNACKIFG;
        }
        UCB0CTL1 |= UCTXSTP;
    }
    while(!(IFG2 & UCB0RXIFG));
    uint8_t dato = UCB0RXBUF;
    //while(!(IFG2 & UCB0RXIFG));
    if(parar) {
        while((UCB0CTL1 & UCTXSTP) != 0) {}
    }
    return dato;
}

void finI2C() {
    if((UCB0STAT & UCNACKIFG) != 0) {
        UCB0STAT &= ~UCNACKIFG;
    }
    UCB0CTL1 |= UCTXSTP;
    while((UCB0CTL1 & UCTXSTP) != 0) {}
}

Obviously, temp[0] is supposed to store the most significant byte while temp[1] is going to store the least significant byte but the opposite is happening: temp[0] is saving LSB and temp[1] is saving MSB. I already checked the I2C data with a logic analyzer but the sequence is the opposite of what my function prints.

\$\endgroup\$
15
  • 2
    \$\begingroup\$ What is the byte order of your compiler? Big endian or little endian? Rather than cast two bytes to a uint16, write code to explicitly determine the byte order - eg: uint16_t val = byte[0] << 8 + byte[1]; \$\endgroup\$
    – Kartman
    Jul 19, 2021 at 23:41
  • 1
    \$\begingroup\$ "Obviously, temp[0] is supposed to store the most significant byte while temp[1] is going to store the least significant byte" - Why is this obvious? This is not how a little-endian machine works. The 'less significant' byte is stored in the memory with the lower address value. This is perfectly normal. Can you explain why it's a problem for you? \$\endgroup\$
    – brhans
    Jul 20, 2021 at 2:27
  • 2
    \$\begingroup\$ Alternative hypothesis: the bytes aren't swapped, they're off by one and the first byte is garbage. Can you show your I2C code and the values of the register constants? \$\endgroup\$
    – DamienD
    Jul 20, 2021 at 14:28
  • 2
    \$\begingroup\$ I would bet on something like that. Some issue in the I2C flow that causes the read buffer to be swapped at the wrong time or one time too many. \$\endgroup\$
    – DamienD
    Jul 20, 2021 at 16:03
  • 2
    \$\begingroup\$ @DamienD You were right. The bytes were not swapped and there was a problem with the I2C cycle. \$\endgroup\$
    – EmTor
    Jul 21, 2021 at 19:25

2 Answers 2

4
\$\begingroup\$

There was a problem with the STOP condition. In the datasheet it says that in case you want to read one single byte, you send the STOP condition before reading, but it doesn't explain what to do when you're reading more than one byte, and that's why I was sending the STOP after reading the last byte in this case. So, apparently the sensor was sending an extra byte after every I2C cycle. This byte was not saved in a variable, but it was saved in the RXBUF register, and every time a new cycle started v[0] was assigned this value, while v[1] was assigned the byte wich was supposed to be the first one.This is the only function I needed to change

void leer_2_bytes_bmp180(uint8_t reg, uint8_t *v) {
    inicioI2C(DIR_I2C_BMP180);
    envioI2C(reg);
    reinicioI2C(DIR_I2C_BMP180, false);
    *v = recepcionI2C(false);
    *(v + 1) = recepcionI2C(true);        
}

I send a true value to recepcionI2C to indicate that this is the last byte which will be read and I removed finI2C because the STOP condition is sent in the last recepcionI2C call.

\$\endgroup\$
0
2
\$\begingroup\$

Can't see any obvious flaw. I would try a read_uint16() function that uses a different idiom to compare the results:

uint16_t val = read_byte();
val <<= 8;
val |= read_byte();

Also advise using 0x%x as a printf format to debug byte order issues.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.