kopia lustrzana https://github.com/luigifcruz/pico-stuff
Add bmp180 library.
rodzic
89be513e1b
commit
fc390b52a9
|
@ -50,3 +50,7 @@ modules.order
|
|||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
build
|
||||
.cache
|
||||
pressure.log
|
|
@ -0,0 +1,9 @@
|
|||
[submodule "pico-examples"]
|
||||
path = pico-examples
|
||||
url = git@github.com:raspberrypi/pico-examples.git
|
||||
[submodule "pico-sdk"]
|
||||
path = pico-sdk
|
||||
url = git@github.com:raspberrypi/pico-sdk.git
|
||||
[submodule "pico-extras"]
|
||||
path = pico-extras
|
||||
url = git@github.com:raspberrypi/pico-extras.git
|
|
@ -0,0 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
include(pico_sdk_import.cmake)
|
||||
|
||||
project(pico-stuff)
|
||||
|
||||
pico_sdk_init()
|
||||
|
||||
add_subdirectory(bmp180)
|
16
README.md
16
README.md
|
@ -1,2 +1,18 @@
|
|||
# pico-stuff
|
||||
I add my Pi Pico (RP2040) stuff here.
|
||||
|
||||
## Header-Only Libraries
|
||||
- BMP180
|
||||
|
||||
## Installation
|
||||
```bash
|
||||
$ git clone --recursive git@github.com:luigifcruz/pico-stuff.git
|
||||
$ cd pico-stuff
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ PICO_SDK_PATH=../pico-sdk cmake ..
|
||||
$ make -j$(nproc -n)
|
||||
```
|
||||
|
||||
## Debug
|
||||
For debug add `#define DEBUG` before the `#include` of a header-only library.
|
|
@ -0,0 +1,20 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(pico-bmp180)
|
||||
|
||||
add_executable(bmp180
|
||||
test.c
|
||||
)
|
||||
|
||||
target_link_libraries(bmp180
|
||||
pico_stdlib
|
||||
pico_stdio
|
||||
hardware_i2c
|
||||
)
|
||||
|
||||
pico_enable_stdio_usb(bmp180 1)
|
||||
pico_enable_stdio_uart(bmp180 0)
|
||||
|
||||
pico_add_extra_outputs(bmp180)
|
||||
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
|
@ -0,0 +1,255 @@
|
|||
#ifndef BMP180_H
|
||||
#define BMP180_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#define BMP_REG_CONTROL 0xF4
|
||||
#define BMP_REG_RESULT 0xF6
|
||||
#define BMP_COM_TEMP 0x2E
|
||||
#define BMP_COM_PRES 0x34
|
||||
#define BMP_CALIB_COEFF_LEN 0x16
|
||||
#define BMP_CALIB_COEFF_REG 0xAA
|
||||
#define BMP_CHIP_ID_REG 0xD0
|
||||
#define BMP_CHIP_ID_VAL 0x55
|
||||
#define BMP_MIN_TEMP_THRESHOLD -40
|
||||
#define BMP_MAX_TEMP_THRESHOLD +85
|
||||
#define BMP_TEMP_DELAY 5
|
||||
|
||||
#define ASSERT_OK(X) { if (X == false) return false; };
|
||||
|
||||
typedef struct {
|
||||
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;
|
||||
} bmp_calib_param_t;
|
||||
|
||||
typedef struct {
|
||||
int addr;
|
||||
int rate;
|
||||
int scl;
|
||||
int sda;
|
||||
i2c_inst_t* inst;
|
||||
} i2c_t;
|
||||
|
||||
typedef struct {
|
||||
i2c_t i2c;
|
||||
uint8_t oss;
|
||||
float temperature;
|
||||
int32_t pressure;
|
||||
bmp_calib_param_t calib;
|
||||
int32_t B5;
|
||||
} bmp_t;
|
||||
|
||||
const uint32_t oss_delay[] = {5, 8, 14, 26};
|
||||
|
||||
bool bmp_check_chip_id(bmp_t* bmp) {
|
||||
uint8_t chip_id_reg = BMP_CHIP_ID_REG;
|
||||
uint8_t chip_id_val[1];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &chip_id_reg, 1, true);
|
||||
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, chip_id_val, 1, false);
|
||||
|
||||
if (chip_id_val[0] != BMP_CHIP_ID_VAL) {
|
||||
#ifdef DEBUG
|
||||
printf("Returned Chip ID: 0x%02x\n", chip_id_val[0]);
|
||||
printf("Check your I2C configuration and connection.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_get_calib_coeffs(bmp_t* bmp) {
|
||||
uint8_t calib_coeffs_reg = BMP_CALIB_COEFF_REG;
|
||||
uint8_t calib_coeffs_val[BMP_CALIB_COEFF_LEN];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &calib_coeffs_reg, 1, true);
|
||||
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, calib_coeffs_val, BMP_CALIB_COEFF_LEN, false);
|
||||
|
||||
int16_t* data = (int16_t*)&bmp->calib;
|
||||
for (int i = 0, j = 1; i < BMP_CALIB_COEFF_LEN / 2; i++, j += 2) {
|
||||
data[i] = (calib_coeffs_val[i * 2] << 8) | calib_coeffs_val[j];
|
||||
|
||||
if ((data[i] == 0) | (data[i] == -1)) {
|
||||
#ifdef DEBUG
|
||||
printf("Calibation data invalid.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("==== CALIBRATION COEFFS ====\n");
|
||||
printf("AC1: %d\n", bmp->calib.AC1);
|
||||
printf("AC2: %d\n", bmp->calib.AC2);
|
||||
printf("AC3: %d\n", bmp->calib.AC3);
|
||||
printf("AC4: %d\n", bmp->calib.AC4);
|
||||
printf("AC5: %d\n", bmp->calib.AC5);
|
||||
printf("AC6: %d\n", bmp->calib.AC6);
|
||||
printf("B1: %d\n", bmp->calib.B1);
|
||||
printf("B2: %d\n", bmp->calib.B2);
|
||||
printf("MB: %d\n", bmp->calib.MB);
|
||||
printf("MC: %d\n", bmp->calib.MC);
|
||||
printf("MD: %d\n", bmp->calib.MD);
|
||||
printf("============================\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t bmp_start_temperature(bmp_t* bmp) {
|
||||
uint8_t temp_reg[] = {
|
||||
BMP_REG_CONTROL,
|
||||
BMP_COM_TEMP
|
||||
};
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_reg, 2, false);
|
||||
return BMP_TEMP_DELAY;
|
||||
}
|
||||
|
||||
bool bmp_read_temperature(bmp_t* bmp) {
|
||||
uint8_t temp_reg = BMP_REG_RESULT;
|
||||
uint8_t temp_val[2];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &temp_reg, 1, true);
|
||||
if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_val, 2, false) != 2) {
|
||||
#ifdef DEBUG
|
||||
printf("Wrong read length.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int16_t UT = (temp_val[0] << 8) + temp_val[1];
|
||||
|
||||
if (UT == (int16_t)0x8000) {
|
||||
#ifdef DEBUG
|
||||
printf("Non-initialized register detected.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t X1 = (((int32_t)UT - bmp->calib.AC6) * bmp->calib.AC5) >> 15;
|
||||
int32_t X2 = (bmp->calib.MC << 11) / (X1 + bmp->calib.MD);
|
||||
bmp->B5 = X1 + X2;
|
||||
float temp = ((bmp->B5 + 8) >> 4) * 0.1f;
|
||||
|
||||
if ((temp <= BMP_MIN_TEMP_THRESHOLD) || (temp >= BMP_MAX_TEMP_THRESHOLD)) {
|
||||
#ifdef DEBUG
|
||||
printf("Temperature beyond threshold: %f\n", temp);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bmp->temperature = temp;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t bmp_start_pressure(bmp_t* bmp) {
|
||||
uint8_t pres_reg[] = {
|
||||
BMP_REG_CONTROL,
|
||||
BMP_COM_PRES + (bmp->oss << 6)
|
||||
};
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_reg, 2, false);
|
||||
return oss_delay[bmp->oss];
|
||||
}
|
||||
|
||||
bool bmp_read_pressure(bmp_t* bmp) {
|
||||
uint8_t pres_reg = BMP_REG_RESULT;
|
||||
uint8_t pres_val[3];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &pres_reg, 1, true);
|
||||
if (i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_val, 3, false) != 3) {
|
||||
#ifdef DEBUG
|
||||
printf("Wrong read length.\n");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t UP = ((pres_val[0] << 16) + (pres_val[1] << 8) + pres_val[2]) >> (8 - bmp->oss);
|
||||
|
||||
int32_t X1, X2, X3, B3, B6, p = 0;
|
||||
uint32_t B4, B7 = 0;
|
||||
|
||||
B6 = bmp->B5 - 4000;
|
||||
X1 = (bmp->calib.B2 * ((B6 * B6) >> 12)) >> 11;
|
||||
X2 = (bmp->calib.AC2 * B6) >> 11;
|
||||
X3 = X1 + X2;
|
||||
B3 = (((bmp->calib.AC1 * 4 + X3) << bmp->oss) + 2) / 4;
|
||||
X1 = (bmp->calib.AC3 * B6) >> 13;
|
||||
X2 = (bmp->calib.B1 * ((B6 * B6) >> 12)) >> 16;
|
||||
X3 = ((X1 + X2) + 2) >> 2;
|
||||
B4 = (bmp->calib.AC4 * (uint32_t)(X3 + 32768)) >> 15;
|
||||
B7 = ((uint32_t)(UP) - B3) * (50000 >> bmp->oss);
|
||||
|
||||
if (B7 < 0x80000000) {
|
||||
p = (B7 * 2) / B4;
|
||||
} else {
|
||||
p = (B7 / B4) * 2;
|
||||
}
|
||||
|
||||
X1 = (p >> 8) * (p >> 8);
|
||||
X1 = (X1 * 3038) >> 16;
|
||||
X2 = (-7357 * p) >> 16;
|
||||
|
||||
bmp->pressure = p + ((X1 + X2 + 3791) >> 4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_get_temperature(bmp_t* bmp) {
|
||||
sleep_ms(bmp_start_temperature(bmp));
|
||||
return bmp_read_temperature(bmp);
|
||||
}
|
||||
|
||||
// User must call bmp_get_temperature() before calling this method.
|
||||
// Or use the combo bmp_get_pressure_temperature().
|
||||
bool bmp_get_pressure(bmp_t* bmp) {
|
||||
sleep_ms(bmp_start_pressure(bmp));
|
||||
return bmp_read_pressure(bmp);
|
||||
}
|
||||
|
||||
bool bmp_get_pressure_temperature(bmp_t* bmp) {
|
||||
bool res = true;
|
||||
res &= bmp_get_temperature(bmp);
|
||||
res &= bmp_get_pressure(bmp);
|
||||
return res;
|
||||
}
|
||||
|
||||
bool bmp_init(bmp_t* bmp) {
|
||||
i2c_init(bmp->i2c.inst, bmp->i2c.rate);
|
||||
|
||||
if (bmp->oss < 0 || bmp->oss > 3) {
|
||||
#ifdef DEBUG
|
||||
printf("Invalid over-sampling rate (%d). Valid 0 to 3.\n", bmp->oss);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
gpio_set_function(bmp->i2c.scl, GPIO_FUNC_I2C);
|
||||
gpio_set_function(bmp->i2c.sda, GPIO_FUNC_I2C);
|
||||
gpio_pull_up(bmp->i2c.scl);
|
||||
gpio_pull_up(bmp->i2c.sda);
|
||||
|
||||
sleep_ms(100);
|
||||
|
||||
ASSERT_OK(bmp_check_chip_id(bmp));
|
||||
ASSERT_OK(bmp_get_calib_coeffs(bmp));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define DEBUG
|
||||
#include "bmp180.h"
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
getchar();
|
||||
printf("Hello from Pi Pico!\n");
|
||||
|
||||
bmp_t bmp;
|
||||
bmp.oss = 0;
|
||||
bmp.i2c.addr = 0x77;
|
||||
bmp.i2c.inst = i2c1;
|
||||
bmp.i2c.rate = 400000;
|
||||
bmp.i2c.scl = 27;
|
||||
bmp.i2c.sda = 26;
|
||||
|
||||
if (!bmp_init(&bmp))
|
||||
return 1;
|
||||
|
||||
while (true) {
|
||||
if (!bmp_get_pressure_temperature(&bmp))
|
||||
return 1;
|
||||
printf("BMP180 Temperature (C): %f\n", bmp.temperature);
|
||||
printf("BMP180 Pressure (hPa): %f\n", (float)bmp.pressure / 100.0);
|
||||
sleep_ms(250);
|
||||
}
|
||||
|
||||
printf("Bye from pico!\n\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
build/compile_commands.json
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 3617ade198cfdfca24c047f02a0d6948c1c8fdbf
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 89b8071d2a99e1af25b01c6cb0380ae0216053ca
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 2d5789eca89658a7f0a01e2d6010c0f254605d72
|
|
@ -0,0 +1,62 @@
|
|||
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
|
||||
|
||||
# This can be dropped into an external project to help locate this SDK
|
||||
# It should be include()ed prior to project()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
|
||||
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
|
||||
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
|
||||
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
|
||||
endif ()
|
||||
|
||||
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
|
||||
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
|
||||
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
|
||||
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
|
||||
|
||||
if (NOT PICO_SDK_PATH)
|
||||
if (PICO_SDK_FETCH_FROM_GIT)
|
||||
include(FetchContent)
|
||||
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
|
||||
if (PICO_SDK_FETCH_FROM_GIT_PATH)
|
||||
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
|
||||
endif ()
|
||||
FetchContent_Declare(
|
||||
pico_sdk
|
||||
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
|
||||
GIT_TAG master
|
||||
)
|
||||
if (NOT pico_sdk)
|
||||
message("Downloading Raspberry Pi Pico SDK")
|
||||
FetchContent_Populate(pico_sdk)
|
||||
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
|
||||
endif ()
|
||||
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
|
||||
else ()
|
||||
message(FATAL_ERROR
|
||||
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
|
||||
if (NOT EXISTS ${PICO_SDK_PATH})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
|
||||
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
|
||||
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
|
||||
endif ()
|
||||
|
||||
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
|
||||
|
||||
include(${PICO_SDK_INIT_CMAKE_FILE})
|
Ładowanie…
Reference in New Issue