0.3.0 MSP300

This commit is contained in:
Rob Tillaart 2024-05-13 12:41:34 +02:00
parent a869cfa834
commit 73f5c82212
12 changed files with 421 additions and 83 deletions

View File

@ -6,6 +6,21 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/)
and this project adheres to [Semantic Versioning](http://semver.org/).
## [0.3.0] - 2024-05-09
- Fix read bug, thanks to Gabo-Bravo
- updated readme.md
- added **uint8_t getStatus()** + defines for error codes.
- update the default I2C address to 0x28 (within range).
- rewrite **readPT()** and cache pressure, temperature and status.
- add **readP()** to read pressure and status only. (faster).
- add **getPmin()** and **getPmax()** for calibration.
- add **MSP300_performance.ino** to measure I2C read performance.
- add **MSP300_demo_pressure_only.ino**
- add **MSP300_fast_pressure.ino**
- update keywords.txt
----
## [0.2.0] - 2023-12-05
- refactor begin()
- update readme.md

View File

@ -1,7 +1,7 @@
//
// FILE: MSP300.cpp
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.3.0
// PURPOSE: Arduino library for I2C MSP300 pressure transducer.
// URL: https://github.com/RobTillaart/MSP300
@ -15,7 +15,10 @@ MSP300::MSP300(const uint8_t deviceAddress, TwoWire *wire)
_wire = wire;
_error = MSP300_OK;
_maxValue = 100;
_raw = 0;
_pressure = 0;
_temperature = 0;
_status = MSP300_OK;
setPressureCounts(1000, 15000);
}
@ -52,9 +55,21 @@ uint8_t MSP300::getAddress()
//
// CALIBRATION
//
void MSP300::setPressureCounts(uint16_t Pmin, uint16_t Pmax)
void MSP300::setPressureCounts(int Pmin, int Pmax)
{
_pressureFactor = 1.0 / (Pmax - Pmin);
_Pmin = Pmin;
_Pmax = Pmax;
_pressureFactor = _maxValue / (_Pmax - _Pmin);
}
int MSP300::getPmin()
{
return _Pmin;
}
int MSP300::getPmax()
{
return _Pmax;
}
@ -62,36 +77,54 @@ void MSP300::setPressureCounts(uint16_t Pmin, uint16_t Pmax)
//
// READ
//
uint32_t MSP300::readP()
{
_request();
// read status + pressure
uint32_t raw = _read(2);
int P = raw && 0x3FFF; // 14 bit
_pressure = (P - _Pmin) * _pressureFactor;
_status = (raw >> 14); // 2 bit
return raw;
}
uint32_t MSP300::readPT()
{
_request();
_read(4); // read all data.
// TODO check status
// uint8_t status = (_raw >> 30);
// 00 = OK
// 01 = reserved
// 10 = stale data
// 11 = error
return _raw;
// read status, pressure and temperature
uint32_t raw = _read(4);
int T = (raw >> 5) && 0x07FF; // 11 bit
_temperature = T * (200.0 / 2048) - 50.0;
int P = (raw >> 16) && 0x3FFF; // 14 bit
_pressure = (P - _Pmin) * _pressureFactor;
_status = (raw >> 30); // 2 bit
return raw;
}
uint8_t MSP300::getStatus()
{
return _status;
}
float MSP300::getPressure()
{
// formula page 5 datasheet
int pres = (_raw >> 16) && 0x3FFF;
return pres * (_maxValue * _pressureFactor);
return _pressure;
}
float MSP300::getTemperature()
{
int temp = (_raw >> 5) && 0x07FF;
return temp * (200.0 / 2048) - 50.0;
return _temperature;
}
int MSP300::lastError()
{
int e = _error;
@ -111,19 +144,21 @@ void MSP300::_request()
}
void MSP300::_read(uint8_t bytes)
uint32_t MSP300::_read(uint8_t bytes)
{
if (_wire->requestFrom(_address, bytes) != bytes)
{
_error = MSP300_ERROR;
return; // keep last value
_error = MSP300_REQUEST_ERROR;
// report a read error.
return (uint32_t(MSP300_READ_ERROR) << 30);
}
_raw = 0;
uint32_t raw = 0;
for (int i= 0; i < bytes; i++)
{
_raw <<= 8;
_raw = _wire->read();
raw <<= 8;
raw |= _wire->read();
}
return raw;
}

View File

@ -2,7 +2,7 @@
//
// FILE: MSP300.h
// AUTHOR: Rob Tillaart
// VERSION: 0.2.0
// VERSION: 0.3.0
// PURPOSE: Arduino library for I2C MSP300 pressure transducer.
// URL: https://github.com/RobTillaart/MSP300
@ -11,12 +11,15 @@
#include "Wire.h"
#define MSP300_LIB_VERSION (F("0.2.0"))
#define MSP300_LIB_VERSION (F("0.3.0"))
// ERROR CODES
// ERROR AND STATUS CODES
#define MSP300_OK 0
#define MSP300_ERROR 100
#define MSP300_RESERVED 1
#define MSP300_STALE_DATA 2
#define MSP300_READ_ERROR 3
#define MSP300_REQUEST_ERROR 100
/////////////////////////////////////////////////
@ -27,7 +30,7 @@
class MSP300
{
public:
explicit MSP300(const uint8_t deviceAddress = 0x20, TwoWire *wire = &Wire);
explicit MSP300(const uint8_t deviceAddress = 0x28, TwoWire *wire = &Wire);
bool begin(int maxValue);
bool isConnected();
@ -37,12 +40,21 @@ public:
uint8_t getAddress();
// READ
uint32_t readPT();
uint32_t readP(); // returns _raw, reads S + P
uint32_t readPT(); // returns _raw, reads S + P + T
uint8_t getStatus(); // 0 == OK, other = error.
float getPressure();
float getTemperature();
// CALIBRATION
void setPressureCounts(uint16_t Pmin = 1000, uint16_t Pmax = 15000);
// use with care!
// read datasheet page 5
// Pmin = count at zero pressure
// Pmax = count at max pressure (which depends on sensor);
// 1000 and 15000 are the default counts from datasheet.
void setPressureCounts(int Pmin = 1000, int Pmax = 15000);
int getPmin();
int getPmax();
// ERROR HANDLING
int lastError();
@ -52,13 +64,18 @@ private:
uint8_t _address;
int _error;
int _maxValue;
uint32_t _raw;
// default span reversed.
float _pressureFactor = 1.0/14000.0;
float _pressure;
float _temperature;
uint8_t _status;
float _pressureFactor;
int _Pmin;
int _Pmax;
TwoWire* _wire;
void _request();
void _read(uint8_t bytes);
uint32_t _read(uint8_t bytes);
};

View File

@ -13,19 +13,25 @@
Arduino library for I2C MSP300 pressure transducer.
The library is experimental and not tested yet (no hardware).
## Description
**Experimental**
The MSP300 is an industrial digital pressure transducer.
This library implements the I2C version (J) of the sensor.
It is written based upon the datasheet.
The code is written based upon the datasheet,
it is not actually tested by me yet.
The library does not implement the SPI or analog version.
Note: be aware to buy the right sensor: PSI/BAR, SPI/I2C/analog and I2C address as these are hardcoded.
(OK pressure output can be converted)
OK, The pressure value can be converted with **Pressure** library, see below.
```
PSI = 1.45037737738e-5 * BAR;
BAR = 6.89475729318e+4 * PSI;
```
As the sensor is industrial quality, many applications can be realized with it.
@ -33,6 +39,10 @@ Issues, remarks, experience and improvements are welcome,
please open an issue on https://github.com/RobTillaart/MSP300.
#### 0.3.0 Bug fix
A read bug has been fixed and this makes all previous versions obsolete.
#### 0.2.0 Breaking change
Version 0.2.0 introduced a breaking change.
@ -44,6 +54,9 @@ before calling **begin()**.
#### Available pressure ranges
Again: be aware to buy the right sensor: PSI/BAR, SPI/I2C/analog and I2C address as these are hardcoded.
(OK pressure output can be converted)
- PSI := 100, 200, 300, 500, 1K, 3K, 5K, 10K, 15K
- BAR := 7, 10, 20, 35, 70, 200, 350, 700, 1000
@ -66,7 +79,7 @@ It provide 0.5-4.5 volt output which matches many ADC ranges.
White wire is the output (page 4 datasheet).
This version is not supported in the library.
The analog version is not supported in the library.
#### Related libraries
@ -80,24 +93,63 @@ This library is related to:
## I2C
#### Address
#### I2C Address
The MSP300 has a fixed address, however there a five different supported.
So without a multiplexer you can have up to 5 transducers on one I2C bus.
The address is in the product number of the sensor you buy. (check datasheet Page 7).
| code | address |
|:------:|:---------:|
| 0 | 0x28 |
| 1 | 0x36 |
| 2 | 0x46 |
| 3 | 0x48 |
| 4 | 0x51 |
| code | address | decimal |
|:------:|:---------:|:-------:|
| 0 | 0x28 | 24 |
| 1 | 0x36 | 54 |
| 2 | 0x46 | 70 |
| 3 | 0x48 | 72 |
| 4 | 0x51 | 81 |
#### Speed
#### I2C multiplexing
The sensor should work at 100 - 400 KHz I2C.
Sometimes you need to control more devices than possible with the default
address range the device provides.
This is possible with an I2C multiplexer e.g. TCA9548 which creates up
to eight channels (think of it as I2C subnets) which can use the complete
address range of the device.
Drawback of using a multiplexer is that it takes more administration in
your code e.g. which device is on which channel.
This will slow down the access, which must be taken into account when
deciding which devices are on which channel.
Also note that switching between channels will slow down other devices
too if they are behind the multiplexer.
- https://github.com/RobTillaart/TCA9548
#### I2C Speed
The sensor is specified to work at 100 - 400 KHz I2C.
An example performance sketch can be used to see the duration of
the most important **readPT()** call.
As I have no hardware yet, the performance figures are not available.
It is also not known yet if and how well the sensor operates above
and below the specified range.
To elaborate table with measurements.
| I2C clock | readPT() | Notes |
|:-----------:|:----------:|:-------:|
| 50000 | |
| 100000 | |
| 200000 | |
| 300000 | |
| 400000 | | max advised speed
| 500000 | |
| 600000 | |
Operating the sensor outside the specified range may cause incorrect
readings and/or shorten lifetime. This is unknown territory.
## Interface
@ -113,25 +165,40 @@ The library has a number of functions which are all quite straightforward.
- **MSP300(uint8_t address = 0x20, TwoWire \*wire = &Wire)** constructor,
default address and I2C bus.
- **bool begin(int maxValue)** initialize internals.
maxValue is the maximum the sensor can read.
maxValue is the maximum pressure the sensor can read.
- **bool isConnected()** See if address set in constructor is on the bus.
- **bool setAddress(const uint8_t deviceAddress)** set address for e.g. second sensor.
- **bool setAddress(const uint8_t deviceAddress)** set address runtime
e.g. when the address is unknown at compile time.
- **uint8_t getAddress()** returns address set.
#### Read
- **uint32_t readPT()** must be called before pressure or temperature can be read.
- **uint32_t readP()** read status and pressure.
Does not update the temperature.
Returns the raw value which is useful for debugging.
- **uint32_t readPT()** reads status, pressure and temperature.
Returns the raw value which is useful for debugging.
- **uint8_t getStatus()** returns status. Should be 0 after read.
- **float getPressure()** returns the pressure in PSI or BAR (whatever sensor you have).
For converting PSI to BAR or other pressure unit one can use the **Pressure** library.
See above.
Multiple calls will return the same (cached) value.
Call readP() or readPT() to update.
- **float getTemperature()** returns the temperature in degrees Celsius.
Range 0..55° Celsius
Compensated range 0..55° Celsius.
Multiple calls will return the same (cached) temperature.
Call readPT() to update.
#### Calibration
- **void setPressureCounts(uint16_t Pmin = 1000, uint16_t Pmax = 15000)** set the count rates.
Pressure calibration
- **void setPressureCounts(int Pmin = 1000, int Pmax = 15000)** set the count rates.
Use with care. Check datasheet for details.
- **int getPmin()** return current value.
- **int getPmax()** return current value.
#### Error handling
@ -139,12 +206,15 @@ Use with care. Check datasheet for details.
- **int lastError()** returns the last error set. Note: will reset the error!
## Error codes
## Error and Status codes
| define | value |
|:---------------|:-------:|
|:-----------------------|:-------:|
| MSP300_OK | 0 |
| MSP300_ERROR | 100 |
| MSP300_RESERVED | 1 |
| MSP300_STALE_DATA | 2 |
| MSP300_READ_ERROR | 3 |
| MSP300_REQUEST_ERROR | 100 |
## Operation
@ -158,20 +228,17 @@ The examples show the basic working of the functions.
- improve documentation
- get hardware
- test
- test performance
#### Should
- add examples
- elaborate error handling.
- test accuracy?
- improve status / errorhandling
#### Could
- test I2C performance.
- add **setTemperatureOffset(float offset = 0)**
- add **setPressureOffset(float offset = 0)**
- add Temperature calibration.
- unit tests
- add simple class for the analog version
- MSP300A

View File

@ -8,16 +8,19 @@
#include "MSP300.h"
MSP300 MSP(0x2C);
MSP300 MSP(0x28);
uint32_t lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.println();
Serial.println("MSP300_LIB_VERSION: ");
Serial.println(MSP300_LIB_VERSION);
Serial.println();
Wire.begin();
Wire.setClock(400000);
@ -25,6 +28,7 @@ void setup()
bool b = MSP.begin(100);
Serial.println(b ? "true" : "false");
Serial.println(MSP.isConnected());
Serial.println();
}
@ -36,6 +40,8 @@ void loop()
uint32_t x = MSP.readPT();
Serial.print(x, HEX);
Serial.print('\t');
Serial.print(MSP.getStatus());
Serial.print('\t');
Serial.print(MSP.getPressure(), 3);
Serial.print('\t');
Serial.print(MSP.getTemperature(), 3);

View File

@ -0,0 +1,53 @@
//
// FILE: MSP300_demo_pressure_only.ino
// AUTHOR: Rob Tillaart
// PURPOSE: minimal demo pressure only
// URL: https://github.com/RobTillaart/MSP300
#include "MSP300.h"
MSP300 MSP(0x28);
uint32_t lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.println();
Serial.println("MSP300_LIB_VERSION: ");
Serial.println(MSP300_LIB_VERSION);
Serial.println();
Wire.begin();
Wire.setClock(400000);
bool b = MSP.begin(100);
Serial.println(b ? "true" : "false");
Serial.println(MSP.isConnected());
Serial.println();
}
void loop()
{
if (millis() - lastTime > 1000)
{
lastTime = millis();
uint32_t x = MSP.readP();
Serial.print(x, HEX);
Serial.print('\t');
Serial.print(MSP.getStatus());
Serial.print('\t');
Serial.print(MSP.getPressure(), 3);
Serial.print('\n');
}
delay(100);
}
// -- END OF FILE --

View File

@ -0,0 +1,48 @@
//
// FILE: MSP300_fast_pressure.ino
// AUTHOR: Rob Tillaart
// PURPOSE: fast pressure reading
// URL: https://github.com/RobTillaart/MSP300
//
// datasheet states 1 ms refresh time so lets try.
#include "MSP300.h"
MSP300 MSP(0x28);
uint32_t lastTime = 0;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.println();
Serial.println("MSP300_LIB_VERSION: ");
Serial.println(MSP300_LIB_VERSION);
Serial.println();
Wire.begin();
Wire.setClock(400000);
bool b = MSP.begin(100);
Serial.println(b ? "true" : "false");
Serial.println(MSP.isConnected());
Serial.println();
}
void loop()
{
// try a sample every millisecond
if (micros() - lastTime >= 1000)
{
lastTime = micros();
MSP.readP();
Serial.println(MSP.getPressure(), 1);
}
}
// -- END OF FILE --

View File

@ -0,0 +1,66 @@
//
// FILE: MSP300_performance.ino
// AUTHOR: Rob Tillaart
// PURPOSE: measure I2C readPT timing MSP300 pressure transducer
// URL: https://github.com/RobTillaart/MSP300
#include "MSP300.h"
MSP300 MSP(0x28);
volatile uint32_t x = 0;
uint32_t start, stop;
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println(__FILE__);
Serial.println();
Serial.println("MSP300_LIB_VERSION: ");
Serial.println(MSP300_LIB_VERSION);
Serial.println();
Wire.begin();
bool b = MSP.begin(100);
Serial.println(b ? "true" : "false");
Serial.println(MSP.isConnected());
// HEADER
Serial.println();
Serial.println("| speed | readP() | readPT() |");
Serial.println("|:-------:|:-------:|:--------:|");
// TABLE
for (uint32_t speed = 50000; speed <= 500000; speed += 50000)
{
Wire.setClock(speed);
start = micros();
x = MSP.readP();
stop = micros();
Serial.print("| ");
Serial.print(speed);
Serial.print(" | ");
Serial.print(stop - start);
delay(100);
start = micros();
x = MSP.readPT();
stop = micros();
Serial.print(" | ");
Serial.print(stop - start);
Serial.print(" |\n");
delay(100);
}
Serial.println("\ndone...");
}
void loop()
{
}
// -- END OF FILE --

View File

@ -11,11 +11,15 @@ isConnected KEYWORD2
setAddress KEYWORD2
getAddress KEYWORD2
readP KEYWORD2
readPT KEYWORD2
getStatus KEYWORD2
getPressure KEYWORD2
getTemperature KEYWORD2
setPressureCounts KEYWORD2
getPmin KEYWORD2
getPmax KEYWORD2
lastError KEYWORD2
@ -24,5 +28,8 @@ lastError KEYWORD2
MSP300_LIB_VERSION LITERAL1
MSP300_OK LITERAL1
MSP300_ERROR LITERAL1
MSP300_RESERVED LITERAL1
MSP300_STALE_DATA LITERAL1
MSP300_READ_ERROR LITERAL1
MSP300_REQUEST_ERROR LITERAL1

View File

@ -15,7 +15,7 @@
"type": "git",
"url": "https://github.com/RobTillaart/MSP300"
},
"version": "0.2.0",
"version": "0.3.0",
"license": "MIT",
"frameworks": "*",
"platforms": "*",

View File

@ -1,5 +1,5 @@
name=MSP300
version=0.2.0
version=0.3.0
author=Rob Tillaart <rob.tillaart@gmail.com>
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
sentence=Arduino Library for MSP300 pressure transducer (I2C).

View File

@ -38,18 +38,42 @@ unittest_teardown()
unittest(test_constants)
{
assertEqual(000, MSP300_OK);
assertEqual(100, MSP300_ERROR);
assertEqual(001, MSP300_RESERVED);
assertEqual(002, MSP300_STALE_DATA);
assertEqual(003, MSP300_READ_ERROR);
assertEqual(100, MSP300_REQUEST_ERROR);
}
unittest(test_constructors)
unittest(test_constructor)
{
Wire.begin();
MSP300 MSP(0x2C);
MSP300 MSP(0x28);
MSP.begin(100);
// assertEqual(0, MSP.read());
assertEqual(1, 1);
assertEqual(MSP300_OK, MSP.lastError());
assertEqual(0, MSP.getStatus());
assertEqual(0, MSP.getPressure());
assertEqual(0, MSP.getTemperature());
}
unittest(test_PressureCount)
{
Wire.begin();
MSP300 MSP(0x28);
// default values
assertEqual(1000, MSP.getPmin());
assertEqual(15000, MSP.getPmax());
// changed values
MSP.setPressureCounts(1012, 14980);
assertEqual(1012, MSP.getPmin());
assertEqual(14980, MSP.getPmax());
}