Skip to content

Commit 44a4901

Browse files
Merge pull request #11467 from nventurino/feature/ms5525-pitot
Add support for MS5525DSO digital airspeed sensor
2 parents 0684d47 + ddef163 commit 44a4901

9 files changed

Lines changed: 272 additions & 1 deletion

File tree

src/main/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,8 @@ main_sources(COMMON_SRC
219219
drivers/pitotmeter/pitotmeter_adc.h
220220
drivers/pitotmeter/pitotmeter_ms4525.c
221221
drivers/pitotmeter/pitotmeter_ms4525.h
222+
drivers/pitotmeter/pitotmeter_ms5525.c
223+
drivers/pitotmeter/pitotmeter_ms5525.h
222224
drivers/pitotmeter/pitotmeter_dlvr_l10d.c
223225
drivers/pitotmeter/pitotmeter_dlvr_l10d.h
224226
drivers/pitotmeter/pitotmeter_msp.c

src/main/drivers/bus.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@ typedef enum {
141141

142142
/* Other hardware */
143143
DEVHW_MS4525, // Pitot meter
144+
DEVHW_MS5525, // Pitot meter
144145
DEVHW_DLVR, // Pitot meter
145146
DEVHW_M25P16, // SPI NOR flash
146147
DEVHW_W25N, // SPI 128MB or 256MB flash from Winbond W25N family
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
/*
2+
* This file is part of INAV.
3+
*
4+
* INAV is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* INAV is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with INAV. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include <stdbool.h>
19+
#include <stdint.h>
20+
21+
#include "platform.h"
22+
#include "build/debug.h"
23+
24+
#include "common/utils.h"
25+
#include "common/maths.h"
26+
#include "drivers/time.h"
27+
#include "drivers/bus_i2c.h"
28+
#include "drivers/pitotmeter/pitotmeter.h"
29+
#include "drivers/pitotmeter/pitotmeter_ms5525.h"
30+
31+
// MS5525 I2C Addresses
32+
#define MS5525_ADDR_1 0x76
33+
#define MS5525_ADDR_2 0x77
34+
35+
#define CMD_RESET 0x1E // ADC reset command
36+
#define CMD_ADC_READ 0x00 // ADC read command
37+
#define CMD_ADC_CONV 0x40 // ADC conversion command
38+
#define CMD_ADC_D1 0x00 // ADC D1 conversion (Pressure)
39+
#define CMD_ADC_D2 0x10 // ADC D2 conversion (Temperature)
40+
#define CMD_ADC_4096 0x08 // ADC OSR=4096
41+
#define CMD_PROM_RD 0xA0 // Prom read command
42+
#define PROM_NB 8
43+
44+
typedef struct __attribute__ ((__packed__)) ms5525Ctx_s {
45+
uint16_t c[6]; // c1 through c6
46+
uint32_t up; // up (24 bits) + step (top 8 bits)
47+
uint32_t ut; // ut (24 bits)
48+
} ms5525Ctx_t;
49+
50+
STATIC_ASSERT(sizeof(ms5525Ctx_t) <= BUS_SCRATCHPAD_MEMORY_SIZE, busDevice_scratchpad_memory_too_small);
51+
52+
static int8_t ms5525_crc(uint16_t *prom)
53+
{
54+
int32_t i, j;
55+
uint32_t res = 0;
56+
uint8_t crc = prom[7] & 0xF;
57+
prom[7] &= 0xFF00;
58+
59+
bool blankEeprom = true;
60+
61+
for (i = 0; i < 16; i++) {
62+
if (prom[i >> 1]) {
63+
blankEeprom = false;
64+
}
65+
if (i & 1)
66+
res ^= ((prom[i >> 1]) & 0x00FF);
67+
else
68+
res ^= (prom[i >> 1] >> 8);
69+
for (j = 8; j > 0; j--) {
70+
if (res & 0x8000)
71+
res ^= 0x1800;
72+
res <<= 1;
73+
}
74+
}
75+
prom[7] |= crc;
76+
if (!blankEeprom && crc == ((res >> 12) & 0xF))
77+
return 0;
78+
79+
return -1;
80+
}
81+
82+
static bool ms5525_read_adc(pitotDev_t *pitot, uint32_t *result)
83+
{
84+
uint8_t rxbuf[3];
85+
if (busReadBuf(pitot->busDev, CMD_ADC_READ, rxbuf, 3)) {
86+
*result = (rxbuf[0] << 16) | (rxbuf[1] << 8) | rxbuf[2];
87+
return true;
88+
}
89+
return false;
90+
}
91+
92+
static bool ms5525_start(pitotDev_t * pitot)
93+
{
94+
ms5525Ctx_t * ctx = busDeviceGetScratchpadMemory(pitot->busDev);
95+
uint8_t step = ctx->up >> 24;
96+
97+
if (step == 0) {
98+
return busWrite(pitot->busDev, CMD_ADC_CONV + CMD_ADC_D1 + CMD_ADC_4096, 1);
99+
} else {
100+
return busWrite(pitot->busDev, CMD_ADC_CONV + CMD_ADC_D2 + CMD_ADC_4096, 1);
101+
}
102+
}
103+
104+
static bool ms5525_read(pitotDev_t * pitot)
105+
{
106+
ms5525Ctx_t * ctx = busDeviceGetScratchpadMemory(pitot->busDev);
107+
uint8_t step = ctx->up >> 24;
108+
109+
uint32_t adc_val = 0;
110+
if (!ms5525_read_adc(pitot, &adc_val)) {
111+
return false;
112+
}
113+
114+
if (step == 0) {
115+
ctx->up = adc_val | (1 << 24);
116+
return true;
117+
} else {
118+
ctx->ut = adc_val;
119+
ctx->up &= 0x00FFFFFF; // clear step back to 0
120+
return true;
121+
}
122+
}
123+
124+
static void ms5525_calculate(pitotDev_t * pitot, float *pressure, float *temperature)
125+
{
126+
ms5525Ctx_t * ctx = busDeviceGetScratchpadMemory(pitot->busDev);
127+
128+
uint32_t up = ctx->up & 0x00FFFFFF;
129+
uint32_t ut = ctx->ut;
130+
131+
if (up == 0 || ut == 0) {
132+
return; // Wait until both are read at least once
133+
}
134+
135+
// 5525DSO-pp001DS coefficients (1 psi):
136+
// Q1=15, Q2=17, Q3=7, Q4=5, Q5=7, Q6=21
137+
int64_t dT = (int64_t)ut - ((int64_t)ctx->c[4] << 7); // c[5] is c[4] (0-indexed)
138+
int64_t off = ((int64_t)ctx->c[1] << 17) + (((int64_t)ctx->c[3] * dT) >> 5); // c[2]=c[1], c[4]=c[3]
139+
int64_t sens = ((int64_t)ctx->c[0] << 15) + (((int64_t)ctx->c[2] * dT) >> 7); // c[1]=c[0], c[3]=c[2]
140+
int64_t temp = 2000 + ((dT * (int64_t)ctx->c[5]) >> 21); // c[6]=c[5]
141+
142+
int64_t p_raw = ((((int64_t)up * sens) >> 21) - off) >> 15;
143+
144+
// Convert 1 PSI sensor output to Pa
145+
// 1 psi = 6894.757 Pa. p_raw is 0.0001 psi per bit -> 0.6894757 Pa per bit.
146+
147+
if (pressure) {
148+
*pressure = (float)p_raw * 0.6894757f;
149+
}
150+
151+
if (temperature) {
152+
*temperature = C_TO_KELVIN(temp / 100.0f);
153+
}
154+
}
155+
156+
static bool deviceDetect(busDevice_t * dev)
157+
{
158+
// Verify an I2C transaction works: read PROM
159+
uint8_t rxbuf[2];
160+
bool ack = busReadBuf(dev, CMD_PROM_RD, rxbuf, 2);
161+
if (ack) {
162+
return true;
163+
}
164+
return false;
165+
}
166+
167+
bool ms5525Detect(pitotDev_t * pitot)
168+
{
169+
pitot->busDev = busDeviceInit(BUSTYPE_I2C, DEVHW_MS5525, 0, OWNER_AIRSPEED);
170+
if (pitot->busDev == NULL) {
171+
return false;
172+
}
173+
174+
// Try primary address 0x76
175+
pitot->busDev->busdev.i2c.address = MS5525_ADDR_1;
176+
if (!deviceDetect(pitot->busDev)) {
177+
// Fallback to secondary 0x77
178+
pitot->busDev->busdev.i2c.address = MS5525_ADDR_2;
179+
if (!deviceDetect(pitot->busDev)) {
180+
busDeviceDeInit(pitot->busDev);
181+
return false;
182+
}
183+
}
184+
185+
// Sensor found, initialize
186+
busWrite(pitot->busDev, CMD_RESET, 1);
187+
delay(5);
188+
189+
ms5525Ctx_t * ctx = busDeviceGetScratchpadMemory(pitot->busDev);
190+
191+
// Read PROM
192+
uint16_t prom[8];
193+
for (int i = 0; i < PROM_NB; i++) {
194+
uint8_t rxbuf[2] = { 0, 0 };
195+
busReadBuf(pitot->busDev, CMD_PROM_RD + i * 2, rxbuf, 2);
196+
prom[i] = (rxbuf[0] << 8 | rxbuf[1]);
197+
}
198+
199+
// Check CRC
200+
if (ms5525_crc(prom) != 0) {
201+
busDeviceDeInit(pitot->busDev);
202+
return false;
203+
}
204+
205+
// Copy to ctx starting from c1 to c6
206+
for (int i = 0; i < 6; i++) {
207+
ctx->c[i] = prom[i+1];
208+
}
209+
210+
// Setup Context
211+
ctx->up = 0;
212+
ctx->ut = 0;
213+
214+
// Pitot delays
215+
pitot->delay = 10000; // max 9.04ms for OSR4096
216+
pitot->calibThreshold = 0.00005f;
217+
pitot->start = ms5525_start;
218+
pitot->get = ms5525_read;
219+
pitot->calculate = ms5525_calculate;
220+
221+
return true;
222+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/*
2+
* This file is part of INAV.
3+
*
4+
* INAV is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* INAV is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with INAV. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#pragma once
19+
20+
#include "drivers/pitotmeter/pitotmeter.h"
21+
22+
bool ms5525Detect(pitotDev_t *pitot);

src/main/fc/settings.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ tables:
1717
values: ["NONE", "AUTO", "BMP085", "MS5611", "BMP280", "MS5607", "LPS25H", "SPL06", "BMP388", "DPS310", "B2SMPB", "MSP", "FAKE"]
1818
enum: baroSensor_e
1919
- name: pitot_hardware
20-
values: ["NONE", "AUTO", "MS4525", "ADC", "VIRTUAL", "FAKE", "MSP", "DLVR-L10D"]
20+
values: ["NONE", "AUTO", "MS4525", "ADC", "VIRTUAL", "FAKE", "MSP", "DLVR-L10D", "MS5525"]
2121
enum: pitotSensor_e
2222
- name: receiver_type
2323
values: ["NONE", "SERIAL", "MSP", "SIM (SITL)"]

src/main/sensors/pitotmeter.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include "drivers/pitotmeter/pitotmeter.h"
3333
#include "drivers/pitotmeter/pitotmeter_ms4525.h"
34+
#include "drivers/pitotmeter/pitotmeter_ms5525.h"
3435
#include "drivers/pitotmeter/pitotmeter_dlvr_l10d.h"
3536
#include "drivers/pitotmeter/pitotmeter_adc.h"
3637
#include "drivers/pitotmeter/pitotmeter_msp.h"
@@ -111,6 +112,19 @@ bool pitotDetect(pitotDev_t *dev, uint8_t pitotHardwareToUse)
111112
}
112113
FALLTHROUGH;
113114

115+
case PITOT_MS5525:
116+
#ifdef USE_PITOT_MS5525
117+
if (ms5525Detect(dev)) {
118+
pitotHardware = PITOT_MS5525;
119+
break;
120+
}
121+
#endif
122+
/* If we are asked for a specific sensor - break out, otherwise - fall through and continue */
123+
if (pitotHardwareToUse != PITOT_AUTODETECT) {
124+
break;
125+
}
126+
FALLTHROUGH;
127+
114128
case PITOT_DLVR:
115129

116130
// Skip autodetection for DLVR (it is indistinguishable from MS4525) and allow only manual config

src/main/sensors/pitotmeter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ typedef enum {
3232
PITOT_FAKE = 5,
3333
PITOT_MSP = 6,
3434
PITOT_DLVR = 7,
35+
PITOT_MS5525 = 8,
3536
} pitotSensor_e;
3637

3738
#define PITOT_MAX PITOT_FAKE

src/main/target/common.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@
9595
// Allow default airspeed sensors
9696
#define USE_PITOT
9797
#define USE_PITOT_MS4525
98+
#define USE_PITOT_MS5525
9899
#define USE_PITOT_MSP
99100
#define USE_PITOT_DLVR
100101

src/main/target/common_hardware.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,6 +401,14 @@
401401
BUSDEV_REGISTER_I2C(busdev_ms4525, DEVHW_MS4525, MS4525_I2C_BUS, 0x28, NONE, DEVFLAGS_USE_RAW_REGISTERS, 0); // Requires 0xFF to passthrough
402402
#endif
403403

404+
#if defined(PITOT_I2C_BUS) && !defined(MS5525_I2C_BUS)
405+
#define MS5525_I2C_BUS PITOT_I2C_BUS
406+
#endif
407+
408+
#if defined(USE_PITOT_MS5525) && defined(MS5525_I2C_BUS)
409+
BUSDEV_REGISTER_I2C(busdev_ms5525, DEVHW_MS5525, MS5525_I2C_BUS, 0x76, NONE, DEVFLAGS_NONE, 0);
410+
#endif
411+
404412

405413
#if defined(PITOT_I2C_BUS) && !defined(DLVR_I2C_BUS)
406414
#define DLVR_I2C_BUS PITOT_I2C_BUS

0 commit comments

Comments
 (0)