* Copyright (c) 2021 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
#include <stdio.h>
#include "pico/stdlib.h"
#include "pico/binary_info.h"
#include "hardware/gpio.h"
#include "hardware/i2c.h"
#define ADDR 0x60
#define INT1_PIN _u(16)
#define MPL3115A2_F_DATA _u(0x01)
#define MPL3115A2_F_STATUS _u(0x00)
#define MPL3115A2_F_SETUP _u(0x0F)
#define MPL3115A2_INT_SOURCE _u(0x12)
#define MPL3115A2_CTRLREG1 _u(0x26)
#define MPL3115A2_CTRLREG2 _u(0x27)
#define MPL3115A2_CTRLREG3 _u(0x28)
#define MPL3115A2_CTRLREG4 _u(0x29)
#define MPL3115A2_CTRLREG5 _u(0x2A)
#define MPL3115A2_PT_DATA_CFG _u(0x13)
#define MPL3115A2_OFF_P _u(0x2B)
#define MPL3115A2_OFF_T _u(0x2C)
#define MPL3115A2_OFF_H _u(0x2D)
#define MPL3115A2_FIFO_DISABLED _u(0x00)
#define MPL3115A2_FIFO_STOP_ON_OVERFLOW _u(0x80)
#define MPL3115A2_FIFO_SIZE 32
#define MPL3115A2_DATA_BATCH_SIZE 5
#define MPL3115A2_ALTITUDE_NUM_REGS 3
#define MPL3115A2_ALTITUDE_INT_SIZE 20
#define MPL3115A2_TEMPERATURE_INT_SIZE 12
#define MPL3115A2_NUM_FRAC_BITS 4
#define PARAM_ASSERTIONS_ENABLE_I2C 1
volatile uint8_t fifo_data[MPL3115A2_FIFO_SIZE * MPL3115A2_DATA_BATCH_SIZE];
volatile bool has_new_data = false;
struct mpl3115a2_data_t {
float temperature;
float altitude;
};
void copy_to_vbuf(uint8_t buf1[], volatile uint8_t buf2[], uint buflen) {
for (size_t i = 0; i < buflen; i++) {
buf2[i] = buf1[i];
}
}
#ifdef i2c_default
void mpl3115a2_read_fifo(volatile uint8_t fifo_buf[]) {
uint8_t reg = MPL3115A2_F_DATA;
uint8_t buf[MPL3115A2_FIFO_SIZE * MPL3115A2_DATA_BATCH_SIZE];
i2c_write_blocking(i2c_default, ADDR, ®, 1, true);
i2c_read_blocking(i2c_default, ADDR, buf, MPL3115A2_FIFO_SIZE * MPL3115A2_DATA_BATCH_SIZE, false);
copy_to_vbuf(buf, fifo_buf, MPL3115A2_FIFO_SIZE * MPL3115A2_DATA_BATCH_SIZE);
}
uint8_t mpl3115a2_read_reg(uint8_t reg) {
uint8_t read;
i2c_write_blocking(i2c_default, ADDR, ®, 1, true);
i2c_read_blocking(i2c_default, ADDR, &read, 1, false);
return read;
}
void mpl3115a2_init() {
uint8_t buf[] = {MPL3115A2_CTRLREG1, 0xB8};
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_CTRLREG2, buf[1] = 0x00;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_CTRLREG3, buf[1] = 0x01;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_CTRLREG4, buf[1] = 0x40;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_CTRLREG5, buf[1] = 0x40;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_F_SETUP, buf[1] = MPL3115A2_FIFO_STOP_ON_OVERFLOW;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
buf[0] = MPL3115A2_CTRLREG1, buf[1] = 0xB9;
i2c_write_blocking(i2c_default, ADDR, buf, 2, false);
}
void gpio_callback(uint gpio, __unused uint32_t events) {
if (gpio == INT1_PIN) {
printf("FIFO overflow!\n");
mpl3115a2_read_fifo(fifo_data);
mpl3115a2_read_reg(MPL3115A2_F_STATUS);
has_new_data = true;
}
}
#endif
void mpl3115a2_convert_fifo_batch(uint8_t start, volatile uint8_t buf[], struct mpl3115a2_data_t *data) {
int32_t h = (int32_t) buf[start] << 24;
h |= (int32_t) buf[start + 1] << 16;
h |= (int32_t) buf[start + 2] << 8;
data->altitude = ((float)h) / 65536.f;
int16_t t = (int16_t) buf[start + 3] << 8;
t |= (int16_t) buf[start + 4];
data->temperature = ((float)t) / 256.f;
}
int main() {
stdio_init_all();
#if !defined(i2c_default) || !defined(PICO_DEFAULT_I2C_SDA_PIN) || !defined(PICO_DEFAULT_I2C_SCL_PIN)
#warning i2c / mpl3115a2_i2c example requires a board with I2C pins
puts("Default I2C pins were not defined");
return 0;
#else
printf("Hello, MPL3115A2. Waiting for something to interrupt me!...\n");
i2c_init(i2c_default, 400 * 1000);
gpio_set_function(PICO_DEFAULT_I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(PICO_DEFAULT_I2C_SDA_PIN);
gpio_pull_up(PICO_DEFAULT_I2C_SCL_PIN);
gpio_init(INT1_PIN);
gpio_pull_up(INT1_PIN);
bi_decl(bi_program_name("Example in the pico-examples library for the MPL3115A2 altimeter"));
bi_decl(bi_1pin_with_name(16, "Interrupt pin 1"));
bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN, PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
mpl3115a2_init();
gpio_set_irq_enabled_with_callback(INT1_PIN, GPIO_IRQ_LEVEL_LOW, true, &gpio_callback);
while (1) {
if (has_new_data) {
float tsum = 0, hsum = 0;
struct mpl3115a2_data_t data;
for (int i = 0; i < MPL3115A2_FIFO_SIZE; i++) {
mpl3115a2_convert_fifo_batch(i * MPL3115A2_DATA_BATCH_SIZE, fifo_data, &data);
tsum += data.temperature;
hsum += data.altitude;
}
printf("%d sample average -> t: %.4f C, h: %.4f m\n", MPL3115A2_FIFO_SIZE, tsum / MPL3115A2_FIFO_SIZE,
hsum / MPL3115A2_FIFO_SIZE);
has_new_data = false;
}
sleep_ms(10);
};
#endif
}