Initial commit.
This commit is contained in:
39
include/README
Normal file
39
include/README
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
This directory is intended for project header files.
|
||||
|
||||
A header file is a file containing C declarations and macro definitions
|
||||
to be shared between several project source files. You request the use of a
|
||||
header file in your project source file (C, C++, etc) located in `src` folder
|
||||
by including it, with the C preprocessing directive `#include'.
|
||||
|
||||
```src/main.c
|
||||
|
||||
#include "header.h"
|
||||
|
||||
int main (void)
|
||||
{
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Including a header file produces the same results as copying the header file
|
||||
into each source file that needs it. Such copying would be time-consuming
|
||||
and error-prone. With a header file, the related declarations appear
|
||||
in only one place. If they need to be changed, they can be changed in one
|
||||
place, and programs that include the header file will automatically use the
|
||||
new version when next recompiled. The header file eliminates the labor of
|
||||
finding and changing all the copies as well as the risk that a failure to
|
||||
find one copy will result in inconsistencies within a program.
|
||||
|
||||
In C, the usual convention is to give header files names that end with `.h'.
|
||||
It is most portable to use only letters, digits, dashes, and underscores in
|
||||
header file names, and at most one dot.
|
||||
|
||||
Read more about using header files in official GCC documentation:
|
||||
|
||||
* Include Syntax
|
||||
* Include Operation
|
||||
* Once-Only Headers
|
||||
* Computed Includes
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
|
||||
100
include/baro_channel.h
Normal file
100
include/baro_channel.h
Normal file
@@ -0,0 +1,100 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "ms5611_crc.h"
|
||||
|
||||
//
|
||||
// One validated MS5611 measurement channel.
|
||||
//
|
||||
// The class owns everything that is identical for both sensors - reset and
|
||||
// PROM/CRC handshake, per-poll validation, error accounting and the 1 second
|
||||
// error LED pulse. Only the five driver calls at the bottom are virtual, and
|
||||
// they are implemented once for the I2C part and once for the SPI part.
|
||||
//
|
||||
|
||||
enum class BaroStatus : uint8_t
|
||||
{
|
||||
NotInitialised = 0,
|
||||
Ok,
|
||||
InitFailed, // reset/handshake did not complete
|
||||
PromCrcError, // factory calibration failed its CRC-4 or is implausible
|
||||
ReadError, // the driver reported a bus/ADC failure
|
||||
OutOfRange, // values outside the MS5611 operating envelope
|
||||
Stale, // sensor answers but has stopped producing new samples
|
||||
};
|
||||
|
||||
// Short, log-friendly name for a status - never returns NULL.
|
||||
const char *baroStatusName(BaroStatus status);
|
||||
|
||||
|
||||
class BaroChannel
|
||||
{
|
||||
public:
|
||||
BaroChannel(const char *name, uint8_t ledPin)
|
||||
: _name(name), _ledPin(ledPin) {}
|
||||
|
||||
// Configures the LED pin and makes the first initialisation attempt.
|
||||
void begin(uint32_t now);
|
||||
|
||||
// One acquisition cycle: read, validate, update status and LED.
|
||||
// Blocks for roughly 2x the ADC conversion time of the configured OSR.
|
||||
void poll(uint32_t now);
|
||||
|
||||
// Releases the error LED once its hold time has elapsed. Cheap, call often.
|
||||
void updateLed(uint32_t now);
|
||||
|
||||
const char *name() const { return _name; }
|
||||
BaroStatus status() const { return _status; }
|
||||
bool isOk() const { return _status == BaroStatus::Ok; }
|
||||
float pressure() const { return _pressure; } // mbar
|
||||
float temperature() const { return _temperature; } // degrees C
|
||||
uint32_t errorCount() const { return _errorCount; }
|
||||
|
||||
protected:
|
||||
// Not deleted through this type - keeps the vtable free of a destructor
|
||||
// slot and avoids dragging in operator delete.
|
||||
~BaroChannel() = default;
|
||||
|
||||
// Reset the part and apply the configured oversampling.
|
||||
virtual bool driverBegin() = 0;
|
||||
// Fill prom[0..7] with the factory calibration words.
|
||||
virtual void driverReadProm(uint16_t *prom) = 0;
|
||||
// True when the driver reported MS5611_READ_OK.
|
||||
virtual bool driverRead() = 0;
|
||||
virtual float driverPressure() = 0;
|
||||
virtual float driverTemperature() = 0;
|
||||
|
||||
private:
|
||||
bool tryInit(uint32_t now);
|
||||
void fail(BaroStatus status, uint32_t now);
|
||||
|
||||
const char *_name;
|
||||
uint8_t _ledPin;
|
||||
|
||||
BaroStatus _status = BaroStatus::NotInitialised;
|
||||
bool _initialised = false;
|
||||
uint32_t _lastInitAttempt = 0;
|
||||
|
||||
float _pressure = NAN;
|
||||
float _temperature = NAN;
|
||||
|
||||
uint8_t _repeatCount = 0;
|
||||
uint8_t _errorStreak = 0;
|
||||
uint32_t _errorCount = 0;
|
||||
|
||||
bool _ledOn = false;
|
||||
uint32_t _ledOffAt = 0;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// The two concrete channels are built in their own translation units on
|
||||
// purpose: MS5611.h and MS5611_SPI.h each define `enum osr_t` and their own
|
||||
// MS5611_READ_OK, so including both in one file does not compile. These
|
||||
// accessors hand out the instances without leaking either driver header.
|
||||
//
|
||||
BaroChannel &baroI2cChannel();
|
||||
BaroChannel &baroSpiChannel();
|
||||
120
include/config.h
Normal file
120
include/config.h
Normal file
@@ -0,0 +1,120 @@
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
//
|
||||
// Project-wide hardware and behaviour configuration.
|
||||
//
|
||||
// Board : NUCLEO-F042K6 (STM32F042K6T6, LQFP32, board MB1180)
|
||||
// 32 KB flash / 6 KB RAM
|
||||
// Sensor: 2x GY-63 breakout carrying a MS5611-01BA03
|
||||
// one on I2C1, one on SPI1
|
||||
//
|
||||
// Pin facts below are taken from ST UM1956 "STM32 Nucleo-32 boards (MB1180)"
|
||||
// Table 10 + the MB1180 C.2 schematic, cross-checked against the STM32duino
|
||||
// variant files for NUCLEO_F042K6.
|
||||
//
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// I2C sensor ("baro0")
|
||||
// ---------------------------------------------------------------------------
|
||||
// STM32duino default Wire pins for this variant:
|
||||
// PIN_WIRE_SDA = PB7 (Arduino D4, routed to the A4 header pad via SB18)
|
||||
// PIN_WIRE_SCL = PB6 (Arduino D5, routed to the A5 header pad via SB16)
|
||||
// Both are the STM32duino defaults, so plain Wire.begin() selects them and no
|
||||
// explicit setSDA()/setSCL() call is required.
|
||||
//
|
||||
// MS5611 I2C address is 1110 11Cx where C is the COMPLEMENT of the CSB pin
|
||||
// (datasheet p.12), therefore:
|
||||
// CSB tied to GND -> 0x77
|
||||
// CSB tied to VCC -> 0x76
|
||||
// Change this if the GY-63 CSB pad is strapped high.
|
||||
#define BARO_I2C_ADDRESS 0x77
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SPI sensor ("baro1")
|
||||
// ---------------------------------------------------------------------------
|
||||
// SPI1 MUST stay on the PB3/PB4/PB5 group on this board.
|
||||
//
|
||||
// The alternative SPI1 group (PA5 SCK / PA6 MISO / PA7 MOSI) is NOT usable
|
||||
// here: with the factory-default solder bridges SB16 and SB18 closed, PA6 is
|
||||
// tied to the same net as PB6 (I2C SCL) and PA5 is tied to the same net as
|
||||
// PB7 (I2C SDA). Driving SPI on PA5/PA6 while I2C runs on PB6/PB7 would put
|
||||
// two peripherals on one net. See UM1956 Table 8 (SB16/SB18).
|
||||
//
|
||||
// SCK = PB3 (Arduino D13) <- also the on-board user LED LD3, see below
|
||||
// MISO = PB4 (Arduino D12) <- connect to sensor SDO
|
||||
// MOSI = PB5 (Arduino D11) <- connect to sensor SDI
|
||||
// These three are the STM32duino defaults (core falls back to Arduino pin
|
||||
// numbers 13/12/11), so plain SPI.begin() selects them.
|
||||
#define BARO_SPI_CS_PIN PA11 // Arduino D10, core default PIN_SPI_SS
|
||||
|
||||
// MS5611 accepts SPI mode 0 and mode 3, up to 20 MHz (datasheet p.5/p.6).
|
||||
// The library hardcodes mode 0; 1 MHz is its default and is plenty here.
|
||||
#define BARO_SPI_CLOCK_HZ 1000000UL
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Error indicator LEDs - one per sensor
|
||||
// ---------------------------------------------------------------------------
|
||||
// IMPORTANT: the NUCLEO-F042K6 has exactly ONE user-controllable LED, and it
|
||||
// is unusable for this project:
|
||||
//
|
||||
// LD1 (COM, tricolor) - driven by the ST-LINK MCU, not by the target
|
||||
// LD2 (PWR, red) - hardwired to the power rail, not by the target
|
||||
// LD3 (user, green) - on PB3 via SB15 + R23, and PB3 is our SPI1 SCK
|
||||
//
|
||||
// So both indicators are external LEDs (LED + ~510R to GND) on free GPIOs.
|
||||
// PB0/PB1 are plain GPIO on this board and collide with nothing we use.
|
||||
#define LED_BARO_I2C_PIN PB0 // Arduino D3 - error LED for the I2C sensor
|
||||
#define LED_BARO_SPI_PIN PB1 // Arduino D6 - error LED for the SPI sensor
|
||||
|
||||
// How long an LED stays lit after an error is detected.
|
||||
#define LED_ERROR_HOLD_MS 1000UL
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// UART
|
||||
// ---------------------------------------------------------------------------
|
||||
// `Serial` on this variant is USART2 (SERIAL_UART_INSTANCE 2) on PA2/PA15,
|
||||
// which is wired to the ST-LINK Virtual COM Port. No extra wiring needed.
|
||||
#define UART_BAUD 115200UL
|
||||
|
||||
// Measurement report rate: 10 Hz.
|
||||
#define REPORT_PERIOD_MS 100UL
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Acquisition
|
||||
// ---------------------------------------------------------------------------
|
||||
// The driver's read() busy-waits through two conversions, so a poll of both
|
||||
// sensors is the loop period, and the report deadline can only be evaluated
|
||||
// on that grid. Keeping the cycle short keeps the 10 Hz output jitter small:
|
||||
//
|
||||
// OSR_STANDARD (1024) 2.28 ms/conv -> ~5 ms/sensor -> ~11 ms cycle
|
||||
// OSR_ULTRA_HIGH (4096) 9.04 ms/conv -> ~19 ms/sensor -> ~37 ms cycle
|
||||
//
|
||||
// Conversion times are the datasheet p.3 maxima. OSR 1024 already resolves
|
||||
// well under a mbar, so it is the better trade here; raise it if resolution
|
||||
// matters more than tight report timing.
|
||||
#define BARO_OVERSAMPLING OSR_STANDARD
|
||||
|
||||
// Retry interval for a sensor that failed to initialise.
|
||||
#define BARO_INIT_RETRY_MS 2000UL
|
||||
|
||||
// Consecutive failed polls after which the channel is torn down and taken
|
||||
// back through the full reset + PROM/CRC handshake. Covers a sensor that was
|
||||
// unplugged, browned out, or otherwise lost its calibration constants.
|
||||
#define BARO_REINIT_AFTER_ERRORS 10
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Validation limits
|
||||
// ---------------------------------------------------------------------------
|
||||
// MS5611-01BA03 operating ranges (datasheet p.2/p.4).
|
||||
#define BARO_PRESSURE_MIN_MBAR 10.0f
|
||||
#define BARO_PRESSURE_MAX_MBAR 1200.0f
|
||||
#define BARO_TEMP_MIN_C (-40.0f)
|
||||
#define BARO_TEMP_MAX_C 85.0f
|
||||
|
||||
// A healthy MS5611 dithers by well under a mbar but never repeats a 24-bit
|
||||
// reading bit-for-bit many times running. Identical pressure AND temperature
|
||||
// this many polls in a row means the sensor stopped converting while still
|
||||
// answering on the bus.
|
||||
#define BARO_STALE_LIMIT 32
|
||||
11
include/ms5611_crc.h
Normal file
11
include/ms5611_crc.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// MS5611 factory PROM CRC-4 (datasheet p.13, algorithm specified in AN520).
|
||||
// `prom` holds the 8 PROM words as read from the part; word 7 carries the
|
||||
// stored CRC in its low nibble. The array is restored before returning.
|
||||
//
|
||||
// Deliberately free of Arduino headers so it can be built and tested on the
|
||||
// host against the AN520 reference vector.
|
||||
bool ms5611PromCrcOk(uint16_t prom[8]);
|
||||
Reference in New Issue
Block a user