commit 42528b07aaf24c7f07b06d1f8b5419af9d25ee99 Author: ladyada Date: Tue Aug 26 16:52:29 2025 -0400 Initial commit - Complete Adafruit SPA06_003 Arduino library Features: - Fixed coefficient parsing with correct bit field extraction - Temperature and pressure compensation algorithms - Pressure readings in hPa (hectopascals) - Adafruit_Sensor unified interface compatibility - Complete register access and configuration API - FIFO support and interrupt handling 🤖 Generated with Claude Code Co-Authored-By: Claude diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..ee67472 --- /dev/null +++ b/.clang-format @@ -0,0 +1,118 @@ +--- +Language: Cpp +BasedOnStyle: Google +AccessModifierOffset: -1 +AlignAfterOpenBracket: Align +AlignConsecutiveAssignments: false +AlignConsecutiveDeclarations: false +AlignEscapedNewlines: Left +AlignOperands: true +AlignTrailingComments: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: false +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: false +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: true +AlwaysBreakTemplateDeclarations: Yes +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterClass: false + AfterControlStatement: false + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: None +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: true +DisableFormat: false +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + - Regex: '^<.*\.h>' + Priority: 1 + - Regex: '^<.*' + Priority: 2 + - Regex: '.*' + Priority: 3 +IncludeIsMainRegex: '([-_](test|unittest))?$' +IndentCaseLabels: true +IndentPPDirectives: None +IndentWidth: 2 +IndentWrappedFunctionNames: false +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Never +ObjCBlockIndentWidth: 2 +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 1 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 200 +PointerAlignment: Left +ReflowComments: true +SortIncludes: true +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInParentheses: false +SpacesInSquareBrackets: false +Standard: Auto +TabWidth: 8 +UseTab: Never \ No newline at end of file diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..a4501f5 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,16 @@ +{ + "permissions": { + "allow": [ + "Bash(arduino-cli lib examples:*)", + "Bash(arduino-cli compile:*)", + "Bash(arduino-cli upload:*)", + "Bash(arduino-cli board:*)", + "Bash(git init:*)", + "WebFetch(domain:raw.githubusercontent.com)", + "Bash(\"/c/Program Files/TortoiseGit/bin/puttygen\" \"C:\\Users\\ladyada\\Dropbox\\shared\\github.ppk\" -O private-openssh -o ~/.ssh/id_rsa)", + "Bash(python3:*)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml new file mode 100644 index 0000000..cb42831 --- /dev/null +++ b/.github/workflows/githubci.yml @@ -0,0 +1,32 @@ +name: Arduino Library CI + +on: [pull_request, push, repository_dispatch] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v4 + with: + python-version: '3.x' + - uses: actions/checkout@v4 + with: + repository: adafruit/ci-arduino + path: ci + + - name: pre-install + run: bash ci/actions_install.sh + + - name: clang + run: python3 ci/run-clang-format.py -e "ci/*" -e "bin/*" -r . + + - name: test platforms + run: python3 ci/build_platform.py main_platforms + + - name: doxy + env: + GH_REPO_TOKEN: ${{ secrets.GH_REPO_TOKEN }} + PRETTYNAME : "Adafruit SPA06_003 Arduino Library" + run: bash ci/doxy_gen_and_deploy.sh \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..fccb94f --- /dev/null +++ b/.gitignore @@ -0,0 +1,57 @@ +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Doxygen documentation +doc/ + +# Arduino build files +build/ + +# IDE files +.vscode/ +*.swp +*.swo +*~ + +# OS generated files +.DS_Store +.DS_Store? +._* +.Spotlight-V100 +.Trashes +ehthumbs.db +Thumbs.db + +# Datasheet files +*.pdf +*.txt +output.txt + +# Claude Code development files +CLAUDE.md \ No newline at end of file diff --git a/Adafruit_SPA06_003.cpp b/Adafruit_SPA06_003.cpp new file mode 100644 index 0000000..fd7dcee --- /dev/null +++ b/Adafruit_SPA06_003.cpp @@ -0,0 +1,753 @@ +/*! + * @file Adafruit_SPA06_003.cpp + * + * @mainpage Adafruit SPA06_003 Digital Pressure Sensor + * + * @section intro_sec Introduction + * + * This is the documentation for Adafruit's SPA06_003 driver for the + * Arduino platform. It is designed specifically to work with the + * Adafruit SPA06_003 breakout: https://www.adafruit.com/products/xxxx + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * @section author Author + * + * Written by Limor 'ladyada' Fried with assistance from Claude Code + * for Adafruit Industries. + * + * @section license License + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#include "Adafruit_SPA06_003.h" + +/*! + * @brief Instantiates a new SPA06_003 class + */ +Adafruit_SPA06_003::Adafruit_SPA06_003() {} + +/*! + * @brief Cleans up the SPA06_003 + */ +Adafruit_SPA06_003::~Adafruit_SPA06_003() { + if (i2c_dev) { + delete i2c_dev; + } + if (temp_sensor) { + delete temp_sensor; + } + if (pressure_sensor) { + delete pressure_sensor; + } +} + +/*! + * @brief Sets up the hardware and initializes I2C + * @param i2c_addr + * The I2C address to be used. + * @param wire + * The Wire object to be used for I2C connections. + * @return True if initialization was successful, otherwise false. + */ +bool Adafruit_SPA06_003::begin(uint8_t i2c_addr, TwoWire *wire) { + if (i2c_dev) { + delete i2c_dev; + } + + i2c_dev = new Adafruit_I2CDevice(i2c_addr, wire); + + if (!i2c_dev->begin()) { + return false; + } + + Adafruit_BusIO_Register chip_id = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_ID, 1); + + if (chip_id.read() != 0x11) { + return false; + } + + // Perform soft reset + if (!reset()) { + return false; + } + delay(10); + + // Wait for coefficients and sensor to be ready + while (!isCoeffReady() || !isSensorReady()) { + delay(10); + } + + // Read calibration coefficients + if (!readCoefficients()) { + return false; + } + + // Set measurement mode to continuous both + setMeasurementMode(SPA06_003_MEAS_CONTINUOUS_BOTH); + + return true; +} + +/*! + * @brief Reads the 24-bit raw pressure data from registers + * @return 24-bit pressure data as uint32_t + */ +uint32_t Adafruit_SPA06_003::getPressureData() { + Adafruit_BusIO_Register psr_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_PSR_B2, 3, MSBFIRST); + + uint32_t psr_data = psr_reg.read(); + + if (psr_data & 0x800000) { + psr_data |= 0xFF000000; + } + + return psr_data; +} + +/*! + * @brief Reads the 24-bit raw temperature data from registers + * @return 24-bit temperature data as uint32_t + */ +uint32_t Adafruit_SPA06_003::getTemperatureData() { + Adafruit_BusIO_Register tmp_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_TMP_B2, 3, MSBFIRST); + + uint32_t tmp_data = tmp_reg.read(); + + if (tmp_data & 0x800000) { + tmp_data |= 0xFF000000; + } + + return tmp_data; +} + +/*! + * @brief Gets the pressure measurement rate + * @return Current pressure measurement rate setting + */ +spa06_003_rate_t Adafruit_SPA06_003::getPressureMeasureRate() { + Adafruit_BusIO_Register prs_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_PRS_CFG, 1); + Adafruit_BusIO_RegisterBits pm_rate_bits = + Adafruit_BusIO_RegisterBits(&prs_cfg_reg, 4, 4); + + return (spa06_003_rate_t)pm_rate_bits.read(); +} + +/*! + * @brief Sets the pressure measurement rate + * @param rate The pressure measurement rate to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setPressureMeasureRate(spa06_003_rate_t rate) { + Adafruit_BusIO_Register prs_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_PRS_CFG, 1); + Adafruit_BusIO_RegisterBits pm_rate_bits = + Adafruit_BusIO_RegisterBits(&prs_cfg_reg, 4, 4); + + return pm_rate_bits.write(rate); +} + +/*! + * @brief Gets the temperature measurement rate + * @return Current temperature measurement rate setting + */ +spa06_003_rate_t Adafruit_SPA06_003::getTemperatureMeasureRate() { + Adafruit_BusIO_Register tmp_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_TMP_CFG, 1); + Adafruit_BusIO_RegisterBits tmp_rate_bits = + Adafruit_BusIO_RegisterBits(&tmp_cfg_reg, 4, 4); + + return (spa06_003_rate_t)tmp_rate_bits.read(); +} + +/*! + * @brief Sets the temperature measurement rate + * @param rate The temperature measurement rate to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setTemperatureMeasureRate(spa06_003_rate_t rate) { + Adafruit_BusIO_Register tmp_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_TMP_CFG, 1); + Adafruit_BusIO_RegisterBits tmp_rate_bits = + Adafruit_BusIO_RegisterBits(&tmp_cfg_reg, 4, 4); + + return tmp_rate_bits.write(rate); +} + +/*! + * @brief Gets the pressure oversampling rate + * @return Current pressure oversampling rate setting + */ +spa06_003_oversample_t Adafruit_SPA06_003::getPressureOversampling() { + Adafruit_BusIO_Register prs_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_PRS_CFG, 1); + Adafruit_BusIO_RegisterBits pm_prc_bits = + Adafruit_BusIO_RegisterBits(&prs_cfg_reg, 4, 0); + + return (spa06_003_oversample_t)pm_prc_bits.read(); +} + +/*! + * @brief Sets the pressure oversampling rate + * @param prc The pressure oversampling rate to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setPressureOversampling(spa06_003_oversample_t prc) { + Adafruit_BusIO_Register prs_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_PRS_CFG, 1); + Adafruit_BusIO_RegisterBits pm_prc_bits = + Adafruit_BusIO_RegisterBits(&prs_cfg_reg, 4, 0); + + if (!pm_prc_bits.write(prc)) { + return false; + } + + return setPresShift(prc > SPA06_003_OVERSAMPLE_8); +} + +/*! + * @brief Gets the temperature oversampling rate + * @return Current temperature oversampling rate setting + */ +spa06_003_oversample_t Adafruit_SPA06_003::getTemperatureOversampling() { + Adafruit_BusIO_Register tmp_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_TMP_CFG, 1); + Adafruit_BusIO_RegisterBits tmp_prc_bits = + Adafruit_BusIO_RegisterBits(&tmp_cfg_reg, 4, 0); + + return (spa06_003_oversample_t)tmp_prc_bits.read(); +} + +/*! + * @brief Sets the temperature oversampling rate + * @param prc The temperature oversampling rate to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setTemperatureOversampling( + spa06_003_oversample_t prc) { + Adafruit_BusIO_Register tmp_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_TMP_CFG, 1); + Adafruit_BusIO_RegisterBits tmp_prc_bits = + Adafruit_BusIO_RegisterBits(&tmp_cfg_reg, 4, 0); + + if (!tmp_prc_bits.write(prc)) { + return false; + } + + return setTempShift(prc > SPA06_003_OVERSAMPLE_8); +} + +/*! + * @brief Checks if calibration coefficients are ready + * @return True if coefficients are ready, false otherwise + */ +bool Adafruit_SPA06_003::isCoeffReady() { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits coef_rdy_bit = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 1, 7); + + return coef_rdy_bit.read(); +} + +/*! + * @brief Checks if sensor is ready + * @return True if sensor is ready, false otherwise + */ +bool Adafruit_SPA06_003::isSensorReady() { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits sensor_rdy_bit = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 1, 6); + + return sensor_rdy_bit.read(); +} + +/*! + * @brief Checks if temperature data is ready + * @return True if temperature data is ready, false otherwise + */ +bool Adafruit_SPA06_003::isTempDataReady() { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits tmp_rdy_bit = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 1, 5); + + return tmp_rdy_bit.read(); +} + +/*! + * @brief Checks if pressure data is ready + * @return True if pressure data is ready, false otherwise + */ +bool Adafruit_SPA06_003::isPresDataReady() { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits prs_rdy_bit = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 1, 4); + + return prs_rdy_bit.read(); +} + +/*! + * @brief Gets the current measurement mode + * @return Current measurement mode setting + */ +spa06_003_meas_mode_t Adafruit_SPA06_003::getMeasurementMode() { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits meas_ctrl_bits = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 3, 0); + + return (spa06_003_meas_mode_t)meas_ctrl_bits.read(); +} + +/*! + * @brief Sets the measurement mode + * @param mode The measurement mode to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setMeasurementMode(spa06_003_meas_mode_t mode) { + Adafruit_BusIO_Register meas_cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_MEAS_CFG, 1); + Adafruit_BusIO_RegisterBits meas_ctrl_bits = + Adafruit_BusIO_RegisterBits(&meas_cfg_reg, 3, 0); + + return meas_ctrl_bits.write(mode); +} + +/*! + * @brief Sets the interrupt polarity + * @param polarity The interrupt polarity to set + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setInterruptPolarity( + spa06_003_int_polarity_t polarity) { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + Adafruit_BusIO_RegisterBits int_hl_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 7); + + return int_hl_bit.write(polarity); +} + +/*! + * @brief Sets the interrupt sources + * @param fifo Enable FIFO interrupt + * @param temp_ready Enable temperature ready interrupt + * @param pres_ready Enable pressure ready interrupt + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setInterruptSource(bool fifo, bool temp_ready, + bool pres_ready) { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + + Adafruit_BusIO_RegisterBits int_fifo_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 6); + Adafruit_BusIO_RegisterBits int_tmp_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 5); + Adafruit_BusIO_RegisterBits int_prs_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 4); + + return int_fifo_bit.write(fifo) && int_tmp_bit.write(temp_ready) && + int_prs_bit.write(pres_ready); +} + +/*! + * @brief Sets the temperature result bit shift + * @param enable True to enable bit shift, false to disable + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setTempShift(bool enable) { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + Adafruit_BusIO_RegisterBits t_shift_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 3); + + return t_shift_bit.write(enable); +} + +/*! + * @brief Sets the pressure result bit shift + * @param enable True to enable bit shift, false to disable + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::setPresShift(bool enable) { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + Adafruit_BusIO_RegisterBits p_shift_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 2); + + return p_shift_bit.write(enable); +} + +/*! + * @brief Enables or disables FIFO + * @param enable True to enable FIFO, false to disable + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::enableFIFO(bool enable) { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + Adafruit_BusIO_RegisterBits fifo_en_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 1); + + return fifo_en_bit.write(enable); +} + +/*! + * @brief Checks if FIFO is enabled + * @return True if FIFO is enabled, false otherwise + */ +bool Adafruit_SPA06_003::isFIFOEnabled() { + Adafruit_BusIO_Register cfg_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_CFG_REG, 1); + Adafruit_BusIO_RegisterBits fifo_en_bit = + Adafruit_BusIO_RegisterBits(&cfg_reg, 1, 1); + + return fifo_en_bit.read(); +} + +/*! + * @brief Checks if FIFO is empty + * @return True if FIFO is empty, false otherwise + */ +bool Adafruit_SPA06_003::isFIFOEmpty() { + Adafruit_BusIO_Register fifo_sts_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_FIFO_STS, 1); + Adafruit_BusIO_RegisterBits fifo_empty_bit = + Adafruit_BusIO_RegisterBits(&fifo_sts_reg, 1, 0); + + return fifo_empty_bit.read(); +} + +/*! + * @brief Checks if FIFO is full + * @return True if FIFO is full, false otherwise + */ +bool Adafruit_SPA06_003::isFIFOFull() { + Adafruit_BusIO_Register fifo_sts_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_FIFO_STS, 1); + Adafruit_BusIO_RegisterBits fifo_full_bit = + Adafruit_BusIO_RegisterBits(&fifo_sts_reg, 1, 1); + + return fifo_full_bit.read(); +} + +/*! + * @brief Gets the interrupt status flags + * @return Interrupt status register value with flags + */ +uint8_t Adafruit_SPA06_003::getStatusFlags() { + Adafruit_BusIO_Register int_sts_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_INT_STS, 1); + + return int_sts_reg.read() & 0x07; +} + +/*! + * @brief Flushes the FIFO buffer + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::flushFIFO() { + Adafruit_BusIO_Register reset_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_RESET, 1); + Adafruit_BusIO_RegisterBits fifo_flush_bit = + Adafruit_BusIO_RegisterBits(&reset_reg, 1, 7); + + return fifo_flush_bit.write(1); +} + +/*! + * @brief Performs a soft reset of the sensor + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::reset() { + Adafruit_BusIO_Register reset_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_RESET, 1); + Adafruit_BusIO_RegisterBits soft_rst_bits = + Adafruit_BusIO_RegisterBits(&reset_reg, 4, 0); + + return soft_rst_bits.write(0x09); +} + +/*! + * @brief Reads calibration coefficients from sensor registers + * @return True if successful, false otherwise + */ +bool Adafruit_SPA06_003::readCoefficients() { + if (!isCoeffReady()) { + return false; + } + + // Read all coefficient data (21 bytes from 0x10 to 0x24) + uint8_t coef_data[21]; + Adafruit_BusIO_Register coef_reg = + Adafruit_BusIO_Register(i2c_dev, SPA06_003_REG_COEF, 21); + + if (!coef_reg.read(coef_data, 21)) { + return false; + } + + // Parse coefficients according to datasheet table + // c0: 12-bit (0x10-0x11) + c0 = (int16_t)((coef_data[0] << 4) | (coef_data[1] >> 4)); + if (c0 & 0x800) { + c0 |= 0xF000; // Sign extend + } + + // c1: 12-bit (0x11-0x12) + c1 = (int16_t)(((coef_data[1] & 0x0F) << 8) | coef_data[2]); + if (c1 & 0x800) { + c1 |= 0xF000; // Sign extend + } + + // c00: 20-bit (0x13-0x15) + uint32_t c00_temp = (((uint32_t)coef_data[3] << 12) & 0xFF000) | + (((uint16_t)coef_data[4] << 4) & 0x00FF0) | + ((coef_data[5] >> 4) & 0x0000F); + if (c00_temp & 0x80000) { + c00 = (int32_t)(c00_temp | 0xFFF00000); // Sign extend + } else { + c00 = (int32_t)c00_temp; + } + + // c10: 20-bit (0x15-0x17) + uint32_t c10_temp = (((uint32_t)coef_data[5] << 16) & 0xF0000) | + (((uint16_t)coef_data[6] << 8) & 0x0FF00) | coef_data[7]; + if (c10_temp & 0x80000) { + c10 = (int32_t)(c10_temp | 0xFFF00000); // Sign extend + } else { + c10 = (int32_t)c10_temp; + } + + // c01: 16-bit (0x18-0x19) + c01 = (int16_t)((coef_data[8] << 8) | coef_data[9]); + + // c11: 16-bit (0x1A-0x1B) + c11 = (int16_t)((coef_data[10] << 8) | coef_data[11]); + + // c20: 16-bit (0x1C-0x1D) + c20 = (int16_t)((coef_data[12] << 8) | coef_data[13]); + + // c21: 16-bit (0x1E-0x1F) + c21 = (int16_t)((coef_data[14] << 8) | coef_data[15]); + + // c30: 16-bit (0x20-0x21) + c30 = (int16_t)((coef_data[16] << 8) | coef_data[17]); + + // c31: 12-bit (0x22 + 0x23 bits 7:4) + c31 = (int16_t)(((coef_data[18] << 4) & 0xFF0) | + ((coef_data[19] >> 4) & 0x00F)); + if (c31 & 0x800) { + c31 |= 0xF000; // Sign extend + } + + // c40: 12-bit (0x23 bits 3:0 + 0x24) + c40 = (int16_t)(((coef_data[19] & 0x0F) << 8) | coef_data[20]); + if (c40 & 0x800) { + c40 |= 0xF000; // Sign extend + } + + return true; +} + +/*! + * @brief Gets scaling factor based on oversampling setting + * @param oversample The oversampling rate + * @return Scaling factor for compensation calculation + */ +float Adafruit_SPA06_003::getScalingFactor(spa06_003_oversample_t oversample) { + switch (oversample) { + case SPA06_003_OVERSAMPLE_1: + return 524288; // Single + case SPA06_003_OVERSAMPLE_2: + return 1572864; // 2x + case SPA06_003_OVERSAMPLE_4: + return 3670016; // 4x + case SPA06_003_OVERSAMPLE_8: + return 7864320; // 8x + case SPA06_003_OVERSAMPLE_16: + return 253952; // 16x + case SPA06_003_OVERSAMPLE_32: + return 516096; // 32x + case SPA06_003_OVERSAMPLE_64: + return 1040384; // 64x + case SPA06_003_OVERSAMPLE_128: + return 2088960; // 128x + default: + return 524288; // Default to single + } +} + +/*! + * @brief Reads compensated temperature value in Celsius + * @return Temperature in degrees Celsius + */ +float Adafruit_SPA06_003::readTemperature() { + // Get current temperature oversampling setting and scale factor + spa06_003_oversample_t oversample = getTemperatureOversampling(); + float kT = getScalingFactor(oversample); + + // Read raw temperature data (24-bit 2's complement) + uint32_t temp_raw = getTemperatureData(); + + // Convert to signed 32-bit + int32_t temp_raw_signed = (int32_t)temp_raw; + + // Calculate scaled measurement result + float temp_raw_sc = (float)temp_raw_signed / kT; + + // Calculate compensated temperature: Tcomp = c0*0.5 + c1*Traw_sc + float temp_comp = (float)c0 * 0.5f + (float)c1 * temp_raw_sc; + + return temp_comp; +} + +/*! + * @brief Reads compensated pressure value in hectopascals + * @return Pressure in hectopascals (hPa) + */ +float Adafruit_SPA06_003::readPressure() { + // Get scaling factors based on current oversampling settings + float kP = getScalingFactor(getPressureOversampling()); + float kT = getScalingFactor(getTemperatureOversampling()); + + // Read raw pressure and temperature data (24-bit 2's complement) + uint32_t pres_raw = getPressureData(); + uint32_t temp_raw = getTemperatureData(); + + // Convert to signed 32-bit + int32_t pres_raw_signed = (int32_t)pres_raw; + int32_t temp_raw_signed = (int32_t)temp_raw; + + // Calculate scaled measurement results + float pres_raw_sc = (float)pres_raw_signed / kP; + float temp_raw_sc = (float)temp_raw_signed / kT; + + // Calculate powers of Praw_sc for the compensation formula + float pres_raw_sc_2 = pres_raw_sc * pres_raw_sc; + float pres_raw_sc_3 = pres_raw_sc_2 * pres_raw_sc; + float pres_raw_sc_4 = pres_raw_sc_3 * pres_raw_sc; + + // Calculate compensated pressure using the formula: + // Pcomp = c00 + c10*Praw_sc + c20*Praw_sc^2 + c30*Praw_sc^3 + c40*Praw_sc^4 + + // Traw_sc*(c01 + c11*Praw_sc + c21*Praw_sc^2 + c31*Praw_sc^3) + + float pres_comp = + (float)c00 + (float)c10 * pres_raw_sc + (float)c20 * pres_raw_sc_2 + + (float)c30 * pres_raw_sc_3 + (float)c40 * pres_raw_sc_4 + + temp_raw_sc * ((float)c01 + (float)c11 * pres_raw_sc + + (float)c21 * pres_raw_sc_2 + (float)c31 * pres_raw_sc_3); + + // Convert from Pascals to hectopascals (hPa) + return pres_comp / 100.0f; +} + +/*! + * @brief Gets the Adafruit_Sensor object for temperature readings + * @return Adafruit_Sensor pointer for temperature + */ +Adafruit_Sensor *Adafruit_SPA06_003::getTemperatureSensor() { + if (!temp_sensor) { + temp_sensor = new Adafruit_SPA06_003_Temp(this); + } + return temp_sensor; +} + +/*! + * @brief Gets the Adafruit_Sensor object for pressure readings + * @return Adafruit_Sensor pointer for pressure + */ +Adafruit_Sensor *Adafruit_SPA06_003::getPressureSensor() { + if (!pressure_sensor) { + pressure_sensor = new Adafruit_SPA06_003_Pressure(this); + } + return pressure_sensor; +} + +/*! + * @brief Gets the sensor_t device data for temperature sensor + * @param sensor Pointer to sensor_t device info struct + */ +void Adafruit_SPA06_003_Temp::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "SPA06_003", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + sensor->min_delay = 0; + sensor->min_value = -40.0; // Datasheet minimum + sensor->max_value = 85.0; // Datasheet maximum + sensor->resolution = 0.01; // Datasheet resolution +} + +/*! + * @brief Gets the latest sensor event for temperature + * @param event Pointer to sensors_event_t struct + * @return True on successful event generation + */ +bool Adafruit_SPA06_003_Temp::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_AMBIENT_TEMPERATURE; + event->timestamp = millis(); + event->temperature = _theSPA06003->readTemperature(); + return true; +} + +/*! + * @brief Gets the sensor_t device data for pressure sensor + * @param sensor Pointer to sensor_t device info struct + */ +void Adafruit_SPA06_003_Pressure::getSensor(sensor_t *sensor) { + /* Clear the sensor_t object */ + memset(sensor, 0, sizeof(sensor_t)); + + /* Insert the sensor name in the fixed length char array */ + strncpy(sensor->name, "SPA06_003", sizeof(sensor->name) - 1); + sensor->name[sizeof(sensor->name) - 1] = 0; + sensor->version = 1; + sensor->sensor_id = _sensorID; + sensor->type = SENSOR_TYPE_PRESSURE; + sensor->min_delay = 0; + sensor->min_value = 300.0; // Datasheet minimum in hPa + sensor->max_value = 1100.0; // Datasheet maximum in hPa + sensor->resolution = 0.012; // Datasheet resolution in hPa +} + +/*! + * @brief Gets the latest sensor event for pressure + * @param event Pointer to sensors_event_t struct + * @return True on successful event generation + */ +bool Adafruit_SPA06_003_Pressure::getEvent(sensors_event_t *event) { + /* Clear the event */ + memset(event, 0, sizeof(sensors_event_t)); + + event->version = sizeof(sensors_event_t); + event->sensor_id = _sensorID; + event->type = SENSOR_TYPE_PRESSURE; + event->timestamp = millis(); + event->pressure = _theSPA06003->readPressure(); + return true; +} \ No newline at end of file diff --git a/Adafruit_SPA06_003.h b/Adafruit_SPA06_003.h new file mode 100644 index 0000000..4ca5ac2 --- /dev/null +++ b/Adafruit_SPA06_003.h @@ -0,0 +1,256 @@ +/*! + * @file Adafruit_SPA06003.h + * + * This is part of Adafruit's SPA06003 driver for the Arduino platform. It is + * designed specifically to work with the Adafruit SPA06003 breakout: + * https://www.adafruit.com/products/xxxx + * + * These sensors use I2C to communicate, 2 pins (SCL+SDA) are required + * to interface with the breakout. + * + * Adafruit invests time and resources providing this open source code, + * please support Adafruit and open-source hardware by purchasing + * products from Adafruit! + * + * Written by Limor 'ladyada' Fried with assistance from Claude Code + * for Adafruit Industries. + * + * MIT license, all text here must be included in any redistribution. + * + */ + +#ifndef _ADAFRUIT_SPA06_003_H +#define _ADAFRUIT_SPA06_003_H + +#include +#include +#include +#include + +#include "Arduino.h" + +// Forward declarations +class Adafruit_SPA06_003_Temp; +class Adafruit_SPA06_003_Pressure; + +/*========================================================================= + I2C ADDRESS/BITS + -----------------------------------------------------------------------*/ +/** + * @brief Default I2C address for SPA06_003 + */ +#define SPA06_003_DEFAULT_ADDR 0x77 + +/*========================================================================= + REGISTERS + -----------------------------------------------------------------------*/ + +/** + * @brief Pressure data registers + */ +#define SPA06_003_REG_PSR_B2 0x00 +#define SPA06_003_REG_PSR_B1 0x01 +#define SPA06_003_REG_PSR_B0 0x02 + +/** + * @brief Temperature data registers + */ +#define SPA06_003_REG_TMP_B2 0x03 +#define SPA06_003_REG_TMP_B1 0x04 +#define SPA06_003_REG_TMP_B0 0x05 + +/** + * @brief Configuration registers + */ +#define SPA06_003_REG_PRS_CFG 0x06 +#define SPA06_003_REG_TMP_CFG 0x07 +#define SPA06_003_REG_MEAS_CFG 0x08 +#define SPA06_003_REG_CFG_REG 0x09 + +/** + * @brief Status registers + */ +#define SPA06_003_REG_INT_STS 0x0A +#define SPA06_003_REG_FIFO_STS 0x0B + +/** + * @brief Control registers + */ +#define SPA06_003_REG_RESET 0x0C +#define SPA06_003_REG_ID 0x0D + +/** + * @brief Calibration coefficient registers + */ +#define SPA06_003_REG_COEF 0x10 + +/*========================================================================= + INTERRUPT STATUS FLAGS (INT_STS register 0x0A) + -----------------------------------------------------------------------*/ +/** + * @brief Interrupt status flag definitions + */ +#define SPA06_003_INT_FIFO_FULL 0x04 ///< FIFO full flag +#define SPA06_003_INT_TMP_RDY 0x02 ///< Temperature measurement ready flag +#define SPA06_003_INT_PRS_RDY 0x01 ///< Pressure measurement ready flag + +/*=========================================================================*/ + +/** + * @brief Measurement rate options (pressure and temperature) + */ +typedef enum { + SPA06_003_RATE_1 = 0x00, ///< 1 measurements per second + SPA06_003_RATE_2 = 0x01, ///< 2 measurements per second + SPA06_003_RATE_4 = 0x02, ///< 4 measurements per second + SPA06_003_RATE_8 = 0x03, ///< 8 measurements per second + SPA06_003_RATE_16 = 0x04, ///< 16 measurements per second + SPA06_003_RATE_32 = 0x05, ///< 32 measurements per second + SPA06_003_RATE_64 = 0x06, ///< 64 measurements per second + SPA06_003_RATE_128 = 0x07, ///< 128 measurements per second + SPA06_003_RATE_25_16 = 0x08, ///< 25/16 samples per second + SPA06_003_RATE_25_8 = 0x09, ///< 25/8 samples per second + SPA06_003_RATE_25_4 = 0x0A, ///< 25/4 samples per second + SPA06_003_RATE_25_2 = 0x0B, ///< 25/2 samples per second + SPA06_003_RATE_25 = 0x0C, ///< 25 samples per second + SPA06_003_RATE_50 = 0x0D, ///< 50 samples per second + SPA06_003_RATE_100 = 0x0E, ///< 100 samples per second + SPA06_003_RATE_200 = 0x0F ///< 200 samples per second +} spa06_003_rate_t; + +/** + * @brief Oversampling rate options (shared by pressure and temperature) + */ +typedef enum { + SPA06_003_OVERSAMPLE_1 = 0x00, ///< Single + SPA06_003_OVERSAMPLE_2 = 0x01, ///< 2 times + SPA06_003_OVERSAMPLE_4 = 0x02, ///< 4 times + SPA06_003_OVERSAMPLE_8 = 0x03, ///< 8 times + SPA06_003_OVERSAMPLE_16 = 0x04, ///< 16 times + SPA06_003_OVERSAMPLE_32 = 0x05, ///< 32 times + SPA06_003_OVERSAMPLE_64 = 0x06, ///< 64 times + SPA06_003_OVERSAMPLE_128 = 0x07 ///< 128 times +} spa06_003_oversample_t; + +/** + * @brief Measurement mode options + */ +typedef enum { + SPA06_003_MEAS_IDLE = 0x00, ///< Idle / Stop background measurement + SPA06_003_MEAS_PRESSURE = 0x01, ///< Pressure measurement (Command Mode) + SPA06_003_MEAS_TEMPERATURE = + 0x02, ///< Temperature measurement (Command Mode) + SPA06_003_MEAS_CONTINUOUS_PRESSURE = + 0x05, ///< Continuous pressure measurement (Background Mode) + SPA06_003_MEAS_CONTINUOUS_TEMPERATURE = + 0x06, ///< Continuous temperature measurement (Background Mode) + SPA06_003_MEAS_CONTINUOUS_BOTH = + 0x07 ///< Continuous pressure and temperature measurement (Background + ///< Mode) +} spa06_003_meas_mode_t; + +/** + * @brief Interrupt polarity options + */ +typedef enum { + SPA06_003_INT_ACTIVE_LOW = 0x00, ///< Interrupt active low + SPA06_003_INT_ACTIVE_HIGH = 0x01 ///< Interrupt active high +} spa06_003_int_polarity_t; + +/*! + * @brief Class that stores state and functions for interacting with SPA06_003 + */ +class Adafruit_SPA06_003 { + public: + Adafruit_SPA06_003(); + ~Adafruit_SPA06_003(); + bool begin(uint8_t i2c_addr = SPA06_003_DEFAULT_ADDR, TwoWire *wire = &Wire); + uint32_t getPressureData(); + uint32_t getTemperatureData(); + spa06_003_rate_t getPressureMeasureRate(); + bool setPressureMeasureRate(spa06_003_rate_t rate); + spa06_003_rate_t getTemperatureMeasureRate(); + bool setTemperatureMeasureRate(spa06_003_rate_t rate); + spa06_003_oversample_t getPressureOversampling(); + bool setPressureOversampling(spa06_003_oversample_t prc); + spa06_003_oversample_t getTemperatureOversampling(); + bool setTemperatureOversampling(spa06_003_oversample_t prc); + bool isCoeffReady(); + bool isSensorReady(); + bool isTempDataReady(); + bool isPresDataReady(); + spa06_003_meas_mode_t getMeasurementMode(); + bool setMeasurementMode(spa06_003_meas_mode_t mode); + bool setInterruptPolarity(spa06_003_int_polarity_t polarity); + bool setInterruptSource(bool fifo, bool temp_ready, bool pres_ready); + bool setTempShift(bool enable); + bool setPresShift(bool enable); + bool enableFIFO(bool enable); + bool isFIFOEnabled(); + bool isFIFOEmpty(); + bool isFIFOFull(); + uint8_t getStatusFlags(); + bool flushFIFO(); + bool reset(); + float readTemperature(); + float readPressure(); + + Adafruit_Sensor *getTemperatureSensor(); + Adafruit_Sensor *getPressureSensor(); + + private: + Adafruit_I2CDevice *i2c_dev; + + // Adafruit Sensor objects + Adafruit_SPA06_003_Temp *temp_sensor = NULL; + Adafruit_SPA06_003_Pressure *pressure_sensor = NULL; + + // Calibration coefficients + int16_t c0, c1; + int32_t c00, c10; // 20-bit 2's complement + int16_t c01, c11, c20, c21, c30; // 16-bit 2's complement + int16_t c31; // 12-bit 2's complement + int16_t c40; // 12-bit 2's complement + + bool readCoefficients(); + float getScalingFactor(spa06_003_oversample_t oversample); +}; + +/*! + * @brief Adafruit Unified Sensor interface for temperature component of + * SPA06_003 + */ +class Adafruit_SPA06_003_Temp : public Adafruit_Sensor { + public: + /** @brief Create an Adafruit_Sensor compatible object for the temp sensor + @param parent A pointer to the SPA06_003 class */ + Adafruit_SPA06_003_Temp(Adafruit_SPA06_003 *parent) { + _theSPA06003 = parent; + } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + + private: + int _sensorID = 60003; + Adafruit_SPA06_003 *_theSPA06003 = NULL; +}; + +/*! + * @brief Adafruit Unified Sensor interface for pressure component of SPA06_003 + */ +class Adafruit_SPA06_003_Pressure : public Adafruit_Sensor { + public: + /** @brief Create an Adafruit_Sensor compatible object for the pressure sensor + @param parent A pointer to the SPA06_003 class */ + Adafruit_SPA06_003_Pressure(Adafruit_SPA06_003 *parent) { + _theSPA06003 = parent; + } + bool getEvent(sensors_event_t *); + void getSensor(sensor_t *); + + private: + int _sensorID = 60003; + Adafruit_SPA06_003 *_theSPA06003 = NULL; +}; + +#endif \ No newline at end of file diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..12f04c8 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,135 @@ + + +# Adafruit Community Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and leaders pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level or type of +experience, education, socio-economic status, nationality, personal appearance, +race, religion, or sexual identity and orientation. + +## Our Standards + +We are committed to providing a friendly, safe and welcoming environment for +all. + +Examples of behavior that contributes to creating a positive environment +include: + +* Be kind and courteous to others +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Collaborating with other community members +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and sexual attention or advances +* The use of inappropriate images, including in a community member's avatar +* The use of inappropriate language, including in a community member's nickname +* Any spamming, flaming, baiting or other attention-stealing behavior +* Excessive or unwelcome helping; answering outside the scope of the question + asked +* Trolling, insulting/derogatory comments, and personal or political attacks +* Promoting or spreading disinformation, lies, or conspiracy theories against + a person, group, organisation, project, or community +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate + +The goal of the standards and moderation guidelines outlined here is to build +and maintain a respectful community. We ask that you don't just aim to be +"technically unimpeachable", but rather try to be your best self. + +We value many things beyond technical expertise, including collaboration and +supporting others within our community. Providing a positive experience for +other community members can have a much more significant impact than simply +providing the correct answer. + +## Our Responsibilities + +Project leaders are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project leaders have the right and responsibility to remove, edit, or +reject messages, comments, commits, code, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any community member for other behaviors that they deem +inappropriate, threatening, offensive, or harmful. + +## Moderation + +Instances of behaviors that violate the Adafruit Community Code of Conduct +may be reported by any member of the community. Community members are +encouraged to report these situations, including situations they witness +involving other community members. + +You may report in the following ways: + +In any situation, you may send an email to . + +On the Adafruit Discord, you may send an open message from any channel +to all Community Moderators by tagging @community moderators. You may +also send an open message from any channel, or a direct message to +@kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442, +@sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175. + +Email and direct message reports will be kept confidential. + +In situations on Discord where the issue is particularly egregious, possibly +illegal, requires immediate action, or violates the Discord terms of service, +you should also report the message directly to Discord. + +These are the steps for upholding our community's standards of conduct. + +1. Any member of the community may report any situation that violates the +Adafruit Community Code of Conduct. All reports will be reviewed and +investigated. +2. If the behavior is an egregious violation, the community member who +committed the violation may be banned immediately, without warning. +3. Otherwise, moderators will first respond to such behavior with a warning. +4. Moderators follow a soft "three strikes" policy - the community member may +be given another chance, if they are receptive to the warning and change their +behavior. +5. If the community member is unreceptive or unreasonable when warned by a +moderator, or the warning goes unheeded, they may be banned for a first or +second offense. Repeated offenses will result in the community member being +banned. + +## Scope + +This Code of Conduct and the enforcement policies listed above apply to all +Adafruit Community venues. This includes but is not limited to any community +spaces (both public and private), the entire Adafruit Discord server, and +Adafruit GitHub repositories. Examples of Adafruit Community spaces include +but are not limited to meet-ups, audio chats on the Adafruit Discord, or +interaction at a conference. + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. As a community +member, you are representing our community, and are expected to behave +accordingly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at +, +and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). + +For other projects adopting the Adafruit Community Code of +Conduct, please contact the maintainers of those projects for enforcement. +If you wish to use this code of conduct for your own project, consider +explicitly mentioning your moderation policy or making a copy with your +own moderation policy so as to avoid confusion. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..695bee5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Adafruit Industries + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..774311f --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Adafruit SPA06_003 [![Build Status](https://github.com/adafruit/Adafruit_SPA06_003/workflows/Arduino%20Library%20CI/badge.svg)](https://github.com/adafruit/Adafruit_SPA06_003/actions)[![Documentation](https://github.com/adafruit/ci-arduino/blob/master/assets/doxygen_badge.svg)](http://adafruit.github.io/Adafruit_SPA06_003/html/index.html) + +
+Adafruit SPA06_003 Breakout
+ +This is the Adafruit SPA06_003 Digital Pressure Sensor library for Arduino. + +Tested and works great with the Adafruit SPA06_003 Breakout Board. + +## About the SPA06_003 + +The SPA06_003 is a miniaturized Digital Barometric Air Pressure Sensor with high accuracy and low current consumption. Key features: + +* Pressure range: 300 ... 1100hPa (+9000m ... -500m relating to sea level) +* Temperature Range: -40...+85°C +* Supply voltage: 1.7 ... 3.6V (VDD), 1.08... 3.6V (VDDIO) +* Small footprint: 2.0mm x 2.5mm; Super-flat: 0.95mm +* Relative accuracy: typ.±0.03hPa, equiv. to ±0.25 m +* Absolute accuracy: typ. ±0.3hPa (300 ... 1100hPa) +* Temperature accuracy: typ. ± 1°C +* Measurement time: 3.6ms for low precision mode +* Average current consumption: 1.7 µA for pressure measurement, 1.5 µA for temperature measurement at 1Hz sampling rate +* I2C and SPI interface +* FIFO: Stores latest 32 pressure or temperature measurements +* Embedded 24-bit ADC + +## Installation + +To install, use the Arduino Library Manager and search for "Adafruit SPA06_003" and install the library. + +## Dependencies + +This library depends on the [Adafruit BusIO library](https://github.com/adafruit/Adafruit_BusIO) + +## Contributing + +Contributions are welcome! Please read our [Code of Conduct](https://github.com/adafruit/Adafruit_SPA06_003/blob/main/CODE_OF_CONDUCT.md) +before contributing to help this project stay welcoming. + +## Documentation and doxygen + +Documentation is produced by doxygen. Contributions should include documentation for any new features. + +## Formatting and clang-format + +This library uses [`clang-format`](https://releases.llvm.org/download.html) to standardize the formatting of `.cpp` and `.h` files. +Contributions should be formatted using `clang-format`: + +The `-i` flag will make the changes to the file. +```bash +clang-format -i *.cpp *.h +``` +If you prefer to make the changes yourself, running `clang-format` without the `-i` flag will print out a formatted version of the file. You can save this to a file and diff it against the original to see the changes. + +Note that the formatting output by `clang-format` is what the automated formatting checker will expect. Any irrelevant changes (such as un-necessary whitespace changes) will result in a failed build until they are addressed. Using the `-i` flag is highly recommended. + +## About this Driver + +Written by Limor 'ladyada' Fried with assistance from Claude Code for Adafruit Industries. MIT license, check license.txt for more information All text above must be included in any redistribution + +To install, use the Arduino Library Manager and search for "Adafruit SPA06_003" and install the library. \ No newline at end of file diff --git a/examples/fulltest_spa06_003/fulltest_spa06_003.ino b/examples/fulltest_spa06_003/fulltest_spa06_003.ino new file mode 100644 index 0000000..e639886 --- /dev/null +++ b/examples/fulltest_spa06_003/fulltest_spa06_003.ino @@ -0,0 +1,226 @@ +/* + Basic test sketch for SPA06_003 Digital Pressure Sensor + + This sketch initializes the sensor and verifies communication. + + Written by Limor 'ladyada' Fried with assistance from Claude Code + for Adafruit Industries. + MIT license, check license.txt for more information +*/ + +#include + +Adafruit_SPA06_003 spa; + +void printMeasureRate(spa06_003_rate_t rate) { + switch (rate) { + case SPA06_003_RATE_1: + Serial.println(F("1 measurements per second")); + break; + case SPA06_003_RATE_2: + Serial.println(F("2 measurements per second")); + break; + case SPA06_003_RATE_4: + Serial.println(F("4 measurements per second")); + break; + case SPA06_003_RATE_8: + Serial.println(F("8 measurements per second")); + break; + case SPA06_003_RATE_16: + Serial.println(F("16 measurements per second")); + break; + case SPA06_003_RATE_32: + Serial.println(F("32 measurements per second")); + break; + case SPA06_003_RATE_64: + Serial.println(F("64 measurements per second")); + break; + case SPA06_003_RATE_128: + Serial.println(F("128 measurements per second")); + break; + case SPA06_003_RATE_25_16: + Serial.println(F("25/16 samples per second")); + break; + case SPA06_003_RATE_25_8: + Serial.println(F("25/8 samples per second")); + break; + case SPA06_003_RATE_25_4: + Serial.println(F("25/4 samples per second")); + break; + case SPA06_003_RATE_25_2: + Serial.println(F("25/2 samples per second")); + break; + case SPA06_003_RATE_25: + Serial.println(F("25 samples per second")); + break; + case SPA06_003_RATE_50: + Serial.println(F("50 samples per second")); + break; + case SPA06_003_RATE_100: + Serial.println(F("100 samples per second")); + break; + case SPA06_003_RATE_200: + Serial.println(F("200 samples per second")); + break; + default: + Serial.println(F("Unknown rate")); + break; + } +} + +void printOversampling(spa06_003_oversample_t prc) { + switch (prc) { + case SPA06_003_OVERSAMPLE_1: + Serial.println(F("Single")); + break; + case SPA06_003_OVERSAMPLE_2: + Serial.println(F("2 times")); + break; + case SPA06_003_OVERSAMPLE_4: + Serial.println(F("4 times")); + break; + case SPA06_003_OVERSAMPLE_8: + Serial.println(F("8 times")); + break; + case SPA06_003_OVERSAMPLE_16: + Serial.println(F("16 times")); + break; + case SPA06_003_OVERSAMPLE_32: + Serial.println(F("32 times")); + break; + case SPA06_003_OVERSAMPLE_64: + Serial.println(F("64 times")); + break; + case SPA06_003_OVERSAMPLE_128: + Serial.println(F("128 times")); + break; + default: + Serial.println(F("Unknown")); + break; + } +} + +void setup() { + Serial.begin(115200); + while (!Serial) delay(10); + + Serial.println("SPA06_003 test!"); + + if (!spa.begin()) { + Serial.println("Could not find a valid SPA06_003 sensor, check wiring!"); + while (1) delay(10); + } + + Serial.println(F("SPA06_003 sensor found and initialized!")); + + Serial.println(F("Setting measurement mode to continuous both...")); + spa.setMeasurementMode(SPA06_003_MEAS_CONTINUOUS_BOTH); + + Serial.print(F("Current measurement mode: ")); + spa06_003_meas_mode_t current_mode = spa.getMeasurementMode(); + + switch (current_mode) { + case SPA06_003_MEAS_IDLE: + Serial.println(F("Idle")); + break; + case SPA06_003_MEAS_PRESSURE: + Serial.println(F("Pressure (Command Mode)")); + break; + case SPA06_003_MEAS_TEMPERATURE: + Serial.println(F("Temperature (Command Mode)")); + break; + case SPA06_003_MEAS_CONTINUOUS_PRESSURE: + Serial.println(F("Continuous pressure")); + break; + case SPA06_003_MEAS_CONTINUOUS_TEMPERATURE: + Serial.println(F("Continuous temperature")); + break; + case SPA06_003_MEAS_CONTINUOUS_BOTH: + Serial.println(F("Continuous both")); + break; + default: + Serial.println(F("Unknown")); + break; + } + + spa.enableFIFO(false); + + spa.setInterruptPolarity(SPA06_003_INT_ACTIVE_HIGH); + + spa.setInterruptSource(false /*fifo*/, true /*temp_ready*/, true /*pres_ready*/); + + spa.setTemperatureOversampling(SPA06_003_OVERSAMPLE_8); + + spa06_003_oversample_t temp_prc = spa.getTemperatureOversampling(); + Serial.print(F("Current temperature oversampling: ")); + printOversampling(temp_prc); + + spa.setTemperatureMeasureRate(SPA06_003_RATE_64); + + spa06_003_rate_t temp_rate = spa.getTemperatureMeasureRate(); + Serial.print(F("Current temperature measurement rate: ")); + printMeasureRate(temp_rate); + + spa.setPressureMeasureRate(SPA06_003_RATE_128); + + spa06_003_rate_t current_rate = spa.getPressureMeasureRate(); + Serial.print(F("Current pressure measurement rate: ")); + printMeasureRate(current_rate); + + spa.setPressureOversampling(SPA06_003_OVERSAMPLE_8); + + spa06_003_oversample_t current_prc = spa.getPressureOversampling(); + Serial.print(F("Current pressure oversampling: ")); + printOversampling(current_prc); +} + +void loop() { + if (spa.isTempDataReady()) { + Serial.print(F("Temperature: ")); + Serial.print(spa.readTemperature()); + Serial.print(F("°C")); + } + + if (spa.isPresDataReady()) { + Serial.print(F(", Pressure: ")); + Serial.print(spa.readPressure()); + Serial.print(F(" hPa")); + } + + uint8_t status_flags = spa.getStatusFlags(); + Serial.print(F(", Status flags: 0x")); + Serial.print(status_flags, HEX); + Serial.print(F(" [")); + + if (status_flags & SPA06_003_INT_FIFO_FULL) { + Serial.print(F("FIFO_FULL ")); + } + if (status_flags & SPA06_003_INT_TMP_RDY) { + Serial.print(F("TMP_RDY ")); + } + if (status_flags & SPA06_003_INT_PRS_RDY) { + Serial.print(F("PRS_RDY ")); + } + if (status_flags == 0) { + Serial.print(F("NONE")); + } + + Serial.println(F("]")); + + Serial.print(F(", FIFO: ")); + if (spa.isFIFOEnabled()) { + Serial.print(F("enabled ")); + if (spa.isFIFOEmpty()) { + Serial.print(F("(empty)")); + } else if (spa.isFIFOFull()) { + Serial.print(F("(full)")); + } else { + Serial.print(F("(partial)")); + } + } else { + Serial.print(F("disabled")); + } + Serial.println(); + + delay(1000); +} \ No newline at end of file diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..94214f2 --- /dev/null +++ b/library.properties @@ -0,0 +1,10 @@ +name=Adafruit SPA06_003 +version=1.0.0 +author=Adafruit +maintainer=Adafruit +sentence=Arduino library for SPA06_003 digital pressure sensor +paragraph=Arduino library for the SPA06_003 miniaturized digital barometric air pressure sensor with high accuracy and low current consumption. Supports I2C communication and includes FIFO buffer for 32 measurements. +category=Sensors +url=https://github.com/adafruit/Adafruit_SPA06_003 +architectures=* +depends=Adafruit BusIO \ No newline at end of file