diff --git a/.github/workflows/check-arduino.yml b/.github/workflows/check-arduino.yml index 34c952b..adb330f 100644 --- a/.github/workflows/check-arduino.yml +++ b/.github/workflows/check-arduino.yml @@ -16,13 +16,13 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Arduino Lint uses: arduino/arduino-lint-action@v1 with: - compliance: strict - library-manager: submit + compliance: specification + library-manager: update # Always use this setting for official repositories. Remove for 3rd party projects. official: true project-type: library diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 63bf08e..38999da 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -34,7 +34,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Compile example sketches uses: arduino/compile-sketches@v1 @@ -42,35 +42,19 @@ jobs: fqbn: arduino:mbed_portenta:envie_m7 platforms: | - name: arduino:mbed_portenta + libraries: | + - source-path: ./ + - name: ArduinoRS485 + sketch-paths: | + - examples enable-deltas-report: true enable-warnings-report: true sketches-report-path: ${{ env.SKETCHES_REPORTS_PATH }} github-token: ${{ secrets.GITHUB_TOKEN }} - name: Save memory usage change report as artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: if-no-files-found: error path: ${{ env.SKETCHES_REPORTS_PATH }} name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} - - report: - needs: compile-examples - # Only run the job when the workflow is triggered by a pull request from this repository (because arduino/report-size-deltas requires write permissions) - if: always() && github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest - steps: - - name: Download sketches reports artifact - id: download-artifact - continue-on-error: true # If compilation failed for all boards then there are no artifacts - uses: actions/download-artifact@v2 - with: - name: ${{ env.SKETCHES_REPORTS_ARTIFACT_NAME }} - path: ${{ env.SKETCHES_REPORTS_PATH }} - - - name: Comment size deltas report to PR - uses: arduino/report-size-deltas@v1 - # If actions/download-artifact failed, there are no artifacts to report from. - if: steps.download-artifact.outcome == 'success' - with: - sketches-reports-source: ${{ env.SKETCHES_REPORTS_PATH }} diff --git a/.github/workflows/report-size-deltas.yml b/.github/workflows/report-size-deltas.yml new file mode 100644 index 0000000..30b6ca0 --- /dev/null +++ b/.github/workflows/report-size-deltas.yml @@ -0,0 +1,24 @@ +name: Report Size Deltas + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/report-size-deltas.ya?ml" + schedule: + # Run at the minimum interval allowed by GitHub Actions. + # Note: GitHub Actions periodically has outages which result in workflow failures. + # In this event, the workflows will start passing again once the service recovers. + - cron: "*/5 * * * *" + workflow_dispatch: + repository_dispatch: + +jobs: + report: + runs-on: ubuntu-latest + steps: + - name: Comment size deltas reports to PRs + uses: arduino/report-size-deltas@v1 + with: + # The name of the workflow artifact created by the sketch compilation workflow + sketches-reports-source: sketches-reports diff --git a/.github/workflows/spell-check.yml b/.github/workflows/spell-check.yml index 01bee87..ef7d894 100644 --- a/.github/workflows/spell-check.yml +++ b/.github/workflows/spell-check.yml @@ -16,7 +16,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v4 - name: Spell check uses: codespell-project/actions-codespell@master diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 0000000..9cde1ac --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,138 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md +name: Sync Labels + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + pull_request: + paths: + - ".github/workflows/sync-labels.ya?ml" + - ".github/label-configuration-files/*.ya?ml" + schedule: + # Run daily at 8 AM UTC to sync with changes to shared label configurations. + - cron: "0 8 * * *" + workflow_dispatch: + repository_dispatch: + +env: + CONFIGURATIONS_FOLDER: .github/label-configuration-files + CONFIGURATIONS_ARTIFACT: label-configuration-files + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download JSON schema for labels configuration file + id: download-schema + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json + location: ${{ runner.temp }}/label-configuration-schema + + - name: Install JSON schema validator + run: | + sudo npm install \ + --global \ + ajv-cli \ + ajv-formats + + - name: Validate local labels configuration + run: | + # See: https://github.com/ajv-validator/ajv-cli#readme + ajv validate \ + --all-errors \ + -c ajv-formats \ + -s "${{ steps.download-schema.outputs.file-path }}" \ + -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" + + download: + needs: check + runs-on: ubuntu-latest + + strategy: + matrix: + filename: + # Filenames of the shared configurations to apply to the repository in addition to the local configuration. + # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels + - universal.yml + + steps: + - name: Download + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} + + - name: Pass configuration files to next job via workflow artifact + uses: actions/upload-artifact@v3 + with: + path: | + *.yaml + *.yml + if-no-files-found: error + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + sync: + needs: download + runs-on: ubuntu-latest + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" + + - name: Determine whether to dry run + id: dry-run + if: > + github.event_name == 'pull_request' || + ( + ( + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' + ) && + github.ref != format('refs/heads/{0}', github.event.repository.default_branch) + ) + run: | + # Use of this flag in the github-label-sync command will cause it to only check the validity of the + # configuration. + echo "::set-output name=flag::--dry-run" + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download configuration files artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + path: ${{ env.CONFIGURATIONS_FOLDER }} + + - name: Remove unneeded artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + - name: Merge label configuration files + run: | + # Merge all configuration files + shopt -s extglob + cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" + + - name: Install github-label-sync + run: sudo npm install --global github-label-sync + + - name: Sync labels + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # See: https://github.com/Financial-Times/github-label-sync + github-label-sync \ + --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ + ${{ steps.dry-run.outputs.flag }} \ + ${{ github.repository }} diff --git a/README.md b/README.md index a770754..1672e27 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,22 @@ -# Machine Control Library for Arduino +# [Deprecated] Portenta Machine Control Library for Arduino + +> [!WARNING] +> This library is deprecated and no longer actively maintained. +> +> We recommend transitioning to the [Arduino_PortentaMachineControl](https://github.com/arduino-libraries/Arduino_PortentaMachineControl) library for ongoing support, new features and contributions. If you need assistance with migration, refer to the [migration guide](https://docs.arduino.cc/tutorials/portenta-machine-control/pmc-arduino-library). +> +> Please note that the [examples](./examples/) provided with this library are not compatible with the new library. [![Check Arduino status](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/check-arduino.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/check-arduino.yml) [![Compile Examples status](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/compile-examples.yml) [![Spell Check status](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_MachineControl/actions/workflows/spell-check.yml) -Arduino Library for the Machine Control +Arduino Library for the Portenta Machine Control -For more information about this library please visit us at https://www.arduino.cc/en/Reference/Arduino_MachineControl +The Portenta Machine Control enhances existing products with minimal effort, allowing companies to implement a standard platform across different equipment models. It is now easy to create an infrastructure of interconnected machines, which can be controlled onsite or via the cloud when needed; moreover, human-machine interaction can be further enahnced via mobile apps thanks to BLE connectivity. +For more information about this library please visit us at https://www.arduino.cc/reference/en/libraries/arduino_machinecontrol/ +For more information about this product: https://www.arduino.cc/pro/hardware/product/portenta-machine-control ## License diff --git a/examples/Analog_Out/Analog_Out.ino b/examples/Analog_Out/Analog_Out.ino index 89110e7..1e77034 100644 --- a/examples/Analog_Out/Analog_Out.ino +++ b/examples/Analog_Out/Analog_Out.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Analog out Example diff --git a/examples/Analog_input/Analog_input_0_10V/Analog_input_0_10V.ino b/examples/Analog_input/Analog_input_0_10V/Analog_input_0_10V.ino index d04c853..21634d8 100644 --- a/examples/Analog_input/Analog_input_0_10V/Analog_input_0_10V.ino +++ b/examples/Analog_input/Analog_input_0_10V/Analog_input_0_10V.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Analog in 0 - 10 V Example @@ -20,7 +32,7 @@ using namespace machinecontrol; float res_divider = 0.28057; -float reference = 3; +float reference = 3.0; void setup() { analogReadResolution(16); diff --git a/examples/Analog_input/Analog_input_4_20mA/Analog_input_4_20mA.ino b/examples/Analog_input/Analog_input_4_20mA/Analog_input_4_20mA.ino index 371310e..cae68fb 100644 --- a/examples/Analog_input/Analog_input_4_20mA/Analog_input_4_20mA.ino +++ b/examples/Analog_input/Analog_input_4_20mA/Analog_input_4_20mA.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Analog in 4 - 20 mA Example @@ -21,7 +33,7 @@ using namespace machinecontrol; #define SENSE_RES 120 -float reference = 3; +float reference = 3.0; void setup() { analogReadResolution(16); diff --git a/examples/Analog_input/Analog_input_NTC/Analog_input_NTC.ino b/examples/Analog_input/Analog_input_NTC/Analog_input_NTC.ino index d37f8af..7628f1f 100644 --- a/examples/Analog_input/Analog_input_NTC/Analog_input_NTC.ino +++ b/examples/Analog_input/Analog_input_NTC/Analog_input_NTC.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Analog in NTC Example @@ -26,7 +38,7 @@ using namespace machinecontrol; #define REFERENCE_RES 100000 -float reference = 3; +float reference = 3.0; float lowest_voltage = 2.7; void setup() { diff --git a/examples/CAN/ReadCan/ReadCan.ino b/examples/CAN/ReadCan/ReadCan.ino index c7273f7..50d96a1 100644 --- a/examples/CAN/ReadCan/ReadCan.ino +++ b/examples/CAN/ReadCan/ReadCan.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* CAN Read Example diff --git a/examples/CAN/WriteCan/WriteCan.ino b/examples/CAN/WriteCan/WriteCan.ino index 6250cfd..7471de7 100644 --- a/examples/CAN/WriteCan/WriteCan.ino +++ b/examples/CAN/WriteCan/WriteCan.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* CAN Write Example diff --git a/examples/Digital_output/Digital_output.ino b/examples/Digital_output/Digital_output.ino index 5bf6b51..c391ceb 100644 --- a/examples/Digital_output/Digital_output.ino +++ b/examples/Digital_output/Digital_output.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Digital Output Example diff --git a/examples/Digital_programmable/CombinedIOExpander/CombinedIOExpander.ino b/examples/Digital_programmable/CombinedIOExpander/CombinedIOExpander.ino index c76ad3d..afcc4d6 100644 --- a/examples/Digital_programmable/CombinedIOExpander/CombinedIOExpander.ino +++ b/examples/Digital_programmable/CombinedIOExpander/CombinedIOExpander.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - IOExpander Read And Write Example @@ -53,14 +65,14 @@ void loop() { Serial.println(); // Write the status value to On to all the Output Pins - setAll(SWITCH_ON); + digital_programmables.writeAll(SWITCH_ON_ALL); // Reads from all Input Pins readAll(); delay(1000); // Write the status value to Off all to all the Output Pins - setAll(SWITCH_OFF); + digital_programmables.writeAll(SWITCH_OFF_ALL); // Reads from all Input Pins readAll(); @@ -69,43 +81,30 @@ void loop() { } -void setAll(PinStatus status) { - // Write the status value to each Pin - digital_programmables.set(IO_WRITE_CH_PIN_00, status); - digital_programmables.set(IO_WRITE_CH_PIN_01, status); - digital_programmables.set(IO_WRITE_CH_PIN_02, status); - digital_programmables.set(IO_WRITE_CH_PIN_03, status); - digital_programmables.set(IO_WRITE_CH_PIN_04, status); - digital_programmables.set(IO_WRITE_CH_PIN_05, status); - digital_programmables.set(IO_WRITE_CH_PIN_06, status); - digital_programmables.set(IO_WRITE_CH_PIN_07, status); - digital_programmables.set(IO_WRITE_CH_PIN_08, status); - digital_programmables.set(IO_WRITE_CH_PIN_09, status); - digital_programmables.set(IO_WRITE_CH_PIN_10, status); - digital_programmables.set(IO_WRITE_CH_PIN_11, status); -} void readAll() { - // Reads from input pins. This API returns -1 if you try to read from a write channel. - Serial.println("IO Pin 00: " + String(digital_programmables.read(IO_READ_CH_PIN_00))); - Serial.println("IO Pin 01: " + String(digital_programmables.read(IO_READ_CH_PIN_01))); - Serial.println("IO Pin 02: " + String(digital_programmables.read(IO_READ_CH_PIN_02))); - Serial.println("IO Pin 03: " + String(digital_programmables.read(IO_READ_CH_PIN_03))); - Serial.println("IO Pin 04: " + String(digital_programmables.read(IO_READ_CH_PIN_04))); - Serial.println("IO Pin 05: " + String(digital_programmables.read(IO_READ_CH_PIN_05))); - Serial.println("IO Pin 06: " + String(digital_programmables.read(IO_READ_CH_PIN_06))); - Serial.println("IO Pin 07: " + String(digital_programmables.read(IO_READ_CH_PIN_07))); - Serial.println("IO Pin 08: " + String(digital_programmables.read(IO_READ_CH_PIN_08))); - Serial.println("IO Pin 09: " + String(digital_programmables.read(IO_READ_CH_PIN_09))); - Serial.println("IO Pin 10: " + String(digital_programmables.read(IO_READ_CH_PIN_10))); - Serial.println("IO Pin 11: " + String(digital_programmables.read(IO_READ_CH_PIN_11))); + uint32_t inputs = digital_programmables.readAll(); + Serial.println("CH00: " + String((inputs & (1 << IO_READ_CH_PIN_00)) >> IO_READ_CH_PIN_00)); + Serial.println("CH01: " + String((inputs & (1 << IO_READ_CH_PIN_01)) >> IO_READ_CH_PIN_01)); + Serial.println("CH02: " + String((inputs & (1 << IO_READ_CH_PIN_02)) >> IO_READ_CH_PIN_02)); + Serial.println("CH03: " + String((inputs & (1 << IO_READ_CH_PIN_03)) >> IO_READ_CH_PIN_03)); + Serial.println("CH04: " + String((inputs & (1 << IO_READ_CH_PIN_04)) >> IO_READ_CH_PIN_04)); + Serial.println("CH05: " + String((inputs & (1 << IO_READ_CH_PIN_05)) >> IO_READ_CH_PIN_05)); + Serial.println("CH06: " + String((inputs & (1 << IO_READ_CH_PIN_06)) >> IO_READ_CH_PIN_06)); + Serial.println("CH07: " + String((inputs & (1 << IO_READ_CH_PIN_07)) >> IO_READ_CH_PIN_07)); + Serial.println("CH08: " + String((inputs & (1 << IO_READ_CH_PIN_08)) >> IO_READ_CH_PIN_08)); + Serial.println("CH09: " + String((inputs & (1 << IO_READ_CH_PIN_09)) >> IO_READ_CH_PIN_09)); + Serial.println("CH10: " + String((inputs & (1 << IO_READ_CH_PIN_10)) >> IO_READ_CH_PIN_10)); + Serial.println("CH11: " + String((inputs & (1 << IO_READ_CH_PIN_11)) >> IO_READ_CH_PIN_11)); + Serial.println(); + inputs = digital_inputs.readAll(); + Serial.println("CH00: " + String((inputs & (1 << DIN_READ_CH_PIN_00)) >> DIN_READ_CH_PIN_00)); + Serial.println("CH01: " + String((inputs & (1 << DIN_READ_CH_PIN_01)) >> DIN_READ_CH_PIN_01)); + Serial.println("CH02: " + String((inputs & (1 << DIN_READ_CH_PIN_02)) >> DIN_READ_CH_PIN_02)); + Serial.println("CH03: " + String((inputs & (1 << DIN_READ_CH_PIN_03)) >> DIN_READ_CH_PIN_03)); + Serial.println("CH04: " + String((inputs & (1 << DIN_READ_CH_PIN_04)) >> DIN_READ_CH_PIN_04)); + Serial.println("CH05: " + String((inputs & (1 << DIN_READ_CH_PIN_05)) >> DIN_READ_CH_PIN_05)); + Serial.println("CH06: " + String((inputs & (1 << DIN_READ_CH_PIN_06)) >> DIN_READ_CH_PIN_06)); + Serial.println("CH07: " + String((inputs & (1 << DIN_READ_CH_PIN_07)) >> DIN_READ_CH_PIN_07)); Serial.println(); - Serial.println("DIN Pin 00: " + String(digital_inputs.read(DIN_READ_CH_PIN_00))); - Serial.println("DIN Pin 01: " + String(digital_inputs.read(DIN_READ_CH_PIN_01))); - Serial.println("DIN Pin 02: " + String(digital_inputs.read(DIN_READ_CH_PIN_02))); - Serial.println("DIN Pin 03: " + String(digital_inputs.read(DIN_READ_CH_PIN_03))); - Serial.println("DIN Pin 04: " + String(digital_inputs.read(DIN_READ_CH_PIN_04))); - Serial.println("DIN Pin 05: " + String(digital_inputs.read(DIN_READ_CH_PIN_05))); - Serial.println("DIN Pin 06: " + String(digital_inputs.read(DIN_READ_CH_PIN_06))); - Serial.println("DIN Pin 07: " + String(digital_inputs.read(DIN_READ_CH_PIN_07))); } diff --git a/examples/Digital_programmable/Digital_input/Digital_input.ino b/examples/Digital_programmable/Digital_input/Digital_input.ino index c94e1a9..beb5ecb 100644 --- a/examples/Digital_programmable/Digital_input/Digital_input.ino +++ b/examples/Digital_programmable/Digital_input/Digital_input.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Digital Input Example @@ -28,7 +40,7 @@ void setup() { } void loop() { - //Reads and Prints all channels and + //Reads and Prints all channels (in a single operation) readAll(); //Read one-by-one each channel and print them one-by-one @@ -62,13 +74,14 @@ void loop() { } uint8_t readAll() { - Serial.println("CH00: " + String(digital_inputs.read(DIN_READ_CH_PIN_00))); - Serial.println("CH01: " + String(digital_inputs.read(DIN_READ_CH_PIN_01))); - Serial.println("CH02: " + String(digital_inputs.read(DIN_READ_CH_PIN_02))); - Serial.println("CH03: " + String(digital_inputs.read(DIN_READ_CH_PIN_03))); - Serial.println("CH04: " + String(digital_inputs.read(DIN_READ_CH_PIN_04))); - Serial.println("CH05: " + String(digital_inputs.read(DIN_READ_CH_PIN_05))); - Serial.println("CH06: " + String(digital_inputs.read(DIN_READ_CH_PIN_06))); - Serial.println("CH07: " + String(digital_inputs.read(DIN_READ_CH_PIN_07))); + uint32_t inputs = digital_inputs.readAll(); + Serial.println("CH00: " + String((inputs & (1 << DIN_READ_CH_PIN_00)) >> DIN_READ_CH_PIN_00)); + Serial.println("CH01: " + String((inputs & (1 << DIN_READ_CH_PIN_01)) >> DIN_READ_CH_PIN_01)); + Serial.println("CH02: " + String((inputs & (1 << DIN_READ_CH_PIN_02)) >> DIN_READ_CH_PIN_02)); + Serial.println("CH03: " + String((inputs & (1 << DIN_READ_CH_PIN_03)) >> DIN_READ_CH_PIN_03)); + Serial.println("CH04: " + String((inputs & (1 << DIN_READ_CH_PIN_04)) >> DIN_READ_CH_PIN_04)); + Serial.println("CH05: " + String((inputs & (1 << DIN_READ_CH_PIN_05)) >> DIN_READ_CH_PIN_05)); + Serial.println("CH06: " + String((inputs & (1 << DIN_READ_CH_PIN_06)) >> DIN_READ_CH_PIN_06)); + Serial.println("CH07: " + String((inputs & (1 << DIN_READ_CH_PIN_07)) >> DIN_READ_CH_PIN_07)); Serial.println(); } diff --git a/examples/Digital_programmable/GPIO_programmable/GPIO_programmable.ino b/examples/Digital_programmable/GPIO_programmable/GPIO_programmable.ino index ce9558a..c7d34ba 100644 --- a/examples/Digital_programmable/GPIO_programmable/GPIO_programmable.ino +++ b/examples/Digital_programmable/GPIO_programmable/GPIO_programmable.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - IOExpander Read And Write Example @@ -12,7 +24,7 @@ This example code is in the public domain. */ - + #include #include "Wire.h" using namespace machinecontrol; @@ -42,52 +54,47 @@ void loop() { digital_programmables.set(IO_WRITE_CH_PIN_03, SWITCH_OFF); delay(1000); + Serial.println(); + // Sets all the status Pins Values to On in one single operation + uint32_t status = ON_VALUE_PIN_10 | ON_VALUE_PIN_08 | ON_VALUE_PIN_06 | ON_VALUE_PIN_04 | ON_VALUE_PIN_02 | ON_VALUE_PIN_00; + digital_programmables.writeAll(status); + delay(1000); + + // Toggles the actual status values of all digital programmables Pins + digital_programmables.toggle(); + delay(1000); + Serial.println(); // Write the status value to On to all the Output Pins - setAll(SWITCH_ON); + digital_programmables.writeAll(SWITCH_ON_ALL); // Reads from all Input Pins readAll(); delay(1000); // Write the status value to Off all to all the Output Pins - setAll(SWITCH_OFF); + digital_programmables.writeAll(SWITCH_OFF_ALL); // Reads from all Input Pins readAll(); Serial.println(); delay(1000); - } -void setAll(PinStatus status) { - // Write the status value to each Pin - digital_programmables.set(IO_WRITE_CH_PIN_00, status); - digital_programmables.set(IO_WRITE_CH_PIN_01, status); - digital_programmables.set(IO_WRITE_CH_PIN_02, status); - digital_programmables.set(IO_WRITE_CH_PIN_03, status); - digital_programmables.set(IO_WRITE_CH_PIN_04, status); - digital_programmables.set(IO_WRITE_CH_PIN_05, status); - digital_programmables.set(IO_WRITE_CH_PIN_06, status); - digital_programmables.set(IO_WRITE_CH_PIN_07, status); - digital_programmables.set(IO_WRITE_CH_PIN_08, status); - digital_programmables.set(IO_WRITE_CH_PIN_09, status); - digital_programmables.set(IO_WRITE_CH_PIN_10, status); - digital_programmables.set(IO_WRITE_CH_PIN_11, status); +uint8_t readAll() { + uint32_t inputs = digital_programmables.readAll(); + Serial.println("CH00: " + String((inputs & (1 << IO_READ_CH_PIN_00)) >> IO_READ_CH_PIN_00)); + Serial.println("CH01: " + String((inputs & (1 << IO_READ_CH_PIN_01)) >> IO_READ_CH_PIN_01)); + Serial.println("CH02: " + String((inputs & (1 << IO_READ_CH_PIN_02)) >> IO_READ_CH_PIN_02)); + Serial.println("CH03: " + String((inputs & (1 << IO_READ_CH_PIN_03)) >> IO_READ_CH_PIN_03)); + Serial.println("CH04: " + String((inputs & (1 << IO_READ_CH_PIN_04)) >> IO_READ_CH_PIN_04)); + Serial.println("CH05: " + String((inputs & (1 << IO_READ_CH_PIN_05)) >> IO_READ_CH_PIN_05)); + Serial.println("CH06: " + String((inputs & (1 << IO_READ_CH_PIN_06)) >> IO_READ_CH_PIN_06)); + Serial.println("CH07: " + String((inputs & (1 << IO_READ_CH_PIN_07)) >> IO_READ_CH_PIN_07)); + Serial.println("CH08: " + String((inputs & (1 << IO_READ_CH_PIN_08)) >> IO_READ_CH_PIN_08)); + Serial.println("CH09: " + String((inputs & (1 << IO_READ_CH_PIN_09)) >> IO_READ_CH_PIN_09)); + Serial.println("CH10: " + String((inputs & (1 << IO_READ_CH_PIN_10)) >> IO_READ_CH_PIN_10)); + Serial.println("CH11: " + String((inputs & (1 << IO_READ_CH_PIN_11)) >> IO_READ_CH_PIN_11)); + Serial.println(); } -void readAll() { - // Reads from input pins. This API returns -1 if you try to read from a write channel. - Serial.println("Pin 00: " + String(digital_programmables.read(IO_READ_CH_PIN_00))); - Serial.println("Pin 01: " + String(digital_programmables.read(IO_READ_CH_PIN_01))); - Serial.println("Pin 02: " + String(digital_programmables.read(IO_READ_CH_PIN_02))); - Serial.println("Pin 03: " + String(digital_programmables.read(IO_READ_CH_PIN_03))); - Serial.println("Pin 04: " + String(digital_programmables.read(IO_READ_CH_PIN_04))); - Serial.println("Pin 05: " + String(digital_programmables.read(IO_READ_CH_PIN_05))); - Serial.println("Pin 06: " + String(digital_programmables.read(IO_READ_CH_PIN_06))); - Serial.println("Pin 07: " + String(digital_programmables.read(IO_READ_CH_PIN_07))); - Serial.println("Pin 08: " + String(digital_programmables.read(IO_READ_CH_PIN_08))); - Serial.println("Pin 09: " + String(digital_programmables.read(IO_READ_CH_PIN_09))); - Serial.println("Pin 10: " + String(digital_programmables.read(IO_READ_CH_PIN_10))); - Serial.println("Pin 11: " + String(digital_programmables.read(IO_READ_CH_PIN_11))); -} diff --git a/examples/Encoders/Encoders.ino b/examples/Encoders/Encoders.ino index 0e91d45..67a4d4c 100644 --- a/examples/Encoders/Encoders.ino +++ b/examples/Encoders/Encoders.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + #include using namespace machinecontrol; diff --git a/examples/RS232/RS232.ino b/examples/RS232/RS232.ino new file mode 100644 index 0000000..1f44fc6 --- /dev/null +++ b/examples/RS232/RS232.ino @@ -0,0 +1,100 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + +/* + RS232 communication + + This sketch shows how to use the SP335ECR1 on the Machine + Control as a RS232 interface, how to periodically send + a string on the RS232 TX channel and how to receive data + from the interface RX channel. + + Circuit: + - Arduino Portenta Machine Control (PMC) + - Device with RS232 interface + - Connect PMC TXN to RS232 Device RXD + - Connect PMC RXP to RS232 Device TXD + - Connect PMC GND to RS232 Device GND + +*/ + +#include + +using namespace machinecontrol; + +constexpr unsigned long sendInterval { 1000 }; +unsigned long sendNow { 0 }; + +unsigned long counter { 0 }; + +void setup() +{ + + Serial.begin(115200); + // Wait for Serial or start after 2.5s + for (auto const timeout = millis() + 2500; !Serial && timeout < millis(); delay(500)) + ; + + delay(2500); + Serial.println("Start RS232 initialization"); + + // Set the PMC Communication Protocols to default config + comm_protocols.init(); + + // RS485/RS232 default config is: + // - RS485/RS232 system disabled + // - RS485 mode + // - Half Duplex + // - No A/B and Y/Z 120 Ohm termination enabled + + // Enable the RS485/RS232 system + comm_protocols.rs485Enable(true); + // Enable the RS232 mode + comm_protocols.rs485ModeRS232(true); + + // Specify baudrate for RS232 communication + comm_protocols.rs485.begin(115200); + // Start in receive mode + comm_protocols.rs485.receive(); + + Serial.println("Initialization done!"); +} + +void loop() +{ + if (comm_protocols.rs485.available()) + Serial.write(comm_protocols.rs485.read()); + + if (millis() > sendNow) { + String log = "["; + log += sendNow; + log += "] "; + + String msg = "hello "; + msg += counter++; + + log += msg; + Serial.println(log); + + // Disable receive mode before transmission + comm_protocols.rs485.noReceive(); + + comm_protocols.rs485.beginTransmission(); + comm_protocols.rs485.println(msg); + comm_protocols.rs485.endTransmission(); + + // Re-enable receive mode after transmission + comm_protocols.rs485.receive(); + + sendNow = millis() + sendInterval; + } +} diff --git a/examples/RS485_fullduplex/RS485_fullduplex.ino b/examples/RS485_fullduplex/RS485_fullduplex.ino index 67f772e..1f13922 100644 --- a/examples/RS485_fullduplex/RS485_fullduplex.ino +++ b/examples/RS485_fullduplex/RS485_fullduplex.ino @@ -1,8 +1,20 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* RS485 Full duplex communication This sketch shows how to use the SP335ECR1 on the Machine - Control as a full duplex RS485 interface, how to periodically + Control as a full duplex (AB and YZ) RS485 interface, how to periodically send a string on the RS485 TX channel and how to receive data from the interface RX channel. @@ -10,6 +22,8 @@ - Portenta H7 - Machine Control - A Slave device with RS485 interface + - Connect TXP to A(+) and TXN to B(-) + - Connect RXP to Y(+) and RXN to Z(-) */ @@ -17,6 +31,8 @@ using namespace machinecontrol; +constexpr unsigned long sendInterval { 1000 }; +unsigned long sendNow { 0 }; unsigned long counter = 0; void setup() @@ -29,37 +45,47 @@ void setup() delay(1000); Serial.println("Start RS485 initialization"); - comm_protocols.rs485.begin(115200); - comm_protocols.rs485.enable = 1; // SDHN_N - comm_protocols.rs485.sel_485 = 1; // RS485_RS232_N - comm_protocols.rs485.half_duplex = 0; // HALF_FULL_N - comm_protocols.rs485.receive(); // RE_N - comm_protocols.rs485.fd_tx_term = 1; // FD_TX_TERM - 120 ohm Y-Z termination enabled when both TERM and FD_TX_TERM are high - comm_protocols.rs485.term = 1; // TERM - 120 ohm A-B termination enabled when high + // Set the PMC Communication Protocols to default config + comm_protocols.init(); + // RS485/RS232 default config is: + // - RS485 mode + // - Half Duplex + // - No A/B and Y/Z 120 Ohm termination enabled + + // Enable the RS485/RS232 system + comm_protocols.rs485Enable(true); + + // Enable Full Duplex mode + // This will also enable A/B and Y/Z 120 Ohm termination resistors + comm_protocols.rs485FullDuplex(true); + + // Specify baudrate, and preamble and postamble times for RS485 communication + comm_protocols.rs485.begin(115200, 0, 500); + + // Start in receive mode + comm_protocols.rs485.receive(); + Serial.println("Initialization done!"); } -constexpr unsigned long sendInterval { 1000 }; -unsigned long sendNow { 0 }; - -constexpr unsigned long halfFullInterval { 5000 }; -unsigned long halfFull { 0 }; -byte halfFullStatus { 0 }; - void loop() { - while (comm_protocols.rs485.available()) + if (comm_protocols.rs485.available()) Serial.write(comm_protocols.rs485.read()); if (millis() > sendNow) { + // Disable receive mode before transmission comm_protocols.rs485.noReceive(); + comm_protocols.rs485.beginTransmission(); comm_protocols.rs485.print("hello "); comm_protocols.rs485.println(counter++); comm_protocols.rs485.endTransmission(); + + // Re-enable receive mode after transmission comm_protocols.rs485.receive(); sendNow = millis() + sendInterval; diff --git a/examples/RS485_halfduplex/RS485_halfduplex.ino b/examples/RS485_halfduplex/RS485_halfduplex.ino new file mode 100644 index 0000000..0291e1a --- /dev/null +++ b/examples/RS485_halfduplex/RS485_halfduplex.ino @@ -0,0 +1,89 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + +/* + RS485 Half Duplex communication + + This sketch shows how to use the SP335ECR1 on the Machine + Control as a half duplex (AB) RS485 interface, how to periodically + send a string on the RS485 TX channel and how to receive data + from the interface RX channel. + + Circuit: + - Portenta H7 + - Machine Control + - A Slave device with RS485 interface + - Connect TXP to A(+) and TXN to B(-) + +*/ + +#include "Arduino_MachineControl.h" + +using namespace machinecontrol; + +constexpr unsigned long sendInterval { 1000 }; +unsigned long sendNow { 0 }; + +unsigned long counter { 0 }; + +void setup() +{ + + Serial.begin(115200); + // Wait for Serial or start after 2.5s + for (auto const timeout = millis() + 2500; !Serial && timeout < millis(); delay(500)) + ; + + delay(2500); + Serial.println("Start RS485 initialization"); + + // Set the PMC Communication Protocols to default config + comm_protocols.init(); + + // RS485/RS232 default config is: + // - RS485 mode + // - Half Duplex + // - No A/B and Y/Z 120 Ohm termination enabled + + // Enable the RS485/RS232 system + comm_protocols.rs485Enable(true); + + // Specify baudrate, and preamble and postamble times for RS485 communication + comm_protocols.rs485.begin(115200, 0, 500); + // Start in receive mode + comm_protocols.rs485.receive(); + + Serial.println("Initialization done!"); +} + +void loop() +{ + if (comm_protocols.rs485.available()) + Serial.write(comm_protocols.rs485.read()); + + if (millis() > sendNow) { + // Disable receive mode before transmission + comm_protocols.rs485.noReceive(); + + comm_protocols.rs485.beginTransmission(); + + comm_protocols.rs485.print("hello "); + comm_protocols.rs485.println(counter++); + + comm_protocols.rs485.endTransmission(); + + // Re-enable receive mode after transmission + comm_protocols.rs485.receive(); + + sendNow = millis() + sendInterval; + } +} diff --git a/examples/RTC/RTC.ino b/examples/RTC/RTC.ino index 954e237..7edf77f 100644 --- a/examples/RTC/RTC.ino +++ b/examples/RTC/RTC.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - RTC Example diff --git a/examples/RTC_Alarm/RTC_Alarm.ino b/examples/RTC_Alarm/RTC_Alarm.ino index c455af6..f5c4325 100644 --- a/examples/RTC_Alarm/RTC_Alarm.ino +++ b/examples/RTC_Alarm/RTC_Alarm.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - RTC Alarm Example diff --git a/examples/Temp_probes_RTD/Temp_probes_RTD.ino b/examples/Temp_probes_RTD/Temp_probes_RTD.ino index 2899dc6..b2c1edb 100644 --- a/examples/Temp_probes_RTD/Temp_probes_RTD.ino +++ b/examples/Temp_probes_RTD/Temp_probes_RTD.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Temperature probes RTD example diff --git a/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino b/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino index 5fef867..a224288 100644 --- a/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino +++ b/examples/Temp_probes_Thermocouples/Temp_probes_Thermocouples.ino @@ -1,3 +1,15 @@ +/* + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ + /* Machine Control - Thermocouples Read Sensors diff --git a/examples/USB_host/TUSB_helpers.h b/examples/USB_host/TUSB_helpers.h new file mode 100644 index 0000000..dddde71 --- /dev/null +++ b/examples/USB_host/TUSB_helpers.h @@ -0,0 +1,151 @@ +/* + _______ _ _ _____ ____ + |__ __| | | | |/ ____| _ \ + | | ___ ___ _ __ _ _| | | | (___ | |_) | + | |/ _ \/ _ \ '_ \| | | | | | |\___ \| _ < + | | __/ __/ | | | |_| | |__| |____) | |_) | + |_|\___|\___|_| |_|\__, |\____/|_____/|____/ + __/ | + |___/ + + TeenyUSB - light weight usb stack for STM32 micro controllers + + Copyright (c) 2019 XToolBox - admin@xtoolbox.org + www.tusb.org + + 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. +*/ + +#pragma once + +#include + +static const tusbh_boot_key_class_t cls_boot_key = { + .backend = &tusbh_boot_keyboard_backend, + //.on_key = process_key +}; + +static const tusbh_boot_mouse_class_t cls_boot_mouse = { + .backend = &tusbh_boot_mouse_backend, + // .on_mouse = process_mouse +}; + +static const tusbh_hid_class_t cls_hid = { + .backend = &tusbh_hid_backend, + //.on_recv_data = process_hid_recv, + //.on_send_done = process_hid_sent, +}; + +static const tusbh_hub_class_t cls_hub = { + .backend = &tusbh_hub_backend, +}; + +static const tusbh_vendor_class_t cls_vendor = { + .backend = &tusbh_vendor_backend, + //.transfer_done = process_vendor_xfer_done +}; + +int msc_ff_mount(tusbh_interface_t* interface, int max_lun, const tusbh_block_info_t* blocks); +int msc_ff_unmount(tusbh_interface_t* interface); + +static const tusbh_msc_class_t cls_msc_bot = { + .backend = &tusbh_msc_bot_backend, + // .mount = msc_ff_mount, + // .unmount = msc_ff_unmount, +}; + +static const tusbh_cdc_acm_class_t cls_cdc_acm = { + .backend = &tusbh_cdc_acm_backend, +}; + +static const tusbh_cdc_rndis_class_t cls_cdc_rndis = { + .backend = &tusbh_cdc_rndis_backend, +}; + +static const tusbh_class_reg_t class_table[] = { + (tusbh_class_reg_t)&cls_boot_key, + (tusbh_class_reg_t)&cls_boot_mouse, + (tusbh_class_reg_t)&cls_hub, + (tusbh_class_reg_t)&cls_msc_bot, + (tusbh_class_reg_t)&cls_cdc_acm, + (tusbh_class_reg_t)&cls_cdc_rndis, + (tusbh_class_reg_t)&cls_hid, + (tusbh_class_reg_t)&cls_vendor, + 0, +}; + +#define MOD_CTRL (0x01 | 0x10) +#define MOD_SHIFT (0x02 | 0x20) +#define MOD_ALT (0x04 | 0x40) +#define MOD_WIN (0x08 | 0x80) + +#define LED_NUM_LOCK 1 +#define LED_CAPS_LOCK 2 +#define LED_SCROLL_LOCK 4 + +#define stdin_recvchar Serial1.write + +static uint8_t key_leds; +static const char knum[] = "1234567890"; +static const char ksign[] = "!@#$%^&*()"; +static const char tabA[] = "\t -=[]\\#;'`,./"; +static const char tabB[] = "\t _+{}|~:\"~<>?"; + +// route the key event to stdin +static int process_key(tusbh_ep_info_t* ep, const uint8_t* keys) +{ + Serial.println(); + + uint8_t modify = keys[0]; + uint8_t key = keys[2]; + uint8_t last_leds = key_leds; + if (key >= KEY_A && key <= KEY_Z) { + char ch = 'A' + key - KEY_A; + if ( (!!(modify & MOD_SHIFT)) == (!!(key_leds & LED_CAPS_LOCK)) ) { + ch += 'a' - 'A'; + } + stdin_recvchar(ch); + Serial.print(ch); + } else if (key >= KEY_1 && key <= KEY_0) { + if (modify & MOD_SHIFT) { + stdin_recvchar(ksign[key - KEY_1]); + } else { + stdin_recvchar(knum[key - KEY_1]); + } + } else if (key >= KEY_TAB && key <= KEY_SLASH) { + if (modify & MOD_SHIFT) { + stdin_recvchar(tabB[key - KEY_TAB]); + } else { + stdin_recvchar(tabA[key - KEY_TAB]); + } + } else if (key == KEY_ENTER) { + stdin_recvchar('\r'); + } else if (key == KEY_CAPSLOCK) { + key_leds ^= LED_CAPS_LOCK; + } else if (key == KEY_NUMLOCK) { + key_leds ^= LED_NUM_LOCK; + } else if (key == KEY_SCROLLLOCK) { + key_leds ^= LED_SCROLL_LOCK; + } + + if (key_leds != last_leds) { + tusbh_set_keyboard_led(ep, key_leds); + } + return 0; +} diff --git a/examples/USB_host/USB_host.ino b/examples/USB_host/USB_host.ino index 7722be0..0fa9695 100644 --- a/examples/USB_host/USB_host.ino +++ b/examples/USB_host/USB_host.ino @@ -1,164 +1,37 @@ /* - _______ _ _ _____ ____ - |__ __| | | | |/ ____| _ \ - | | ___ ___ _ __ _ _| | | | (___ | |_) | - | |/ _ \/ _ \ '_ \| | | | | | |\___ \| _ < - | | __/ __/ | | | |_| | |__| |____) | |_) | - |_|\___|\___|_| |_|\__, |\____/|_____/|____/ - __/ | - |___/ + * IMPORTANT NOTE: + * + * This example is associated with the deprecated Arduino_MachineControl library. + * We have introduced a new and improved library called Arduino_PortentaMachineControl, which offers enhanced features + * and ongoing support. + * We encourage you to update your projects to use the new library. + * + * The functions and syntax in this example are not compatible with Arduino_PortentaMachineControl. + * Please refer to the migration guide for necessary adjustments. + */ - TeenyUSB - light weight usb stack for STM32 micro controllers - - Copyright (c) 2019 XToolBox - admin@xtoolbox.org - www.tusb.org - - 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. -*/ #include +#include + +#include "TUSB_helpers.h" using namespace machinecontrol; +// Redirect log output from MbedOS and low-level libraries to Serial REDIRECT_STDOUT_TO(Serial); -static int process_key(tusbh_ep_info_t* ep, const uint8_t* key); - -static const tusbh_boot_key_class_t cls_boot_key = { - .backend = &tusbh_boot_keyboard_backend, - //.on_key = process_key -}; - -static const tusbh_boot_mouse_class_t cls_boot_mouse = { - .backend = &tusbh_boot_mouse_backend, - // .on_mouse = process_mouse -}; - -static const tusbh_hid_class_t cls_hid = { - .backend = &tusbh_hid_backend, - //.on_recv_data = process_hid_recv, - //.on_send_done = process_hid_sent, -}; - -static const tusbh_hub_class_t cls_hub = { - .backend = &tusbh_hub_backend, -}; - -static const tusbh_vendor_class_t cls_vendor = { - .backend = &tusbh_vendor_backend, - //.transfer_done = process_vendor_xfer_done -}; - -int msc_ff_mount(tusbh_interface_t* interface, int max_lun, const tusbh_block_info_t* blocks); -int msc_ff_unmount(tusbh_interface_t* interface); - -static const tusbh_msc_class_t cls_msc_bot = { - .backend = &tusbh_msc_bot_backend, - // .mount = msc_ff_mount, - // .unmount = msc_ff_unmount, -}; - -static const tusbh_cdc_acm_class_t cls_cdc_acm = { - .backend = &tusbh_cdc_acm_backend, -}; - -static const tusbh_cdc_rndis_class_t cls_cdc_rndis = { - .backend = &tusbh_cdc_rndis_backend, -}; - -static const tusbh_class_reg_t class_table[] = { - (tusbh_class_reg_t)&cls_boot_key, - (tusbh_class_reg_t)&cls_boot_mouse, - (tusbh_class_reg_t)&cls_hub, - (tusbh_class_reg_t)&cls_msc_bot, - (tusbh_class_reg_t)&cls_cdc_acm, - (tusbh_class_reg_t)&cls_cdc_rndis, - (tusbh_class_reg_t)&cls_hid, - (tusbh_class_reg_t)&cls_vendor, - 0, -}; - +USBHost usb; void setup() { Serial1.begin(115200); - usb_controller.init(class_table); + usb_controller.powerEnable(); + usb.Init(USB_CORE_ID_FS, class_table); } void loop() { - usb_controller.usb.Task(); + usb.Task(); } -#define MOD_CTRL (0x01 | 0x10) -#define MOD_SHIFT (0x02 | 0x20) -#define MOD_ALT (0x04 | 0x40) -#define MOD_WIN (0x08 | 0x80) -#define LED_NUM_LOCK 1 -#define LED_CAPS_LOCK 2 -#define LED_SCROLL_LOCK 4 - -#define stdin_recvchar Serial1.write - -static uint8_t key_leds; -static const char knum[] = "1234567890"; -static const char ksign[] = "!@#$%^&*()"; -static const char tabA[] = "\t -=[]\\#;'`,./"; -static const char tabB[] = "\t _+{}|~:\"~<>?"; -// route the key event to stdin -static int process_key(tusbh_ep_info_t* ep, const uint8_t* keys) -{ - printf("\n"); - uint8_t modify = keys[0]; - uint8_t key = keys[2]; - uint8_t last_leds = key_leds; - if (key >= KEY_A && key <= KEY_Z) { - char ch = 'A' + key - KEY_A; - if ( (!!(modify & MOD_SHIFT)) == (!!(key_leds & LED_CAPS_LOCK)) ) { - ch += 'a' - 'A'; - } - stdin_recvchar(ch); - Serial.print(ch); - } else if (key >= KEY_1 && key <= KEY_0) { - if (modify & MOD_SHIFT) { - stdin_recvchar(ksign[key - KEY_1]); - } else { - stdin_recvchar(knum[key - KEY_1]); - } - } else if (key >= KEY_TAB && key <= KEY_SLASH) { - if (modify & MOD_SHIFT) { - stdin_recvchar(tabB[key - KEY_TAB]); - } else { - stdin_recvchar(tabA[key - KEY_TAB]); - } - } else if (key == KEY_ENTER) { - stdin_recvchar('\r'); - } else if (key == KEY_CAPSLOCK) { - key_leds ^= LED_CAPS_LOCK; - } else if (key == KEY_NUMLOCK) { - key_leds ^= LED_NUM_LOCK; - } else if (key == KEY_SCROLLLOCK) { - key_leds ^= LED_SCROLL_LOCK; - } - - if (key_leds != last_leds) { - tusbh_set_keyboard_led(ep, key_leds); - } - return 0; -} diff --git a/library.properties b/library.properties index c3e9c2c..4f5ea82 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,11 @@ name=Arduino_MachineControl -version=1.0.0 +version=1.1.2 author=Arduino maintainer=Arduino -sentence=Arduino Library for Arduino Machine Control -paragraph= +sentence=DEPRECATED. Arduino Library for Portenta Machine Control - PMC +paragraph=This library is no longer actively maintained and is deprecated. Consider migrating to the Arduino_PortentaMachineControl library. category=Communication url=https://github.com/arduino-libraries/Arduino_MachineControl architectures=mbed, mbed_portenta includes=Arduino_MachineControl.h +depends=ArduinoRS485 diff --git a/src/Arduino_MachineControl.h b/src/Arduino_MachineControl.h index 2fe6102..d7088c2 100644 --- a/src/Arduino_MachineControl.h +++ b/src/Arduino_MachineControl.h @@ -3,38 +3,89 @@ #include "utility/MAX31865/MAX31865.h" #include "utility/THERMOCOUPLE/MAX31855.h" -#include "utility/RS485/RS485.h" +#include #include "utility/QEI/QEI.h" #include "utility/ioexpander/ArduinoIOExpander.h" #include "utility/RTC/PCF8563T.h" #include "utility/RTC/PCF8563T.h" -#include "Arduino.h" -#include "mbed.h" +#include +#include +#include -#include "USBHost.h" +#if __has_include("portenta_info.h") +#include "portenta_info.h" +#define TRY_REV2_RECOGNITION +uint8_t* boardInfo(); +#define PMC_R2_SKU (24 << 8 | 3) +#endif namespace machinecontrol { +/** + * The RTDClass allows enabling and selecting the different temperature sensor inputs + * (RTD and thermocouples) + */ class RTDClass { public: + + /** + * Select the input channel to be read (3 channels available) + * + * @param channel (0-2) + */ void selectChannel(int channel) { + +#ifdef TRY_REV2_RECOGNITION + // check if OTP data is present AND the board is mounted on a r2 carrier + auto info = (PortentaBoardInfo*)boardInfo(); + if (info->magic == 0xB5 && info->carrier == PMC_R2_SKU) { + // reverse channels 0 and 2 + switch (channel) { + case 0: + channel = 2; + break; + case 2: + channel = 0; + break; + default: + break; + } + } +#endif +#undef TRY_REV2_RECOGNITION + for (int i=0; i<3; i++) { ch_sel[i] = (i == channel ? 1 : 0); } delay(150); } + + /** + * Enable the CS of the Thermocouple to digital converter + * Disable the CS for the RTD to digital converter + */ void enableTC() { rtd_th = 0; digitalWrite(PI_0, LOW); digitalWrite(PA_6, HIGH); } + + /** + * Enable the CS of the RDT to digital converter. + * Disable the CS of the Thermocouple to digital converter + */ void enableRTD() { rtd_th = 1; digitalWrite(PI_0, HIGH); digitalWrite(PA_6, LOW); } + + /** + * Disable Chip select for both RTD and thermocouple digital converters. + * + */ void disableCS() { digitalWrite(PI_0, HIGH); digitalWrite(PA_6, HIGH); @@ -50,35 +101,74 @@ class RTDClass { extern RTDClass temp_probes; -static mbed::CAN _can(PB_8, PH_13); - +/** + * The COMMClass is used to initialize the CAN and RS485 LEDs and + * establish the power mode of the CAN bus. + */ class COMMClass { public: // to be tested: check if can be made a big pin initialization + + /** + * Shutdown RS485 and CAN LEDs + */ void init() { //SHUTDOWN OF RS485 LEDS - digitalWrite(PA_0, LOW); - digitalWrite(PI_9, LOW); + digitalWrite(PinNameToIndex(PA_0), LOW); + digitalWrite(PinNameToIndex(PI_9), LOW); //SHUTDOWN OF CAN LEDS - digitalWrite(PB_8, LOW); - digitalWrite(PH_13, LOW); - } - + digitalWrite(PinNameToIndex(PB_8), HIGH); + digitalWrite(PinNameToIndex(PH_13), HIGH); + + // SET DEFAULTS for RS485 + rs485Enable(false); + rs485ModeRS232(false); + rs485FullDuplex(false); + rs485YZTerm(false); + rs485ABTerm(false); + rs485Slew(false); + } + + /** + * Set the CAN transceiver in Normal mode. In this mode, the transceiver + * can transmit and receive data via the bus lines CANH and CANL. + */ void enableCAN() { can_disable = 0; } + + /** + * Set the CAN transceiver in standby (low power) mode. In this mode the + * transceiver will not be able to transmit or correctly receive data via the bus lines. + * The wake-up filter on the output of the low-power receiver does not latch bus dominant states, + * but ensures that only bus dominant and bus recessive states that persist longer than tfltr(wake) + * bus are reflected on pin RXD. + */ void disableCAN() { can_disable = 1; } - UART _UART4_ = arduino::UART(PA_0, PI_9, NC, NC); - mbed::CAN& can = _can; + arduino::UART _UART4_ {PA_0, PI_9, NC, NC}; + mbed::CAN can {PB_8, PH_13}; - RS485Class rs485 = RS485Class(_UART4_,PA_0, PI_13,PI_10); -private: - mbed::DigitalOut can_disable = mbed::DigitalOut(PA_13, 0); + RS485Class rs485 {_UART4_, PinNameToIndex(PA_0), PinNameToIndex(PI_13), PinNameToIndex(PI_10)}; + void rs485Enable(bool enable) { digitalWrite(PinNameToIndex(PG_9), enable ? HIGH : LOW); } + void rs485ModeRS232(bool enable) { digitalWrite(PinNameToIndex(PA_10), enable ? LOW : HIGH); } + void rs485YZTerm(bool enable) { digitalWrite(PinNameToIndex(PI_15), enable ? HIGH : LOW); } + void rs485ABTerm(bool enable) { digitalWrite(PinNameToIndex(PI_14), enable ? HIGH : LOW); } + void rs485Slew(bool enable) { digitalWrite(PinNameToIndex(PG_14), enable ? LOW : HIGH); } + void rs485FullDuplex(bool enable) { + digitalWrite(PinNameToIndex(PA_9), enable ? LOW : HIGH); + if (enable) { + // RS485 Full Duplex require YZ and AB 120 Ohm termination enabled + rs485YZTerm(true); + rs485ABTerm(true); + } + } +private: + mbed::DigitalOut can_disable = mbed::DigitalOut(PA_13, 0); }; extern COMMClass comm_protocols; @@ -96,8 +186,18 @@ extern COMMClass comm_protocols; #define ch2_in3 ch_in[10] #define ch2_in4 ch_in[11] +/** + * The AnalogInClass is used to set the resistor configuration for the right type of analog sensor + * i.e. NTC sensors, 4-10mA or 0-10V. + */ class AnalogInClass { public: + + /** + * read the sampled voltage from the selected channel + * @param channel integer for selecting the analog input (0, 1 or 2) + * @return the analog value between 0.0 and 1.0 normalized to a 16-bit value (uint16_t) + */ uint16_t read(int channel) { uint16_t value = 0; switch (channel) { @@ -113,10 +213,13 @@ class AnalogInClass { default: break; } - delay(20); return value; } + /** + * Configure the input resistor dividers to have a ratio of 0.28. + * Maximum input voltage is 10V. + */ void set0_10V() { ch0_in1 = 1; ch0_in2 = 1; @@ -134,6 +237,10 @@ class AnalogInClass { ch2_in4 = 1; } + /** + * Enable a 120 ohm resistor to GND to convert the 4-20mA sensor currents to voltage. + * Note: 24V are available from the carrier to power the 4-20mA sensors. + */ void set4_20mA() { ch0_in1 = 1; ch0_in2 = 0; @@ -151,6 +258,10 @@ class AnalogInClass { ch2_in4 = 0; } + /** + * Enable a 100K resistor in series with the reference voltage. + * The voltage sampled is the voltage division between the 100k resistor and the input resistor (NTC/PTC) + */ void setNTC() { ch0_in1 = 0; ch0_in2 = 0; @@ -193,141 +304,14 @@ class AnalogInClass { extern AnalogInClass analog_in; -class AnalogOutPWMClass { -public: - AnalogOutPWMClass() { - GPIO_InitTypeDef GPIO_InitStruct; - - // Enables peripherals and GPIO Clocks HRTIM1 Peripheral clock enable - __HAL_RCC_HRTIM1_CLK_ENABLE(); - - // Enable GPIO Channels Clock - __HAL_RCC_GPIOG_CLK_ENABLE(); - - // Configure HRTIMA TIMA TA1/A2, TIMB TB1/2, TIMC TC1/2, TIMD TD1/2 and TIME TE1.2 - // channels as alternate function mode - - GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; - GPIO_InitStruct.Pull = GPIO_PULLUP; - GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; - GPIO_InitStruct.Alternate = GPIO_AF2_HRTIM1; - GPIO_InitStruct.Pin = GPIO_PIN_7; - HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - - // Configure the HRTIM peripheral - // Initialize the HRTIM structure - HrtimHandle.Instance = HRTIM1; - HrtimHandle.Init.HRTIMInterruptResquests = HRTIM_IT_NONE; - HrtimHandle.Init.SyncOptions = HRTIM_SYNCOPTION_NONE; - - HAL_HRTIM_Init(&HrtimHandle); - - // Configure the HRTIM TIME PWM channels 2 - sConfig_time_base.Mode = HRTIM_MODE_CONTINUOUS; - sConfig_time_base.Period = 100; - sConfig_time_base.PrescalerRatio = HRTIM_PRESCALERRATIO_DIV1; - sConfig_time_base.RepetitionCounter = 0; - - HAL_HRTIM_TimeBaseConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, &sConfig_time_base); - - sConfig_timerE.DMARequests = HRTIM_TIM_DMA_NONE; - sConfig_timerE.HalfModeEnable = HRTIM_HALFMODE_DISABLED; - sConfig_timerE.StartOnSync = HRTIM_SYNCSTART_DISABLED; - sConfig_timerE.ResetOnSync = HRTIM_SYNCRESET_DISABLED; - sConfig_timerE.DACSynchro = HRTIM_DACSYNC_NONE; - sConfig_timerE.PreloadEnable = HRTIM_PRELOAD_ENABLED; - sConfig_timerE.UpdateGating = HRTIM_UPDATEGATING_INDEPENDENT; - sConfig_timerE.BurstMode = HRTIM_TIMERBURSTMODE_MAINTAINCLOCK; - sConfig_timerE.RepetitionUpdate = HRTIM_UPDATEONREPETITION_ENABLED; - sConfig_timerE.ResetUpdate = HRTIM_TIMUPDATEONRESET_DISABLED; - sConfig_timerE.InterruptRequests = HRTIM_TIM_IT_NONE; - sConfig_timerE.PushPull = HRTIM_TIMPUSHPULLMODE_DISABLED; - sConfig_timerE.FaultEnable = HRTIM_TIMFAULTENABLE_NONE; - sConfig_timerE.FaultLock = HRTIM_TIMFAULTLOCK_READWRITE; - sConfig_timerE.DeadTimeInsertion = HRTIM_TIMDEADTIMEINSERTION_DISABLED; - sConfig_timerE.DelayedProtectionMode = HRTIM_TIMER_D_E_DELAYEDPROTECTION_DISABLED; - sConfig_timerE.UpdateTrigger= HRTIM_TIMUPDATETRIGGER_NONE; - sConfig_timerE.ResetTrigger = HRTIM_TIMRESETTRIGGER_NONE; - - HAL_HRTIM_WaveformTimerConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E,&sConfig_timerE); - - sConfig_compare.AutoDelayedMode = HRTIM_AUTODELAYEDMODE_REGULAR; - sConfig_compare.AutoDelayedTimeout = 0; - sConfig_compare.CompareValue = 1; - - HAL_HRTIM_WaveformCompareConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, HRTIM_COMPAREUNIT_2, &sConfig_compare); - - sConfig_output_config.Polarity = HRTIM_OUTPUTPOLARITY_LOW; - sConfig_output_config.SetSource = HRTIM_OUTPUTRESET_TIMCMP2; - sConfig_output_config.ResetSource = HRTIM_OUTPUTSET_TIMPER; - sConfig_output_config.IdleMode = HRTIM_OUTPUTIDLEMODE_NONE; - sConfig_output_config.IdleLevel = HRTIM_OUTPUTIDLELEVEL_INACTIVE; - sConfig_output_config.FaultLevel = HRTIM_OUTPUTFAULTLEVEL_NONE; - sConfig_output_config.ChopperModeEnable = HRTIM_OUTPUTCHOPPERMODE_DISABLED; - sConfig_output_config.BurstModeEntryDelayed = HRTIM_OUTPUTBURSTMODEENTRY_REGULAR; - sConfig_output_config.ResetSource = HRTIM_OUTPUTRESET_TIMPER; - sConfig_output_config.SetSource = HRTIM_OUTPUTSET_TIMCMP2; - - HAL_HRTIM_WaveformOutputConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, HRTIM_OUTPUT_TE2, &sConfig_output_config); - - // Start PWM signals generation - if (HAL_HRTIM_WaveformOutputStart(&HrtimHandle, HRTIM_OUTPUT_TE2) != HAL_OK) - { - // PWM Generation Error - } - - // Start HRTIM counter - if (HAL_HRTIM_WaveformCounterStart(&HrtimHandle, HRTIM_TIMERID_TIMER_E) != HAL_OK) - { - // PWM Generation Error - } - } - - ~AnalogOutPWMClass(){} - void period_ms(int period) { - sConfig_time_base.Mode = HRTIM_MODE_CONTINUOUS; - sConfig_time_base.Period = period; - sConfig_time_base.PrescalerRatio = HRTIM_PRESCALERRATIO_DIV1; - sConfig_time_base.RepetitionCounter = 0; - - HAL_HRTIM_TimeBaseConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, &sConfig_time_base); - } - - bool write(uint8_t pulse) { - if (pulse > 100) { - pulse = 100; - } - sConfig_compare.CompareValue = pulse; - if (HAL_HRTIM_WaveformCompareConfig(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, HRTIM_COMPAREUNIT_2, &sConfig_compare) != HAL_OK) - { - return false; - } - return true; - } - - bool stop() { - if (HAL_HRTIM_SimplePWMStop(&HrtimHandle, HRTIM_TIMERINDEX_TIMER_E, HRTIM_OUTPUT_TE2) != HAL_OK) - { - return false; - } - return true; - } - -private: - HRTIM_HandleTypeDef HrtimHandle; - - HRTIM_TimeBaseCfgTypeDef sConfig_time_base; - HRTIM_TimerCfgTypeDef sConfig_timerE; - HRTIM_OutputCfgTypeDef sConfig_output_config; - HRTIM_CompareCfgTypeDef sConfig_compare; -}; - - -extern AnalogOutPWMClass analopwm; - - class AnalogOutClass { public: + + /** + * Set output voltage value (PWM) + * @param index select channel + * @param voltage desired output voltage (max 10.5V) + */ void write(int index, float voltage) { if (voltage < 0) { voltage = 0; @@ -341,13 +325,19 @@ class AnalogOutClass { out_1.write(voltage / 10.5); break; case 2: - out_2.write((voltage*9.5)); + out_2.write(voltage / 10.5); break; case 3: out_3.write(voltage / 10.5); break; } } + + /** + * Set the PWM period (frequency) + * @param index select channel + * @param period integer for selecting the period in ms + */ void period_ms(int index, uint8_t period) { switch (index) { case 0: @@ -357,7 +347,7 @@ class AnalogOutClass { out_1.period_ms(period); break; case 2: - out_2.period_ms((period/4)*100); + out_2.period_ms(period); break; case 3: out_3.period_ms(period); @@ -370,8 +360,8 @@ class AnalogOutClass { return out_0; case 1: return out_1; - //case 2: - //return out_2; + case 2: + return out_2; case 3: return out_3; } @@ -379,7 +369,7 @@ class AnalogOutClass { private: mbed::PwmOut out_0 = mbed::PwmOut(PJ_11); mbed::PwmOut out_1 = mbed::PwmOut(PK_1); - AnalogOutPWMClass out_2 = AnalogOutPWMClass(); + mbed::PwmOut out_2 = mbed::PwmOut(PG_7); mbed::PwmOut out_3 = mbed::PwmOut(PC_7); }; @@ -390,12 +380,21 @@ extern AnalogOutClass analog_out; TODO: writeme Use QEI library for mbed since it implements index pin */ - -static QEI _enc_0(PJ_8, PH_12, PH_11, 0); -static QEI _enc_1(PC_13, PI_7, PJ_10, 0); - + /** + * The EncoderClass is a wrapper for manipulating Quadrature Encoder Interface devices. + */ class EncoderClass { public: + /** + * returns the encoder variable depending on the index + * @param index integer for selecting the encoder (0 or 1) + * @return enc_0 for index = 0, enc_1 for index = 1 + */ + EncoderClass() + : enc_0{PJ_8, PH_12, PH_11, 0} + , enc_1{PC_13, PI_7, PJ_10, 0} {}; + + QEI& operator[](int index) { switch (index) { case 0: @@ -405,8 +404,8 @@ class EncoderClass { } } private: - QEI& enc_0 = _enc_0; - QEI& enc_1 = _enc_1; + QEI enc_0; + QEI enc_1; }; extern EncoderClass encoders; @@ -420,14 +419,35 @@ extern EncoderClass encoders; TODO: check if Wire and address are correct */ + +/** + * The ProgrammableDIOClass is used to initialize the IOExpanders and configure the + * thermal shutdown mode of the high side switches. + */ class ProgrammableDIOClass : public ArduinoIOExpanderClass { public: + + /** + * Test connection with the IOExpander and set all the pins to the default mode. + * @return true if OK, false if fault + */ bool init() { return begin(IO_ADD); } + + /** + * Configures the thermal shutdown of the high-side switches (TPS4H160) to operate in latch mode. + * The output latches off when thermal shutdown occurs. + */ void setLatch() { prog_latch_retry = 0; } + + /** + * Configures the thermal shutdown of the high-side switches (TPS4H160) to operate in auto-retry mode. + * The output automatically recovers when TJ < T(SD) – T(hys), but the current is limited to ICL(TSD) + * to avoid repetitive thermal shutdown. + */ void setRetry() { prog_latch_retry = 1; } @@ -438,20 +458,48 @@ class ProgrammableDIOClass : public ArduinoIOExpanderClass { extern ProgrammableDIOClass digital_programmables; +/** + * The DigitalOutputClass is used to interface with the IO Expander and + * set the digital outputs. + */ class DigitalOutputsClass { public: + + /** + * Set all digital outputs at the same time. + * @param val 8 bit integer to set all 8 channels. e.g: + * Set all to HIGH -> val = 255 (0b11111111) + * Set all to LOW -> val = 0 (0b00000000) + */ void setAll(uint8_t val) { for (int i = 0; i < 8; i++) { out[i] = val & 0x1; val = val >> 1; } } + + /** + * Set a particular digital output + * @param index digital output to be set + * @param val set value (HIGH/LOW) + */ void set(int index, bool val) { out[index] = val; } + + /** + * Configures the thermal shutdown of the high-side switches (TPS4H160) to operate in latch mode. + * The output latches off when thermal shutdown occurs. + */ void setLatch() { dig_out_latch_retry = 0; } + + /** + * Configures the thermal shutdown of the high-side switches (TPS4H160) to operate in auto-retry mode. + * The output automatically recovers when TJ < T(SD) – T(hys), but the current is limited to ICL(TSD) + * to avoid repetitive thermal shutdown. + */ void setRetry() { dig_out_latch_retry = 1; } @@ -470,6 +518,10 @@ extern DigitalOutputsClass digital_outputs; class ProgrammableDINClass : public ArduinoIOExpanderClass { public: + /** + * Test connection with the IOExpander and set all the pins to the default mode. + * @return true if OK, false if fault + */ bool init() { return begin(DIN_ADD); } @@ -477,7 +529,11 @@ class ProgrammableDINClass : public ArduinoIOExpanderClass { extern ProgrammableDINClass digital_inputs; - +/** + * The RtcControllerClass is a wrapper for the PCF8563TClass() that is used to + * set and get the time to/from the PCF8563T RTC. + * + */ class RtcControllerClass : public PCF8563TClass { public: mbed::DigitalIn int_pin = mbed::DigitalIn(PB_9,PullUp); @@ -488,30 +544,43 @@ class RtcControllerClass : public PCF8563TClass { extern RtcControllerClass rtc_controller; - +/** + * The USB Class is used to enable/disable the power of the USBA (Host) and configure + * the callbacks for the different host types (i.e. Keyboard, mouse, storage device etc). + */ class USBClass { public: - void init(const tusbh_class_reg_t *class_table) { - usb.Init(USB_CORE_ID_FS, class_table); - } - + USBClass() + : _power{PB_14, 0} + , _usbflag{PB_15} + {}; + + /** + * Enable power to USBA VBUS. + */ void powerEnable() { - power = 0; + _power = 0; } + /** + * Disable power to USBA VBUS. + */ void powerDisable() { - power = 1; + _power = 1; } + /** + * Flag to indicate overcurrent, overtemperature, or reverse−voltage conditions on the USBA VBUS. + * Active−low open−drain output. + * @return true if OK, false if fault + */ bool vflagRead() { - return usbflag; + return _usbflag; } - USBHost usb; - private: - mbed::DigitalOut power = mbed::DigitalOut(PB_14); - mbed::DigitalIn usbflag = mbed::DigitalIn(PB_15); + mbed::DigitalOut _power; + mbed::DigitalIn _usbflag; }; diff --git a/src/utility/QEI/QEI.cpp b/src/utility/QEI/QEI.cpp index 22f32e4..db767db 100644 --- a/src/utility/QEI/QEI.cpp +++ b/src/utility/QEI/QEI.cpp @@ -152,7 +152,9 @@ QEI::QEI(PinName channelA, //X4 encoding uses interrupts on channel A, //and on channel B. channelA_.rise(mbed::callback(this, &QEI::encode)); - channelA_.fall(mbed::callback(this, &QEI::encode)); + if(encoding != X1_ENCODING){ + channelA_.fall(mbed::callback(this, &QEI::encode)); + } //If we're using X4 encoding, then attach interrupts to channel B too. if (encoding == X4_ENCODING) { @@ -191,6 +193,20 @@ int QEI::getRevolutions(void) { } +// +-------------+ +// | X1 Encoding | +// +-------------+ +// +// When observing states two patterns will appear: +// +// Counter clockwise rotation: +// +// 10 -> 10 -> 10 -> 10 -> ... +// +// Clockwise rotation: +// +// 11 -> 11 -> 11 -> ... +// // +-------------+ // | X2 Encoding | // +-------------+ @@ -243,8 +259,15 @@ void QEI::encode(void) { //2-bit state. currState_ = (chanA << 1) | (chanB); - - if (encoding_ == X2_ENCODING) { + + if(encoding_ == X1_ENCODING){ + if(currState_ == 0x3){ + pulses_++; + } + if(currState_ == 0x2){ + pulses_--; + } + } else if (encoding_ == X2_ENCODING) { //11->00->11->00 is counter clockwise rotation or "forward". if ((prevState_ == 0x3 && currState_ == 0x0) || diff --git a/src/utility/QEI/QEI.h b/src/utility/QEI/QEI.h index 5ab79d2..8e6fba0 100644 --- a/src/utility/QEI/QEI.h +++ b/src/utility/QEI/QEI.h @@ -148,7 +148,7 @@ class QEI { public: typedef enum Encoding { - + X1_ENCODING, X2_ENCODING, X4_ENCODING diff --git a/src/utility/RS485/RS485.cpp b/src/utility/RS485/RS485.cpp deleted file mode 100644 index 5b544ad..0000000 --- a/src/utility/RS485/RS485.cpp +++ /dev/null @@ -1,178 +0,0 @@ -/* - This file is part of the ArduinoRS485 library. - Copyright (c) 2020 Arduino SA. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#include "RS485.h" - -RS485Class::RS485Class(HardwareSerial& hwSerial, PinName txPin, PinName dePin, PinName rePin) : - _serial(&hwSerial), - _txPin(txPin), - _dePin(dePin), - _rePin(rePin), - _transmisionBegun(false) -{ -} - -void RS485Class::begin(unsigned long baudrate) -{ - begin(baudrate, SERIAL_8N1); -} - -void RS485Class::begin(unsigned long baudrate, uint16_t config) -{ - _baudrate = baudrate; - _config = config; - - if (_dePin != NC) { - pinMode(_dePin, OUTPUT); - digitalWrite(_dePin, LOW); - } - - if (_rePin != NC) { - pinMode(_rePin, OUTPUT); - digitalWrite(_rePin, HIGH); - } - - _transmisionBegun = false; - - half_duplex.output(); - - _serial->begin(baudrate, config); -} - -void RS485Class::end() -{ - _serial->end(); - - if (_rePin != NC) { - digitalWrite(_rePin, LOW); - pinMode(_dePin, INPUT); - } - - if (_dePin != NC) { - digitalWrite(_dePin, LOW); - pinMode(_rePin, INPUT); - } -} - -int RS485Class::available() -{ - return _serial->available(); -} - -int RS485Class::peek() -{ - return _serial->peek(); -} - -int RS485Class::read(void) -{ - return _serial->read(); -} - -size_t RS485Class::readBytes(char *buf, size_t length) -{ - return _serial->readBytes(buf, length); -} - -void RS485Class::flush() -{ - return _serial->flush(); -} - -size_t RS485Class::write(uint8_t b) -{ - if (!_transmisionBegun) { - setWriteError(); - return 0; - } - - return _serial->write(b); -} - -RS485Class::operator bool() -{ - return true; -} - -void RS485Class::beginTransmission() -{ - if (_dePin > -1) { - digitalWrite(_dePin, HIGH); - delayMicroseconds(50); - } - - _transmisionBegun = true; -} - -void RS485Class::endTransmission() -{ - _serial->flush(); - - if (_dePin != NC) { - delayMicroseconds(500); - digitalWrite(_dePin, LOW); - } - - _transmisionBegun = false; -} - -void RS485Class::receive() -{ - if (_rePin != NC) { - digitalWrite(_rePin, LOW); - } -} - -void RS485Class::noReceive() -{ - if (_rePin != NC) { - digitalWrite(_rePin, HIGH); - } -} - -void RS485Class::sendBreak(unsigned int duration) -{ - _serial->flush(); - _serial->end(); - if (_txPin != NC) { - pinMode(_txPin, OUTPUT); - digitalWrite(_txPin, LOW); - } - delay(duration); - _serial->begin(_baudrate, _config); -} - -void RS485Class::sendBreakMicroseconds(unsigned int duration) -{ - _serial->flush(); - _serial->end(); - if (_txPin != NC) { - pinMode(_txPin, OUTPUT); - digitalWrite(_txPin, LOW); - } - delayMicroseconds(duration); - _serial->begin(_baudrate, _config); -} - -void RS485Class::setPins(PinName txPin, PinName dePin, PinName rePin) -{ - _txPin = txPin; - _dePin = dePin; - _rePin = rePin; -} diff --git a/src/utility/RS485/RS485.h b/src/utility/RS485/RS485.h deleted file mode 100644 index dbe8eea..0000000 --- a/src/utility/RS485/RS485.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - This file is part of the ArduinoRS485 library. - Copyright (c) 2020 Arduino SA. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -*/ - -#ifndef _RS485_MACHINECONTROL_H_INCLUDED -#define _RS485_MACHINECONTROL_H_INCLUDED - -#include "Arduino.h" -#include "mbed.h" - -class RS485Class : public HardwareSerial { - public: - RS485Class(HardwareSerial& hwSerial, PinName txPin = NC, PinName dePin = NC, PinName rePin = NC); - - virtual void begin(unsigned long baudrate); - virtual void begin(unsigned long baudrate, uint16_t config); - virtual void end(); - virtual int available(); - virtual int peek(); - virtual int read(void); - virtual size_t readBytes(char *buf, size_t length); - virtual size_t readBytes(uint8_t *buf, size_t length) { return readBytes((char *)buf, length); }; - virtual void flush(); - virtual size_t write(uint8_t b); - using Print::write; // pull in write(str) and write(buf, size) from Print - virtual operator bool(); - - void beginTransmission(); - void endTransmission(); - void receive(); - void noReceive(); - - void sendBreak(unsigned int duration); - void sendBreakMicroseconds(unsigned int duration); - - void setPins(PinName txPin, PinName dePin, PinName rePin); - - mbed::DigitalInOut half_duplex = mbed::DigitalInOut(PA_9); - mbed::DigitalOut sel_485 = mbed::DigitalOut(PA_10); - mbed::DigitalOut slew_n = mbed::DigitalOut(PG_14); - mbed::DigitalOut fd_tx_term = mbed::DigitalOut(PI_15); - mbed::DigitalOut term = mbed::DigitalOut(PI_14); - mbed::DigitalOut enable = mbed::DigitalOut(PG_9); - - private: - HardwareSerial* _serial; - PinName _txPin; - PinName _dePin = NC; - PinName _rePin = NC; - - - bool _transmisionBegun; - unsigned long _baudrate; - uint16_t _config; -}; - -#endif diff --git a/src/utility/RTC/PCF8563T.cpp b/src/utility/RTC/PCF8563T.cpp index 7998a9d..a21b36a 100644 --- a/src/utility/RTC/PCF8563T.cpp +++ b/src/utility/RTC/PCF8563T.cpp @@ -28,7 +28,7 @@ #define PCF8563T_MONTHS_REG 0x07 #define PCF8563T_YEARS_REG 0x08 -// allarm management +// alarm management #define PCF8563T_MINUTE_ALARM_REG 0x09 #define PCF8563T_MINUTE_ALARM_AE_M_MASK 0x80 #define PCF8563T_MINUTE_ALARM_ON 0x7F @@ -49,10 +49,20 @@ #define PCF8563T_STATUS_2_CLEAR_INT 0xF7 #define PCF8563T_STATUS_2_INT_OFF 0x7d +/** + * Object constructor + * + */ PCF8563TClass::PCF8563TClass() { } +/** + * Start the communication with the RTC + * Initialize I2C (Wire1) bus and check if the chip is connected by sending an ACK on the I2C bus. + * @return true if the RTC Controller is on the I2C bus, false if it is not. + * + */ bool PCF8563TClass::begin() { Wire1.begin(); // join i2c bus @@ -64,12 +74,22 @@ bool PCF8563TClass::begin() return false; } +/** + * Set Year number's value + * Save an unsigned byte with the Year's value + * @param years Year's unsigned byte + */ void PCF8563TClass::setYears(uint8_t years) { uint8_t dec = years / 10; uint8_t unit = years - (dec * 10); writeByte(PCF8563T_YEARS_REG, ((dec << 4) + unit)); } +/** + * Set Month number's value + * Save an unsigned byte with the Month's value + * @param months Month's unsigned byte (0 to 12) + */ void PCF8563TClass::setMonths(uint8_t months) { uint8_t offset = 0; if (months > 9) { @@ -78,35 +98,65 @@ void PCF8563TClass::setMonths(uint8_t months) { writeByte(PCF8563T_MONTHS_REG, months + offset); } +/** + * Set Day number's value + * Save an unsigned byte with the Day's value + * @param days day's unsigned byte + */ void PCF8563TClass::setDays(uint8_t days) { uint8_t dec = days / 10; uint8_t unit = days - (dec * 10); writeByte(PCF8563T_DAYS_REG, ((dec << 4) + unit)); } +/** + * Set Hour(s) number's value + * Save an unsigned byte with the Hour(s) value + * @param hours hour unsigned byte (0 - 23) + */ void PCF8563TClass::setHours(uint8_t hours) { uint8_t dec = hours / 10; uint8_t unit = hours - (dec * 10); writeByte(PCF8563T_HOURS_REG, ((dec << 4) + unit)); //check formula on datasheet val + 6 * (val / 10) } +/** + * Set Minute(s) number's value + * Save an unsigned byte with the Minute(s) value + * @param minutes minute unsigned byte (0-60) + */ void PCF8563TClass::setMinutes(uint8_t minutes) { uint8_t dec = minutes / 10; uint8_t unit = minutes - (dec * 10); writeByte(PCF8563T_MINUTES_REG, ((dec << 4) + unit)); } +/** + * Set Second(s) number's value + * Save an unsigned byte with the Second(s) value + * @param seconds Second(s) unsigned byte (0-60) + */ void PCF8563TClass::setSeconds(uint8_t seconds) { uint8_t dec = seconds / 10; uint8_t unit = seconds - (dec * 10); writeByte(PCF8563T_VL_SECONDS_REG, ((dec << 4) + unit)); } +/** + * Get Year(s) number's value + * Get unsigned byte with the Year(s) value + * @return byte with Year(s) value + */ uint8_t PCF8563TClass::getYears() { uint8_t years = readByte(PCF8563T_YEARS_REG); return (years & 0x0F) + ((years >> 4)*10); } +/** + * Get Month(s) month's value + * Get unsigned byte with the month(s) value + * @return byte with Month(s) value + */ uint8_t PCF8563TClass::getMonths() { uint8_t months = readByte(PCF8563T_MONTHS_REG) & 0x1F; if(months > 9) { @@ -116,27 +166,50 @@ uint8_t PCF8563TClass::getMonths() { } } +/** + * Get Day(s) number's value + * Get unsigned byte with the Day(s) value + * @return byte with Day(s) value + */ uint8_t PCF8563TClass::getDays() { - uint8_t days = readByte(PCF8563T_DAYS_REG); + uint8_t days = readByte(PCF8563T_DAYS_REG) & 0x3F; return (days & 0x0F) + ((days >> 4)*10); } +/** + * Get Hour(s) number's value + * Get unsigned byte with the Hour(s) value + * @return byte with Hour(s) value + */ uint8_t PCF8563TClass::getHours() { uint8_t hours = readByte(PCF8563T_HOURS_REG) & 0x3F; return (hours & 0x0F) + ((hours >> 4)*10); } +/** + * Get Minute(s) number's value + * Get unsigned byte with the Minute(s) value + * @return byte with Minute(s) value + */ uint8_t PCF8563TClass::getMinutes() { uint8_t minutes = (readByte(PCF8563T_MINUTES_REG)) & 0x7F ; return (minutes & 0x0F) + ((minutes >> 4)*10); } +/** + * Get Second(s) number's value + * Get unsigned byte with the Second(s) value + * @return byte with Second(s) value + */ uint8_t PCF8563TClass::getSeconds() { uint8_t seconds = readByte(PCF8563T_VL_SECONDS_REG) & 0x7F; return (seconds & 0x0F) + ((seconds >> 4)*10); } - +/** + * Set time Epoch format + * + */ void PCF8563TClass::setEpoch() { struct tm time; time.tm_sec = getSeconds(); @@ -150,6 +223,12 @@ void PCF8563TClass::setEpoch() { set_time(seconds); } +/** + * Set time with Epoch format + * + * + * @param seconds number of seconds (time_t type) + */ void PCF8563TClass::setEpoch(time_t seconds) { struct tm time; _rtc_localtime(seconds, &time, RTC_FULL_LEAP_YEAR_SUPPORT); @@ -163,7 +242,19 @@ void PCF8563TClass::setEpoch(time_t seconds) { set_time(seconds); } - +/** + * Set time with Epoch format + * + * Convert the input values to Epoch format + * example: Tue, 06 Jul 2021 11:55:27 GMT -> 1625572527 + * + * @param years number of years + * @param mohths number of months + * @param days number of days + * @param hours number of hours + * @param minutes number of minutes + * @param seconds number of seconds + */ void PCF8563TClass::setEpoch(uint8_t years, uint8_t months, uint8_t days, uint8_t hours, uint8_t minutes, uint8_t seconds) { struct tm time; time_t utcsec; @@ -179,6 +270,15 @@ void PCF8563TClass::setEpoch(uint8_t years, uint8_t months, uint8_t days, uint8_ set_time(utcsec); } +/** + * Get epoch number + * Convert real time to difference between actual time and Epoch(Unix time) + * Saved into time_t type + * + * example: 1625572527 -> Tue, 06 Jul 2021 11:55:27 GMT + * + * @return number of seconds after Unix time (time_t type) + */ time_t PCF8563TClass::getEpoch() { struct tm time; time_t seconds; @@ -194,18 +294,35 @@ time_t PCF8563TClass::getEpoch() { return seconds; } +/** + * Enable alarm + * + */ void PCF8563TClass::enableAlarm() { writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_CLEAR_INT) | PCF8563T_STATUS_2_AIE_MASK); } +/** + * Disable alarm + * + */ void PCF8563TClass::disableAlarm() { writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_INT_OFF)); } +/** + * Clear alarm status + * + */ void PCF8563TClass::clearAlarm() { writeByte(PCF8563T_STATUS_2_REG, (readByte(PCF8563T_STATUS_2_REG) & PCF8563T_STATUS_2_CLEAR_INT) | PCF8563T_STATUS_2_AIE_MASK); } +/** + * Set alarm's minute + * + * @param minutes minute(s) value for the Alarm (byte type) + */ void PCF8563TClass::setMinuteAlarm(uint8_t minutes) { uint8_t dec = minutes / 10; uint8_t unit = minutes - (dec * 10); @@ -213,21 +330,39 @@ void PCF8563TClass::setMinuteAlarm(uint8_t minutes) { writeByte(PCF8563T_MINUTE_ALARM_REG , min_alarm); } +/** + * Disable and clear the minute of the Alarm + * + */ void PCF8563TClass::disableMinuteAlarm() { writeByte(PCF8563T_MINUTE_ALARM_REG, readByte(PCF8563T_MINUTE_ALARM_REG) | PCF8563T_MINUTE_ALARM_AE_M_MASK); } +/** + * Set Alarm's hour + * + * @param hours hour(s) value for the Alarm (byte type) + */ void PCF8563TClass::setHourAlarm(uint8_t hours) { uint8_t dec = hours / 10; uint8_t unit = hours - (dec * 10); uint8_t hour_alarm = PCF8563T_HOUR_ALARM_AE_H_MASK & ((dec << 4) + unit); - writeByte(PCF8563T_HOURS_REG, hour_alarm); //check formula on datasheet val + 6 * (val / 10) + writeByte(PCF8563T_HOUR_ALARM_REG, hour_alarm); //check formula on datasheet val + 6 * (val / 10) } +/** + * Disable and clear the hour of the Alarm + * + */ void PCF8563TClass::disableHourAlarm() { writeByte(PCF8563T_HOUR_ALARM_REG, readByte(PCF8563T_HOUR_ALARM_REG) | PCF8563T_HOUR_ALARM_AE_H_MASK); } +/** + * Set Alarm's day + * + * @param days day value for the Alarm (byte type) + */ void PCF8563TClass::setDayAlarm(uint8_t days) { uint8_t dec = days / 10; uint8_t unit = days - (dec * 10); @@ -235,6 +370,10 @@ void PCF8563TClass::setDayAlarm(uint8_t days) { writeByte(PCF8563T_DAY_ALARM_REG, day_alarm); } +/** + * Disable and clear the day of the Alarm + * + */ void PCF8563TClass::disableDayAlarm() { writeByte(PCF8563T_DAY_ALARM_REG, readByte(PCF8563T_DAY_ALARM_REG) | PCF8563T_DAY_ALARM_AE_D_MASK ); } diff --git a/src/utility/THERMOCOUPLE/MAX31855.cpp b/src/utility/THERMOCOUPLE/MAX31855.cpp index 6053867..4e86718 100644 --- a/src/utility/THERMOCOUPLE/MAX31855.cpp +++ b/src/utility/THERMOCOUPLE/MAX31855.cpp @@ -19,10 +19,30 @@ #include "MAX31855.h" +const double MAX31855Class::Jm210_760[] ; +const double MAX31855Class::J760_1200[] ; +const double MAX31855Class::Km270_0[] ; +const double MAX31855Class::K0_1372[] ; + +const double MAX31855Class::InvJ_neg[] ; +const double MAX31855Class::InvJ0_760[] ; +const double MAX31855Class::InvJ760_1200[] ; + +const double MAX31855Class::InvK_neg[] ; +const double MAX31855Class::InvK0_500[] ; +const double MAX31855Class::InvK500_1372[] ; + +const MAX31855Class::coefftable MAX31855Class::CoeffJ[]; +const MAX31855Class::coefftable MAX31855Class::CoeffK[]; + +const MAX31855Class::coefftable MAX31855Class::InvCoeffJ[]; +const MAX31855Class::coefftable MAX31855Class::InvCoeffK[]; + MAX31855Class::MAX31855Class(int cs, SPIClass& spi) : _cs(cs), _spi(&spi), - _spiSettings(4000000, MSBFIRST, SPI_MODE0) + _spiSettings(4000000, MSBFIRST, SPI_MODE0), + _coldOffset(2.10f) { } @@ -72,10 +92,78 @@ uint32_t MAX31855Class::readSensor() return read; } +double MAX31855Class::polynomial(double value, int tableEntries, coefftable const (*table) ) +{ + double output = 0; + double valuePower = 1; + for (int i=0;i0) { + voltage += 0.118597600000E+00 * exp( -0.118343200000E-03 * pow(temp-0.126968600000E+03, 2)); + } + return voltage; +} + +double MAX31855Class::mvtoTemp(int type, double voltage) { + coefftable const (*table); + int tableEntries; + + switch (type) { + case PROBE_J: + table = InvCoeffJ; + tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable); + break; + case PROBE_K: + table = InvCoeffK; + tableEntries = sizeof(InvCoeffJ)/sizeof(coefftable); + break; + } + return polynomial(voltage, tableEntries, table); +} + float MAX31855Class::readTemperature(int type) { uint32_t rawword; - float celsius; + int32_t measuredTempInt; + int32_t measuredColdInt; + double measuredTemp; + double measuredCold; + double measuredVolt; rawword = readSensor(); @@ -83,23 +171,48 @@ float MAX31855Class::readTemperature(int type) if (rawword & 0x7) { return NAN; } - // The temperature is stored in the last 14 word's bits + // The cold junction temperature is stored in the last 14 word's bits + // whereas the ttermocouple temperature (non linearized) is in the topmost 18 bits // sent by the Thermocouple-to-Digital Converter + + // sign extend thermocouple value if (rawword & 0x80000000) { // Negative value, drop the lower 18 bits and explicitly extend sign bits. - rawword = 0xFFFFC000 | ((rawword >> 18) & 0x00003FFFF); + measuredTempInt = 0xFFFC0000 | ((rawword >> 18) & 0x00003FFFF); } else { // Positive value, just drop the lower 18 bits. - rawword >>= 18; + measuredTempInt = rawword>>18; } - // multiply for the LSB value - celsius = rawword * 0.25f; - if (type == PROBE_J) { - // conversion factor from K type to J type - celsius = celsius * 4/5; + // convert it to degrees + measuredTemp = measuredTempInt * 0.25f; + + // sign extend cold junction temperature + measuredColdInt = (rawword>>4)&0xfff; + if (measuredColdInt&0x800) { + // Negative value, sign extend + measuredColdInt |= 0xfffff000; } - return celsius; + + // convert it to degrees + measuredCold = (measuredColdInt/16.0f); + // now the tricky part... since MAX31855K is considering a linear response + // and is trimemd for K thermocouples, we have to convert the reading back + // to mV and then use NIST polynomial approximation to determine temperature + // we know that reading from chip is calculated as: + // temp = chip_temperature + thermocouple_voltage/0.041276f + // + // convert temperature to mV is accomplished converting the chip temperature + // to mV using NIST polynomial and then by adding the measured voltage + // calculated inverting the function above + // this way we calculate the voltage we would have measured if cold junction + // was at 0 degrees celsius + + measuredVolt = coldTempTomv(type, measuredCold - _coldOffset)+(measuredTemp - measuredCold) * 0.041276f; + + // finally from the cold junction compensated voltage we calculate the temperature + // using NIST polynomial approximation for the thermocouple type we are using + return mvtoTemp(type,measuredVolt); } float MAX31855Class::readReferenceTemperature(int type) @@ -126,4 +239,9 @@ float MAX31855Class::readReferenceTemperature(int type) return ref; } +void MAX31855Class::setColdOffset(float offset) +{ + _coldOffset = offset; +} + MAX31855Class THERM; diff --git a/src/utility/THERMOCOUPLE/MAX31855.h b/src/utility/THERMOCOUPLE/MAX31855.h index f5c2b3a..c2c5380 100644 --- a/src/utility/THERMOCOUPLE/MAX31855.h +++ b/src/utility/THERMOCOUPLE/MAX31855.h @@ -36,13 +36,66 @@ class MAX31855Class { float readTemperature(int type = PROBE_K); float readReferenceTemperature(int type = PROBE_K); + void setColdOffset(float offset); private: uint32_t readSensor(); - + float _coldOffset; int _cs; SPIClass* _spi; SPISettings _spiSettings; + + // NIST coefficient tables + static constexpr double Jm210_760[] = { 0.000000000000E+00, 0.503811878150E-01, 0.304758369300E-04,-0.856810657200E-07, 0.132281952950E-09,-0.170529583370E-12, 0.209480906970E-15,-0.125383953360E-18, 0.156317256970E-22 }; + static constexpr double J760_1200[] = { 0.296456256810E+03,-0.149761277860E+01, 0.317871039240E-02,-0.318476867010E-05, 0.157208190040E-08,-0.306913690560E-12 }; + + static constexpr double Km270_0[] = { 0.000000000000E+00, 0.394501280250E-01, 0.236223735980E-04,-0.328589067840E-06,-0.499048287770E-08,-0.675090591730E-10,-0.574103274280E-12,-0.310888728940E-14,-0.104516093650E-16,-0.198892668780E-19,-0.163226974860E-22 }; + static constexpr double K0_1372[] = { -0.176004136860E-01, 0.389212049750E-01, 0.185587700320E-04,-0.994575928740E-07, 0.318409457190E-09,-0.560728448890E-12, 0.560750590590E-15,-0.320207200030E-18, 0.971511471520E-22,-0.121047212750E-25 }; + + static constexpr double InvJ_neg[] = { 0.0000000E+00, 1.9528268E+01, -1.2286185E+00, -1.0752178E+00, -5.9086933E-01, -1.7256713E-01, -2.8131513E-02,-2.3963370E-03,-8.3823321E-05}; + static constexpr double InvJ0_760[] = { 0.000000E+00, 1.978425E+01, -2.001204E-01, 1.036969E-02, -2.549687E-04, 3.585153E-06, -5.344285E-08, 5.099890E-10 }; + static constexpr double InvJ760_1200[] = { -3.11358187E+03, 3.00543684E+02, -9.94773230E+00, 1.70276630E-01, -1.43033468E-03, 4.73886084E-06 }; + + static constexpr double InvK_neg[] = { 0.0000000E+00, 2.5173462E+01, 1.1662878E+00, 1.0833638E+00, 8.9773540E-01, 3.7342377E-01, 8.6632643E-02, 1.0450598E-02, 5.1920577E-04 }; + static constexpr double InvK0_500[] = { 0.000000E+00, 2.508355E+01, 7.860106E-02, -2.503131E-01, 8.315270E-02, -1.228034E-02, 9.804036E-04, -4.413030E-05, 1.057734E-06, -1.052755E-08 }; + static constexpr double InvK500_1372[] = { -1.318058E+02, 4.830222E+01, -1.646031E+00, 5.464731E-02, -9.650715E-04, 8.802193E-06, -3.110810E-08 }; + + typedef struct { + int size; + double max; + const double *coeffs; + } coefftable; + + static constexpr coefftable CoeffJ []= { + {0,-210, NULL}, + {sizeof(Jm210_760) / sizeof(double), 760.0f, &Jm210_760[0]}, + {sizeof(J760_1200) / sizeof(double), 1200.0f, &J760_1200[0]} + }; + + static constexpr coefftable CoeffK []= { + {0,-270, NULL}, + {sizeof(Jm210_760) / sizeof(double), 0.0f, &Km270_0[0]}, + {sizeof(K0_1372) / sizeof(double), 1200.0f, &K0_1372[0]} + }; + + static constexpr coefftable InvCoeffJ []= { + {0,-0.895, NULL}, + {sizeof(InvJ_neg) / sizeof(double), 0.0f, &InvJ_neg[0]}, + {sizeof(InvJ0_760) / sizeof(double), 42.919f, &InvJ0_760[0]}, + {sizeof(InvJ760_1200) / sizeof(double), 69.533f, &InvJ760_1200[0]} + }; + + static constexpr coefftable InvCoeffK []= { + {0,-5.891, NULL}, + {sizeof(InvK_neg) / sizeof(double), 0.0f, &InvK_neg[0]}, + {sizeof(InvK0_500) / sizeof(double), 20.644f, &InvK0_500[0]}, + {sizeof(InvK500_1372) / sizeof(double), 54.886f, &InvK500_1372[0]}, + }; + + double mvtoTemp(int type, double voltage); + double coldTempTomv(int type, double temp); + double polynomial(double value, int tableEntries, coefftable const (*table) ); + }; extern MAX31855Class THERM; diff --git a/src/utility/ioexpander/ArduinoIOExpander.cpp b/src/utility/ioexpander/ArduinoIOExpander.cpp index 3dc1be0..461e72e 100644 --- a/src/utility/ioexpander/ArduinoIOExpander.cpp +++ b/src/utility/ioexpander/ArduinoIOExpander.cpp @@ -83,11 +83,40 @@ int ArduinoIOExpanderClass::read(int pin) return -1; } +void ArduinoIOExpanderClass::writeAll(uint32_t banks) { + _tca.writeAll(banks & 0xFF, (banks >> 8) & 0xFF, 0x00); +} + +uint32_t ArduinoIOExpanderClass::readAll() +{ + uint8_t banks[3]; + _tca.readAll(banks); + return *(uint32_t*)banks; +} + + +void ArduinoIOExpanderClass::toggle(){ + writeAll(~(readAll())); +} + void ArduinoIOExpanderClass::initPins() { if (_tca.getAddress() == IO_ADD) { PinStatus status = SWITCH_OFF; + set(IO_WRITE_CH_PIN_00, status); + set(IO_WRITE_CH_PIN_01, status); + set(IO_WRITE_CH_PIN_02, status); + set(IO_WRITE_CH_PIN_03, status); + set(IO_WRITE_CH_PIN_04, status); + set(IO_WRITE_CH_PIN_05, status); + set(IO_WRITE_CH_PIN_06, status); + set(IO_WRITE_CH_PIN_07, status); + set(IO_WRITE_CH_PIN_08, status); + set(IO_WRITE_CH_PIN_09, status); + set(IO_WRITE_CH_PIN_10, status); + set(IO_WRITE_CH_PIN_11, status); + pinMode(IO_WRITE_CH_PIN_00, OUTPUT); pinMode(IO_WRITE_CH_PIN_01, OUTPUT); pinMode(IO_WRITE_CH_PIN_02, OUTPUT); @@ -113,18 +142,7 @@ void ArduinoIOExpanderClass::initPins() pinMode(IO_READ_CH_PIN_10, INPUT); pinMode(IO_READ_CH_PIN_11, INPUT); - set(IO_WRITE_CH_PIN_00, status); - set(IO_WRITE_CH_PIN_01, status); - set(IO_WRITE_CH_PIN_02, status); - set(IO_WRITE_CH_PIN_03, status); - set(IO_WRITE_CH_PIN_04, status); - set(IO_WRITE_CH_PIN_05, status); - set(IO_WRITE_CH_PIN_06, status); - set(IO_WRITE_CH_PIN_07, status); - set(IO_WRITE_CH_PIN_08, status); - set(IO_WRITE_CH_PIN_09, status); - set(IO_WRITE_CH_PIN_10, status); - set(IO_WRITE_CH_PIN_11, status); + writeAll(SWITCH_OFF_ALL); } else { pinMode(DIN_READ_CH_PIN_00, INPUT); pinMode(DIN_READ_CH_PIN_01, INPUT); diff --git a/src/utility/ioexpander/ArduinoIOExpander.h b/src/utility/ioexpander/ArduinoIOExpander.h index 28993d1..e7cd402 100644 --- a/src/utility/ioexpander/ArduinoIOExpander.h +++ b/src/utility/ioexpander/ArduinoIOExpander.h @@ -25,6 +25,24 @@ #define SWITCH_ON HIGH #define SWITCH_OFF LOW +#define SWITCH_ON_ALL 0x0000FFFF +#define SWITCH_OFF_ALL 0x00000000 + +enum { + ON_VALUE_PIN_00 = 0x01, + ON_VALUE_PIN_01 = 0x02, + ON_VALUE_PIN_02 = 0x04, + ON_VALUE_PIN_03 = 0x08, + ON_VALUE_PIN_04 = 0x80, + ON_VALUE_PIN_05 = 0x40, + ON_VALUE_PIN_06 = 0x20, + ON_VALUE_PIN_07 = 0x10, + ON_VALUE_PIN_08 = 0x100, + ON_VALUE_PIN_09 = 0x200, + ON_VALUE_PIN_10 = 0x400, + ON_VALUE_PIN_11 = 0x800, +}; + enum { IO_WRITE_CH_PIN_00 = TCA6424A_P00, IO_WRITE_CH_PIN_01 = TCA6424A_P01, @@ -77,8 +95,10 @@ class ArduinoIOExpanderClass { void setAddress(uint8_t address); bool set(int pin, PinStatus status); bool set(int pin, int status) { return set( pin, (PinStatus)status); }; - + void writeAll(uint32_t banks); int read(int pin); + uint32_t readAll(); + void toggle(); bool pinMode(int pin, PinMode direction); private: diff --git a/src/utility/ioexpander/I2Cdev.cpp b/src/utility/ioexpander/I2Cdev.cpp index 5525624..40b5dfc 100644 --- a/src/utility/ioexpander/I2Cdev.cpp +++ b/src/utility/ioexpander/I2Cdev.cpp @@ -3,6 +3,9 @@ // 2013-06-05 by Jeff Rowberg // // Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument +// 2020-01-20 - hardija : complete support for Teensy 3.x +// 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications // 2013-05-05 - fix issue with writing bit values to words (Sasquatch/Farzanegan) // 2012-06-09 - fix major issue with reading > 32 bytes at a time with Arduino Wire @@ -87,11 +90,6 @@ THE SOFTWARE. #endif -#ifndef BUFFER_LENGTH -// band-aid fix for platforms without Wire-defined BUFFER_LENGTH (removed from some official implementations) -#define BUFFER_LENGTH 32 -#endif - /** Default constructor. */ I2Cdev::I2Cdev() { @@ -105,9 +103,9 @@ I2Cdev::I2Cdev() { * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout, void *wireObj) { uint8_t b; - uint8_t count = readByte(devAddr, regAddr, &b, timeout); + uint8_t count = readByte(devAddr, regAddr, &b, timeout, wireObj); *data = b & (1 << bitNum); return count; } @@ -120,9 +118,9 @@ int8_t I2Cdev::readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout, void *wireObj) { uint16_t b; - uint8_t count = readWord(devAddr, regAddr, &b, timeout); + uint8_t count = readWord(devAddr, regAddr, &b, timeout, wireObj); *data = b & (1 << bitNum); return count; } @@ -136,14 +134,14 @@ int8_t I2Cdev::readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout, void *wireObj) { // 01101001 read byte // 76543210 bit numbers // xxx args: bitStart=4, length=3 // 010 masked // -> 010 shifted uint8_t count, b; - if ((count = readByte(devAddr, regAddr, &b, timeout)) != 0) { + if ((count = readByte(devAddr, regAddr, &b, timeout, wireObj)) != 0) { uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); b &= mask; b >>= (bitStart - length + 1); @@ -161,7 +159,7 @@ int8_t I2Cdev::readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (1 = success, 0 = failure, -1 = timeout) */ -int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout, void *wireObj) { // 1101011001101001 read byte // fedcba9876543210 bit numbers // xxx args: bitStart=12, length=3 @@ -169,7 +167,7 @@ int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uin // -> 010 shifted uint8_t count; uint16_t w; - if ((count = readWord(devAddr, regAddr, &w, timeout)) != 0) { + if ((count = readWord(devAddr, regAddr, &w, timeout, wireObj)) != 0) { uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1); w &= mask; w >>= (bitStart - length + 1); @@ -185,8 +183,8 @@ int8_t I2Cdev::readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uin * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout) { - return readBytes(devAddr, regAddr, 1, data, timeout); +int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout, void *wireObj) { + return readBytes(devAddr, regAddr, 1, data, timeout, wireObj); } /** Read single word from a 16-bit device register. @@ -196,8 +194,8 @@ int8_t I2Cdev::readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_ * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Status of read operation (true = success) */ -int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout) { - return readWords(devAddr, regAddr, 1, data, timeout); +int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout, void *wireObj) { + return readWords(devAddr, regAddr, 1, data, timeout, wireObj); } /** Read multiple bytes from an 8-bit device register. @@ -208,7 +206,7 @@ int8_t I2Cdev::readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Number of bytes read (-1 indicates failure) */ -int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout) { +int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -219,74 +217,66 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8 Serial.print("..."); #endif - int8_t count = 0; + uint8_t count = 0; uint32_t t1 = millis(); #if (I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; #if (ARDUINO < 100) // Arduino v00xx (before v1.0), Wire library // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.send(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.receive(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->receive(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); #endif } - - Wire.endTransmission(); } #elif (ARDUINO == 100) // Arduino v1.0.0, Wire library // Adds standardized write() and read() stream methods instead of send() and receive() // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.read(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); #endif } - - Wire.endTransmission(); } #elif (ARDUINO > 100) // Arduino v1.0.1+, Wire library // Adds official support for repeated start condition, yay! // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length; k += min((int)length, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)min(length - k, BUFFER_LENGTH)); - - for (; Wire.available() && (timeout == 0 || millis() - t1 < timeout); count++) { - data[count] = Wire.read(); + for (int k = 0; k < length; k += min((int)length, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->requestFrom((uint8_t)devAddr, (uint8_t)min((int)length - k, I2CDEVLIB_WIRE_BUFFER_LENGTH)); + for (; useWire->available() && (timeout == 0 || millis() - t1 < timeout); count++) { + data[count] = useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -328,7 +318,7 @@ int8_t I2Cdev::readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8 * @param timeout Optional read timeout in milliseconds (0 to disable, leave off to use default class value in I2Cdev::readTimeout) * @return Number of words read (-1 indicates failure) */ -int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout) { +int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -339,32 +329,33 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 Serial.print("..."); #endif - int8_t count = 0; + uint8_t count = 0; uint32_t t1 = millis(); #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; #if (ARDUINO < 100) // Arduino v00xx (before v1.0), Wire library // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.send(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->send(regAddr); + useWire->endTransmission(); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.receive() << 8; + data[count] = useWire->receive() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.receive(); + data[count] |= useWire->receive(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -373,31 +364,28 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 } msb = !msb; } - - Wire.endTransmission(); } #elif (ARDUINO == 100) // Arduino v1.0.0, Wire library // Adds standardized write() and read() stream methods instead of send() and receive() // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.read() << 8; + data[count] = useWire->read() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.read(); + data[count] |= useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -406,31 +394,28 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 } msb = !msb; } - - Wire.endTransmission(); } #elif (ARDUINO > 100) // Arduino v1.0.1+, Wire library // Adds official support for repeated start condition, yay! // I2C/TWI subsystem uses internal buffer that breaks with large data requests - // so if user requests more than BUFFER_LENGTH bytes, we have to do it in + // so if user requests more than I2CDEVLIB_WIRE_BUFFER_LENGTH bytes, we have to do it in // smaller chunks instead of all at once - for (uint8_t k = 0; k < length * 2; k += min(length * 2, BUFFER_LENGTH)) { - Wire.beginTransmission(devAddr); - Wire.write(regAddr); - Wire.endTransmission(); - Wire.beginTransmission(devAddr); - Wire.requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes + for (uint8_t k = 0; k < length * 2; k += min(length * 2, I2CDEVLIB_WIRE_BUFFER_LENGTH)) { + useWire->beginTransmission(devAddr); + useWire->write(regAddr); + useWire->endTransmission(); + useWire->requestFrom(devAddr, (uint8_t)(length * 2)); // length=words, this wants bytes bool msb = true; // starts with MSB, then LSB - for (; Wire.available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { + for (; useWire->available() && count < length && (timeout == 0 || millis() - t1 < timeout);) { if (msb) { // first byte is bits 15-8 (MSb=15) - data[count] = Wire.read() << 8; + data[count] = useWire->read() << 8; } else { // second byte is bits 7-0 (LSb=0) - data[count] |= Wire.read(); + data[count] |= useWire->read(); #ifdef I2CDEV_SERIAL_DEBUG Serial.print(data[count], HEX); if (count + 1 < length) Serial.print(" "); @@ -439,8 +424,6 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 } msb = !msb; } - - Wire.endTransmission(); } #endif @@ -479,11 +462,11 @@ int8_t I2Cdev::readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint1 * @param value New bit value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data) { +bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj) { uint8_t b; - readByte(devAddr, regAddr, &b); + readByte(devAddr, regAddr, &b, I2Cdev::readTimeout, wireObj); b = (data != 0) ? (b | (1 << bitNum)) : (b & ~(1 << bitNum)); - return writeByte(devAddr, regAddr, b); + return writeByte(devAddr, regAddr, b, wireObj); } /** write a single bit in a 16-bit device register. @@ -493,11 +476,11 @@ bool I2Cdev::writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t * @param value New bit value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data) { +bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj) { uint16_t w; - readWord(devAddr, regAddr, &w); + readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj); w = (data != 0) ? (w | (1 << bitNum)) : (w & ~(1 << bitNum)); - return writeWord(devAddr, regAddr, w); + return writeWord(devAddr, regAddr, w, wireObj); } /** Write multiple bits in an 8-bit device register. @@ -508,7 +491,7 @@ bool I2Cdev::writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_ * @param data Right-aligned value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data) { +bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj) { // 010 value to write // 76543210 bit numbers // xxx args: bitStart=4, length=3 @@ -517,13 +500,13 @@ bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8 // 10100011 original & ~mask // 10101011 masked | value uint8_t b; - if (readByte(devAddr, regAddr, &b) != 0) { + if (readByte(devAddr, regAddr, &b, I2Cdev::readTimeout, wireObj) != 0) { uint8_t mask = ((1 << length) - 1) << (bitStart - length + 1); data <<= (bitStart - length + 1); // shift data into correct position data &= mask; // zero all non-important bits in data b &= ~(mask); // zero all important bits in existing byte b |= data; // combine data with existing byte - return writeByte(devAddr, regAddr, b); + return writeByte(devAddr, regAddr, b, wireObj); } else { return false; } @@ -537,7 +520,7 @@ bool I2Cdev::writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8 * @param data Right-aligned value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data) { +bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj) { // 010 value to write // fedcba9876543210 bit numbers // xxx args: bitStart=12, length=3 @@ -546,13 +529,13 @@ bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint // 1010001110010110 original & ~mask // 1010101110010110 masked | value uint16_t w; - if (readWord(devAddr, regAddr, &w) != 0) { + if (readWord(devAddr, regAddr, &w, I2Cdev::readTimeout, wireObj) != 0) { uint16_t mask = ((1 << length) - 1) << (bitStart - length + 1); data <<= (bitStart - length + 1); // shift data into correct position data &= mask; // zero all non-important bits in data w &= ~(mask); // zero all important bits in existing word w |= data; // combine data with existing word - return writeWord(devAddr, regAddr, w); + return writeWord(devAddr, regAddr, w, wireObj); } else { return false; } @@ -564,8 +547,8 @@ bool I2Cdev::writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint * @param data New byte value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { - return writeBytes(devAddr, regAddr, 1, &data); +bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj) { + return writeBytes(devAddr, regAddr, 1, &data, wireObj); } /** Write single word to a 16-bit device register. @@ -574,8 +557,8 @@ bool I2Cdev::writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data) { * @param data New word value to write * @return Status of operation (true = success) */ -bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) { - return writeWords(devAddr, regAddr, 1, &data); +bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj) { + return writeWords(devAddr, regAddr, 1, &data, wireObj); } /** Write multiple bytes to an 8-bit device register. @@ -585,7 +568,7 @@ bool I2Cdev::writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data) { * @param data Buffer to copy new data from * @return Status of operation (true = success) */ -bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data) { +bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t* data, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -596,14 +579,20 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ Serial.print("..."); #endif uint8_t status = 0; + +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.beginTransmission(devAddr); - Wire.send((uint8_t) regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->send((uint8_t) regAddr); // send address #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - Wire.beginTransmission(devAddr); - Wire.write((uint8_t) regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->write((uint8_t) regAddr); // send address #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::beginTransmission(devAddr); Fastwire::write(regAddr); @@ -614,21 +603,21 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ if (i + 1 < length) Serial.print(" "); #endif #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.send((uint8_t) data[i]); + useWire->send((uint8_t) data[i]); #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - Wire.write((uint8_t) data[i]); + useWire->write((uint8_t) data[i]); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::write((uint8_t) data[i]); #endif } #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.endTransmission(); + useWire->endTransmission(); #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - status = Wire.endTransmission(); + status = useWire->endTransmission(); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::stop(); //status = Fastwire::endTransmission(); @@ -646,7 +635,7 @@ bool I2Cdev::writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_ * @param data Buffer to copy new data from * @return Status of operation (true = success) */ -bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data) { +bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t* data, void *wireObj) { #ifdef I2CDEV_SERIAL_DEBUG Serial.print("I2C (0x"); Serial.print(devAddr, HEX); @@ -657,14 +646,20 @@ bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16 Serial.print("..."); #endif uint8_t status = 0; + +#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE + TwoWire *useWire = &Wire; + if (wireObj) useWire = (TwoWire *)wireObj; +#endif + #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.beginTransmission(devAddr); - Wire.send(regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->send(regAddr); // send address #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - Wire.beginTransmission(devAddr); - Wire.write(regAddr); // send address + useWire->beginTransmission(devAddr); + useWire->write(regAddr); // send address #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::beginTransmission(devAddr); Fastwire::write(regAddr); @@ -675,13 +670,13 @@ bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16 if (i + 1 < length) Serial.print(" "); #endif #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.send((uint8_t)(data[i] >> 8)); // send MSB - Wire.send((uint8_t)data[i]); // send LSB + useWire->send((uint8_t)(data[i] >> 8)); // send MSB + useWire->send((uint8_t)data[i]); // send LSB #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - Wire.write((uint8_t)(data[i] >> 8)); // send MSB - Wire.write((uint8_t)data[i]); // send LSB + useWire->write((uint8_t)(data[i] >> 8)); // send MSB + useWire->write((uint8_t)data[i]); // send LSB #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::write((uint8_t)(data[i] >> 8)); // send MSB status = Fastwire::write((uint8_t)data[i]); // send LSB @@ -689,11 +684,11 @@ bool I2Cdev::writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16 #endif } #if ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO < 100) || I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_NBWIRE) - Wire.endTransmission(); + useWire->endTransmission(); #elif ((I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE && ARDUINO >= 100) \ || (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_SBWIRE && ARDUINO >= 100) \ || I2CDEV_IMPLEMENTATION == I2CDEV_TEENSY_3X_WIRE) - status = Wire.endTransmission(); + status = useWire->endTransmission(); #elif (I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE) Fastwire::stop(); //status = Fastwire::endTransmission(); @@ -753,7 +748,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; #endif TWSR = 0; // no prescaler => prescaler = 1 - TWBR = ((16000L / khz) - 16) / 2; // change the I2C clock rate + TWBR = F_CPU / 2000 / khz - 8; // change the I2C clock rate TWCR = 1 << TWEN; // enable twi module, no interrupt } @@ -993,7 +988,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; TWBR = ((CPU_FREQ / TWI_FREQ) - 16) / 2; // bitrate register // enable twi module, acks, and twi interrupt - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA); /* TWEN - TWI Enable Bit TWIE - TWI Interrupt Enable @@ -1062,7 +1057,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; } void twii_SetStart() { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWSTA); } void twi_write01() { @@ -1145,19 +1140,19 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; void twi_reply(uint8_t ack) { // transmit master read ready signal, with or without ack if (ack){ - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT) | _BV(TWEA); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT) | (1 << TWEA); } else { - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWINT); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWINT); } } void twi_stop(void) { // send stop condition - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT) | _BV(TWSTO); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT) | (1 << TWSTO); // wait for stop condition to be exectued on bus // TWINT is not set after a stop condition! - while (TWCR & _BV(TWSTO)) { + while (TWCR & (1 << TWSTO)) { continue; } @@ -1167,7 +1162,7 @@ uint16_t I2Cdev::readTimeout = I2CDEV_DEFAULT_READ_TIMEOUT; void twi_releaseBus(void) { // release bus - TWCR = _BV(TWEN) | _BV(TWIE) | _BV(TWEA) | _BV(TWINT); + TWCR = (1 << TWEN) | (1 << TWIE) | (1 << TWEA) | (1 << TWINT); // update twi state twi_state = TWI_READY; diff --git a/src/utility/ioexpander/I2Cdev.h b/src/utility/ioexpander/I2Cdev.h index 60c3195..5b59c56 100644 --- a/src/utility/ioexpander/I2Cdev.h +++ b/src/utility/ioexpander/I2Cdev.h @@ -3,6 +3,7 @@ // 2013-06-05 by Jeff Rowberg // // Changelog: +// 2021-09-28 - allow custom Wire object as transaction function argument // 2020-01-20 - hardija : complete support for Teensy 3.x // 2015-10-30 - simondlevy : support i2c_t3 for Teensy3.1 // 2013-05-06 - add Francesco Ferrara's Fastwire v0.24 implementation with small modifications @@ -48,6 +49,11 @@ THE SOFTWARE. #ifndef _I2CDEV_H_ #define _I2CDEV_H_ +// ----------------------------------------------------------------------------- +// Enable deprecated pgmspace typedefs in avr-libc +// ----------------------------------------------------------------------------- +#define __PROG_TYPES_COMPAT__ + // ----------------------------------------------------------------------------- // I2C interface implementation setting // ----------------------------------------------------------------------------- @@ -99,10 +105,26 @@ THE SOFTWARE. #endif #ifdef SPARK - #include + #include "application.h" #define ARDUINO 101 + #define BUFFER_LENGTH 32 #endif +#ifndef I2CDEVLIB_WIRE_BUFFER_LENGTH + #if defined(I2C_BUFFER_LENGTH) + // Arduino ESP32 core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH I2C_BUFFER_LENGTH + #elif defined(BUFFER_LENGTH) + // Arduino AVR core Wire and many others use this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH BUFFER_LENGTH + #elif defined(SERIAL_BUFFER_SIZE) + // Arduino SAMD core Wire uses this + #define I2CDEVLIB_WIRE_BUFFER_LENGTH SERIAL_BUFFER_SIZE + #else + // should be a safe fallback, though possibly inefficient + #define I2CDEVLIB_WIRE_BUFFER_LENGTH 32 + #endif +#endif // 1000ms default read timeout (modify with "I2Cdev::readTimeout = [ms];") #define I2CDEV_DEFAULT_READ_TIMEOUT 1000 @@ -111,23 +133,23 @@ class I2Cdev { public: I2Cdev(); - static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout); - static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout); - - static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data); - static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data); - static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data); - static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data); - static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data); - static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data); - static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data); - static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data); + static int8_t readBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWord(uint8_t devAddr, uint8_t regAddr, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + static int8_t readWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, uint16_t timeout=I2Cdev::readTimeout, void *wireObj=0); + + static bool writeBit(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint8_t data, void *wireObj=0); + static bool writeBitW(uint8_t devAddr, uint8_t regAddr, uint8_t bitNum, uint16_t data, void *wireObj=0); + static bool writeBits(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint8_t data, void *wireObj=0); + static bool writeBitsW(uint8_t devAddr, uint8_t regAddr, uint8_t bitStart, uint8_t length, uint16_t data, void *wireObj=0); + static bool writeByte(uint8_t devAddr, uint8_t regAddr, uint8_t data, void *wireObj=0); + static bool writeWord(uint8_t devAddr, uint8_t regAddr, uint16_t data, void *wireObj=0); + static bool writeBytes(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint8_t *data, void *wireObj=0); + static bool writeWords(uint8_t devAddr, uint8_t regAddr, uint8_t length, uint16_t *data, void *wireObj=0); static uint16_t readTimeout; }; @@ -240,7 +262,7 @@ class I2Cdev { /* TWI Status is in TWSR, in the top 5 bits: TWS7 - TWS3 */ - #define TW_STATUS_MASK (_BV(TWS7)|_BV(TWS6)|_BV(TWS5)|_BV(TWS4)|_BV(TWS3)) + #define TW_STATUS_MASK ((1 << TWS7)|(1 << TWS6)|(1 << TWS5)|(1 << TWS4)|(1 << TWS3)) #define TW_STATUS (TWSR & TW_STATUS_MASK) #define TW_START 0x08 #define TW_REP_START 0x10 @@ -275,11 +297,11 @@ class I2Cdev { //#define _SFR_BYTE(sfr) _MMIO_BYTE(_SFR_ADDR(sfr)) #ifndef sbi // set bit - #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) + #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= (1 << bit)) #endif // sbi #ifndef cbi // clear bit - #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) + #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~(1 << bit)) #endif // cbi extern TwoWire Wire; diff --git a/src/utility/ioexpander/TCA6424A.cpp b/src/utility/ioexpander/TCA6424A.cpp index 6c63e73..550e237 100644 --- a/src/utility/ioexpander/TCA6424A.cpp +++ b/src/utility/ioexpander/TCA6424A.cpp @@ -87,7 +87,7 @@ uint8_t TCA6424A::readBank(uint8_t bank) { * @param banks Container for all bank's pin values (P00-P27) */ void TCA6424A::readAll(uint8_t *banks) { - I2Cdev::readBytes(devAddr, TCA6424A_RA_INPUT0, 3, banks); + I2Cdev::readBytes(devAddr, TCA6424A_RA_INPUT0 | TCA6424A_AUTO_INCREMENT, 3, banks); } /** Get all pin logic levels from all banks. * Reads into individual 1-byte containers. @@ -96,7 +96,7 @@ void TCA6424A::readAll(uint8_t *banks) { * @param bank2 Container for Bank 2's pin values (P20-P27) */ void TCA6424A::readAll(uint8_t *bank0, uint8_t *bank1, uint8_t *bank2) { - I2Cdev::readBytes(devAddr, TCA6424A_RA_INPUT0, 3, buffer); + I2Cdev::readBytes(devAddr, TCA6424A_RA_INPUT0 | TCA6424A_AUTO_INCREMENT, 3, buffer); *bank0 = buffer[0]; *bank1 = buffer[1]; *bank2 = buffer[2];