Skip to content

Commit 1797681

Browse files
#622 i2c altimeter issue fix (#630)
* #622 i2c altimeter issue * fixed review comments * Remove "FIFO overflow!" message --------- Co-authored-by: Peter Harper <[email protected]>
1 parent df5fcd5 commit 1797681

File tree

4 files changed

+71
-8
lines changed

4 files changed

+71
-8
lines changed

i2c/mpl3115a2_i2c/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@ add_executable(mpl3115a2_i2c
22
mpl3115a2_i2c.c
33
)
44

5+
target_include_directories(mpl3115a2_i2c PUBLIC
6+
${CMAKE_CURRENT_SOURCE_DIR}
7+
)
8+
9+
target_link_libraries(mpl3115a2_i2c
10+
pico_stdlib
11+
hardware_i2c
12+
)
13+
514
# pull in common dependencies and additional i2c hardware support
615
target_link_libraries(mpl3115a2_i2c pico_stdlib hardware_i2c)
716

i2c/mpl3115a2_i2c/README.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ This example code shows how to interface the Raspberry Pi Pico to an MPL3115A2 a
44

55
The board used in this example https://www.adafruit.com/product/1893[comes from Adafruit], but any MPL3115A2 breakouts should work similarly.
66

7-
The MPL3115A2 makes available two ways of reading its temperature and pressure data. The first is known as polling, where the Pico will continuously read data out of a set of auto-incrementing registers which are refreshed with new data every so often. The second, which this example will demonstrate, uses a 160-byte first-in-first-out (FIFO) queue and configurable interrupts to tell the Pico when to read data. More information regarding when the interrupts can be triggered available https://www.nxp.com/docs/en/data-sheet/MPL3115A2.pdf[in the datasheet]. This example waits for the 32 sample FIFO to overflow, detects this via an interrupt pin, and then averages the 32 samples taken. The sensor is configured to take a sample every second.
7+
The MPL3115A2 makes available two ways of reading its temperature and pressure data. The first is known as polling, where the Pico will continuously read data out of a set of auto-incrementing registers which are refreshed with new data every so often. The second, which this example will demonstrate, uses a 160-byte first-in-first-out (FIFO) queue and configurable interrupts to tell the Pico when to read data. More information regarding when the interrupts can be triggered is available at https://www.nxp.com/docs/en/data-sheet/MPL3115A2.pdf[in the datasheet]. This example waits for the 32 sample FIFO to overflow, detects this via an interrupt pin, and then averages the 32 samples taken. The sensor is configured to take a sample every second.
88

99
Bit math is used to convert the temperature and altitude data from the raw bits collected in the registers. Take the temperature calculation as an example: it is a 12-bit signed number with 8 integer bits and 4 fractional bits. First, we read the 2 8-bit registers and store them in a buffer. Then, we concatenate them into one unsigned 16-bit integer starting with the OUT_T_MSB register, thus making sure that the last bit of this register is aligned with the MSB in our 16 bit unsigned integer so it is correctly interpreted as the signed bit when we later cast this to a signed 16-bit integer. Finally, the entire number is converted to a float implicitly when we multiply it by 1/2^8 to shift it 8 bits to the right of the decimal point. Though only the last 4 bits of the OUT_T_LSB register hold data, this does not matter as the remaining 4 are held at zero and "disappear" when we shift the decimal point left by 8. Similar logic is applied to the altitude calculation.
1010

i2c/mpl3115a2_i2c/mpl3115a2_i2c.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "pico/binary_info.h"
1010
#include "hardware/gpio.h"
1111
#include "hardware/i2c.h"
12+
#include "mpl3115a2_i2c.h"
1213

1314
/* Example code to talk to an MPL3115A2 altimeter sensor via I2C
1415
@@ -42,6 +43,11 @@
4243
#define MPL3115A2_OFF_T _u(0x2C)
4344
#define MPL3115A2_OFF_H _u(0x2D)
4445

46+
/*** Sea-level pressure registers ***/
47+
#define MPL3115A2_BAR_IN_MSB _u(0x14)
48+
#define MPL3115A2_BAR_IN_LSB _u(0x15)
49+
50+
4551
#define MPL3115A2_FIFO_DISABLED _u(0x00)
4652
#define MPL3115A2_FIFO_STOP_ON_OVERFLOW _u(0x80)
4753
#define MPL3115A2_FIFO_SIZE 32
@@ -56,12 +62,24 @@
5662
volatile uint8_t fifo_data[MPL3115A2_FIFO_SIZE * MPL3115A2_DATA_BATCH_SIZE];
5763
volatile bool has_new_data = false;
5864

59-
struct mpl3115a2_data_t {
60-
// Q8.4 fixed point
61-
float temperature;
62-
// Q16.4 fixed-point
63-
float altitude;
64-
};
65+
66+
/*** Sea-level pressure functions ***/
67+
// Set sea-level pressure in hectopascals (hPa)
68+
void mpl3115a2_set_sealevel_pressure(float hPa) {
69+
uint16_t bars = (uint16_t)(hPa * 50); // Convert hPa to BAR_IN value (2 Pa/LSB)
70+
uint8_t buf[] = {MPL3115A2_BAR_IN_MSB, (bars >> 8) & 0xFF, bars & 0xFF};
71+
i2c_write_blocking(i2c_default, ADDR, buf, 3, false);
72+
}
73+
74+
// Get current sea-level pressure setting in hPa
75+
float mpl3115a2_get_sealevel_pressure() {
76+
uint8_t reg = MPL3115A2_BAR_IN_MSB;
77+
uint8_t buf[2];
78+
i2c_write_blocking(i2c_default, ADDR, &reg, 1, true);
79+
i2c_read_blocking(i2c_default, ADDR, buf, 2, false);
80+
uint16_t bars = (buf[0] << 8) | buf[1];
81+
return (float)bars / 50.0f; // Convert back to hPa
82+
}
6583

6684
void copy_to_vbuf(uint8_t buf1[], volatile uint8_t buf2[], uint buflen) {
6785
for (size_t i = 0; i < buflen; i++) {
@@ -109,6 +127,9 @@ void mpl3115a2_init() {
109127
buf[0] = MPL3115A2_CTRLREG5, buf[1] = 0x40;
110128
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
111129

130+
/*** Default sea-level pressure (1013.25 hPa) ***/
131+
mpl3115a2_set_sealevel_pressure(1013.25f);
132+
112133
// set p, t and h offsets here if needed
113134
// eg. 2's complement number: 0xFF subtracts 1 meter
114135
//buf[0] = MPL3115A2_OFF_H, buf[1] = 0xFF;
@@ -132,7 +153,6 @@ void gpio_callback(uint gpio, __unused uint32_t events) {
132153
// FIFO overflow interrupt
133154
// watermark bits set to 0 in F_SETUP reg, so only possible event is an overflow
134155
// otherwise, we would read F_STATUS to confirm it was an overflow
135-
printf("FIFO overflow!\n");
136156
// drain the fifo
137157
mpl3115a2_read_fifo(fifo_data);
138158
// read status register to clear interrupt bit
@@ -186,6 +206,9 @@ int main() {
186206

187207
mpl3115a2_init();
188208

209+
// Uncomment to overwrite default sea-level pressure:
210+
// mpl3115a2_set_sealevel_pressure(1020.0f); // Local weather pressure
211+
189212
gpio_set_irq_enabled_with_callback(INT1_PIN, GPIO_IRQ_LEVEL_LOW, true, &gpio_callback);
190213

191214
while (1) {
@@ -200,6 +223,7 @@ int main() {
200223
}
201224
printf("%d sample average -> t: %.4f C, h: %.4f m\n", MPL3115A2_FIFO_SIZE, tsum / MPL3115A2_FIFO_SIZE,
202225
hsum / MPL3115A2_FIFO_SIZE);
226+
mpl3115a2_get_sealevel_pressure(); // Show current setting
203227
has_new_data = false;
204228
}
205229
sleep_ms(10);

i2c/mpl3115a2_i2c/mpl3115a2_i2c.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// mpl3115a2.h
2+
#ifndef _MPL3115A2_H
3+
#define _MPL3115A2_H
4+
5+
#include "pico/stdlib.h"
6+
7+
#ifdef __cplusplus
8+
extern "C" {
9+
#endif
10+
11+
struct mpl3115a2_data_t {
12+
// Q8.4 fixed point
13+
float temperature;
14+
// Q16.4 fixed-point
15+
float altitude;
16+
};
17+
18+
void mpl3115a2_init(void);
19+
void mpl3115a2_read_fifo(volatile uint8_t* fifo_buf);
20+
void mpl3115a2_convert_fifo_batch(uint8_t start, volatile uint8_t* buf, struct mpl3115a2_data_t* data);
21+
22+
// Add NEW prototypes
23+
void mpl3115a2_set_sealevel_pressure(float hPa);
24+
float mpl3115a2_get_sealevel_pressure(void);
25+
26+
#ifdef __cplusplus
27+
}
28+
#endif
29+
30+
#endif // _MPL3115A2_H

0 commit comments

Comments
 (0)