kopia lustrzana https://github.com/luigifcruz/pico-stuff
rodzic
d296565562
commit
bfabf02146
|
@ -2,13 +2,14 @@
|
|||
I add my Pi Pico (RP2040) stuff here. There are complete [apps](/apps) and [libraries](/lib) for sensors or complicated tasks.
|
||||
|
||||
## Libraries
|
||||
- [BMP180](/lib/bmp180): Header-only library for the BMP180 atmospheric pressure sensor.
|
||||
- [BMP180](/lib/bmp180): Header-only library for the BMP180 atmospheric pressure and temperature sensor.
|
||||
- [BMP390](/lib/bmp390): Header-only library for the BMP390 atmospheric pressure and temperature sensor.
|
||||
- [USB Network Stack](/lib/usb_network_stack): Library using TinyUSB's implementation of the RNDIS protocol to enable network over USB.
|
||||
|
||||
## Apps
|
||||
- [PiccoloSDR](/apps/piccolosdr): A primitive direct-sampling SDR.
|
||||
- [ADC DMA Chain](/apps/adc_dma_chain): Chained DMA data acquisition from the ADC.
|
||||
- [Barometer](/apps/barometer): Barometer polling the temperature and atmospheric pressure from a BMP180.
|
||||
- [Barometer](/apps/barometer): Read temperature and atmospheric pressure from a BMP180.
|
||||
- [Iperf Server](/apps/iperf_server): A tool to measure the performance of the TinyUSB's TCP/IP stack over USB.
|
||||
- [TCP Server](/apps/tcp_server): A TCP server example to send high-frequency data to the host computer.
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ project(pico-barometer)
|
|||
|
||||
add_executable(barometer test.c)
|
||||
|
||||
target_link_libraries(barometer LINK_PUBLIC bmp180)
|
||||
target_link_libraries(barometer LINK_PUBLIC bmp390)
|
||||
|
||||
pico_add_extra_outputs(barometer)
|
||||
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
# Barometer
|
||||
This example can read temperature and atmospheric pressure using the BMP180 sensor.
|
||||
This example can read temperature and atmospheric pressure using the BMP180 or BMP390 sensor.
|
||||
|
||||
### Dependencies Device
|
||||
- [BMP180](/lib/bmp180) Library.
|
||||
- [BMP180](/lib/bmp180) or [BMP390](/lib/bmp390) Library.
|
||||
|
||||
### Usage
|
||||
This program will start collecting samples when it receives a char from the virtual serial port. It will also output the following messages:
|
||||
|
||||
![BMP180 Barometer Example](/apps/barometer/media/barometer_bmp180_example.gif)
|
||||
![BMP180 Barometer Example](/apps/barometer/media/barometer_bmp180_example.gif)
|
||||
|
|
|
@ -1,21 +1,20 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#define DEBUG
|
||||
#include "bmp180.h"
|
||||
#include "bmp390.h"
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
getchar();
|
||||
sleep_ms(5000);
|
||||
printf("Hello from Pi Pico!\n");
|
||||
|
||||
bmp_t bmp;
|
||||
bmp.oss = 0;
|
||||
bmp.oss = 5;
|
||||
bmp.i2c.addr = 0x77;
|
||||
bmp.i2c.inst = i2c1;
|
||||
bmp.i2c.rate = 400000;
|
||||
bmp.i2c.scl = 27;
|
||||
bmp.i2c.sda = 26;
|
||||
bmp.i2c.scl = 3;
|
||||
bmp.i2c.sda = 2;
|
||||
|
||||
if (!bmp_init(&bmp))
|
||||
return 1;
|
||||
|
@ -23,9 +22,10 @@ int main() {
|
|||
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("---------------------------------------------\n");
|
||||
printf("Temperature (ºC): %f\n", bmp.temperature);
|
||||
printf("Pressure (hPa): %f\n", bmp.pressure);
|
||||
printf("Altitude (m): %f\n", bmp.altitude);
|
||||
}
|
||||
|
||||
printf("Bye from pico!\n\n");
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
add_subdirectory(bmp180)
|
||||
add_subdirectory(usb_network_stack)
|
||||
add_subdirectory(bmp390)
|
||||
add_subdirectory(usb_network_stack)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Pico Libraries
|
||||
These are libraries to make things easier or add support for some sensor.
|
||||
|
||||
- [BMP180](/lib/bmp180): Header-only library for the BMP180 atmospheric pressure sensor.
|
||||
- [BMP180](/lib/bmp180): Header-only library for the BMP180 atmospheric pressure and temperature sensor.
|
||||
- [BMP390](/lib/bmp390): Header-only library for the BMP390 atmospheric pressure and temperature sensor.
|
||||
- [USB Network Stack](/lib/usb_network_stack): Library using TinyUSB's implementation of the RNDIS protocol to enable network over USB.
|
||||
|
||||
## Debug
|
||||
|
@ -9,4 +10,4 @@ For debug add `#define DEBUG` before the `#include` of a header-only library.
|
|||
|
||||
## Usage
|
||||
Q: How can I use these libraries on my project?
|
||||
A: Just copy and paste the header-only library file to your project.
|
||||
A: Just copy and paste the header-only library file to your project.
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct {
|
|||
uint8_t oss;
|
||||
float temperature;
|
||||
int32_t pressure;
|
||||
float altitude;
|
||||
bmp_calib_param_t calib;
|
||||
int32_t B5;
|
||||
} bmp_t;
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
add_library(bmp390 bmp390.h)
|
||||
|
||||
target_link_libraries(bmp390
|
||||
pico_stdlib
|
||||
pico_stdio
|
||||
hardware_i2c
|
||||
)
|
||||
|
||||
target_include_directories(bmp390 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
|
@ -0,0 +1,2 @@
|
|||
# BMP180 Library
|
||||
This is a library for the BMP390 atmospheric pressure and temperature sensor. It can output the temperature (ºC) and the barometric pressure (hPa). For an example of how to use it, check out the [barometer](/apps/better-barometer) example.
|
|
@ -0,0 +1,324 @@
|
|||
#ifndef BMP390_H
|
||||
#define BMP390_H
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "pico/stdio.h"
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/i2c.h"
|
||||
|
||||
#define BMP_RESET_REG 0x7E
|
||||
#define BMP_RESET_VAL 0xB6
|
||||
#define BMP_SENSOR_ID_REG 0x00
|
||||
#define BMP_SENSOR_ID_VAL 0x60
|
||||
#define BMP_OSR_REG 0x1C
|
||||
#define BMP_CAL_REG 0x31
|
||||
#define BMP_CAL_LEN 0x15
|
||||
#define BMP_TEMPERATURE_REG 0x07
|
||||
#define BMP_PRESSURE_REG 0x04
|
||||
#define BMP_MODE_REG 0x1B
|
||||
#define BMP_MODE_VAL 0x13 // Forced Mode, Temp Enable, Pressure Enable
|
||||
#define BMP_STATUS_REG 0x03
|
||||
|
||||
#define ASSERT_OK(X) { if (X == false) return false; };
|
||||
|
||||
typedef struct {
|
||||
uint16_t T1;
|
||||
uint16_t T2;
|
||||
int8_t T3;
|
||||
int16_t P1;
|
||||
int16_t P2;
|
||||
int8_t P3;
|
||||
int8_t P4;
|
||||
uint16_t P5;
|
||||
uint16_t P6;
|
||||
int8_t P7;
|
||||
int8_t P8;
|
||||
int16_t P9;
|
||||
int8_t P10;
|
||||
int8_t P11;
|
||||
} bmp_calib_param_t;
|
||||
|
||||
typedef struct {
|
||||
double T1;
|
||||
double T2;
|
||||
double T3;
|
||||
double P1;
|
||||
double P2;
|
||||
double P3;
|
||||
double P4;
|
||||
double P5;
|
||||
double P6;
|
||||
double P7;
|
||||
double P8;
|
||||
double P9;
|
||||
double P10;
|
||||
double P11;
|
||||
} bmp_calib_part_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;
|
||||
float pressure;
|
||||
float altitude;
|
||||
bmp_calib_param_t calib;
|
||||
bmp_calib_part_param_t calib_part;
|
||||
} bmp_t;
|
||||
|
||||
bool bmp_reset(bmp_t* bmp) {
|
||||
uint8_t data_buffer[] = {
|
||||
BMP_RESET_REG,
|
||||
BMP_RESET_VAL
|
||||
};
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("INFO: Successfully reset sensor.\n");
|
||||
#endif
|
||||
|
||||
sleep_ms(10);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_check_chip_id(bmp_t* bmp) {
|
||||
uint8_t chip_id_reg = BMP_SENSOR_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_SENSOR_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;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("INFO: Successfully checked the Chip ID.\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_set_oversampling_rate(bmp_t* bmp) {
|
||||
uint8_t data_buffer[] = {
|
||||
BMP_OSR_REG,
|
||||
(bmp->oss << 3) | (bmp->oss << 0)
|
||||
};
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("INFO: Successfully configured oversampling rate.\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
bool bmp_get_calib_coeffs(bmp_t* bmp) {
|
||||
uint8_t calib_coeffs_reg = BMP_CAL_REG;
|
||||
uint8_t calib_coeffs_val[BMP_CAL_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_CAL_LEN, false);
|
||||
|
||||
bmp->calib.T1 = (calib_coeffs_val[1] << 8) | calib_coeffs_val[0];
|
||||
bmp->calib.T2 = (calib_coeffs_val[3] << 8) | calib_coeffs_val[2];
|
||||
bmp->calib.T3 = calib_coeffs_val[4];
|
||||
bmp->calib.P1 = (calib_coeffs_val[6] << 8) | calib_coeffs_val[5];
|
||||
bmp->calib.P2 = (calib_coeffs_val[8] << 8) | calib_coeffs_val[7];
|
||||
bmp->calib.P3 = calib_coeffs_val[9];
|
||||
bmp->calib.P4 = calib_coeffs_val[10];
|
||||
bmp->calib.P5 = (calib_coeffs_val[12] << 8) | calib_coeffs_val[11];
|
||||
bmp->calib.P6 = (calib_coeffs_val[14] << 8) | calib_coeffs_val[13];
|
||||
bmp->calib.P7 = calib_coeffs_val[15];
|
||||
bmp->calib.P8 = calib_coeffs_val[16];
|
||||
bmp->calib.P9 = (calib_coeffs_val[18] << 8) | calib_coeffs_val[17];
|
||||
bmp->calib.P10 = calib_coeffs_val[19];
|
||||
bmp->calib.P11 = calib_coeffs_val[20];
|
||||
|
||||
bmp->calib_part.T1 = (double)bmp->calib.T1 / pow(2, -8.0);
|
||||
bmp->calib_part.T2 = (double)bmp->calib.T2 / pow(2, 30.0);
|
||||
bmp->calib_part.T3 = (double)bmp->calib.T3 / pow(2, 48.0);
|
||||
|
||||
bmp->calib_part.P1 = ((double)bmp->calib.P1 - pow(2, 14.0)) / pow(2, 20.0);
|
||||
bmp->calib_part.P2 = ((double)bmp->calib.P2 - pow(2, 14.0)) / pow(2, 29.0);
|
||||
bmp->calib_part.P3 = (double)bmp->calib.P3 / pow(2, 32.0);
|
||||
bmp->calib_part.P4 = (double)bmp->calib.P4 / pow(2, 37.0);
|
||||
bmp->calib_part.P5 = (double)bmp->calib.P5 / pow(2, -3.0);
|
||||
bmp->calib_part.P6 = (double)bmp->calib.P6 / pow(2, 6.0);
|
||||
bmp->calib_part.P7 = (double)bmp->calib.P7 / pow(2, 8.0);
|
||||
bmp->calib_part.P8 = (double)bmp->calib.P8 / pow(2, 15.0);
|
||||
bmp->calib_part.P9 = (double)bmp->calib.P9 / pow(2, 48.0);
|
||||
bmp->calib_part.P10 = (double)bmp->calib.P10 / pow(2, 48.0);
|
||||
bmp->calib_part.P11 = (double)bmp->calib.P11 / pow(2.0, 65.0);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("==== CALIBRATION COEFFS ====\n");
|
||||
printf("T1: %lf\n", bmp->calib_part.T1);
|
||||
printf("T2: %lf\n", bmp->calib_part.T2);
|
||||
printf("T3: %lf\n", bmp->calib_part.T3);
|
||||
printf("P1: %lf\n", bmp->calib_part.P1);
|
||||
printf("P2: %lf\n", bmp->calib_part.P2);
|
||||
printf("P3: %lf\n", bmp->calib_part.P3);
|
||||
printf("P4: %lf\n", bmp->calib_part.P4);
|
||||
printf("P5: %lf\n", bmp->calib_part.P5);
|
||||
printf("P6: %lf\n", bmp->calib_part.P6);
|
||||
printf("P7: %lf\n", bmp->calib_part.P7);
|
||||
printf("P8: %lf\n", bmp->calib_part.P8);
|
||||
printf("P9: %lf\n", bmp->calib_part.P9);
|
||||
printf("P10: %lf\n", bmp->calib_part.P10);
|
||||
printf("P11: %lf\n", bmp->calib_part.P11);
|
||||
printf("============================\n");
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_read_uncalibrated_temperature(bmp_t* bmp) {
|
||||
uint8_t temp_reg = BMP_TEMPERATURE_REG;
|
||||
uint8_t temp_val[3];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &temp_reg, 1, true);
|
||||
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, temp_val, 3, false);
|
||||
|
||||
bmp->temperature = (temp_val[2] << 16) | (temp_val[1] << 8) | temp_val[0];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_read_uncalibrated_pressure(bmp_t* bmp) {
|
||||
uint8_t pres_reg = BMP_PRESSURE_REG;
|
||||
uint8_t pres_val[3];
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &pres_reg, 1, true);
|
||||
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, pres_val, 3, false);
|
||||
|
||||
bmp->pressure = (pres_val[2] << 16) | (pres_val[1] << 8) | pres_val[0];
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool bmp_calibrate_temperature(bmp_t* bmp) {
|
||||
double par1 = bmp->temperature - bmp->calib_part.T1;
|
||||
double par2 = par1 * bmp->calib_part.T2;
|
||||
bmp->temperature = par2 + (par1 * par1) * bmp->calib_part.T3;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_calibrate_pressure(bmp_t* bmp) {
|
||||
double out1, out2, out3;
|
||||
|
||||
{
|
||||
double par1 = bmp->calib_part.P6 * bmp->temperature;
|
||||
double par2 = bmp->calib_part.P7 * pow(bmp->temperature, 2.0);
|
||||
double par3 = bmp->calib_part.P8 * pow(bmp->temperature, 3.0);
|
||||
out1 = bmp->calib_part.P5 + par1 + par2 + par3;
|
||||
}
|
||||
|
||||
{
|
||||
double par1 = bmp->calib_part.P2 * bmp->temperature;
|
||||
double par2 = bmp->calib_part.P3 * pow(bmp->temperature, 2.0);
|
||||
double par3 = bmp->calib_part.P4 * pow(bmp->temperature, 3.0);
|
||||
out2 = bmp->pressure * (bmp->calib_part.P1 + par1 + par2 + par3);
|
||||
}
|
||||
|
||||
{
|
||||
double par1 = pow(bmp->pressure, 2.0);
|
||||
double par2 = bmp->calib_part.P9 + bmp->calib_part.P10 * bmp->temperature;
|
||||
double par3 = par1 * par2;
|
||||
out3 = par3 + bmp->calib_part.P11 * pow(bmp->pressure, 3);
|
||||
}
|
||||
|
||||
bmp->pressure = (out1 + out2 + out3) / 100.0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_calculate_altitude(bmp_t* bmp) {
|
||||
bmp->altitude = ((pow((1013.25 / bmp->pressure), (1/5.257)) - 1) * (bmp->temperature + 273.15)) / 0.0065;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_get_pressure_temperature(bmp_t* bmp) {
|
||||
bool res = true;
|
||||
|
||||
{
|
||||
uint8_t data_buffer[] = {
|
||||
BMP_MODE_REG,
|
||||
BMP_MODE_VAL
|
||||
};
|
||||
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, data_buffer, 2, false);
|
||||
}
|
||||
|
||||
{
|
||||
uint8_t status = 0x00;
|
||||
while ((status & 0x60) != 0x60) {
|
||||
uint8_t status_reg = BMP_STATUS_REG;
|
||||
i2c_write_blocking(bmp->i2c.inst, bmp->i2c.addr, &status_reg, 1, true);
|
||||
i2c_read_blocking(bmp->i2c.inst, bmp->i2c.addr, &status, 1, false);
|
||||
sleep_ms(1);
|
||||
}
|
||||
}
|
||||
|
||||
res &= bmp_read_uncalibrated_temperature(bmp);
|
||||
res &= bmp_read_uncalibrated_pressure(bmp);
|
||||
res &= bmp_calibrate_temperature(bmp);
|
||||
res &= bmp_calibrate_pressure(bmp);
|
||||
res &= bmp_calculate_altitude(bmp);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool bmp_init(bmp_t* bmp) {
|
||||
i2c_init(bmp->i2c.inst, bmp->i2c.rate);
|
||||
|
||||
if (bmp->oss < 0 || bmp->oss > 5) {
|
||||
#ifdef DEBUG
|
||||
printf("Invalid over-sampling rate (%d). Valid 0 to 5.\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_reset(bmp));
|
||||
ASSERT_OK(bmp_check_chip_id(bmp));
|
||||
ASSERT_OK(bmp_set_oversampling_rate(bmp));
|
||||
ASSERT_OK(bmp_get_calib_coeffs(bmp));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool bmp_get_temperature(bmp_t* bmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bmp_get_pressure(bmp_t* bmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
Ładowanie…
Reference in New Issue