Initial commit.

This commit is contained in:
conky
2026-08-31 15:45:58 +03:00
commit ec9805b01a
22 changed files with 1536 additions and 0 deletions

39
include/README Normal file
View 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
View 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
View 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
View 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]);