diff --git a/.gitignore b/.gitignore index 3850bf0..7d8e366 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ !important .vscode/tasks.json __pycache__ profiles.json +.DS_Store diff --git a/Node/Common/sensors/inc/DPS310.h b/Node/Common/sensors/inc/DPS310.h new file mode 100644 index 0000000..8cad4a9 --- /dev/null +++ b/Node/Common/sensors/inc/DPS310.h @@ -0,0 +1,415 @@ +#ifndef DPS310_H_INCLUDED +#define DPS310_H_INCLUDED + +#include "dps_config.h" +#include "dps310_config.h" + +class TwoWire; + +class Dps310 +{ +public: + Dps310(); + + ~Dps310(); + /** + * I2C begin function with standard address + */ + void begin(TwoWire &bus); + + /** + * Standard I2C begin function + * + * @param &bus: I2CBus which connects MC to the sensor + * @param slaveAddress: I2C address of the sensor (0x77 or 0x76) + */ + void begin(TwoWire &bus, uint8_t slaveAddress); + + /** + * End function for Dps310 + * Sets the sensor to idle mode + */ + void end(void); + + /** + * returns the Product ID of the connected Dps310 sensor + */ + uint8_t getProductId(void); + + /** + * returns the Revision ID of the connected Dps310 sensor + */ + uint8_t getRevisionId(void); + + /** + * Sets the Dps310 to standby mode + * + * @return status code + */ + int16_t standby(void); + + /** + * performs one temperature measurement + * + * @param &result: reference to a float value where the result will be written + * @return status code + */ + int16_t measureTempOnce(float &result); + + /** + * performs one temperature measurement with specified oversamplingRate + * + * @param &result: reference to a float where the result will be written + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128, which are defined as integers 0 - 7 + * The number of measurements equals to 2^n, if the value written to the register field is n. 2^n internal measurements are combined to return a more exact measurement + * @return status code + */ + int16_t measureTempOnce(float &result, uint8_t oversamplingRate); + + /** + * starts a single temperature measurement + * + * @return status code + */ + int16_t startMeasureTempOnce(void); + + /** + * starts a single temperature measurement with specified oversamplingRate + * + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128, which are defined as integers 0 - 7 + * @return status code + */ + int16_t startMeasureTempOnce(uint8_t oversamplingRate); + + /** + * performs one pressure measurement + * + * @param &result: reference to a float value where the result will be written + * @return status code + */ + int16_t measurePressureOnce(float &result); + + /** + * performs one pressure measurement with specified oversamplingRate + * + * @param &result: reference to a float where the result will be written + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * @return status code + */ + int16_t measurePressureOnce(float &result, uint8_t oversamplingRate); + + /** + * starts a single pressure measurement + * + * @return status code + */ + int16_t startMeasurePressureOnce(void); + + /** + * starts a single pressure measurement with specified oversamplingRate + * + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * @return status code + */ + int16_t startMeasurePressureOnce(uint8_t oversamplingRate); + + /** + * gets the result a single temperature or pressure measurement in °C or Pa + * + * @param &result: reference to a float value where the result will be written + * @return status code + */ + int16_t getSingleResult(float &result); + + /** + * starts a continuous temperature measurement with specified measurement rate and oversampling rate + * If measure rate is n and oversampling rate is m, the DPS310 performs 2^(n+m) internal measurements per second. + * The DPS310 cannot operate with high precision and high speed at the same time. Consult the datasheet for more information. + * + * @param measureRate: DPS__MEASUREMENT_RATE_1, DPS__MEASUREMENT_RATE_2,DPS__MEASUREMENT_RATE_4 ... DPS__MEASUREMENT_RATE_128 + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * + * @return status code + * + */ + int16_t startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate); + + /** + * starts a continuous temperature measurement with specified measurement rate and oversampling rate + * + * @param measureRate: DPS__MEASUREMENT_RATE_1, DPS__MEASUREMENT_RATE_2,DPS__MEASUREMENT_RATE_4 ... DPS__MEASUREMENT_RATE_128 + * @param oversamplingRate: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * @return status code + */ + int16_t startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate); + + /** + * starts a continuous temperature and pressure measurement with specified measurement rate and oversampling rate for temperature and pressure measurement respectvely. + * + * @param tempMr measure rate for temperature + * @param tempOsr oversampling rate for temperature + * @param prsMr measure rate for pressure + * @param prsOsr oversampling rate for pressure + * @return status code + */ + int16_t startMeasureBothCont(uint8_t tempMr, uint8_t tempOsr, uint8_t prsMr, uint8_t prsOsr); + + /** + * Gets the interrupt status flag of the FIFO + * + * @return 1 if the FIFO is full and caused an interrupt + * 0 if the FIFO is not full or FIFO interrupt is disabled + * -1 on fail + */ + int16_t getIntStatusFifoFull(void); + + /** + * Gets the interrupt status flag that indicates a finished temperature measurement + * + * @return 1 if a finished temperature measurement caused an interrupt; + * 0 if there is no finished temperature measurement or interrupts are disabled; + * -1 on fail. + */ + int16_t getIntStatusTempReady(void); + + /** + * Gets the interrupt status flag that indicates a finished pressure measurement + * + * @return 1 if a finished pressure measurement caused an interrupt; + * 0 if there is no finished pressure measurement or interrupts are disabled; + * -1 on fail. + */ + int16_t getIntStatusPrsReady(void); + + /** + * Function to fix a hardware problem on some devices + * You have this problem if you measure a temperature which is too high (e.g. 60°C when temperature is around 20°C) + * Call correctTemp() directly after begin() to fix this issue + */ + int16_t correctTemp(void); + +private: + //scaling factor table + static const int32_t scaling_facts[DPS__NUM_OF_SCAL_FACTS]; + + dps::Mode m_opMode; + + //flags + uint8_t m_initFail; + + uint8_t m_productID; + uint8_t m_revisionID; + + //settings + uint8_t m_tempMr; + uint8_t m_tempOsr; + uint8_t m_prsMr; + uint8_t m_prsOsr; + + // compensation coefficients for both dps310 and dps422 + int32_t m_c00; + int32_t m_c10; + int32_t m_c01; + int32_t m_c11; + int32_t m_c20; + int32_t m_c21; + int32_t m_c30; + + // last measured scaled temperature (necessary for pressure compensation) + float m_lastTempScal; + + //bus specific + uint8_t m_SpiI2c; //0=SPI, 1=I2C + + //used for I2C + TwoWire *m_i2cbus; + uint8_t m_slaveAddress; + + uint8_t m_tempSensor; + + //compensation coefficients + int32_t m_c0Half; + int32_t m_c1; + + /** + * Initializes the sensor. + * This function has to be called from begin() + * and requires a valid bus initialization. + */ + void init(void); + + /** + * reads the compensation coefficients from the sensor + * this is called once from init(), which is called from begin() + * + * @return 0 on success, -1 on fail + */ + int16_t readcoeffs(void); + + /** + * Sets the Operation Mode of the sensor + * + * @param opMode: the new OpMode as defined by dps::Mode; CMD_BOTH should not be used for DPS310 + * @return 0 on success, -1 on fail + */ + int16_t setOpMode(uint8_t opMode); + + /** + * Configures temperature measurement + * + * @param temp_mr: DPS__MEASUREMENT_RATE_1, DPS__MEASUREMENT_RATE_2,DPS__MEASUREMENT_RATE_4 ... DPS__MEASUREMENT_RATE_128 + * @param temp_osr: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * + * @return 0 normally or -1 on fail + */ + int16_t configTemp(uint8_t temp_mr, uint8_t temp_osr); + + /** + * Configures pressure measurement + * + * @param prs_mr: DPS__MEASUREMENT_RATE_1, DPS__MEASUREMENT_RATE_2,DPS__MEASUREMENT_RATE_4 ... DPS__MEASUREMENT_RATE_128 + * @param prs_osr: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * @return 0 normally or -1 on fail + */ + int16_t configPressure(uint8_t prs_mr, uint8_t prs_osr); + + int16_t flushFIFO(); + + float calcTemp(int32_t raw); + + float calcPressure(int32_t raw); + + int16_t enableFIFO(); + + int16_t disableFIFO(); + + /** + * calculates the time that the sensor needs for 2^mr measurements with an oversampling rate of 2^osr (see table "pressure measurement time (ms) versus oversampling rate") + * Note that the total measurement time for temperature and pressure must not be more than 1 second. + * Timing behavior of pressure and temperature sensors can be considered the same. + * + * @param mr: DPS__MEASUREMENT_RATE_1, DPS__MEASUREMENT_RATE_2,DPS__MEASUREMENT_RATE_4 ... DPS__MEASUREMENT_RATE_128 + * @param osr: DPS__OVERSAMPLING_RATE_1, DPS__OVERSAMPLING_RATE_2, DPS__OVERSAMPLING_RATE_4 ... DPS__OVERSAMPLING_RATE_128 + * @return time that the sensor needs for this measurement + */ + uint16_t calcBusyTime(uint16_t temp_rate, uint16_t temp_osr); + + /** + * reads the next raw value from the FIFO + * + * @param value: the raw pressure or temperature value read from the pressure register blocks, where the LSB of PRS_B0 marks wheather the value is a temperatur or a pressure. + * + * @return -1 on fail + * 0 if result is a temperature raw value + * 1 if result is a pressure raw value + */ + int16_t getFIFOvalue(int32_t *value); + + int16_t getContResults(float *tempBuffer, uint8_t &tempCount, float *prsBuffer, uint8_t &prsCount); + + /** + * Gets the results from continuous measurements and writes them to given arrays + * + * @param *tempBuffer: The start address of the buffer where the temperature results are written + * If this is NULL, no temperature results will be written out + * @param &tempCount: The size of the buffer for temperature results. + * When the function ends, it will contain the number of bytes written to the buffer. + * @param *prsBuffer: The start address of the buffer where the pressure results are written + * If this is NULL, no pressure results will be written out + * @param &prsCount: The size of the buffer for pressure results. + * When the function ends, it will contain the number of bytes written to the buffer. + * @param reg The FIFO empty register field; needed since this field is different for each sensor + * @return status code + */ + int16_t getContResults(float *tempBuffer, uint8_t &tempCount, float *prsBuffer, uint8_t &prsCount, RegMask_t reg); + + /** + * reads a byte from the sensor + * + * @param regAdress: Address that has to be read + * @return register content or -1 on fail + */ + int16_t readByte(uint8_t regAddress); + + /** + * reads a block from the sensor + * + * @param regAdress: Address that has to be read + * @param length: Length of data block + * @param buffer: Buffer where data will be stored + * @return number of bytes that have been read successfully, which might not always equal to length due to rx-Buffer overflow etc. + */ + int16_t readBlock(RegBlock_t regBlock, uint8_t *buffer); + + /** + * writes a byte to a given register of the sensor without checking + * + * @param regAdress: Address of the register that has to be updated + * @param data: Byte that will be written to the register + * @return 0 if byte was written successfully + * or -1 on fail + */ + int16_t writeByte(uint8_t regAddress, uint8_t data); + + /** + * writes a byte to a register of the sensor + * + * @param regAdress: Address of the register that has to be updated + * @param data: Byte that will be written to the register + * @param check: If this is true, register content will be read after writing + * to check if update was successful + * @return 0 if byte was written successfully + * or -1 on fail + */ + int16_t writeByte(uint8_t regAddress, uint8_t data, uint8_t check); + + /** + * updates a bit field of the sensor without checking + * + * @param regMask: Mask of the register that has to be updated + * @param data: BitValues that will be written to the register + * @return 0 if byte was written successfully + * or -1 on fail + */ + int16_t writeByteBitfield(uint8_t data, RegMask_t regMask); + + /** + * updates a bit field of the sensor + * + * regMask: Mask of the register that has to be updated + * data: BitValues that will be written to the register + * check: enables/disables check after writing; 0 disables check. + * if check fails, -1 will be returned + * @return 0 if byte was written successfully + * or -1 on fail + */ + int16_t writeByteBitfield(uint8_t data, uint8_t regAddress, uint8_t mask, uint8_t shift, uint8_t check); + + /** + * reads a bit field from the sensor + * regMask: Mask of the register that has to be updated + * data: BitValues that will be written to the register + * @return read and processed bits + * or -1 on fail + */ + int16_t readByteBitfield(RegMask_t regMask); + + /** + * @brief converts non-32-bit negative numbers to 32-bit negative numbers with 2's complement + * + * @param raw The raw number of less than 32 bits + * @param length The bit length + */ + void getTwosComplement(int32_t *raw, uint8_t length); + + /** + * @brief Get a raw result from a given register block + * + * @param raw The address where the raw value is to be written + * @param reg The register block to be read from + * @return status code + */ + int16_t getRawResult(int32_t *raw, RegBlock_t reg); +}; + +#endif \ No newline at end of file diff --git a/Node/Common/sensors/inc/DpsRegister.h b/Node/Common/sensors/inc/DpsRegister.h new file mode 100644 index 0000000..6cfb964 --- /dev/null +++ b/Node/Common/sensors/inc/DpsRegister.h @@ -0,0 +1,19 @@ +#ifndef DPSREGISTER_H_INCLUDED +#define DPSREGISTER_H_INCLUDED + +#include + +typedef struct +{ + uint8_t regAddress; + uint8_t mask; + uint8_t shift; +} RegMask_t; + +typedef struct +{ + uint8_t regAddress; + uint8_t length; +} RegBlock_t; + +#endif \ No newline at end of file diff --git a/Node/Common/sensors/inc/dps310_config.h b/Node/Common/sensors/inc/dps310_config.h new file mode 100644 index 0000000..e017fe9 --- /dev/null +++ b/Node/Common/sensors/inc/dps310_config.h @@ -0,0 +1,49 @@ +#ifndef DPS310_CONFIG_H_ +#define DPS310_CONFIG_H_ + +#define DPS310_NUM_OF_REGMASKS 16 + +enum Interrupt_source_310_e +{ + DPS310_NO_INTR = 0, + DPS310_PRS_INTR = 1, + DPS310_TEMP_INTR = 2, + DPS310_BOTH_INTR = 3, + DPS310_FIFO_FULL_INTR = 4, +}; + +namespace dps310 +{ + +enum Registers_e +{ + PROD_ID = 0, + REV_ID, + TEMP_SENSOR, // internal vs external + TEMP_SENSORREC, //temperature sensor recommendation + TEMP_SE, //temperature shift enable (if temp_osr>3) + PRS_SE, //pressure shift enable (if prs_osr>3) + FIFO_FL, //FIFO flush + FIFO_EMPTY, //FIFO empty + FIFO_FULL, //FIFO full + INT_HL, + INT_SEL, //interrupt select +}; + +const RegMask_t registers[DPS310_NUM_OF_REGMASKS] = { + {0x0D, 0x0F, 0}, // PROD_ID + {0x0D, 0xF0, 4}, // REV_ID + {0x07, 0x80, 7}, // TEMP_SENSOR + {0x28, 0x80, 7}, // TEMP_SENSORREC + {0x09, 0x08, 3}, // TEMP_SE + {0x09, 0x04, 2}, // PRS_SE + {0x0C, 0x80, 7}, // FIFO_FL + {0x0B, 0x01, 0}, // FIFO_EMPTY + {0x0B, 0x02, 1}, // FIFO_FULL + {0x09, 0x80, 7}, // INT_HL + {0x09, 0x70, 4}, // INT_SEL +}; + +const RegBlock_t coeffBlock = {0x10, 18}; +} // namespace dps310 +#endif \ No newline at end of file diff --git a/Node/Common/sensors/inc/dps_config.h b/Node/Common/sensors/inc/dps_config.h new file mode 100644 index 0000000..9df3992 --- /dev/null +++ b/Node/Common/sensors/inc/dps_config.h @@ -0,0 +1,130 @@ + +#ifndef DPS_CONSTS_H_ +#define DPS_CONSTS_H_ +#include "DpsRegister.h" + +/////////// DPS310 /////////// +#define DPS310__PROD_ID 0x00 +#define DPS310__SPI_WRITE_CMD 0x00U +#define DPS310__SPI_READ_CMD 0x80U +#define DPS310__SPI_RW_MASK 0x80U +#define DPS310__SPI_MAX_FREQ 1000000U + +#define DPS310__OSR_SE 3U + +// DPS310 has 10 milliseconds of spare time for each synchronous measurement / per second for asynchronous measurements +// this is for error prevention on friday-afternoon-products :D +// you can set it to 0 if you dare, but there is no warranty that it will still work +#define DPS310__BUSYTIME_FAILSAFE 10U +#define DPS310__MAX_BUSYTIME ((1000U - DPS310__BUSYTIME_FAILSAFE) * DPS__BUSYTIME_SCALING) + +#define DPS310__REG_ADR_SPI3W 0x09U +#define DPS310__REG_CONTENT_SPI3W 0x01U + +/////////// DPS422 /////////// +#define DPS422__PROD_ID 0x0A + +/////////// common /////////// + +// slave address same for 422 and 310 (to be proved for future sensors) +#define DPS__FIFO_SIZE 32 +#define DPS__STD_SLAVE_ADDRESS 0x77U +#define DPS__RESULT_BLOCK_LENGTH 3 +#define NUM_OF_COMMON_REGMASKS 16 + +#define DPS__MEASUREMENT_RATE_1 0 +#define DPS__MEASUREMENT_RATE_2 1 +#define DPS__MEASUREMENT_RATE_4 2 +#define DPS__MEASUREMENT_RATE_8 3 +#define DPS__MEASUREMENT_RATE_16 4 +#define DPS__MEASUREMENT_RATE_32 5 +#define DPS__MEASUREMENT_RATE_64 6 +#define DPS__MEASUREMENT_RATE_128 7 + +#define DPS__OVERSAMPLING_RATE_1 DPS__MEASUREMENT_RATE_1 +#define DPS__OVERSAMPLING_RATE_2 DPS__MEASUREMENT_RATE_2 +#define DPS__OVERSAMPLING_RATE_4 DPS__MEASUREMENT_RATE_4 +#define DPS__OVERSAMPLING_RATE_8 DPS__MEASUREMENT_RATE_8 +#define DPS__OVERSAMPLING_RATE_16 DPS__MEASUREMENT_RATE_16 +#define DPS__OVERSAMPLING_RATE_32 DPS__MEASUREMENT_RATE_32 +#define DPS__OVERSAMPLING_RATE_64 DPS__MEASUREMENT_RATE_64 +#define DPS__OVERSAMPLING_RATE_128 DPS__MEASUREMENT_RATE_128 + +//we use 0.1 ms units for time calculations, so 10 units are one millisecond +#define DPS__BUSYTIME_SCALING 10U + +#define DPS__NUM_OF_SCAL_FACTS 8 + +// status code +#define DPS__SUCCEEDED 0 +#define DPS__FAIL_UNKNOWN -1 +#define DPS__FAIL_INIT_FAILED -2 +#define DPS__FAIL_TOOBUSY -3 +#define DPS__FAIL_UNFINISHED -4 + +namespace dps +{ + +/** + * @brief Operating mode. + * + */ +enum Mode +{ + IDLE = 0x00, + CMD_PRS = 0x01, + CMD_TEMP = 0x02, + CMD_BOTH = 0x03, // only for DPS422 + CONT_PRS = 0x05, + CONT_TMP = 0x06, + CONT_BOTH = 0x07 +}; + +enum RegisterBlocks_e +{ + PRS = 0, // pressure value + TEMP, // temperature value +}; + +const RegBlock_t registerBlocks[2] = { + {0x00, 3}, + {0x03, 3}, +}; + +/** + * @brief registers for configuration and flags; these are the same for both 310 and 422, might need to be adapted for future sensors + * + */ +enum Config_Registers_e +{ + TEMP_MR = 0, // temperature measure rate + TEMP_OSR, // temperature measurement resolution + PRS_MR, // pressure measure rate + PRS_OSR, // pressure measurement resolution + MSR_CTRL, // measurement control + FIFO_EN, + + TEMP_RDY, + PRS_RDY, + INT_FLAG_FIFO, + INT_FLAG_TEMP, + INT_FLAG_PRS, +}; + +const RegMask_t config_registers[NUM_OF_COMMON_REGMASKS] = { + {0x07, 0x70, 4}, // TEMP_MR + {0x07, 0x07, 0}, // TEMP_OSR + {0x06, 0x70, 4}, // PRS_MR + {0x06, 0x07, 0}, // PRS_OSR + {0x08, 0x07, 0}, // MSR_CTRL + {0x09, 0x02, 1}, // FIFO_EN + + {0x08, 0x20, 5}, // TEMP_RDY + {0x08, 0x10, 4}, // PRS_RDY + {0x0A, 0x04, 2}, // INT_FLAG_FIFO + {0x0A, 0x02, 1}, // INT_FLAG_TEMP + {0x0A, 0x01, 0}, // INT_FLAG_PRS +}; + +} // namespace dps +#endif /* DPS_CONSTS_H_ */ diff --git a/Node/Common/sensors/inc/file.h b/Node/Common/sensors/inc/file.h deleted file mode 100644 index fefa00a..0000000 --- a/Node/Common/sensors/inc/file.h +++ /dev/null @@ -1 +0,0 @@ -// This file is intentionally left blank \ No newline at end of file diff --git a/Node/Common/sensors/src/DPS310.cpp b/Node/Common/sensors/src/DPS310.cpp new file mode 100644 index 0000000..af077a7 --- /dev/null +++ b/Node/Common/sensors/src/DPS310.cpp @@ -0,0 +1,763 @@ +#include "Dps310.h" +#include + +using namespace dps; +using namespace dps310; + +const int32_t Dps310::scaling_facts[DPS__NUM_OF_SCAL_FACTS] = {524288, 1572864, 3670016, 7864320, 253952, 516096, 1040384, 2088960}; + +Dps310::Dps310(void) +{ + //assume that initialization has failed before it has been done + m_initFail = 1U; +} + +Dps310::~Dps310(void) +{ + end(); +} + +void Dps310::end(void) +{ + standby(); +} + +uint8_t Dps310::getProductId(void) +{ + return m_productID; +} + +uint8_t Dps310::getRevisionId(void) +{ + return m_revisionID; +} + +int16_t Dps310::getContResults(float *tempBuffer, + uint8_t &tempCount, + float *prsBuffer, + uint8_t &prsCount, + RegMask_t fifo_empty_reg) +{ + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in background mode + if (!(m_opMode & 0x04)) + { + return DPS__FAIL_TOOBUSY; + } + + if (!tempBuffer || !prsBuffer) + { + return DPS__FAIL_UNKNOWN; + } + tempCount = 0U; + prsCount = 0U; + + //while FIFO is not empty + while (readByteBitfield(fifo_empty_reg) == 0) + { + int32_t raw_result; + float result; + //read next result from FIFO + int16_t type = getFIFOvalue(&raw_result); + switch (type) + { + case 0: //temperature + if (tempCount < DPS__FIFO_SIZE) + { + result = calcTemp(raw_result); + tempBuffer[tempCount++] = result; + } + break; + case 1: //pressure + if (prsCount < DPS__FIFO_SIZE) + { + result = calcPressure(raw_result); + prsBuffer[prsCount++] = result; + } + break; + case -1: //read failed + break; + } + } + return DPS__SUCCEEDED; +} + +int16_t Dps310::getContResults(float *tempBuffer, + uint8_t &tempCount, + float *prsBuffer, + uint8_t &prsCount) +{ + return getContResults(tempBuffer, tempCount, prsBuffer, prsCount, registers[FIFO_EMPTY]); +} + +int16_t Dps310::getSingleResult(float &result) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + + //read finished bit for current opMode + int16_t rdy; + switch (m_opMode) + { + case CMD_TEMP: //temperature + rdy = readByteBitfield(config_registers[TEMP_RDY]); + break; + case CMD_PRS: //pressure + rdy = readByteBitfield(config_registers[PRS_RDY]); + break; + default: //DPS310 not in command mode + return DPS__FAIL_TOOBUSY; + } + //read new measurement result + switch (rdy) + { + case DPS__FAIL_UNKNOWN: //could not read ready flag + return DPS__FAIL_UNKNOWN; + case 0: //ready flag not set, measurement still in progress + return DPS__FAIL_UNFINISHED; + case 1: //measurement ready, expected case + Mode oldMode = m_opMode; + m_opMode = IDLE; //opcode was automatically reseted by DPS310 + int32_t raw_val; + switch (oldMode) + { + case CMD_TEMP: //temperature + getRawResult(&raw_val, registerBlocks[TEMP]); + result = calcTemp(raw_val); + return DPS__SUCCEEDED; // TODO + case CMD_PRS: //pressure + getRawResult(&raw_val, registerBlocks[PRS]); + result = calcPressure(raw_val); + return DPS__SUCCEEDED; // TODO + default: + return DPS__FAIL_UNKNOWN; //should already be filtered above + } + } + return DPS__FAIL_UNKNOWN; +} + +int16_t Dps310::measureTempOnce(float &result) +{ + return measureTempOnce(result, m_tempOsr); +} + +int16_t Dps310::measureTempOnce(float &result, uint8_t oversamplingRate) +{ + //Start measurement + int16_t ret = startMeasureTempOnce(oversamplingRate); + if (ret != DPS__SUCCEEDED) + { + return ret; + } + + //wait until measurement is finished + delay(calcBusyTime(0U, m_tempOsr) / DPS__BUSYTIME_SCALING); + delay(DPS310__BUSYTIME_FAILSAFE); + + ret = getSingleResult(result); + if (ret != DPS__SUCCEEDED) + { + standby(); + } + return ret; +} + +int16_t Dps310::startMeasureTempOnce(void) +{ + return startMeasureTempOnce(m_tempOsr); +} + +int16_t Dps310::startMeasureTempOnce(uint8_t oversamplingRate) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if (m_opMode != IDLE) + { + return DPS__FAIL_TOOBUSY; + } + + if (oversamplingRate != m_tempOsr) + { + //configuration of oversampling rate + if (configTemp(0U, oversamplingRate) != DPS__SUCCEEDED) + { + return DPS__FAIL_UNKNOWN; + } + } + + //set device to temperature measuring mode + return setOpMode(CMD_TEMP); +} + +int16_t Dps310::measurePressureOnce(float &result) +{ + return measurePressureOnce(result, m_prsOsr); +} + +int16_t Dps310::measurePressureOnce(float &result, uint8_t oversamplingRate) +{ + //start the measurement + int16_t ret = startMeasurePressureOnce(oversamplingRate); + if (ret != DPS__SUCCEEDED) + { + return ret; + } + + //wait until measurement is finished + delay(calcBusyTime(0U, m_prsOsr) / DPS__BUSYTIME_SCALING); + delay(DPS310__BUSYTIME_FAILSAFE); + + ret = getSingleResult(result); + if (ret != DPS__SUCCEEDED) + { + standby(); + } + return ret; +} + +int16_t Dps310::startMeasurePressureOnce(void) +{ + return startMeasurePressureOnce(m_prsOsr); +} + +int16_t Dps310::startMeasurePressureOnce(uint8_t oversamplingRate) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if (m_opMode != IDLE) + { + return DPS__FAIL_TOOBUSY; + } + //configuration of oversampling rate, lowest measure rate to avoid conflicts + if (oversamplingRate != m_prsOsr) + { + if (configPressure(0U, oversamplingRate)) + { + return DPS__FAIL_UNKNOWN; + } + } + //set device to pressure measuring mode + return setOpMode(CMD_PRS); +} + +int16_t Dps310::startMeasureTempCont(uint8_t measureRate, uint8_t oversamplingRate) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if (m_opMode != IDLE) + { + return DPS__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if (calcBusyTime(measureRate, oversamplingRate) >= DPS310__MAX_BUSYTIME) + { + return DPS__FAIL_UNFINISHED; + } + //update precision and measuring rate + if (configTemp(measureRate, oversamplingRate)) + { + return DPS__FAIL_UNKNOWN; + } + + if (enableFIFO()) + { + return DPS__FAIL_UNKNOWN; + } + //Start measuring in background mode + if (Dps310::setOpMode(CONT_TMP)) + { + return DPS__FAIL_UNKNOWN; + } + return DPS__SUCCEEDED; +} + +int16_t Dps310::startMeasurePressureCont(uint8_t measureRate, uint8_t oversamplingRate) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if (m_opMode != IDLE) + { + return DPS__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if (calcBusyTime(measureRate, oversamplingRate) >= DPS310__MAX_BUSYTIME) + { + return DPS__FAIL_UNFINISHED; + } + //update precision and measuring rate + if (configPressure(measureRate, oversamplingRate)) + return DPS__FAIL_UNKNOWN; + //enable result FIFO + if (enableFIFO()) + { + return DPS__FAIL_UNKNOWN; + } + //Start measuring in background mode + if (Dps310::setOpMode(CONT_PRS)) + { + return DPS__FAIL_UNKNOWN; + } + return DPS__SUCCEEDED; +} + +int16_t Dps310::startMeasureBothCont(uint8_t tempMr, + uint8_t tempOsr, + uint8_t prsMr, + uint8_t prsOsr) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //abort if device is not in idling mode + if (m_opMode != IDLE) + { + return DPS__FAIL_TOOBUSY; + } + //abort if speed and precision are too high + if (calcBusyTime(tempMr, tempOsr) + calcBusyTime(prsMr, prsOsr) >= DPS310__MAX_BUSYTIME) + { + return DPS__FAIL_UNFINISHED; + } + //update precision and measuring rate + if (configTemp(tempMr, tempOsr)) + { + return DPS__FAIL_UNKNOWN; + } + //update precision and measuring rate + if (configPressure(prsMr, prsOsr)) + return DPS__FAIL_UNKNOWN; + //enable result FIFO + if (enableFIFO()) + { + return DPS__FAIL_UNKNOWN; + } + //Start measuring in background mode + if (setOpMode(CONT_BOTH)) + { + return DPS__FAIL_UNKNOWN; + } + return DPS__SUCCEEDED; +} + +int16_t Dps310::standby(void) +{ + //abort if initialization failed + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + //set device to idling mode + int16_t ret = setOpMode(IDLE); + if (ret != DPS__SUCCEEDED) + { + return ret; + } + ret = disableFIFO(); + return ret; +} + +int16_t Dps310::correctTemp(void) +{ + if (m_initFail) + { + return DPS__FAIL_INIT_FAILED; + } + writeByte(0x0E, 0xA5); + writeByte(0x0F, 0x96); + writeByte(0x62, 0x02); + writeByte(0x0E, 0x00); + writeByte(0x0F, 0x00); + + //perform a first temperature measurement (again) + //the most recent temperature will be saved internally + //and used for compensation when calculating pressure + float trash; + measureTempOnce(trash); + + return DPS__SUCCEEDED; +} + +int16_t Dps310::getIntStatusFifoFull(void) +{ + return readByteBitfield(config_registers[INT_FLAG_FIFO]); +} + +int16_t Dps310::getIntStatusTempReady(void) +{ + return readByteBitfield(config_registers[INT_FLAG_TEMP]); +} + +int16_t Dps310::getIntStatusPrsReady(void) +{ + return readByteBitfield(config_registers[INT_FLAG_PRS]); +} + +//////// Declaration of private functions starts here //////// + +int16_t Dps310::setOpMode(uint8_t opMode) +{ + if (writeByteBitfield(opMode, config_registers[MSR_CTRL]) == -1) + { + return DPS__FAIL_UNKNOWN; + } + m_opMode = (Mode)opMode; + return DPS__SUCCEEDED; +} + +int16_t Dps310::configTemp(uint8_t tempMr, uint8_t tempOsr) +{ + tempMr &= 0x07; + tempOsr &= 0x07; + // two accesses to the same register; for readability + int16_t ret = writeByteBitfield(tempMr, config_registers[TEMP_MR]); + ret = writeByteBitfield(tempOsr, config_registers[TEMP_OSR]); + + //abort immediately on fail + if (ret != DPS__SUCCEEDED) + { + return DPS__FAIL_UNKNOWN; + } + m_tempMr = tempMr; + m_tempOsr = tempOsr; +} + +int16_t Dps310::configPressure(uint8_t prsMr, uint8_t prsOsr) +{ + prsMr &= 0x07; + prsOsr &= 0x07; + int16_t ret = writeByteBitfield(prsMr, config_registers[PRS_MR]); + ret = writeByteBitfield(prsOsr, config_registers[PRS_OSR]); + + //abort immediately on fail + if (ret != DPS__SUCCEEDED) + { + return DPS__FAIL_UNKNOWN; + } + m_prsMr = prsMr; + m_prsOsr = prsOsr; +} + +int16_t Dps310::enableFIFO() +{ + return writeByteBitfield(1U, config_registers[FIFO_EN]); +} + +int16_t Dps310::disableFIFO() +{ + int16_t ret = flushFIFO(); + ret = writeByteBitfield(0U, config_registers[FIFO_EN]); + return ret; +} + +uint16_t Dps310::calcBusyTime(uint16_t mr, uint16_t osr) +{ + //formula from datasheet (optimized) + return ((uint32_t)20U << mr) + ((uint32_t)16U << (osr + mr)); +} + +int16_t Dps310::getFIFOvalue(int32_t *value) +{ + uint8_t buffer[DPS__RESULT_BLOCK_LENGTH] = {0}; + + //abort on invalid argument or failed block reading + if (value == NULL || readBlock(registerBlocks[PRS], buffer) != DPS__RESULT_BLOCK_LENGTH) + return DPS__FAIL_UNKNOWN; + *value = (uint32_t)buffer[0] << 16 | (uint32_t)buffer[1] << 8 | (uint32_t)buffer[2]; + getTwosComplement(value, 24); + return buffer[2] & 0x01; +} + +int16_t Dps310::readByte(uint8_t regAddress) +{ + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regAddress); + m_i2cbus->endTransmission(false); + //request 1 byte from slave + if (m_i2cbus->requestFrom(m_slaveAddress, 1U, 1U) > 0) + { + return m_i2cbus->read(); //return this byte on success + } + else + { + return DPS__FAIL_UNKNOWN; //if 0 bytes were read successfully + } +} +void Dps310::begin(TwoWire &bus) +{ + begin(bus, DPS__STD_SLAVE_ADDRESS); +} + +void Dps310::begin(TwoWire &bus, uint8_t slaveAddress) +{ + //this flag will show if the initialization was successful + m_initFail = 0U; + + //Set I2C bus connection + m_SpiI2c = 1U; + m_i2cbus = &bus; + m_slaveAddress = slaveAddress; + + // Init bus + m_i2cbus->begin(); + + delay(50); //startup time of Dps310 + + init(); +} + +void Dps310::init(void) +{ + int16_t prodId = readByteBitfield(registers[PROD_ID]); + if (prodId < 0) + { + //Connected device is not a Dps310 + m_initFail = 1U; + return; + } + m_productID = prodId; + + int16_t revId = readByteBitfield(registers[REV_ID]); + if (revId < 0) + { + m_initFail = 1U; + return; + } + m_revisionID = revId; + + //find out which temperature sensor is calibrated with coefficients... + int16_t sensor = readByteBitfield(registers[TEMP_SENSORREC]); + if (sensor < 0) + { + m_initFail = 1U; + return; + } + + //...and use this sensor for temperature measurement + m_tempSensor = sensor; + if (writeByteBitfield((uint8_t)sensor, registers[TEMP_SENSOR]) < 0) + { + m_initFail = 1U; + return; + } + + //read coefficients + if (readcoeffs() < 0) + { + m_initFail = 1U; + return; + } + + //set to standby for further configuration + standby(); + + //set measurement precision and rate to standard values; + configTemp(DPS__MEASUREMENT_RATE_4, DPS__OVERSAMPLING_RATE_8); + configPressure(DPS__MEASUREMENT_RATE_4, DPS__OVERSAMPLING_RATE_8); + + //perform a first temperature measurement + //the most recent temperature will be saved internally + //and used for compensation when calculating pressure + float trash; + measureTempOnce(trash); + + //make sure the DPS310 is in standby after initialization + standby(); + + // Fix IC with a fuse bit problem, which lead to a wrong temperature + // Should not affect ICs without this problem + correctTemp(); +} + +int16_t Dps310::readcoeffs(void) +{ + // TODO: remove magic number + uint8_t buffer[18]; + //read COEF registers to buffer + int16_t ret = readBlock(coeffBlock, buffer); + + //compose coefficients from buffer content + m_c0Half = ((uint32_t)buffer[0] << 4) | (((uint32_t)buffer[1] >> 4) & 0x0F); + getTwosComplement(&m_c0Half, 12); + //c0 is only used as c0*0.5, so c0_half is calculated immediately + m_c0Half = m_c0Half / 2U; + + //now do the same thing for all other coefficients + m_c1 = (((uint32_t)buffer[1] & 0x0F) << 8) | (uint32_t)buffer[2]; + getTwosComplement(&m_c1, 12); + m_c00 = ((uint32_t)buffer[3] << 12) | ((uint32_t)buffer[4] << 4) | (((uint32_t)buffer[5] >> 4) & 0x0F); + getTwosComplement(&m_c00, 20); + m_c10 = (((uint32_t)buffer[5] & 0x0F) << 16) | ((uint32_t)buffer[6] << 8) | (uint32_t)buffer[7]; + getTwosComplement(&m_c10, 20); + + m_c01 = ((uint32_t)buffer[8] << 8) | (uint32_t)buffer[9]; + getTwosComplement(&m_c01, 16); + + m_c11 = ((uint32_t)buffer[10] << 8) | (uint32_t)buffer[11]; + getTwosComplement(&m_c11, 16); + m_c20 = ((uint32_t)buffer[12] << 8) | (uint32_t)buffer[13]; + getTwosComplement(&m_c20, 16); + m_c21 = ((uint32_t)buffer[14] << 8) | (uint32_t)buffer[15]; + getTwosComplement(&m_c21, 16); + m_c30 = ((uint32_t)buffer[16] << 8) | (uint32_t)buffer[17]; + getTwosComplement(&m_c30, 16); + return DPS__SUCCEEDED; +} + +int16_t Dps310::writeByte(uint8_t regAddress, uint8_t data) +{ + return writeByte(regAddress, data, 0U); +} + +int16_t Dps310::writeByte(uint8_t regAddress, uint8_t data, uint8_t check) +{ + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regAddress); //Write Register number to buffer + m_i2cbus->write(data); //Write data to buffer + if (m_i2cbus->endTransmission() != 0) //Send buffer content to slave + { + return DPS__FAIL_UNKNOWN; + } + else + { + if (check == 0) + return 0; //no checking + if (readByte(regAddress) == data) //check if desired by calling function + { + return DPS__SUCCEEDED; + } + else + { + return DPS__FAIL_UNKNOWN; + } + } +} + +float Dps310::calcTemp(int32_t raw) +{ + float temp = raw; + + //scale temperature according to scaling table and oversampling + temp /= scaling_facts[m_tempOsr]; + + //update last measured temperature + //it will be used for pressure compensation + m_lastTempScal = temp; + + //Calculate compensated temperature + temp = m_c0Half + m_c1 * temp; + + return temp; +} + +float Dps310::calcPressure(int32_t raw) +{ + float prs = raw; + + //scale pressure according to scaling table and oversampling + prs /= scaling_facts[m_prsOsr]; + + //Calculate compensated pressure + prs = m_c00 + prs * (m_c10 + prs * (m_c20 + prs * m_c30)) + m_lastTempScal * (m_c01 + prs * (m_c11 + prs * m_c21)); + + //return pressure + return prs; +} + +int16_t Dps310::flushFIFO() +{ + return writeByteBitfield(1U, registers[FIFO_FL]); +} + +int16_t Dps310::writeByteBitfield(uint8_t data, RegMask_t regMask) +{ + return writeByteBitfield(data, regMask.regAddress, regMask.mask, regMask.shift, 0U); +} + +int16_t Dps310::writeByteBitfield(uint8_t data, + uint8_t regAddress, + uint8_t mask, + uint8_t shift, + uint8_t check) +{ + int16_t old = readByte(regAddress); + if (old < 0) + { + //fail while reading + return old; + } + return writeByte(regAddress, ((uint8_t)old & ~mask) | ((data << shift) & mask), check); +} + +int16_t Dps310::readByteBitfield(RegMask_t regMask) +{ + int16_t ret = readByte(regMask.regAddress); + if (ret < 0) + { + return ret; + } + return (((uint8_t)ret) & regMask.mask) >> regMask.shift; +} + +int16_t Dps310::readBlock(RegBlock_t regBlock, uint8_t *buffer) +{ + //do not read if there is no buffer + if (buffer == NULL) + { + return 0; //0 bytes read successfully + } + + m_i2cbus->beginTransmission(m_slaveAddress); + m_i2cbus->write(regBlock.regAddress); + m_i2cbus->endTransmission(false); + //request length bytes from slave + int16_t ret = m_i2cbus->requestFrom(m_slaveAddress, regBlock.length, 1U); + //read all received bytes to buffer + for (int16_t count = 0; count < ret; count++) + { + buffer[count] = m_i2cbus->read(); + } + return ret; +} + +void Dps310::getTwosComplement(int32_t *raw, uint8_t length) +{ + if (*raw & ((uint32_t)1 << (length - 1))) + { + *raw -= (uint32_t)1 << length; + } +} + +int16_t Dps310::getRawResult(int32_t *raw, RegBlock_t reg) +{ + uint8_t buffer[DPS__RESULT_BLOCK_LENGTH] = {0}; + if (readBlock(reg, buffer) != DPS__RESULT_BLOCK_LENGTH) + return DPS__FAIL_UNKNOWN; + + *raw = (uint32_t)buffer[0] << 16 | (uint32_t)buffer[1] << 8 | (uint32_t)buffer[2]; + getTwosComplement(raw, 24); + return DPS__SUCCEEDED; +} diff --git a/Node/Common/sensors/src/file.cpp b/Node/Common/sensors/src/file.cpp deleted file mode 100644 index fefa00a..0000000 --- a/Node/Common/sensors/src/file.cpp +++ /dev/null @@ -1 +0,0 @@ -// This file is intentionally left blank \ No newline at end of file diff --git a/Node/WindTunnel/main.cpp b/Node/WindTunnel/main.cpp index 572e448..757129b 100644 --- a/Node/WindTunnel/main.cpp +++ b/Node/WindTunnel/main.cpp @@ -1,14 +1,77 @@ #include +#include "DPS310.h" +#include "Wire.h" + +Dps310 pvtSensor; void setup() { - pinMode(LED_BUILTIN, OUTPUT); + pinMode(A0, INPUT); //Distance + pinMode(A1, INPUT); // Distance + pinMode(A2, INPUT); // Distance + pinMode(A3, INPUT); // Distance + pinMode(A11, INPUT); // Diff pressure + pinMode(A12, INPUT); // Diff pressure + pinMode(A13, INPUT); // Strain gauge + pinMode(A7, INPUT); // Strain gauges + pinMode(A8, INPUT); // Accel x + pinMode(A9, INPUT); // Accel y + pinMode(A10, INPUT); // Accel z + + pvtSensor.begin(Wire); + Serial.begin(9600); + Wire.begin(); } void loop() { - digitalWrite(LED_BUILTIN, HIGH); - delay(1000); - digitalWrite(LED_BUILTIN, LOW); - delay(1000); + int distance1, distance2, distance3, distance4 = 0; // distance sensors + int diff1, diff2 = 0; // Diff pressure sensors + int amp; // Strain gauge + int accelX, accelY, accelZ = 0; // Accel + float pressure, temperature; + + pvtSensor.measureTempOnce(temperature); + pvtSensor.measurePressureOnce(pressure); + distance1 = analogRead(A0); + distance2 = analogRead(A1); + distance3 = analogRead(A2); + distance4 = analogRead(A3); + diff1 = analogRead(A11); + diff2 = analogRead(A12); + //Strain guage has a reference pin, so this is subtracted from the output pin to get the true value + amp = analogRead(A13) - analogRead(A7); + accelX = analogRead(A8); + accelY = analogRead(A9); + accelZ = analogRead(A10); + + Serial.print("Pressure: "); + Serial.println(pressure); + + Serial.print("Temperature: "); + Serial.println(temperature); + + Serial.print("Distance sensors: 1: "); + Serial.print(distance1); + Serial.print(" 2: "); + Serial.print(distance2); + Serial.print(" 3: "); + Serial.print(distance3); + Serial.print(" 4: "); + Serial.println(distance4); + + Serial.print("Differential pressure sensor 1: "); + Serial.print(diff1); + Serial.print(" 2: "); + Serial.println(diff2); + + Serial.print("Strain gauge: "); + Serial.println(amp); + + Serial.print("Acceleration x: "); + Serial.print(accelX); + Serial.print(" y: "); + Serial.print(accelY); + Serial.print(" z: "); + Serial.print(accelZ); } diff --git a/Node/platformio.ini b/Node/platformio.ini index 1c3ff31..37f865d 100644 --- a/Node/platformio.ini +++ b/Node/platformio.ini @@ -16,9 +16,11 @@ include_dir = Common platform = atmelsam board = sodaq_autonomo framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./DTS/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -27,9 +29,11 @@ build_flags = platform = atmelavr board = uno framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./DTS/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -38,9 +42,11 @@ build_flags = platform = atmelsam board = sodaq_autonomo framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./Vacuum/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -49,9 +55,11 @@ build_flags = platform = atmelavr board = uno framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./Vacuum/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -60,9 +68,11 @@ build_flags = platform = atmelsam board = sodaq_autonomo framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./WindTunnel/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -71,9 +81,24 @@ build_flags = platform = atmelavr board = uno framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = + -I./WindTunnel/ + -I./Common/drivers/inc + -I./Common/sensors/inc + +[env:WindTunnel-Mega] +platform = atmelavr +board = ATmega2560 +framework = arduino +src_filter = + + + + + + +build_flags = -I./WindTunnel/ -I./Common/drivers/inc -I./Common/sensors/inc @@ -82,9 +107,11 @@ build_flags = platform = atmelavr board = uno framework = arduino -src_filter = +src_filter = + -build_flags = + + + + +build_flags = -I./Examples/ -I./Common/drivers/inc -I./Common/sensors/inc