I2C lost arbitration

Here’s what I see:

[root@milkv-duo]~# ./bmp180
wiringXSetup duo
bmp180_setup
wiringXI2CSetup(/dev/i2c-1, 0x77)
fd_i2c: 0x4
wiringXI2CReadReg8(0x4, 0xd0)
bmp180 setup completed
reading bmp180 calibration parameters…
function bmp180_get_calib_params(0x4, 0xffddeb70)
AC1: 0
AC2: -80
AC3: 0
AC4: 2080
AC5: 0
AC6: 20224
B1: 0
B2: 0
MB: -32768
MC: 0
MD: 2560
bmp180_get_temperature
bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 80
ut: 1879048192
UT: 1879048192 | AC5: 0 | AC6: 20224 | MC: 0 | MD: 2560
X1: 0 | X2: 0
bmp180_get_pressure
bmp180_get_up
out_msb: -95 | out_lsb: -44 | out_xlsb: 0
up: -1520 | oversampling: 0
UP: -1520 | bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 79
ut: 939524096
UT: 939524096 | AC5: 0 | AC6: 20224 | MC: 0 | MD: 2560
X1: 0 | X2: 0
B5: 0 | B6: -4000
X1: 0 | X2: 156 | X3: 156
B3: 39 | X1: 0 | X2: 0 | X3: 0
B4: 2080 | B7: -77950000
X1: 250873921 | X1: 29689 | X2: 29689
p: 4064084
sea_level_pressure: 2147483648.000000
Temperature: 0 | Pressure: 4064084 | Altitude: 30886.353516
bmp180_get_temperature
bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 79
ut: 939524096
UT: 939524096 | AC5: 0 | AC6: 20224 | MC: 0 | MD: 2560
X1: 0 | X2: 0
bmp180_get_pressure
bmp180_get_up
out_msb: -95 | out_lsb: -44 | out_xlsb: 0
up: -1520 | oversampling: 0
UP: -1520 | bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 78
ut: 469762048
UT: 469762048 | AC5: 0 | AC6: 20224 | MC: 0 | MD: 2560
X1: 0 | X2: 0
B5: 0 | B6: -4000
X1: 0 | X2: 156 | X3: 156
B3: 39 | X1: 0 | X2: 0 | X3: 0
B4: 2080 | B7: -77950000
X1: 250873921 | X1: 29689 | X2: 29689
p: 4064084
sea_level_pressure: 2147483648.000000
Temperature: 0 | Pressure: 4064084 | Altitude: 30886.353516
^C

This is my output:

root@milkv-duo:~/projects/thapq_sensor/src# ./thapq_sensor 
wiringXSetup duo
dht22 setup
wiringXValidGPIO(15)
dht22 setup completed
bmp180_setup
wiringXI2CSetup(/dev/i2c-1, 0x77)
fd_i2c: 0x4
wiringXI2CReadReg8(0x4, 0xd0)
bmp180 setup completed
reading bmp180 calibration parameters...
function bmp180_get_calib_params(0x4, 0xffd803c0)
AC1: 30
AC2: -5
AC3: 7168
AC4: 0
AC5: 0
AC6: 0
B1: 0
B2: 0
MB: -32768
MC: 0
MD: 0
reading from dht22...
Data not good, skip
bmp180_get_temperature
bmp180_get_B5
bmp180_get_ut
out_msb: 102
out_lsb: 27
ut: 816
UT:  816 | AC5: 0 | AC6: 0 | MC:  0 | MD:  0
X1:  0 | X2:  -1
bmp180_get_pressure
bmp180_get_up
out_msb:  -98 | out_lsb:  -22 | out_xlsb: 0
up: 0 | oversampling: 0
UP: 0 | bmp180_get_B5
bmp180_get_ut
out_msb: 102
out_lsb: 27
ut: 816
UT:  816 | AC5: 0 | AC6: 0 | MC:  0 | MD:  0
X1:  0 | X2:  -1
B5: -1 | B6: -4001
X1: 0 | X2: 9 | X3: 9
B3: 32 | X1: -3501 | X2: 0 | X3: -875
B4: 0 | B7: -1600000
 X1: 1 | X1: 0 | X2: 0
p: 945
sea_level_pressure: 2147483648.000000
Temperature: 0 | Pressure: 945 | Altitude: 41594.378906 

Well, sounds like it will take some time to review this code. Did you compose it yourself, or you ported some Arduino code, or else?

I composed it, based on the below datasheet, and I made some changes based on the github repository(that’s the code I have used for arduino nano):

BST-BMP180-DS000-09.pdf

Now I have changed back code bmp180.c so that will resemble the datasheet algorithm, but the result is the same… I think is has something to do with the calibration data.
As you can see the calibration data from arduino nano code is complete:

09:43:35.727 -> ac1 = 7195
09:43:37.463 -> ac2 = -1085
09:43:37.463 -> ac3 = -14736
09:43:37.496 -> ac4 = 32024
09:43:37.496 -> ac5 = 25157
09:43:37.529 -> ac6 = 17830
09:43:37.529 -> b1 = 6515
09:43:37.529 -> b2 = 39
09:43:37.563 -> mb = -32768
09:43:37.563 -> mc = -11786
09:43:37.563 -> md = 2724

As the one that we have is incompolete, as there calibration data that are 0.

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

#include <wiringx.h>

#include <bmp180.h>
#include <math.h>

int bmp180_setup(int oversampling)
{
	printf("wiringXI2CSetup(%s, 0x%x)\n", BMP180_I2C_DEV, BMP180_I2C_ADDR);
	int fd_i2c = wiringXI2CSetup(BMP180_I2C_DEV, BMP180_I2C_ADDR);
	printf("fd_i2c: 0x%x\n", fd_i2c);
	if (fd_i2c < 0) {
        	printf("I2C Setup failed: 0x%x\n", fd_i2c);
		wiringXGC();
        	return -1;
	}
//    bmp180_init(fd_i2c);
        printf("wiringXI2CReadReg8(0x%x, 0x%x)\n", fd_i2c, BMP180_CHIP_ID);
	int8_t chip_id = wiringXI2CReadReg8(fd_i2c, BMP180_CHIP_ID);
	if (chip_id != 0x55){
		printf("BMP180 wrong chip ID. Got %xd, expected 0x55\n", chip_id);
		return -1;
	}

	oss = oversampling;
	return fd_i2c;
}

void bmp180_init(int fd) 
{
    // use the "handheld device dynamic" optimal setting (see datasheet)

    // 500ms sampling time, x16 filter
//    const uint8_t reg_config_val = ((0x04 << 5) | (0x05 << 2)) & 0xFC;
//    wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, reg_config_val);

    // osrs_t x1, osrs_p x4, normal mode operation
//    const uint8_t reg_ctrl_meas_val = (0x00 << 5) | (0x03 << 2) | (0x03);
//    wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, reg_ctrl_meas_val);
}

void bmp180_get_calib_params(int fd, struct bmp180_calib_param* params) 
{
	printf("function bmp180_get_calib_params(0x%x, 0x%x)\n", fd, &params);
	int8_t ac1_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC1_MSB);
	int8_t ac1_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC1_LSB);
        params->ac1 = ac1_msb << 8 + ac1_lsb;
//	printf("reading calibration parameter AC1\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC1_MSB);
//	printf("%d\n", ac1_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC1_LSB);
//	printf("%d\n", ac1_lsb);
	printf("AC1: %d\n", params->ac1);

	int8_t ac2_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC2_MSB);
	int8_t ac2_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC2_LSB);
        params->ac2 = ac2_msb << 8 + ac2_lsb;
//	printf("reading calibration parameter AC2\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC2_MSB);
//	printf("%d\n", ac2_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC2_LSB);
//	printf("%d\n", ac2_msb);
	printf("AC2: %d\n", params->ac2);

	int8_t ac3_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC3_MSB);
	int8_t ac3_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC3_LSB);
        params->ac3 = ac3_msb << 8 + ac3_lsb;
//	printf("reading calibration parameter AC3\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC3_MSB);
//	printf("%d\n", ac3_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC3_LSB);
//	printf("%d\n", ac3_msb);
	printf("AC3: %d\n", params->ac3);

	uint8_t ac4_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC4_MSB);
	uint8_t ac4_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC4_LSB);
        params->ac4 = ac4_msb << 8 + ac4_lsb;
//	printf("reading calibration parameter AC4\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC4_MSB);
//	printf("%d\n", ac4_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC4_LSB);
//	printf("%d\n", ac4_msb);
	printf("AC4: %d\n", params->ac4);

	uint8_t ac5_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC5_MSB);
	uint8_t ac5_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC5_LSB);
        params->ac5 = ac5_msb << 8 + ac5_lsb;
//	printf("reading calibration parameter AC5\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC5_MSB);
//	printf("%d\n", ac5_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC5_LSB);
//	printf("%d\n", ac5_msb);
	printf("AC5: %d\n", params->ac5);

	uint8_t ac6_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC6_MSB);
	uint8_t ac6_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC6_LSB);
        params->ac6 = ac6_msb << 8 + ac6_lsb;
//	printf("reading calibration parameter AC6\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC6_MSB);
//	printf("%d\n", ac6_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC6_LSB);
//	printf("%d\n", ac6_msb);
	printf("AC6: %d\n", params->ac6);

	int8_t b1_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B1_MSB);
	int8_t b1_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B1_LSB);
        params->b1 = b1_msb << 8 + b1_lsb;
//	printf("reading calibration parameter B1\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B1_MSB);
//	printf("%d\n", b1_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B1_LSB);
//	printf("%d\n", b1_msb);
	printf("B1: %d\n", params->b1);

	int8_t b2_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B2_MSB);
	int8_t b2_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B2_LSB);
        params->b2 = b2_msb << 8 + b2_lsb;
//	printf("reading calibration parameter B2\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B2_MSB);
//	printf("%d\n", b2_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B2_LSB);
//	printf("%d\n", b2_msb);
	printf("B2: %d\n", params->b2);

	int8_t mb_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MB_MSB);
	int8_t mb_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MB_LSB);
        params->mb = mb_msb << 8 + mb_lsb;
//	printf("reading calibration parameter MB\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MB_MSB);
//	printf("%d\n", mb_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MB_LSB);
//	printf("%d\n", mb_msb);
	printf("MB: %d\n", params->mb);

	int8_t mc_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MC_MSB);
	int8_t mc_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MC_LSB);
        params->mc = mc_msb << 8 + mc_lsb;
//	printf("reading calibration parameter MC\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MC_MSB);
//	printf("%d\n", mc_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MC_LSB);
//	printf("%d\n", mc_msb);
	printf("MC: %d\n", params->mc);

	int8_t md_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MD_MSB);
	int8_t md_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MD_LSB);
        params->md = md_msb << 8 + md_lsb; 
//	printf("reading calibration parameter MD\n");
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MD_MSB);
//	printf("%d\n", md_msb);
//	printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MD_LSB);
//	printf("%d\n", md_msb);
	printf("MD: %d\n", params->md);
}

int32_t bmp180_get_ut(int fd)
{
  printf("bmp180_get_ut\n");
	wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, BMP180_CTRL_TEMP);
        delayMicroseconds(5000);
	int8_t out_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_MSB);
	int8_t out_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_LSB);
	int32_t ut = out_msb << 8; 
	printf("ut: 0x%x | %d\n", ut, ut);
	        ut += out_lsb;
	printf("ut: 0x%x | %d\n", ut, ut);
	printf("out_msb: %d\n",out_msb);
	printf("out_lsb: %d\n",out_lsb);
	return ut;
}

int32_t bmp180_get_up(int fd)
{
  printf("bmp180_get_up\n");
        wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, BMP180_CTRL_PRESSURE_0 + (oss << 6));
	if (oss == BMP180_ULTRALOWPOWER)
	   delayMicroseconds(5000);
	else if (oss == BMP180_STANDARD)
           delayMicroseconds(8000);
	else if (oss == BMP180_HIGHRES)
	   delayMicroseconds(14000);
	else
           delayMicroseconds(26000);
	int8_t out_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_MSB);
	int8_t out_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_LSB);
	int8_t out_xlsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_XLSB);

	int32_t up = out_msb << 16;
	printf("up: 0x%x | %d\n", up, up);
                up +=out_lsb << 8;
	printf("up: 0x%x | %d\n", up, up);
	        up +=out_xlsb;
	printf("up: 0x%x | %d\n", up, up);
	        up >>=8-oss;
	printf("up: 0x%x | %d\n", up, up);
	printf("out_msb:  | %d | ", out_msb);
	printf("out_lsb:  | %d | ", out_lsb);
	printf("out_xlsb: | %d\n", out_xlsb);
	printf("oversampling: %d\n", oss);
	return up;

}

int32_t bmp180_get_B5(int fd, const struct bmp180_calib_param params)
{
  printf("bmp180_get_B5\n");
  int32_t UT = bmp180_get_ut(fd);
  printf("UT:  %u | ", UT);
  printf("AC5: %u | ", params.ac5);
  printf("AC6: %u | ", params.ac6);
  printf("MC:  %d | ", params.mc);
  printf("MD:  %d\n", params.md);
//  int32_t X1 = (UT - (int32_t)params.ac6) * ((int32_t)params.ac5) >> 15;
  int32_t X1 = (UT - (int32_t)params.ac6) * ((int32_t)params.ac5) / 32768;
  printf("X1:  %d | ", X1);
//  int32_t X2 = ((int32_t)params.mc << 11) / (X1 + (int32_t)params.md);
  int32_t X2 = ((int32_t)params.mc * 2048) / (X1 + (int32_t)params.md);
  printf("X2:  %d\n", X2);
  return X1 + X2;
}

int32_t bmp180_get_temperature(int fd, const struct bmp180_calib_param params)
{
	printf("bmp180_get_temperature\n");
	int32_t B5 = bmp180_get_B5(fd, params);
	B5 += 8;
	B5 >>= 4;
	B5 /= 10;
	return B5;
//	return ((B5 + 8) >> 4) / 10;
}

int32_t bmp180_get_pressure(int fd, const struct bmp180_calib_param params)
{
	printf("bmp180_get_pressure\n");
        int32_t UP = bmp180_get_up(fd);
	printf("UP: %d\n", UP);
	int32_t B5 = bmp180_get_B5(fd, params);
	printf("B5: %d | ", B5);
	int32_t B6 = B5 - 4000;
	printf("B6: %d\n", B6);
//	int32_t X1 = ((params.b2 * B6 * B6) >> 12) >> 11;
	int32_t X1 = (params.b2 * (B6 * B6 / 4096)) / 2048;
	printf("X1: %d | ", X1);
//	int32_t X2 = (params.ac2 * B6) >> 11;
	int32_t X2 = params.ac2 * B6 / 2048;
	printf("X2: %d | ", X2);
	int32_t X3 = X1 + X2;
	printf("X3: %d\n", X3);
//	int32_t B3 = (((params.ac1 * 4 + X3) << oss) + 2) >> 2;
	int32_t B3 = (((params.ac1 * 4 + X3) << oss) + 2) / 4;
	printf("B3: %d | ", B3);
//	X1 = (params.ac3 * B6) >> 13;
	X1 = params.ac3 * B6 / 8192;
	printf("X1: %d | ", X1);
//	X2 = ((params.b1 * B6 * B6) >> 12) >> 16;
	X2 = (params.b1 * (B6 * B6 / 4096)) / 65536;
	printf("X2: %d | ", X2);
//	X3 = ((X1 + X2) + 2) >> 2;
	X3 = ((X1 + X2) + 2) / 4;
	printf("X3: %d\n", X3);
//	uint32_t B4 = ((uint32_t)params.ac4 * (uint32_t)(X3 + 32768)) >> 15;
	uint32_t B4 = params.ac4 * (uint32_t)(X3 + 32768) / 32768;
	printf("B4: %d | ", B4);
//	uint32_t B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oss);
	uint32_t B7 = ((uint32_t)UP - B3) * (50000 >> oss);
	printf("B7: %d\n ", B7);
	int32_t p;
	if (B7 < 0x80000000) 
		p = (B7 * 2) / B4;
	else
		p = (B7 / B4) * 2;
//	X1 = (p >> 8) * (p >> 8);
	X1 = (p / 256) * (p / 256);
	printf("X1: %d | ", X1);
//	X1 = (X1 * 3038) >> 16;
	X1 = (X1 * 3038) / 65536;
	printf("X1: %d | ", X1);
	X2 = (-7357 * p) / 65536;
	printf("X2: %d\n", X1);
	p = p + (X1 + X2 + 3791) / 16;
	printf("p: %d\n", p);
	return p;
}

I bet the reason must be in either register numbers, or width, or endianness.

I have managed to get the temp write by getting the right calibration numbers with:

       params->ac1 = ac1_msb << 8;
        params->ac1 +=  ac1_lsb;

instead of

        params->ac1 = ac1_msb << 8 + ac1_lsb;

ac1 is int16_t;

1 Like

This means the << operator has truly lower priority than addition.

params->ac1 = (ac1_msb << 8) + ac1_lsb;

This will do the job.

The altitude is negative :smile: and the pressure supposed to be 1020.32 hPa…
Temperature: 21.70C | Pressure: 1587.84 milibar | Altitude: -394.04 m

1 Like

Here’s what I get:

[root@milkv-duo]~# ./bmp180
wiringXSetup duo
bmp180_setup
wiringXI2CSetup(/dev/i2c-1, 0x77)
fd_i2c: 0x4
wiringXI2CReadReg8(0x4, 0xd0)
bmp180 setup completed
reading bmp180 calibration parameters…
function bmp180_get_calib_params(0x4, 0xffdbbb70)
AC1: 7344
AC2: -1348
AC3: -14607
AC4: 33468
AC5: 25427
AC6: 20384
B1: 6515
B2: 39
MB: -32768
MC: -12042
MD: 2560
bmp180_get_temperature
bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 40
ut: 28712
UT: 28712 | AC5: 25427 | AC6: 20384 | MC: -12042 | MD: 2560
X1: 6462 | X2: -2733
bmp180_get_pressure
bmp180_get_up
out_msb: -95 | out_lsb: 60 | out_xlsb: 0
up: -24260 | oversampling: 0
UP: -24260 | bmp180_get_B5
bmp180_get_ut
out_msb: 112
out_lsb: 40
ut: 28712
UT: 28712 | AC5: 25427 | AC6: 20384 | MC: -12042 | MD: 2560
X1: 6462 | X2: -2733
B5: 3729 | B6: -271
X1: 0 | X2: 178 | X3: 178
B3: 7389 | X1: 483 | X2: 1 | X3: 121
B4: 33591 | B7: -1582450000
X1: 396900 | X1: 18398 | X2: 18398
p: 162516
sea_level_pressure: 2147483648.000000
Temperature: 23 | Pressure: 162516 | Altitude: 37044.406250
^C

I simply isolated every bitwise shift, without reading much what it does. ;D

yes, but the pressure is too high, it should be 102000 and the altitude is ~30 less.

I think I need to tinker a bit with how it works, what it reads from the sensor, and what it does wrong in these conversions.
I’m beginning to learn C from here, lol, wish me luck.

1 Like

It OK now, I have managed to calculated the right values… working with int types was a mission impossible for me:)

Temperature: 23.70C | Pressure: 967.76milibar | Altitude: 400.24m
main.c

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <math.h>

#include <wiringx.h>

#include <bmp180.h>

unsigned long __stack_chk_guard;

void __stack_chk_guard_setup(void)
{
     __stack_chk_guard = 0xBAAAAAAD;//provide some magic numbers
}

void __stack_chk_fail(void)
{
	printf("variable corrupted");

}// will be called when guard variable is corrupted

int bmp180_i2c;
struct bmp180_calib_param bmp180_calib_params;

int setup()
{
    // wiringx setup to duo
    printf("wiringXSetup duo\n");
    if (wiringXSetup("duo", NULL) == -1)
    {
        wiringXGC();
	return -1;
    }

    // bmp180 setup
    printf("bmp180_setup\n");
    bmp180_i2c = bmp180_setup(BMP180_ULTRALOWPOWER);
    if (bmp180_i2c == -1)
	    exit(-1);
    printf("bmp180 setup completed\n");

    printf("reading bmp180 calibration parameters...\n");
    bmp180_get_calib_params(bmp180_i2c, &bmp180_calib_params);

}

void loop()
{

	float temp = (float) bmp180_get_temperature(bmp180_i2c, bmp180_calib_params); 
	float pressure = (float) bmp180_get_pressure(bmp180_i2c, bmp180_calib_params);

	int32_t altitude_meters = 0; // altitude at sea level
        int32_t sea_level_pressure = (int32_t)(pressure / pow(1.0 - altitude_meters / 44330, 5.255));
	//float sea_level_pressure = 101325;
	sea_level_pressure = 101500;
	printf("pressure: %f\n", pressure);
	printf("sea_level_pressure: %d\n", sea_level_pressure);
	printf("pressure / sea_level_pressure: %f\n", pressure / sea_level_pressure);
	//printf("pow(pressure / sea_level_pressure, 0.1903): %f\n", pow((float)(pressure / sea_level_pressure), 0.1903));
	float pressure_div = pressure / (float)sea_level_pressure;
	printf("pow(pressure / sea_level_pressure, 0.1903): %f\n", pow(pressure_div, 1/5.255));
	printf("pressure_div: %f\n", pressure_div);
	float altitude = 44330 * (1.0 - pow(pressure_div, 0.1903));

	printf("Temperature: %.2fC | ", temp / 10);
        printf("Pressure: %.2fmilibar | ", pressure / 100);
	printf("Altitude: %.2fm", altitude);
	printf("\n");
}

int main()
{
	if (setup() == -1)
	{
		printf("Setup failed\n");	
		return 0;
	}

	while(1)
	{
		loop();
		delayMicroseconds(1500000);
	}

}

bmp180.h

#ifndef _BMP180_H_
#define _BMP180_H_

#define DEBUG_BMP180 0
#define BMP180_I2C_DEV "/dev/i2c-1"

#define BMP180_I2C_ADDR  0x77

// hardware registers
#define BMP180_REG_CTRL_MEAS  0xF4
#define BMP180_REG_SOFT_RESET 0xE0
#define BMP180_CHIP_ID        0xD0
#define BMP180_READ  1
#define BMP180_WRITE 0
#define BMP180_READ_ADDR  0xEF
#define BMP180_WRITE_ADDR 0xEE
#define BMP180_ULTRALOWPOWER 0 // 00b 1x read | Ultra low power mode
#define BMP180_STANDARD      1 // 01b 2x read | Standard mode
#define BMP180_HIGHRES       2 // 10b 4x read | High-res mode
#define BMP180_ULTRAHIGHRES  3 // 11b 8x read | Ultra high-res mode

#define BMP180_CTRL_TEMP        0x2E
#define BMP180_CTRL_PRESSURE_0  0x34
#define BMP180_CTRL_PRESSURE_1  0x74
#define BMP180_CTRL_PRESSURE_2  0xB4
#define BMP180_CTRL_PRESSURE_3  0xF4

#define BMP180_REG_OUT_XLSB 0xF8
#define BMP180_REG_OUT_LSB  0xF7
#define BMP180_REG_OUT_MSB  0xF6

// calibration registers
#define BMP180_REG_AC1_MSB 0xAA
#define BMP180_REG_AC1_LSB 0xAB
#define BMP180_REG_AC2_MSB 0xAC
#define BMP180_REG_AC2_LSB 0xAD
#define BMP180_REG_AC3_MSB 0xAE
#define BMP180_REG_AC3_LSB 0xAF
#define BMP180_REG_AC4_MSB 0xB0
#define BMP180_REG_AC4_LSB 0xB1
#define BMP180_REG_AC5_MSB 0xB2
#define BMP180_REG_AC5_LSB 0xB3
#define BMP180_REG_AC6_MSB 0xB4
#define BMP180_REG_AC6_LSB 0xB5
#define BMP180_REG_B1_MSB  0xB6
#define BMP180_REG_B1_LSB  0xB7
#define BMP180_REG_B2_MSB  0xB8
#define BMP180_REG_B2_LSB  0xB9
#define BMP180_REG_MB_MSB  0xBA
#define BMP180_REG_MB_LSB  0xBB
#define BMP180_REG_MC_MSB  0xBC
#define BMP180_REG_MC_LSB  0xBD
#define BMP180_REG_MD_MSB  0xBE
#define BMP180_REG_MD_LSB  0xBF


static int oss;
/*
* Immutable calibration data read from bmp180
*/
struct bmp180_calib_param {
    int16_t ac1;
    int16_t ac2;
    int16_t ac3;
    uint16_t ac4;
    uint16_t ac5;
    uint16_t ac6;
    int16_t b1;
    int16_t b2;
    int16_t mb;
    int16_t mc;
    int16_t md;
};

int bmp180_setup(int oversampling);
void bmp180_init(int fd);
void bmp180_get_calib_params(int fd, struct bmp180_calib_param* params); 
uint16_t bmp180_get_ut(int fd);
uint32_t bmp180_get_up(int fd);
int32_t bmp180_get_B5(int fd, const struct bmp180_calib_param params);
int32_t bmp180_get_temperature(int fd, const struct bmp180_calib_param params);
int32_t bmp180_get_pressure(int fd, const struct bmp180_calib_param params);

#endif

bmp180.c

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>

#include <wiringx.h>

#include <bmp180.h>
#include <math.h>

int bmp180_setup(int oversampling)
{
	printf("wiringXI2CSetup(%s, 0x%x)\n", BMP180_I2C_DEV, BMP180_I2C_ADDR);
	int fd_i2c = wiringXI2CSetup(BMP180_I2C_DEV, BMP180_I2C_ADDR);
	printf("fd_i2c: 0x%x\n", fd_i2c);
	if (fd_i2c < 0) {
        	printf("I2C Setup failed: 0x%x\n", fd_i2c);
		wiringXGC();
        	return -1;
	}
//	printf("bmp180_init\n");
//        bmp180_init(fd_i2c);
        printf("wiringXI2CReadReg8(0x%x, 0x%x)\n", fd_i2c, BMP180_CHIP_ID);
	int8_t chip_id = wiringXI2CReadReg8(fd_i2c, BMP180_CHIP_ID);
	if (chip_id != 0x55){
		printf("BMP180 wrong chip ID. Got %xd, expected 0x55\n", chip_id);
		return -1;
	}

	oss = oversampling;
	return fd_i2c;
}

void bmp180_init(int fd) 
{
//    const uint8_t reg_ctrl_meas_val = (oss << 6) | (0x01 << 5) | (0x00);
//    wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, reg_ctrl_meas_val);
}

void bmp180_get_calib_params(int fd, struct bmp180_calib_param* params) 
{
	if (DEBUG_BMP180 == 1) {
		printf("function bmp180_get_calib_params(0x%x, 0x%x)\n", fd, &params);
	}
	int8_t ac1_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC1_MSB);
	int8_t ac1_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC1_LSB);
        params->ac1 = (ac1_msb << 8) + ac1_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC1_MSB);
		printf("%d\n", ac1_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC1_LSB);
		printf("%d\n", ac1_lsb);
		printf("AC1: %d\n", params->ac1);
	}

	int8_t ac2_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC2_MSB);
	int8_t ac2_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC2_LSB);
        params->ac2 = (ac2_msb << 8) + ac2_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC2_MSB);
		printf("%d\n", ac2_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC2_LSB);
		printf("%d\n", ac2_lsb);
		printf("AC2: %d\n", params->ac2);
	}

	int8_t ac3_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC3_MSB);
	int8_t ac3_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC3_LSB);
        params->ac3 = (ac3_msb << 8) + ac3_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC3_MSB);
		printf("%d\n", ac3_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC3_LSB);
		printf("%d\n", ac3_lsb);
		printf("AC3: %d\n", params->ac3);
	}

	uint8_t ac4_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC4_MSB);
	uint8_t ac4_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC4_LSB);
        params->ac4 = (ac4_msb << 8) + ac4_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC4_MSB);
		printf("%d\n", ac4_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC4_LSB);
		printf("%d\n", ac4_lsb);
		printf("AC4: %d\n", params->ac4);
	}

	uint8_t ac5_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC5_MSB);
	uint8_t ac5_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC5_LSB);
        params->ac5 = (ac5_msb << 8) + ac5_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC5_MSB);
		printf("%d\n", ac5_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC5_LSB);
		printf("%d\n", ac5_lsb);
		printf("AC5: %d\n", params->ac5);
	}

	uint8_t ac6_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC6_MSB);
	uint8_t ac6_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_AC6_LSB);
        params->ac6 = (ac6_msb << 8) + ac6_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC6_MSB);
		printf("%d\n", ac6_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_AC6_LSB);
		printf("%d\n", ac6_lsb);
		printf("AC6: %d\n", params->ac6);
	}

	int8_t b1_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B1_MSB);
	int8_t b1_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B1_LSB);
        params->b1 = (b1_msb << 8) + b1_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B1_MSB);
		printf("%d\n", b1_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B1_LSB);
		printf("%d\n", b1_lsb);
		printf("B1: %d\n", params->b1);
	}

	int8_t b2_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B2_MSB);
	int8_t b2_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_B2_LSB);
        params->b2 = (b2_msb << 8) + b2_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B2_MSB);
		printf("%d\n", b2_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_B2_LSB);
		printf("%d\n", b2_lsb);
		printf("B2: %d\n", params->b2);
	}

	int8_t mb_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MB_MSB);
	int8_t mb_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MB_LSB);
        params->mb = (mb_msb << 8) + mb_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MB_MSB);
		printf("%d\n", mb_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MB_LSB);
		printf("%d\n", mb_lsb);
		printf("MB: %d\n", params->mb);
	}

	int8_t mc_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MC_MSB);
	int8_t mc_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MC_LSB);
        params->mc = (mc_msb << 8) + mc_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MC_MSB);
		printf("%d\n", mc_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MC_LSB);
		printf("%d\n", mc_lsb);
		printf("MC: %d\n", params->mc);
	}

	int8_t md_msb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MD_MSB);
	int8_t md_lsb = (int8_t)wiringXI2CReadReg8(fd, BMP180_REG_MD_LSB);

        params->md = (md_msb << 8) + md_lsb;
	if (DEBUG_BMP180 == 1) {
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MD_MSB);
		printf("%d\n", md_msb);
		printf("wiringXI2CReadReg8(0x%x, 0x%X) = ", fd, BMP180_REG_MD_LSB);
		printf("%d\n", md_lsb);
		printf("MD: %d\n", params->md);
	}
}

uint16_t bmp180_get_ut(int fd)
{
	if (DEBUG_BMP180 == 1) {
		printf("bmp180_get_ut\n");
	}
	wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, BMP180_CTRL_TEMP);
        delayMicroseconds(5000);
	uint8_t out_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_MSB);
	uint8_t out_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_LSB);
	uint16_t ut = (out_msb << 8) + out_lsb; 
	if (DEBUG_BMP180 == 1) {
		printf("out_msb: %d\n",out_msb);
		printf("out_lsb: %d\n",out_lsb);
		printf("ut: 0x%x | %d\n", ut, ut);
	}
	return ut;
}

uint32_t bmp180_get_up(int fd)
{
	if (DEBUG_BMP180 == 1) {
		printf("bmp180_get_up\n");
	}	
        wiringXI2CWriteReg8(fd, BMP180_REG_CTRL_MEAS, BMP180_CTRL_PRESSURE_0 + (oss << 6));
	if (oss == BMP180_ULTRALOWPOWER)
	   delayMicroseconds(5000);
	else if (oss == BMP180_STANDARD)
           delayMicroseconds(8000);
	else if (oss == BMP180_HIGHRES)
	   delayMicroseconds(14000);
	else
           delayMicroseconds(26000);
	uint8_t out_msb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_MSB);
	uint8_t out_lsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_LSB);
	uint8_t out_xlsb = (uint8_t)wiringXI2CReadReg8(fd, BMP180_REG_OUT_XLSB);

	uint32_t up = ((out_msb << 16) + (out_lsb << 8) + out_xlsb) >> (8 - oss);
	if (DEBUG_BMP180 == 1) {
		printf("out_msb: %d | ", out_msb);
		printf("out_lsb: %d | ", out_lsb);
		printf("out_xlsb: %d | ", out_xlsb);
		printf("oversampling: %d\n", oss);
		printf("up: %d\n ", up);
	}
	return up;
}

int32_t bmp180_get_B5(int fd, const struct bmp180_calib_param params)
{	
	if (DEBUG_BMP180 == 1) {
  		printf("bmp180_get_B5\n");
	}

	int32_t UT = bmp180_get_ut(fd);
	if (DEBUG_BMP180 == 1) {
		printf("UT:  %u | ", UT);
		printf("AC5: %u | ", params.ac5);
		printf("AC6: %u | ", params.ac6);
		printf("MC:  %d | ", params.mc);
		printf("MD:  %d\n", params.md);
	}

	int32_t X1 = (UT - (int32_t)params.ac6) * ((int32_t)params.ac5) >> 15;
	int32_t X2 = ((int32_t)params.mc << 11) / (X1 + (int32_t)params.md);
	if (DEBUG_BMP180 == 1) {
		printf("X1:  %d | ", X1);
	  	printf("X2:  %d\n", X2);
		printf("X1 + X2:  %d\n", X1 + X2);
	}

	return X1 + X2;
}

int32_t bmp180_get_temperature(int fd, const struct bmp180_calib_param params)
{
	if (DEBUG_BMP180 == 1) {
		printf("bmp180_get_temperature\n");
	}
	int32_t B5 = bmp180_get_B5(fd, params);
	return ((B5 + 8) >> 4);
}

int32_t bmp180_get_pressure(int fd, const struct bmp180_calib_param params)
{
	if (DEBUG_BMP180 == 1) {
		printf("bmp180_get_pressure\n");
	}

        int32_t UP = bmp180_get_up(fd);
  	if (DEBUG_BMP180 == 1) {
		printf("UP: %d\n", UP);
	}

	int32_t B5 = bmp180_get_B5(fd, params);
	if (DEBUG_BMP180 == 1) {
		printf("B5: %d | ", B5);
	}

	int32_t B6 = B5 - 4000;
	if (DEBUG_BMP180 == 1) {
		printf("B6: %d\n", B6);
	}

	int32_t X1 = ((int32_t)params.b2 * ((B6 * B6) >> 12)) >> 11;
	if (DEBUG_BMP180 == 1) {
		printf("X1: %d | ", X1);
	}

	int32_t X2 = ((int32_t)params.ac2 * B6) >> 11;
	if (DEBUG_BMP180 == 1) {
		printf("X2: %d | ", X2);
	}

	int32_t X3 = X1 + X2;
	if (DEBUG_BMP180 == 1) {
		printf("X3: %d\n", X3);
	}

	int32_t B3 = ((((int32_t)params.ac1 * 4 + X3) << oss) + 2) >> 2;
	if (DEBUG_BMP180 == 1) {
		printf("B3: %d | ", B3);
	}

	X1 = ((int32_t)params.ac3 * B6) >> 13;
	if (DEBUG_BMP180 == 1) {
		printf("X1: %d | ", X1);
	}

	X2 = ((int32_t)params.b1 * ((B6 * B6) >> 12)) >> 16;
	if (DEBUG_BMP180 == 1) {
		printf("X2: %d | ", X2);
	}

	X3 = ((X1 + X2) + 2) >> 2;
	if (DEBUG_BMP180 == 1) {
		printf("X3: %d\n", X3);
	}

	uint32_t B4 = ((uint32_t)params.ac4 * (uint32_t)(X3 + 32768)) >> 15;
	if (DEBUG_BMP180 == 1) {
		printf("B4: %d | ", B4);
	}

	uint32_t B7 = ((uint32_t)UP - B3) * (uint32_t)(50000UL >> oss);
	if (DEBUG_BMP180 == 1) {
		printf("B7: %d\n ", B7);
	}
	int32_t p;
	if (B7 < 0x80000000) 
		p = (B7 * 2) / B4;
	else
		p = (B7 / B4) * 2;

	X1 = (p >> 8) * (p >> 8);
	if (DEBUG_BMP180 == 1) {
		printf("X1: %d | ", X1);
	}

	X1 = (X1 * 3038) >> 16;
	if (DEBUG_BMP180 == 1) {
		printf("X1: %d | ", X1);
	}

	X2 = (-7357 * p) >> 16;
	if (DEBUG_BMP180 == 1) {
		printf("X2: %d\n", X1);
	}
	p = p + ((X1 + X2 + 3791) >> 4) ;
  	if (DEBUG_BMP180 == 1) {
		printf("p: %d\n", p);
	}
	return p;
}
1 Like

You certainly rewrote a lot of it.
If you don’t mind, we could start gathering such drivers in a dedicated repository, if you don’t mind.

Here:

[root@milkv-duo]~# ./bmp180
wiringXSetup duo
bmp180_setup
wiringXI2CSetup(/dev/i2c-1, 0x77)
fd_i2c: 0x4
wiringXI2CReadReg8(0x4, 0xd0)
bmp180 setup completed
reading bmp180 calibration parameters…
pressure: 100681.000000
sea_level_pressure: 101500
pressure / sea_level_pressure: 0.991931
pow(pressure / sea_level_pressure, 0.1903): 0.998459
pressure_div: 0.991931
Temperature: 24.70C | Pressure: 1006.81milibar | Altitude: 68.29m
pressure: 100675.000000
sea_level_pressure: 101500
pressure / sea_level_pressure: 0.991872
pow(pressure / sea_level_pressure, 0.1903): 0.998448
pressure_div: 0.991872
Temperature: 24.70C | Pressure: 1006.75milibar | Altitude: 68.80m
pressure: 100684.000000
sea_level_pressure: 101500
pressure / sea_level_pressure: 0.991961
pow(pressure / sea_level_pressure, 0.1903): 0.998465
pressure_div: 0.991961
Temperature: 24.60C | Pressure: 1006.84milibar | Altitude: 68.04m
^C

[root@milkv-duo]~# ./bmp280_i2c
Temp. = 24.69 C
Pressure = 99.824 kPa
Temp. = 24.69 C
Pressure = 99.823 kPa
Temp. = 24.70 C
Pressure = 99.826 kPa
^C

:birthday:

Sure we can gather such drivers in a dedicated repository, but I’m not an expert programmer… At least I can upload it to my duo-example repository. I will let you know once I have done that.

1 Like

Here it is: GitHub - protektwar/duo-examples: Milk-V Duo official C/C++ examples in bmp180 directory.

1 Like

I don’t think the format of these examples suits us. For example, I’m sure example code repository should have drivers code repository as a submodule.

Sound like a good idea… but I will have to research how do to that, as I said I’m not an expert programmer.

1 Like

Don’t worry, I’m trying to invest some effort in it as well, it’s just not always convenient.
At some point, we’ll make it happen, one way or another.