├── .gitattributes ├── .github ├── PULL_REQUEST_TEMPLATE │ └── adafruit_circuitpython_pr.md └── workflows │ ├── build.yml │ ├── failure-help-text.yml │ ├── release_gh.yml │ └── release_pypi.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .readthedocs.yaml ├── CODE_OF_CONDUCT.md ├── LICENSE ├── LICENSES ├── CC-BY-4.0.txt ├── MIT.txt └── Unlicense.txt ├── README.rst ├── README.rst.license ├── adafruit_seesaw ├── __init__.py ├── analoginput.py ├── attiny8x7.py ├── attinyx16.py ├── crickit.py ├── digitalio.py ├── keypad.py ├── neopixel.py ├── pwmout.py ├── robohat.py ├── rotaryio.py ├── samd09.py ├── seesaw.py └── tftshield18.py ├── docs ├── _static │ ├── favicon.ico │ └── favicon.ico.license ├── api.rst ├── api.rst.license ├── conf.py ├── examples.rst ├── examples.rst.license ├── index.rst ├── index.rst.license └── requirements.txt ├── examples ├── seesaw_analogin_test.py ├── seesaw_ano_rotary_7segment_demo.py ├── seesaw_ano_rotary_simpletest.py ├── seesaw_arcade_qt_multi_board.py ├── seesaw_arcade_qt_simpletest.py ├── seesaw_attiny_simpletest.py ├── seesaw_crickit_test.py ├── seesaw_digitalio_test.py ├── seesaw_eeprom_test.py ├── seesaw_gamepad_qt.py ├── seesaw_joy_featherwing.py ├── seesaw_minitft_featherwing.py ├── seesaw_neopixel_test.py ├── seesaw_pc_joystick.py ├── seesaw_pwmout_test.py ├── seesaw_quadrotary.py ├── seesaw_rotary_multiples.py ├── seesaw_rotary_neopixel.py ├── seesaw_rotary_simpletest.py ├── seesaw_simpletest.py └── seesaw_soil_simpletest.py ├── optional_requirements.txt ├── pyproject.toml ├── requirements.txt └── ruff.toml /.gitattributes: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | .py text eol=lf 6 | .rst text eol=lf 7 | .txt text eol=lf 8 | .yaml text eol=lf 9 | .toml text eol=lf 10 | .license text eol=lf 11 | .md text eol=lf 12 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/adafruit_circuitpython_pr.md: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | Thank you for contributing! Before you submit a pull request, please read the following. 6 | 7 | Make sure any changes you're submitting are in line with the CircuitPython Design Guide, available here: https://docs.circuitpython.org/en/latest/docs/design_guide.html 8 | 9 | If your changes are to documentation, please verify that the documentation builds locally by following the steps found here: https://adafru.it/build-docs 10 | 11 | Before submitting the pull request, make sure you've run Pylint and Black locally on your code. You can do this manually or using pre-commit. Instructions are available here: https://adafru.it/check-your-code 12 | 13 | Please remove all of this text before submitting. Include an explanation or list of changes included in your PR, as well as, if applicable, a link to any related issues. 14 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | name: Build CI 6 | 7 | on: [pull_request, push] 8 | 9 | jobs: 10 | test: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Run Build CI workflow 14 | uses: adafruit/workflows-circuitpython-libs/build@main 15 | -------------------------------------------------------------------------------- /.github/workflows/failure-help-text.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Scott Shawcroft for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | name: Failure help text 6 | 7 | on: 8 | workflow_run: 9 | workflows: ["Build CI"] 10 | types: 11 | - completed 12 | 13 | jobs: 14 | post-help: 15 | runs-on: ubuntu-latest 16 | if: ${{ github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event == 'pull_request' }} 17 | steps: 18 | - name: Post comment to help 19 | uses: adafruit/circuitpython-action-library-ci-failed@v1 20 | -------------------------------------------------------------------------------- /.github/workflows/release_gh.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | name: GitHub Release Actions 6 | 7 | on: 8 | release: 9 | types: [published] 10 | 11 | jobs: 12 | upload-release-assets: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Run GitHub Release CI workflow 16 | uses: adafruit/workflows-circuitpython-libs/release-gh@main 17 | with: 18 | github-token: ${{ secrets.GITHUB_TOKEN }} 19 | upload-url: ${{ github.event.release.upload_url }} 20 | -------------------------------------------------------------------------------- /.github/workflows/release_pypi.yml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | name: PyPI Release Actions 6 | 7 | on: 8 | release: 9 | types: [published] 10 | 11 | jobs: 12 | upload-release-assets: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Run PyPI Release CI workflow 16 | uses: adafruit/workflows-circuitpython-libs/release-pypi@main 17 | with: 18 | pypi-username: ${{ secrets.pypi_username }} 19 | pypi-password: ${{ secrets.pypi_password }} 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Kattni Rembor, written for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | # Do not include files and directories created by your personal work environment, such as the IDE 6 | # you use, except for those already listed here. Pull requests including changes to this file will 7 | # not be accepted. 8 | 9 | # This .gitignore file contains rules for files generated by working with CircuitPython libraries, 10 | # including building Sphinx, testing with pip, and creating a virual environment, as well as the 11 | # MacOS and IDE-specific files generated by using MacOS in general, or the PyCharm or VSCode IDEs. 12 | 13 | # If you find that there are files being generated on your machine that should not be included in 14 | # your git commit, you should create a .gitignore_global file on your computer to include the 15 | # files created by your personal setup. To do so, follow the two steps below. 16 | 17 | # First, create a file called .gitignore_global somewhere convenient for you, and add rules for 18 | # the files you want to exclude from git commits. 19 | 20 | # Second, configure Git to use the exclude file for all Git repositories by running the 21 | # following via commandline, replacing "path/to/your/" with the actual path to your newly created 22 | # .gitignore_global file: 23 | # git config --global core.excludesfile path/to/your/.gitignore_global 24 | 25 | # CircuitPython-specific files 26 | *.mpy 27 | 28 | # Python-specific files 29 | __pycache__ 30 | *.pyc 31 | 32 | # Sphinx build-specific files 33 | _build 34 | 35 | # This file results from running `pip -e install .` in a local repository 36 | *.egg-info 37 | 38 | # Virtual environment-specific files 39 | .env 40 | .venv 41 | 42 | # MacOS-specific files 43 | *.DS_Store 44 | 45 | # IDE-specific files 46 | .idea 47 | .vscode 48 | *~ 49 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Justin Myers for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | repos: 6 | - repo: https://github.com/pre-commit/pre-commit-hooks 7 | rev: v4.5.0 8 | hooks: 9 | - id: check-yaml 10 | - id: end-of-file-fixer 11 | - id: trailing-whitespace 12 | - repo: https://github.com/astral-sh/ruff-pre-commit 13 | rev: v0.3.4 14 | hooks: 15 | - id: ruff-format 16 | - id: ruff 17 | args: ["--fix"] 18 | - repo: https://github.com/fsfe/reuse-tool 19 | rev: v3.0.1 20 | hooks: 21 | - id: reuse 22 | -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | # Read the Docs configuration file 6 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 7 | 8 | # Required 9 | version: 2 10 | 11 | sphinx: 12 | configuration: docs/conf.py 13 | 14 | build: 15 | os: ubuntu-20.04 16 | tools: 17 | python: "3" 18 | 19 | python: 20 | install: 21 | - requirements: docs/requirements.txt 22 | - requirements: requirements.txt 23 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Adafruit Community Code of Conduct 8 | 9 | ## Our Pledge 10 | 11 | In the interest of fostering an open and welcoming environment, we as 12 | contributors and leaders pledge to making participation in our project and 13 | our community a harassment-free experience for everyone, regardless of age, body 14 | size, disability, ethnicity, gender identity and expression, level or type of 15 | experience, education, socio-economic status, nationality, personal appearance, 16 | race, religion, or sexual identity and orientation. 17 | 18 | ## Our Standards 19 | 20 | We are committed to providing a friendly, safe and welcoming environment for 21 | all. 22 | 23 | Examples of behavior that contributes to creating a positive environment 24 | include: 25 | 26 | * Be kind and courteous to others 27 | * Using welcoming and inclusive language 28 | * Being respectful of differing viewpoints and experiences 29 | * Collaborating with other community members 30 | * Gracefully accepting constructive criticism 31 | * Focusing on what is best for the community 32 | * Showing empathy towards other community members 33 | 34 | Examples of unacceptable behavior by participants include: 35 | 36 | * The use of sexualized language or imagery and sexual attention or advances 37 | * The use of inappropriate images, including in a community member's avatar 38 | * The use of inappropriate language, including in a community member's nickname 39 | * Any spamming, flaming, baiting or other attention-stealing behavior 40 | * Excessive or unwelcome helping; answering outside the scope of the question 41 | asked 42 | * Trolling, insulting/derogatory comments, and personal or political attacks 43 | * Promoting or spreading disinformation, lies, or conspiracy theories against 44 | a person, group, organisation, project, or community 45 | * Public or private harassment 46 | * Publishing others' private information, such as a physical or electronic 47 | address, without explicit permission 48 | * Other conduct which could reasonably be considered inappropriate 49 | 50 | The goal of the standards and moderation guidelines outlined here is to build 51 | and maintain a respectful community. We ask that you don’t just aim to be 52 | "technically unimpeachable", but rather try to be your best self. 53 | 54 | We value many things beyond technical expertise, including collaboration and 55 | supporting others within our community. Providing a positive experience for 56 | other community members can have a much more significant impact than simply 57 | providing the correct answer. 58 | 59 | ## Our Responsibilities 60 | 61 | Project leaders are responsible for clarifying the standards of acceptable 62 | behavior and are expected to take appropriate and fair corrective action in 63 | response to any instances of unacceptable behavior. 64 | 65 | Project leaders have the right and responsibility to remove, edit, or 66 | reject messages, comments, commits, code, issues, and other contributions 67 | that are not aligned to this Code of Conduct, or to ban temporarily or 68 | permanently any community member for other behaviors that they deem 69 | inappropriate, threatening, offensive, or harmful. 70 | 71 | ## Moderation 72 | 73 | Instances of behaviors that violate the Adafruit Community Code of Conduct 74 | may be reported by any member of the community. Community members are 75 | encouraged to report these situations, including situations they witness 76 | involving other community members. 77 | 78 | You may report in the following ways: 79 | 80 | In any situation, you may send an email to . 81 | 82 | On the Adafruit Discord, you may send an open message from any channel 83 | to all Community Moderators by tagging @community moderators. You may 84 | also send an open message from any channel, or a direct message to 85 | @kattni#1507, @tannewt#4653, @Dan Halbert#1614, @cater#2442, 86 | @sommersoft#0222, @Mr. Certainly#0472 or @Andon#8175. 87 | 88 | Email and direct message reports will be kept confidential. 89 | 90 | In situations on Discord where the issue is particularly egregious, possibly 91 | illegal, requires immediate action, or violates the Discord terms of service, 92 | you should also report the message directly to Discord. 93 | 94 | These are the steps for upholding our community’s standards of conduct. 95 | 96 | 1. Any member of the community may report any situation that violates the 97 | Adafruit Community Code of Conduct. All reports will be reviewed and 98 | investigated. 99 | 2. If the behavior is an egregious violation, the community member who 100 | committed the violation may be banned immediately, without warning. 101 | 3. Otherwise, moderators will first respond to such behavior with a warning. 102 | 4. Moderators follow a soft "three strikes" policy - the community member may 103 | be given another chance, if they are receptive to the warning and change their 104 | behavior. 105 | 5. If the community member is unreceptive or unreasonable when warned by a 106 | moderator, or the warning goes unheeded, they may be banned for a first or 107 | second offense. Repeated offenses will result in the community member being 108 | banned. 109 | 110 | ## Scope 111 | 112 | This Code of Conduct and the enforcement policies listed above apply to all 113 | Adafruit Community venues. This includes but is not limited to any community 114 | spaces (both public and private), the entire Adafruit Discord server, and 115 | Adafruit GitHub repositories. Examples of Adafruit Community spaces include 116 | but are not limited to meet-ups, audio chats on the Adafruit Discord, or 117 | interaction at a conference. 118 | 119 | This Code of Conduct applies both within project spaces and in public spaces 120 | when an individual is representing the project or its community. As a community 121 | member, you are representing our community, and are expected to behave 122 | accordingly. 123 | 124 | ## Attribution 125 | 126 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 127 | version 1.4, available at 128 | , 129 | and the [Rust Code of Conduct](https://www.rust-lang.org/en-US/conduct.html). 130 | 131 | For other projects adopting the Adafruit Community Code of 132 | Conduct, please contact the maintainers of those projects for enforcement. 133 | If you wish to use this code of conduct for your own project, consider 134 | explicitly mentioning your moderation policy or making a copy with your 135 | own moderation policy so as to avoid confusion. 136 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Dean Miller for Adafruit Industries 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSES/CC-BY-4.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution 4.0 International Creative Commons Corporation 2 | ("Creative Commons") is not a law firm and does not provide legal services 3 | or legal advice. Distribution of Creative Commons public licenses does not 4 | create a lawyer-client or other relationship. Creative Commons makes its licenses 5 | and related information available on an "as-is" basis. Creative Commons gives 6 | no warranties regarding its licenses, any material licensed under their terms 7 | and conditions, or any related information. Creative Commons disclaims all 8 | liability for damages resulting from their use to the fullest extent possible. 9 | 10 | Using Creative Commons Public Licenses 11 | 12 | Creative Commons public licenses provide a standard set of terms and conditions 13 | that creators and other rights holders may use to share original works of 14 | authorship and other material subject to copyright and certain other rights 15 | specified in the public license below. The following considerations are for 16 | informational purposes only, are not exhaustive, and do not form part of our 17 | licenses. 18 | 19 | Considerations for licensors: Our public licenses are intended for use by 20 | those authorized to give the public permission to use material in ways otherwise 21 | restricted by copyright and certain other rights. Our licenses are irrevocable. 22 | Licensors should read and understand the terms and conditions of the license 23 | they choose before applying it. Licensors should also secure all rights necessary 24 | before applying our licenses so that the public can reuse the material as 25 | expected. Licensors should clearly mark any material not subject to the license. 26 | This includes other CC-licensed material, or material used under an exception 27 | or limitation to copyright. More considerations for licensors : wiki.creativecommons.org/Considerations_for_licensors 28 | 29 | Considerations for the public: By using one of our public licenses, a licensor 30 | grants the public permission to use the licensed material under specified 31 | terms and conditions. If the licensor's permission is not necessary for any 32 | reason–for example, because of any applicable exception or limitation to copyright–then 33 | that use is not regulated by the license. Our licenses grant only permissions 34 | under copyright and certain other rights that a licensor has authority to 35 | grant. Use of the licensed material may still be restricted for other reasons, 36 | including because others have copyright or other rights in the material. A 37 | licensor may make special requests, such as asking that all changes be marked 38 | or described. Although not required by our licenses, you are encouraged to 39 | respect those requests where reasonable. More considerations for the public 40 | : wiki.creativecommons.org/Considerations_for_licensees Creative Commons Attribution 41 | 4.0 International Public License 42 | 43 | By exercising the Licensed Rights (defined below), You accept and agree to 44 | be bound by the terms and conditions of this Creative Commons Attribution 45 | 4.0 International Public License ("Public License"). To the extent this Public 46 | License may be interpreted as a contract, You are granted the Licensed Rights 47 | in consideration of Your acceptance of these terms and conditions, and the 48 | Licensor grants You such rights in consideration of benefits the Licensor 49 | receives from making the Licensed Material available under these terms and 50 | conditions. 51 | 52 | Section 1 – Definitions. 53 | 54 | a. Adapted Material means material subject to Copyright and Similar Rights 55 | that is derived from or based upon the Licensed Material and in which the 56 | Licensed Material is translated, altered, arranged, transformed, or otherwise 57 | modified in a manner requiring permission under the Copyright and Similar 58 | Rights held by the Licensor. For purposes of this Public License, where the 59 | Licensed Material is a musical work, performance, or sound recording, Adapted 60 | Material is always produced where the Licensed Material is synched in timed 61 | relation with a moving image. 62 | 63 | b. Adapter's License means the license You apply to Your Copyright and Similar 64 | Rights in Your contributions to Adapted Material in accordance with the terms 65 | and conditions of this Public License. 66 | 67 | c. Copyright and Similar Rights means copyright and/or similar rights closely 68 | related to copyright including, without limitation, performance, broadcast, 69 | sound recording, and Sui Generis Database Rights, without regard to how the 70 | rights are labeled or categorized. For purposes of this Public License, the 71 | rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 72 | 73 | d. Effective Technological Measures means those measures that, in the absence 74 | of proper authority, may not be circumvented under laws fulfilling obligations 75 | under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, 76 | and/or similar international agreements. 77 | 78 | e. Exceptions and Limitations means fair use, fair dealing, and/or any other 79 | exception or limitation to Copyright and Similar Rights that applies to Your 80 | use of the Licensed Material. 81 | 82 | f. Licensed Material means the artistic or literary work, database, or other 83 | material to which the Licensor applied this Public License. 84 | 85 | g. Licensed Rights means the rights granted to You subject to the terms and 86 | conditions of this Public License, which are limited to all Copyright and 87 | Similar Rights that apply to Your use of the Licensed Material and that the 88 | Licensor has authority to license. 89 | 90 | h. Licensor means the individual(s) or entity(ies) granting rights under this 91 | Public License. 92 | 93 | i. Share means to provide material to the public by any means or process that 94 | requires permission under the Licensed Rights, such as reproduction, public 95 | display, public performance, distribution, dissemination, communication, or 96 | importation, and to make material available to the public including in ways 97 | that members of the public may access the material from a place and at a time 98 | individually chosen by them. 99 | 100 | j. Sui Generis Database Rights means rights other than copyright resulting 101 | from Directive 96/9/EC of the European Parliament and of the Council of 11 102 | March 1996 on the legal protection of databases, as amended and/or succeeded, 103 | as well as other essentially equivalent rights anywhere in the world. 104 | 105 | k. You means the individual or entity exercising the Licensed Rights under 106 | this Public License. Your has a corresponding meaning. 107 | 108 | Section 2 – Scope. 109 | 110 | a. License grant. 111 | 112 | 1. Subject to the terms and conditions of this Public License, the Licensor 113 | hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, 114 | irrevocable license to exercise the Licensed Rights in the Licensed Material 115 | to: 116 | 117 | A. reproduce and Share the Licensed Material, in whole or in part; and 118 | 119 | B. produce, reproduce, and Share Adapted Material. 120 | 121 | 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions 122 | and Limitations apply to Your use, this Public License does not apply, and 123 | You do not need to comply with its terms and conditions. 124 | 125 | 3. Term. The term of this Public License is specified in Section 6(a). 126 | 127 | 4. Media and formats; technical modifications allowed. The Licensor authorizes 128 | You to exercise the Licensed Rights in all media and formats whether now known 129 | or hereafter created, and to make technical modifications necessary to do 130 | so. The Licensor waives and/or agrees not to assert any right or authority 131 | to forbid You from making technical modifications necessary to exercise the 132 | Licensed Rights, including technical modifications necessary to circumvent 133 | Effective Technological Measures. For purposes of this Public License, simply 134 | making modifications authorized by this Section 2(a)(4) never produces Adapted 135 | Material. 136 | 137 | 5. Downstream recipients. 138 | 139 | A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed 140 | Material automatically receives an offer from the Licensor to exercise the 141 | Licensed Rights under the terms and conditions of this Public License. 142 | 143 | B. No downstream restrictions. You may not offer or impose any additional 144 | or different terms or conditions on, or apply any Effective Technological 145 | Measures to, the Licensed Material if doing so restricts exercise of the Licensed 146 | Rights by any recipient of the Licensed Material. 147 | 148 | 6. No endorsement. Nothing in this Public License constitutes or may be construed 149 | as permission to assert or imply that You are, or that Your use of the Licensed 150 | Material is, connected with, or sponsored, endorsed, or granted official status 151 | by, the Licensor or others designated to receive attribution as provided in 152 | Section 3(a)(1)(A)(i). 153 | 154 | b. Other rights. 155 | 156 | 1. Moral rights, such as the right of integrity, are not licensed under this 157 | Public License, nor are publicity, privacy, and/or other similar personality 158 | rights; however, to the extent possible, the Licensor waives and/or agrees 159 | not to assert any such rights held by the Licensor to the limited extent necessary 160 | to allow You to exercise the Licensed Rights, but not otherwise. 161 | 162 | 2. Patent and trademark rights are not licensed under this Public License. 163 | 164 | 3. To the extent possible, the Licensor waives any right to collect royalties 165 | from You for the exercise of the Licensed Rights, whether directly or through 166 | a collecting society under any voluntary or waivable statutory or compulsory 167 | licensing scheme. In all other cases the Licensor expressly reserves any right 168 | to collect such royalties. 169 | 170 | Section 3 – License Conditions. 171 | 172 | Your exercise of the Licensed Rights is expressly made subject to the following 173 | conditions. 174 | 175 | a. Attribution. 176 | 177 | 1. If You Share the Licensed Material (including in modified form), You must: 178 | 179 | A. retain the following if it is supplied by the Licensor with the Licensed 180 | Material: 181 | 182 | i. identification of the creator(s) of the Licensed Material and any others 183 | designated to receive attribution, in any reasonable manner requested by the 184 | Licensor (including by pseudonym if designated); 185 | 186 | ii. a copyright notice; 187 | 188 | iii. a notice that refers to this Public License; 189 | 190 | iv. a notice that refers to the disclaimer of warranties; 191 | 192 | v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 193 | 194 | B. indicate if You modified the Licensed Material and retain an indication 195 | of any previous modifications; and 196 | 197 | C. indicate the Licensed Material is licensed under this Public License, and 198 | include the text of, or the URI or hyperlink to, this Public License. 199 | 200 | 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner 201 | based on the medium, means, and context in which You Share the Licensed Material. 202 | For example, it may be reasonable to satisfy the conditions by providing a 203 | URI or hyperlink to a resource that includes the required information. 204 | 205 | 3. If requested by the Licensor, You must remove any of the information required 206 | by Section 3(a)(1)(A) to the extent reasonably practicable. 207 | 208 | 4. If You Share Adapted Material You produce, the Adapter's License You apply 209 | must not prevent recipients of the Adapted Material from complying with this 210 | Public License. 211 | 212 | Section 4 – Sui Generis Database Rights. 213 | 214 | Where the Licensed Rights include Sui Generis Database Rights that apply to 215 | Your use of the Licensed Material: 216 | 217 | a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, 218 | reuse, reproduce, and Share all or a substantial portion of the contents of 219 | the database; 220 | 221 | b. if You include all or a substantial portion of the database contents in 222 | a database in which You have Sui Generis Database Rights, then the database 223 | in which You have Sui Generis Database Rights (but not its individual contents) 224 | is Adapted Material; and 225 | 226 | c. You must comply with the conditions in Section 3(a) if You Share all or 227 | a substantial portion of the contents of the database. 228 | 229 | For the avoidance of doubt, this Section 4 supplements and does not replace 230 | Your obligations under this Public License where the Licensed Rights include 231 | other Copyright and Similar Rights. 232 | 233 | Section 5 – Disclaimer of Warranties and Limitation of Liability. 234 | 235 | a. Unless otherwise separately undertaken by the Licensor, to the extent possible, 236 | the Licensor offers the Licensed Material as-is and as-available, and makes 237 | no representations or warranties of any kind concerning the Licensed Material, 238 | whether express, implied, statutory, or other. This includes, without limitation, 239 | warranties of title, merchantability, fitness for a particular purpose, non-infringement, 240 | absence of latent or other defects, accuracy, or the presence or absence of 241 | errors, whether or not known or discoverable. Where disclaimers of warranties 242 | are not allowed in full or in part, this disclaimer may not apply to You. 243 | 244 | b. To the extent possible, in no event will the Licensor be liable to You 245 | on any legal theory (including, without limitation, negligence) or otherwise 246 | for any direct, special, indirect, incidental, consequential, punitive, exemplary, 247 | or other losses, costs, expenses, or damages arising out of this Public License 248 | or use of the Licensed Material, even if the Licensor has been advised of 249 | the possibility of such losses, costs, expenses, or damages. Where a limitation 250 | of liability is not allowed in full or in part, this limitation may not apply 251 | to You. 252 | 253 | c. The disclaimer of warranties and limitation of liability provided above 254 | shall be interpreted in a manner that, to the extent possible, most closely 255 | approximates an absolute disclaimer and waiver of all liability. 256 | 257 | Section 6 – Term and Termination. 258 | 259 | a. This Public License applies for the term of the Copyright and Similar Rights 260 | licensed here. However, if You fail to comply with this Public License, then 261 | Your rights under this Public License terminate automatically. 262 | 263 | b. Where Your right to use the Licensed Material has terminated under Section 264 | 6(a), it reinstates: 265 | 266 | 1. automatically as of the date the violation is cured, provided it is cured 267 | within 30 days of Your discovery of the violation; or 268 | 269 | 2. upon express reinstatement by the Licensor. 270 | 271 | c. For the avoidance of doubt, this Section 6(b) does not affect any right 272 | the Licensor may have to seek remedies for Your violations of this Public 273 | License. 274 | 275 | d. For the avoidance of doubt, the Licensor may also offer the Licensed Material 276 | under separate terms or conditions or stop distributing the Licensed Material 277 | at any time; however, doing so will not terminate this Public License. 278 | 279 | e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 280 | 281 | Section 7 – Other Terms and Conditions. 282 | 283 | a. The Licensor shall not be bound by any additional or different terms or 284 | conditions communicated by You unless expressly agreed. 285 | 286 | b. Any arrangements, understandings, or agreements regarding the Licensed 287 | Material not stated herein are separate from and independent of the terms 288 | and conditions of this Public License. 289 | 290 | Section 8 – Interpretation. 291 | 292 | a. For the avoidance of doubt, this Public License does not, and shall not 293 | be interpreted to, reduce, limit, restrict, or impose conditions on any use 294 | of the Licensed Material that could lawfully be made without permission under 295 | this Public License. 296 | 297 | b. To the extent possible, if any provision of this Public License is deemed 298 | unenforceable, it shall be automatically reformed to the minimum extent necessary 299 | to make it enforceable. If the provision cannot be reformed, it shall be severed 300 | from this Public License without affecting the enforceability of the remaining 301 | terms and conditions. 302 | 303 | c. No term or condition of this Public License will be waived and no failure 304 | to comply consented to unless expressly agreed to by the Licensor. 305 | 306 | d. Nothing in this Public License constitutes or may be interpreted as a limitation 307 | upon, or waiver of, any privileges and immunities that apply to the Licensor 308 | or You, including from the legal processes of any jurisdiction or authority. 309 | 310 | Creative Commons is not a party to its public licenses. Notwithstanding, Creative 311 | Commons may elect to apply one of its public licenses to material it publishes 312 | and in those instances will be considered the "Licensor." The text of the 313 | Creative Commons public licenses is dedicated to the public domain under the 314 | CC0 Public Domain Dedication. Except for the limited purpose of indicating 315 | that material is shared under a Creative Commons public license or as otherwise 316 | permitted by the Creative Commons policies published at creativecommons.org/policies, 317 | Creative Commons does not authorize the use of the trademark "Creative Commons" 318 | or any other trademark or logo of Creative Commons without its prior written 319 | consent including, without limitation, in connection with any unauthorized 320 | modifications to any of its public licenses or any other arrangements, understandings, 321 | or agreements concerning use of licensed material. For the avoidance of doubt, 322 | this paragraph does not form part of the public licenses. 323 | 324 | Creative Commons may be contacted at creativecommons.org. 325 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License Copyright (c) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice (including the next 11 | paragraph) shall be included in all copies or substantial portions of the 12 | Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 17 | OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 19 | OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /LICENSES/Unlicense.txt: -------------------------------------------------------------------------------- 1 | This is free and unencumbered software released into the public domain. 2 | 3 | Anyone is free to copy, modify, publish, use, compile, sell, or distribute 4 | this software, either in source code form or as a compiled binary, for any 5 | purpose, commercial or non-commercial, and by any means. 6 | 7 | In jurisdictions that recognize copyright laws, the author or authors of this 8 | software dedicate any and all copyright interest in the software to the public 9 | domain. We make this dedication for the benefit of the public at large and 10 | to the detriment of our heirs and successors. We intend this dedication to 11 | be an overt act of relinquishment in perpetuity of all present and future 12 | rights to this software under copyright law. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 17 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 18 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH 19 | THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. For more information, 20 | please refer to 21 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | 2 | Introduction 3 | ============ 4 | 5 | .. image:: https://readthedocs.org/projects/adafruit-circuitpython-seesaw/badge/?version=latest 6 | :target: https://docs.circuitpython.org/projects/seesaw/en/latest/ 7 | :alt: Documentation Status 8 | 9 | .. image:: https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_Bundle/main/badges/adafruit_discord.svg 10 | :target: https://adafru.it/discord 11 | :alt: Discord 12 | 13 | .. image:: https://github.com/adafruit/Adafruit_CircuitPython_seesaw/workflows/Build%20CI/badge.svg 14 | :target: https://github.com/adafruit/Adafruit_CircuitPython_seesaw/actions 15 | :alt: Build Status 16 | 17 | .. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json 18 | :target: https://github.com/astral-sh/ruff 19 | :alt: Code Style: Ruff 20 | 21 | CircuitPython module for use with the Adafruit ATSAMD09 seesaw. 22 | 23 | Dependencies 24 | ============= 25 | This driver depends on: 26 | 27 | * `Adafruit CircuitPython `_ 28 | * `Bus Device `_ 29 | 30 | Please ensure all dependencies are available on the CircuitPython filesystem. 31 | This is easily achieved by downloading 32 | `the Adafruit library and driver bundle `_. 33 | 34 | Installing from PyPI 35 | ==================== 36 | 37 | On supported GNU/Linux systems like the Raspberry Pi, you can install the driver locally `from 38 | PyPI `_. To install for current user: 39 | 40 | .. code-block:: shell 41 | 42 | pip3 install adafruit-circuitpython-seesaw 43 | 44 | To install system-wide (this may be required in some cases): 45 | 46 | .. code-block:: shell 47 | 48 | sudo pip3 install adafruit-circuitpython-seesaw 49 | 50 | To install in a virtual environment in your current project: 51 | 52 | .. code-block:: shell 53 | 54 | mkdir project-name && cd project-name 55 | python3 -m venv .venv 56 | source .venv/bin/activate 57 | pip3 install adafruit-circuitpython-seesaw 58 | 59 | Usage Example 60 | ============= 61 | 62 | See examples/seesaw_simpletest.py for usage example. 63 | 64 | Documentation 65 | ============= 66 | 67 | API documentation for this library can be found on `Read the Docs `_. 68 | 69 | For information on building library documentation, please check out `this guide `_. 70 | 71 | Contributing 72 | ============ 73 | 74 | Contributions are welcome! Please read our `Code of Conduct 75 | `_ 76 | before contributing to help this project stay welcoming. 77 | -------------------------------------------------------------------------------- /README.rst.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2017 Scott Shawcroft, written for Adafruit Industries 2 | 3 | SPDX-License-Identifier: MIT 4 | -------------------------------------------------------------------------------- /adafruit_seesaw/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_seesaw/5a4cd087cfe50e5fdcf2475c2023c41a2449711c/adafruit_seesaw/__init__.py -------------------------------------------------------------------------------- /adafruit_seesaw/analoginput.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.analoginput` 8 | ==================================================== 9 | """ 10 | 11 | __version__ = "0.0.0+auto.0" 12 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 13 | 14 | 15 | class AnalogInput: 16 | """CircuitPython-compatible class for analog inputs 17 | 18 | This class is intended to be a compatible subset of `analogio.AnalogIn` 19 | 20 | :param ~adafruit_seesaw.seesaw.Seesaw seesaw: The device 21 | :param int pin: The pin number on the device""" 22 | 23 | def __init__(self, seesaw, pin, delay=0.008): 24 | self._seesaw = seesaw 25 | self._pin = pin 26 | self._delay = delay 27 | 28 | def deinit(self): 29 | pass 30 | 31 | @property 32 | def value(self): 33 | """The current analog value on the pin, as an integer from 0..65535 (inclusive)""" 34 | return self._seesaw.analog_read(self._pin, self._delay) 35 | 36 | @property 37 | def reference_voltage(self): 38 | """The reference voltage for the pin""" 39 | return 3.3 40 | -------------------------------------------------------------------------------- /adafruit_seesaw/attiny8x7.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.attiny8x7` - Pin definition for Adafruit ATtiny8x7 Breakout with seesaw 8 | ================================================================================== 9 | """ 10 | 11 | __version__ = "0.0.0+auto.0" 12 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 13 | 14 | 15 | class ATtiny8x7_Pinmap: 16 | """This class is automatically used by `adafruit_seesaw.seesaw.Seesaw` when 17 | a ATtiny8x7 Breakout is detected. 18 | 19 | It is also a reference for the capabilities of each pin.""" 20 | 21 | #: The pins capable of analog output 22 | analog_pins = (0, 1, 2, 3, 6, 7, 18, 19, 20) 23 | 24 | """The effective bit resolution of the PWM pins""" 25 | pwm_width = 16 # we dont actually use all 16 bits but whatever 26 | 27 | """The pins capable of PWM output""" 28 | pwm_pins = (0, 1, 9, 12, 13) # 8 bit PWM mode 29 | pwm_pins += (6, 7, 8) # 16 bit PWM mode 30 | 31 | """No pins on this board are capable of touch input""" 32 | touch_pins = () 33 | -------------------------------------------------------------------------------- /adafruit_seesaw/attinyx16.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | """ 6 | `adafruit_seesaw.attinyx16` - Pin definition for Adafruit ATtinyx16 Breakout with seesaw 7 | ================================================================================== 8 | """ 9 | 10 | __version__ = "0.0.0+auto.0" 11 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 12 | 13 | 14 | class ATtinyx16_Pinmap: 15 | """This class is automatically used by `adafruit_seesaw.seesaw.Seesaw` when 16 | a ATtinyx16 Breakout (PID 5690, PID 5681) is detected. 17 | 18 | It is also a reference for the capabilities of each pin.""" 19 | 20 | """The pins capable of analog output""" 21 | analog_pins = (0, 1, 2, 3, 4, 5, 14, 15, 16) 22 | 23 | """The effective bit resolution of the PWM pins""" 24 | pwm_width = 16 # we dont actually use all 16 bits but whatever 25 | 26 | """The pins capable of PWM output""" 27 | pwm_pins = (0, 1, 7, 11, 16) # 8 bit PWM mode 28 | pwm_pins += (4, 5, 6) # 16 bit PWM mode 29 | 30 | """No pins on this board are capable of touch input""" 31 | touch_pins = () 32 | -------------------------------------------------------------------------------- /adafruit_seesaw/crickit.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.crickit` - Pin definition for Adafruit CRICKIT 8 | =============================================================== 9 | """ 10 | 11 | try: 12 | from micropython import const 13 | except ImportError: 14 | 15 | def const(x): 16 | return x 17 | 18 | 19 | __version__ = "0.0.0+auto.0" 20 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 21 | 22 | # The ordering here reflects the seesaw firmware pinmap for crickit, 23 | # not logical ordering of the crickit terminals. 24 | 25 | _CRICKIT_SIGNAL1 = const(2) 26 | _CRICKIT_SIGNAL2 = const(3) 27 | _CRICKIT_SIGNAL3 = const(40) 28 | _CRICKIT_SIGNAL4 = const(41) 29 | _CRICKIT_SIGNAL5 = const(11) 30 | _CRICKIT_SIGNAL6 = const(10) 31 | _CRICKIT_SIGNAL7 = const(9) 32 | _CRICKIT_SIGNAL8 = const(8) 33 | 34 | _CRICKIT_SERVO4 = const(14) 35 | _CRICKIT_SERVO3 = const(15) 36 | _CRICKIT_SERVO2 = const(16) 37 | _CRICKIT_SERVO1 = const(17) 38 | 39 | _CRICKIT_MOTOR2B = const(18) 40 | _CRICKIT_MOTOR2A = const(19) 41 | _CRICKIT_MOTOR1A = const(22) 42 | _CRICKIT_MOTOR1B = const(23) 43 | _CRICKIT_DRIVE4 = const(42) 44 | _CRICKIT_DRIVE3 = const(43) 45 | _CRICKIT_DRIVE2 = const(12) 46 | _CRICKIT_DRIVE1 = const(13) 47 | 48 | _CRICKIT_CAPTOUCH1 = const(4) 49 | _CRICKIT_CAPTOUCH2 = const(5) 50 | _CRICKIT_CAPTOUCH3 = const(6) 51 | _CRICKIT_CAPTOUCH4 = const(7) 52 | 53 | # seesaw firmware has indexed lists of pins by function. 54 | # These "pin" numbers map to real PAxx, PBxx pins on the board implementing seesaaw 55 | # They may or may not match. 56 | # See seesaw/include/SeesawConfig.h and seesaw/boards/crickit/board_config.h for the pin choices. 57 | # You must look at both files and combine the defaults in SeesawConfig.h with the 58 | # overrides in crickit/board_config.h. 59 | # PA pins are nn 60 | # PB pins are 32+nn 61 | 62 | 63 | class Crickit_Pinmap: 64 | # seesaw firmware analog pin map: 65 | # analog[0]: 2 analog[1]: 3 analog[2]:40 analog[3]:41 66 | # analog[4]:11 analog[5]:10 analog[6]: 9 analog[7]: 8 67 | # no special remapping: same order as constants above 68 | analog_pins = ( 69 | _CRICKIT_SIGNAL1, 70 | _CRICKIT_SIGNAL2, 71 | _CRICKIT_SIGNAL3, 72 | _CRICKIT_SIGNAL4, 73 | _CRICKIT_SIGNAL5, 74 | _CRICKIT_SIGNAL6, 75 | _CRICKIT_SIGNAL7, 76 | _CRICKIT_SIGNAL8, 77 | ) 78 | 79 | pwm_width = 16 80 | 81 | # seesaw firmware pwm pin map: 82 | # pwm[0]:14 pwm[1]:15 pwm[2]:16 pwm[3]:17 pwm[4]:18 pwm[5]:19 83 | # pwm[6]:22 pwm[7]:23 pwm[8]:42 pwm[9]:43 pwm[10]:12 pwm[11]:13 84 | # Note that servo pins are in reverse order (17-14), and motor pins are shuffled. 85 | pwm_pins = ( 86 | _CRICKIT_SERVO4, 87 | _CRICKIT_SERVO3, 88 | _CRICKIT_SERVO2, 89 | _CRICKIT_SERVO1, 90 | _CRICKIT_MOTOR2B, 91 | _CRICKIT_MOTOR2A, 92 | _CRICKIT_MOTOR1A, 93 | _CRICKIT_MOTOR1B, 94 | _CRICKIT_DRIVE4, 95 | _CRICKIT_DRIVE3, 96 | _CRICKIT_DRIVE2, 97 | _CRICKIT_DRIVE1, 98 | ) 99 | 100 | # seesaw firmware touch pin map: 101 | # touch[0]: 4 touch[1]: 5 touch[2]: 6 touch[3]: 7 102 | touch_pins = ( 103 | _CRICKIT_CAPTOUCH1, 104 | _CRICKIT_CAPTOUCH2, 105 | _CRICKIT_CAPTOUCH3, 106 | _CRICKIT_CAPTOUCH4, 107 | ) 108 | -------------------------------------------------------------------------------- /adafruit_seesaw/digitalio.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.digitalio` 8 | ==================================================== 9 | """ 10 | 11 | import digitalio 12 | 13 | __version__ = "0.0.0+auto.0" 14 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 15 | 16 | 17 | class DigitalIO: 18 | """CircuitPython-compatible class for digital I/O pins 19 | 20 | This class is intended to be a compatible subset of `digitalio.DigitalInOut`. 21 | 22 | Due to technical limitations, PULL_DOWNs are not supported. 23 | 24 | :param ~adafruit_seesaw.seesaw.Seesaw seesaw: The device 25 | :param int pin: The pin number on the device""" 26 | 27 | def __init__(self, seesaw, pin): 28 | self._seesaw = seesaw 29 | self._pin = pin 30 | self._drive_mode = digitalio.DriveMode.PUSH_PULL 31 | self._direction = digitalio.Direction.INPUT 32 | self._pull = None 33 | self._value = False 34 | 35 | def deinit(self): 36 | pass 37 | 38 | def switch_to_output(self, value=False, drive_mode=digitalio.DriveMode.PUSH_PULL): 39 | """Switch the pin to output mode""" 40 | self._seesaw.pin_mode(self._pin, self._seesaw.OUTPUT) 41 | self._seesaw.digital_write(self._pin, value) 42 | self._drive_mode = drive_mode 43 | self._pull = None 44 | 45 | def switch_to_input(self, pull=None): 46 | """Switch the pin to input mode""" 47 | if pull == digitalio.Pull.DOWN: 48 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT_PULLDOWN) 49 | elif pull == digitalio.Pull.UP: 50 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT_PULLUP) 51 | else: 52 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT) 53 | self._pull = pull 54 | 55 | @property 56 | def direction(self): 57 | """Retrieve or set the direction of the pin""" 58 | return self._direction 59 | 60 | @direction.setter 61 | def direction(self, value): 62 | if value == digitalio.Direction.OUTPUT: 63 | self.switch_to_output() 64 | elif value == digitalio.Direction.INPUT: 65 | self.switch_to_input() 66 | else: 67 | raise ValueError("Out of range") 68 | self._direction = value 69 | 70 | @property 71 | def value(self): 72 | """Retrieve or set the value of the pin""" 73 | if self._direction == digitalio.Direction.OUTPUT: 74 | return self._value 75 | return self._seesaw.digital_read(self._pin) 76 | 77 | @value.setter 78 | def value(self, val): 79 | if not 0 <= val <= 1: 80 | raise ValueError("Out of range") 81 | self._seesaw.digital_write(self._pin, val) 82 | self._value = val 83 | 84 | @property 85 | def drive_mode(self): 86 | """Retrieve or set the drive mode of an output pin""" 87 | return self._drive_mode 88 | 89 | @drive_mode.setter 90 | def drive_mode(self, mode): 91 | pass 92 | 93 | @property 94 | def pull(self): 95 | """Retrieve or set the pull mode of an input pin""" 96 | return self._pull 97 | 98 | @pull.setter 99 | def pull(self, mode): 100 | if self._direction == digitalio.Direction.OUTPUT: 101 | raise AttributeError("cannot set pull on an output pin") 102 | if mode == digitalio.Pull.DOWN: 103 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT_PULLDOWN) 104 | elif mode == digitalio.Pull.UP: 105 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT_PULLUP) 106 | elif mode is None: 107 | self._seesaw.pin_mode(self._pin, self._seesaw.INPUT) 108 | else: 109 | raise ValueError("Out of range") 110 | -------------------------------------------------------------------------------- /adafruit_seesaw/keypad.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.keypad` 8 | ==================================================== 9 | """ 10 | 11 | try: 12 | from micropython import const 13 | except ImportError: 14 | 15 | def const(x): 16 | return x 17 | 18 | 19 | from adafruit_seesaw.seesaw import Seesaw 20 | 21 | __version__ = "0.0.0+auto.0" 22 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 23 | 24 | _KEYPAD_BASE = const(0x10) 25 | 26 | _KEYPAD_STATUS = const(0x00) 27 | _KEYPAD_EVENT = const(0x01) 28 | _KEYPAD_INTENSET = const(0x02) 29 | _KEYPAD_INTENCLR = const(0x03) 30 | _KEYPAD_COUNT = const(0x04) 31 | _KEYPAD_FIFO = const(0x10) 32 | 33 | 34 | class KeyEvent: 35 | """Holds information about a key event in its properties 36 | 37 | :param int num: The number of the key 38 | :param int edge: One of the EDGE propertes of `adafruit_seesaw.keypad.Keypad` 39 | """ 40 | 41 | def __init__(self, num, edge): 42 | self.number = int(num) 43 | self.edge = int(edge) 44 | 45 | 46 | # pylint: enable=too-few-public-methods 47 | 48 | 49 | class Keypad(Seesaw): 50 | """On compatible SeeSaw devices, reads from a keypad. 51 | 52 | :param ~busio.I2C i2c_bus: Bus the SeeSaw is connected to 53 | :param int addr: I2C address of the SeeSaw device 54 | :param ~digitalio.DigitalInOut drdy: Pin connected to SeeSaw's 'ready' output""" 55 | 56 | #: Indicates that the key is currently pressed 57 | EDGE_HIGH = 0 58 | #: Indicates that the key is currently released 59 | EDGE_LOW = 1 60 | #: Indicates that the key was recently pressed 61 | EDGE_FALLING = 2 62 | #: Indicates that the key was recently released 63 | EDGE_RISING = 3 64 | 65 | def __init__(self, i2c_bus, addr=0x49, drdy=None): 66 | super().__init__(i2c_bus, addr, drdy) 67 | self._interrupt_enabled = False 68 | 69 | @property 70 | def interrupt_enabled(self): 71 | """Retrieve or set the interrupt enable flag""" 72 | return self._interrupt_enabled 73 | 74 | @interrupt_enabled.setter 75 | def interrupt_enabled(self, value): 76 | if value not in {True, False}: 77 | raise ValueError("interrupt_enabled must be True or False") 78 | 79 | self._interrupt_enabled = value 80 | if value: 81 | self.write8(_KEYPAD_BASE, _KEYPAD_INTENSET, 1) 82 | else: 83 | self.write8(_KEYPAD_BASE, _KEYPAD_INTENCLR, 1) 84 | 85 | @property 86 | def count(self): # noqa: PLR6301 87 | """Retrieve or set the number of keys""" 88 | return self.read8(_KEYPAD_BASE, _KEYPAD_COUNT) 89 | 90 | @count.setter 91 | def count(self, value): # noqa: PLR6301 92 | raise AttributeError("count is read only") 93 | 94 | def set_event(self, key, edge, enable): 95 | """Control which kinds of events are set 96 | 97 | :param int key: The key number 98 | :param int edge: The type of event 99 | :param bool enable: True to enable the event, False to disable it""" 100 | 101 | if enable not in {True, False}: 102 | raise ValueError("event enable must be True or False") 103 | if edge > 3 or edge < 0: 104 | raise ValueError("invalid edge") 105 | 106 | cmd = bytearray(2) 107 | cmd[0] = key 108 | cmd[1] = (1 << (edge + 1)) | enable 109 | 110 | self.write(_KEYPAD_BASE, _KEYPAD_EVENT, cmd) 111 | 112 | def read_keypad(self, num): 113 | """Read data from the keypad 114 | 115 | :param int num: The number of bytes to read""" 116 | ret = bytearray(num) 117 | self.read(_KEYPAD_BASE, _KEYPAD_FIFO, ret) 118 | return ret 119 | -------------------------------------------------------------------------------- /adafruit_seesaw/neopixel.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.neopixel` 8 | ==================================================== 9 | """ 10 | 11 | import struct 12 | 13 | from adafruit_pixelbuf import PixelBuf 14 | 15 | try: 16 | from micropython import const 17 | except ImportError: 18 | 19 | def const(x): 20 | return x 21 | 22 | 23 | ### hack to make sure this module is not placed in root CIRCUITPY/lib folder 24 | if "." not in __name__: 25 | raise ImportError( 26 | "seesaw neopixel being imported from unexpected location - is seesaw neopixel use intended?" 27 | ) 28 | 29 | __version__ = "0.0.0+auto.0" 30 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 31 | 32 | _NEOPIXEL_BASE = const(0x0E) 33 | 34 | _NEOPIXEL_STATUS = const(0x00) 35 | _NEOPIXEL_PIN = const(0x01) 36 | _NEOPIXEL_SPEED = const(0x02) 37 | _NEOPIXEL_BUF_LENGTH = const(0x03) 38 | _NEOPIXEL_BUF = const(0x04) 39 | _NEOPIXEL_SHOW = const(0x05) 40 | 41 | # try lower values if IO errors 42 | _OUTPUT_BUFFER_SIZE = const(24) 43 | 44 | # Pixel color order constants 45 | RGB = "RGB" 46 | """Red Green Blue""" 47 | GRB = "GRB" 48 | """Green Red Blue""" 49 | RGBW = "RGBW" 50 | """Red Green Blue White""" 51 | GRBW = "GRBW" 52 | """Green Red Blue White""" 53 | 54 | 55 | class NeoPixel(PixelBuf): 56 | """Control NeoPixels connected to a seesaw 57 | 58 | :param ~adafruit_seesaw.seesaw.Seesaw seesaw: The device 59 | :param int pin: The pin number on the device 60 | :param int n: The number of pixels 61 | :param int bpp: The number of bytes per pixel 62 | :param float brightness: The brightness, from 0.0 to 1.0 63 | :param bool auto_write: Automatically update the pixels when changed 64 | :param tuple pixel_order: The layout of the pixels. 65 | Use one of the order constants such as RGBW.""" 66 | 67 | def __init__( 68 | self, seesaw, pin, n, *, bpp=None, brightness=1.0, auto_write=True, pixel_order="GRB" 69 | ): 70 | self._seesaw = seesaw 71 | self._pin = pin 72 | if not pixel_order: 73 | pixel_order = GRB if bpp == 3 else GRBW 74 | elif isinstance(pixel_order, tuple): 75 | # convert legacy pixel order into PixelBuf pixel order 76 | order_list = ["RGBW"[order] for order in pixel_order] 77 | pixel_order = "".join(order_list) 78 | 79 | super().__init__( 80 | n, 81 | byteorder=pixel_order, 82 | brightness=brightness, 83 | auto_write=auto_write, 84 | ) 85 | 86 | cmd = bytearray([pin]) 87 | self._seesaw.write(_NEOPIXEL_BASE, _NEOPIXEL_PIN, cmd) 88 | cmd = struct.pack(">H", n * self.bpp) 89 | self._seesaw.write(_NEOPIXEL_BASE, _NEOPIXEL_BUF_LENGTH, cmd) 90 | self.output_buffer = bytearray(_OUTPUT_BUFFER_SIZE) 91 | 92 | def _transmit(self, buffer: bytearray) -> None: 93 | """Update the pixels even if auto_write is False""" 94 | 95 | step = _OUTPUT_BUFFER_SIZE - 2 96 | for i in range(0, len(buffer), step): 97 | self.output_buffer[0:2] = struct.pack(">H", i) 98 | self.output_buffer[2:] = buffer[i : i + step] 99 | self._seesaw.write(_NEOPIXEL_BASE, _NEOPIXEL_BUF, self.output_buffer) 100 | 101 | self._seesaw.write(_NEOPIXEL_BASE, _NEOPIXEL_SHOW) 102 | 103 | def deinit(self): 104 | pass 105 | -------------------------------------------------------------------------------- /adafruit_seesaw/pwmout.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.pwmout` 8 | ==================================================== 9 | """ 10 | 11 | __version__ = "0.0.0+auto.0" 12 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 13 | 14 | 15 | class PWMOut: 16 | """A single seesaw channel that matches the :py:class:`~pwmio.PWMOut` API.""" 17 | 18 | def __init__(self, seesaw, pin): 19 | self._seesaw = seesaw 20 | self._pin = pin 21 | self._dc = 0 22 | self._frequency = 0 23 | 24 | @property 25 | def frequency(self): 26 | """The overall PWM frequency in Hertz.""" 27 | return self._frequency 28 | 29 | @frequency.setter 30 | def frequency(self, frequency): 31 | self._seesaw.set_pwm_freq(self._pin, frequency) 32 | self._frequency = frequency 33 | 34 | @property 35 | def duty_cycle(self): 36 | """16-bit value that dictates how much of one cycle is high (1) versus low (0). 37 | 65535 (0xffff) will always be high, 0 will always be low, 38 | and 32767 (0x7fff) will be half high and then half low. 39 | """ 40 | return self._dc 41 | 42 | @duty_cycle.setter 43 | def duty_cycle(self, value): 44 | if not 0 <= value <= 0xFFFF: 45 | raise ValueError("Must be 0 to 65535") 46 | self._seesaw.analog_write(self._pin, value) 47 | self._dc = value 48 | 49 | @property 50 | def fraction(self): 51 | """Expresses duty_cycle as a fractional value. Ranges from 0.0-1.0.""" 52 | return self.duty_cycle / 65535 53 | 54 | @fraction.setter 55 | def fraction(self, value): 56 | if not 0.0 <= value <= 1.0: 57 | raise ValueError("Must be 0.0 to 1.0") 58 | self.duty_cycle = int(value * 65535) 59 | -------------------------------------------------------------------------------- /adafruit_seesaw/robohat.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2019 wallarug Robotics Masters 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.robohat` - Pin definition for RoboHAT 8 | ====================================================== 9 | """ 10 | 11 | try: 12 | from micropython import const 13 | except ImportError: 14 | 15 | def const(x): 16 | return x 17 | 18 | 19 | __version__ = "0.0.0+auto.0" 20 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 21 | 22 | # Robo HAT MM1 Board: https://www.crowdsupply.com/robotics-masters/robo-hat-mm1 23 | 24 | # The ordering here reflects the seesaw firmware (mm1_hat) pinmap for Robo HAT MM1, 25 | # not logical ordering of the HAT terminals. 26 | 27 | _MM1_D0 = const(55) # (RX to RPI_TX) 28 | _MM1_D1 = const(54) # (TX to RPI_RX) 29 | _MM1_D2 = const(34) # ADC (GPS_TX) 30 | _MM1_D3 = const(35) # ADC (GPS_RX) 31 | _MM1_D4 = const(0) # (GPS_SDA) 32 | _MM1_D5 = const(1) # (GPS_SCL) 33 | _MM1_D6 = const(28) # (POWER_ENABLE) 34 | _MM1_D7 = const(2) # (BATTERY) 35 | _MM1_D8 = const(20) # (NEOPIXEL) 36 | _MM1_D9 = const(43) # PWM (SPI_SCK) 37 | _MM1_D10 = const(41) # PWM (SPI_SS) 38 | _MM1_D11 = const(42) # PWM (SPI_MOSI) 39 | _MM1_D12 = const(40) # PWM (SPI_MISO) 40 | _MM1_D13 = const(21) # LED 41 | _MM1_D14 = const(3) # (POWER_OFF) 42 | 43 | _MM1_SERVO8 = const(8) 44 | _MM1_SERVO7 = const(9) 45 | _MM1_SERVO6 = const(10) 46 | _MM1_SERVO5 = const(11) 47 | _MM1_SERVO4 = const(19) 48 | _MM1_SERVO3 = const(18) 49 | _MM1_SERVO2 = const(17) 50 | _MM1_SERVO1 = const(16) 51 | 52 | _MM1_RCH1 = const(7) 53 | _MM1_RCH2 = const(6) 54 | _MM1_RCH3 = const(5) 55 | _MM1_RCH4 = const(4) 56 | 57 | 58 | # seesaw firmware has indexed lists of pins by function. 59 | # These "pin" numbers map to real PAxx, PBxx pins on the board implementing seesaaw 60 | # They may or may not match. 61 | # See seesaw/include/SeesawConfig.h and seesaw/boards/robohatmm1/board_config.h for the pin choices. 62 | 63 | # You must look at both files and combine the defaults in SeesawConfig.h with the 64 | # overrides in robohatmm1/board_config.h. 65 | # PA pins are nn 66 | # PB pins are 32+nn 67 | 68 | 69 | class MM1_Pinmap: 70 | """This class is automatically used by `adafruit_seesaw.seesaw.Seesaw` when 71 | a RoboHAT board is detected. 72 | 73 | It is also a reference for the capabilities of each pin.""" 74 | 75 | # seesaw firmware (mm1_hat) analog pin map: 76 | # analog[0]:47 analog[1]:48 analog[2]: analog[3]: 77 | # analog[4]: analog[5]: analog[6]: analog[7]: 78 | # 79 | #: The pins capable of analog output 80 | analog_pins = (_MM1_D3, _MM1_D2) 81 | 82 | #: The effective bit resolution of the PWM pins 83 | pwm_width = 16 84 | 85 | # seesaw firmware (mm1_hat) pwm pin map: 86 | # pwm[0]:16 pwm[1]:17 pwm[2]:18 pwm[3]:19 pwm[4]:11 pwm[5]:10 87 | # pwm[6]:9 pwm[7]:8 pwm[8]:40 pwm[9]:41 pwm[10]:42 pwm[11]:43 88 | # 89 | #: The pins capable of PWM output 90 | pwm_pins = ( 91 | _MM1_SERVO1, 92 | _MM1_SERVO2, 93 | _MM1_SERVO3, 94 | _MM1_SERVO4, 95 | _MM1_SERVO5, 96 | _MM1_SERVO6, 97 | _MM1_SERVO7, 98 | _MM1_SERVO8, 99 | _MM1_D12, 100 | _MM1_D10, 101 | _MM1_D11, 102 | _MM1_D9, 103 | ) 104 | 105 | # seesaw firmware touch pin map: 106 | # touch[0]: 7 touch[1]: 6 touch[2]: 5 touch[3]: 4 107 | #: The pins capable of touch input 108 | touch_pins = (_MM1_RCH1, _MM1_RCH2, _MM1_RCH3, _MM1_RCH4) 109 | -------------------------------------------------------------------------------- /adafruit_seesaw/rotaryio.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.rotaryio` 8 | ==================================================== 9 | """ 10 | 11 | __version__ = "0.0.0+auto.0" 12 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 13 | 14 | 15 | class IncrementalEncoder: 16 | """IncrementalEncoder determines the relative rotational position based 17 | on two series of pulses.""" 18 | 19 | def __init__(self, seesaw, encoder=0): 20 | """Create an IncrementalEncoder object associated with the given 21 | eesaw device.""" 22 | self._seesaw = seesaw 23 | self._encoder = encoder 24 | 25 | @property 26 | def position(self): 27 | """The current position in terms of pulses. The number of pulses per 28 | rotation is defined by the specific hardware.""" 29 | return self._seesaw.encoder_position(self._encoder) 30 | 31 | @position.setter 32 | def position(self, value): 33 | self._seesaw.set_encoder_position(value, self._encoder) 34 | -------------------------------------------------------------------------------- /adafruit_seesaw/samd09.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.samd09` - Pin definition for Adafruit SAMD09 Breakout with seesaw 8 | ================================================================================== 9 | """ 10 | 11 | try: 12 | from micropython import const 13 | except ImportError: 14 | 15 | def const(x): 16 | return x 17 | 18 | 19 | __version__ = "0.0.0+auto.0" 20 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 21 | 22 | _ADC_INPUT_0_PIN = const(0x02) 23 | _ADC_INPUT_1_PIN = const(0x03) 24 | _ADC_INPUT_2_PIN = const(0x04) 25 | _ADC_INPUT_3_PIN = const(0x05) 26 | 27 | _PWM_0_PIN = const(0x04) 28 | _PWM_1_PIN = const(0x05) 29 | _PWM_2_PIN = const(0x06) 30 | _PWM_3_PIN = const(0x07) 31 | 32 | 33 | class SAMD09_Pinmap: 34 | """This class is automatically used by `adafruit_seesaw.seesaw.Seesaw` when 35 | a SAMD09 Breakout is detected. 36 | 37 | It is also a reference for the capabilities of each pin.""" 38 | 39 | #: The pins capable of analog output 40 | analog_pins = ( 41 | _ADC_INPUT_0_PIN, 42 | _ADC_INPUT_1_PIN, 43 | _ADC_INPUT_2_PIN, 44 | _ADC_INPUT_3_PIN, 45 | ) 46 | 47 | """The effective bit resolution of the PWM pins""" 48 | pwm_width = 8 49 | 50 | """The pins capable of PWM output""" 51 | pwm_pins = (_PWM_0_PIN, _PWM_1_PIN, _PWM_2_PIN, _PWM_3_PIN) 52 | 53 | """No pins on this board are capable of touch input""" 54 | touch_pins = () 55 | -------------------------------------------------------------------------------- /adafruit_seesaw/seesaw.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2017 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | """ 6 | `adafruit_seesaw.seesaw` 7 | ==================================================== 8 | 9 | An I2C to whatever helper chip. 10 | 11 | * Author(s): Dean Miller 12 | 13 | Implementation Notes 14 | -------------------- 15 | 16 | **Hardware:** 17 | 18 | * Adafruit `ATSAMD09 Breakout with seesaw 19 | `_ (Product ID: 3657) 20 | 21 | **Software and Dependencies:** 22 | 23 | * Adafruit CircuitPython firmware: https://circuitpython.org/ 24 | * or Adafruit Blinka: https://circuitpython.org/blinka 25 | * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice 26 | """ 27 | 28 | # This code needs to be broken up into analogio, busio, digitalio, and pulseio 29 | # compatible classes so we won't bother with some lints until then. 30 | 31 | import struct 32 | import time 33 | 34 | try: 35 | from micropython import const 36 | except ImportError: 37 | 38 | def const(x): 39 | return x 40 | 41 | 42 | from adafruit_bus_device.i2c_device import I2CDevice 43 | 44 | __version__ = "0.0.0+auto.0" 45 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 46 | 47 | _STATUS_BASE = const(0x00) 48 | 49 | _GPIO_BASE = const(0x01) 50 | _SERCOM0_BASE = const(0x02) 51 | 52 | _TIMER_BASE = const(0x08) 53 | _ADC_BASE = const(0x09) 54 | _DAC_BASE = const(0x0A) 55 | _INTERRUPT_BASE = const(0x0B) 56 | _DAP_BASE = const(0x0C) 57 | _EEPROM_BASE = const(0x0D) 58 | _NEOPIXEL_BASE = const(0x0E) 59 | _TOUCH_BASE = const(0x0F) 60 | _ENCODER_BASE = const(0x11) 61 | 62 | _GPIO_DIRSET_BULK = const(0x02) 63 | _GPIO_DIRCLR_BULK = const(0x03) 64 | _GPIO_BULK = const(0x04) 65 | _GPIO_BULK_SET = const(0x05) 66 | _GPIO_BULK_CLR = const(0x06) 67 | _GPIO_BULK_TOGGLE = const(0x07) 68 | _GPIO_INTENSET = const(0x08) 69 | _GPIO_INTENCLR = const(0x09) 70 | _GPIO_INTFLAG = const(0x0A) 71 | _GPIO_PULLENSET = const(0x0B) 72 | _GPIO_PULLENCLR = const(0x0C) 73 | 74 | _STATUS_HW_ID = const(0x01) 75 | _STATUS_VERSION = const(0x02) 76 | _STATUS_OPTIONS = const(0x03) 77 | _STATUS_TEMP = const(0x04) 78 | _STATUS_SWRST = const(0x7F) 79 | 80 | _TIMER_STATUS = const(0x00) 81 | _TIMER_PWM = const(0x01) 82 | _TIMER_FREQ = const(0x02) 83 | 84 | _ADC_STATUS = const(0x00) 85 | _ADC_INTEN = const(0x02) 86 | _ADC_INTENCLR = const(0x03) 87 | _ADC_WINMODE = const(0x04) 88 | _ADC_WINTHRESH = const(0x05) 89 | _ADC_CHANNEL_OFFSET = const(0x07) 90 | 91 | _SERCOM_STATUS = const(0x00) 92 | _SERCOM_INTEN = const(0x02) 93 | _SERCOM_INTENCLR = const(0x03) 94 | _SERCOM_BAUD = const(0x04) 95 | _SERCOM_DATA = const(0x05) 96 | 97 | _NEOPIXEL_STATUS = const(0x00) 98 | _NEOPIXEL_PIN = const(0x01) 99 | _NEOPIXEL_SPEED = const(0x02) 100 | _NEOPIXEL_BUF_LENGTH = const(0x03) 101 | _NEOPIXEL_BUF = const(0x04) 102 | _NEOPIXEL_SHOW = const(0x05) 103 | 104 | _TOUCH_CHANNEL_OFFSET = const(0x10) 105 | 106 | _SAMD09_HW_ID_CODE = const(0x55) 107 | _ATTINY806_HW_ID_CODE = const(0x84) 108 | _ATTINY807_HW_ID_CODE = const(0x85) 109 | _ATTINY816_HW_ID_CODE = const(0x86) 110 | _ATTINY817_HW_ID_CODE = const(0x87) 111 | _ATTINY1616_HW_ID_CODE = const(0x88) 112 | _ATTINY1617_HW_ID_CODE = const(0x89) 113 | 114 | _ENCODER_STATUS = const(0x00) 115 | _ENCODER_INTENSET = const(0x10) 116 | _ENCODER_INTENCLR = const(0x20) 117 | _ENCODER_POSITION = const(0x30) 118 | _ENCODER_DELTA = const(0x40) 119 | 120 | # TODO: update when we get real PID 121 | _CRICKIT_PID = const(9999) 122 | _ROBOHATMM1_PID = const(9998) 123 | _5690_PID = const(5690) 124 | _5681_PID = const(5681) 125 | _5743_PID = const(5743) 126 | 127 | 128 | class Seesaw: 129 | """Driver for Seesaw i2c generic conversion trip 130 | 131 | :param ~busio.I2C i2c_bus: Bus the SeeSaw is connected to 132 | :param int addr: I2C address of the SeeSaw device 133 | :param ~digitalio.DigitalInOut drdy: Pin connected to SeeSaw's 'ready' output 134 | :param bool reset: Whether to do a software reset on init""" 135 | 136 | INPUT = const(0x00) 137 | OUTPUT = const(0x01) 138 | INPUT_PULLUP = const(0x02) 139 | INPUT_PULLDOWN = const(0x03) 140 | 141 | def __init__(self, i2c_bus, addr=0x49, drdy=None, reset=True): 142 | self._drdy = drdy 143 | if drdy is not None: 144 | drdy.switch_to_input() 145 | 146 | self.i2c_device = I2CDevice(i2c_bus, addr) 147 | if reset: 148 | self.sw_reset() 149 | 150 | self.chip_id = self.read8(_STATUS_BASE, _STATUS_HW_ID) 151 | if self.chip_id not in { 152 | _ATTINY806_HW_ID_CODE, 153 | _ATTINY807_HW_ID_CODE, 154 | _ATTINY816_HW_ID_CODE, 155 | _ATTINY817_HW_ID_CODE, 156 | _ATTINY1616_HW_ID_CODE, 157 | _ATTINY1617_HW_ID_CODE, 158 | _SAMD09_HW_ID_CODE, 159 | }: 160 | raise RuntimeError( 161 | f"Seesaw hardware ID returned 0x{self.chip_id:x} is not " 162 | "correct! Please check your wiring." 163 | ) 164 | 165 | pid = self.get_version() >> 16 166 | if pid == _CRICKIT_PID: 167 | from adafruit_seesaw.crickit import Crickit_Pinmap # noqa: PLC0415 168 | 169 | self.pin_mapping = Crickit_Pinmap 170 | elif pid == _ROBOHATMM1_PID: 171 | from adafruit_seesaw.robohat import MM1_Pinmap # noqa: PLC0415 172 | 173 | self.pin_mapping = MM1_Pinmap 174 | elif (pid in {_5690_PID, _5681_PID, _5743_PID}) or ( 175 | self.chip_id in {_ATTINY816_HW_ID_CODE, _ATTINY806_HW_ID_CODE, _ATTINY1616_HW_ID_CODE} 176 | ): 177 | from adafruit_seesaw.attinyx16 import ATtinyx16_Pinmap # noqa: PLC0415 178 | 179 | self.pin_mapping = ATtinyx16_Pinmap 180 | elif self.chip_id == _SAMD09_HW_ID_CODE: 181 | from adafruit_seesaw.samd09 import SAMD09_Pinmap # noqa: PLC0415 182 | 183 | self.pin_mapping = SAMD09_Pinmap 184 | elif self.chip_id in { 185 | _ATTINY817_HW_ID_CODE, 186 | _ATTINY807_HW_ID_CODE, 187 | _ATTINY1617_HW_ID_CODE, 188 | }: 189 | from adafruit_seesaw.attiny8x7 import ATtiny8x7_Pinmap # noqa: PLC0415 190 | 191 | self.pin_mapping = ATtiny8x7_Pinmap 192 | 193 | def sw_reset(self, post_reset_delay=0.5): 194 | """Trigger a software reset of the SeeSaw chip""" 195 | self.write8(_STATUS_BASE, _STATUS_SWRST, 0xFF) 196 | time.sleep(post_reset_delay) 197 | 198 | def get_options(self): 199 | """Retrieve the 'options' word from the SeeSaw board""" 200 | buf = bytearray(4) 201 | self.read(_STATUS_BASE, _STATUS_OPTIONS, buf) 202 | ret = struct.unpack(">I", buf)[0] 203 | return ret 204 | 205 | def get_version(self): 206 | """Retrieve the 'version' word from the SeeSaw board""" 207 | buf = bytearray(4) 208 | self.read(_STATUS_BASE, _STATUS_VERSION, buf) 209 | ret = struct.unpack(">I", buf)[0] 210 | return ret 211 | 212 | def pin_mode(self, pin, mode): 213 | """Set the mode of a pin by number""" 214 | if pin >= 32: 215 | self.pin_mode_bulk_b(1 << (pin - 32), mode) 216 | else: 217 | self.pin_mode_bulk(1 << pin, mode) 218 | 219 | def digital_write(self, pin, value): 220 | """Set the value of an output pin by number""" 221 | if pin >= 32: 222 | self.digital_write_bulk_b(1 << (pin - 32), value) 223 | else: 224 | self.digital_write_bulk(1 << pin, value) 225 | 226 | def digital_read(self, pin): 227 | """Get the value of an input pin by number""" 228 | if pin >= 32: 229 | return self.digital_read_bulk_b(1 << (pin - 32)) != 0 230 | return self.digital_read_bulk(1 << pin) != 0 231 | 232 | def digital_read_bulk(self, pins, delay=0.008): 233 | """Get the values of all the pins on the 'A' port as a bitmask""" 234 | buf = bytearray(4) 235 | self.read(_GPIO_BASE, _GPIO_BULK, buf, delay=delay) 236 | try: 237 | ret = struct.unpack(">I", buf)[0] 238 | except OverflowError: 239 | buf[0] = buf[0] & 0x3F 240 | ret = struct.unpack(">I", buf)[0] 241 | return ret & pins 242 | 243 | def digital_read_bulk_b(self, pins, delay=0.008): 244 | """Get the values of all the pins on the 'B' port as a bitmask""" 245 | buf = bytearray(8) 246 | self.read(_GPIO_BASE, _GPIO_BULK, buf, delay=delay) 247 | ret = struct.unpack(">I", buf[4:])[0] 248 | return ret & pins 249 | 250 | def set_GPIO_interrupts(self, pins, enabled): 251 | """Enable or disable the GPIO interrupt""" 252 | cmd = struct.pack(">I", pins) 253 | if enabled: 254 | self.write(_GPIO_BASE, _GPIO_INTENSET, cmd) 255 | else: 256 | self.write(_GPIO_BASE, _GPIO_INTENCLR, cmd) 257 | 258 | def get_GPIO_interrupt_flag(self, delay=0.008): 259 | """Read and clear GPIO interrupts that have fired""" 260 | buf = bytearray(4) 261 | self.read(_GPIO_BASE, _GPIO_INTFLAG, buf, delay=delay) 262 | return struct.unpack(">I", buf)[0] 263 | 264 | def analog_read(self, pin, delay=0.008): 265 | """Read the value of an analog pin by number""" 266 | buf = bytearray(2) 267 | if pin not in self.pin_mapping.analog_pins: 268 | raise ValueError("Invalid ADC pin") 269 | 270 | if self.chip_id == _SAMD09_HW_ID_CODE: 271 | offset = self.pin_mapping.analog_pins.index(pin) 272 | else: 273 | offset = pin 274 | 275 | self.read(_ADC_BASE, _ADC_CHANNEL_OFFSET + offset, buf, delay) 276 | ret = struct.unpack(">H", buf)[0] 277 | return ret 278 | 279 | def touch_read(self, pin): 280 | """Read the value of a touch pin by number""" 281 | buf = bytearray(2) 282 | 283 | if pin not in self.pin_mapping.touch_pins: 284 | raise ValueError("Invalid touch pin") 285 | 286 | self.read( 287 | _TOUCH_BASE, 288 | _TOUCH_CHANNEL_OFFSET + self.pin_mapping.touch_pins.index(pin), 289 | buf, 290 | ) 291 | ret = struct.unpack(">H", buf)[0] 292 | return ret 293 | 294 | def moisture_read(self): 295 | """Read the value of the moisture sensor""" 296 | buf = bytearray(2) 297 | 298 | self.read(_TOUCH_BASE, _TOUCH_CHANNEL_OFFSET, buf, 0.005) 299 | ret = struct.unpack(">H", buf)[0] 300 | time.sleep(0.001) 301 | 302 | # retry if reading was bad 303 | count = 0 304 | while ret > 4095: 305 | self.read(_TOUCH_BASE, _TOUCH_CHANNEL_OFFSET, buf, 0.005) 306 | ret = struct.unpack(">H", buf)[0] 307 | time.sleep(0.001) 308 | count += 1 309 | if count > 3: 310 | raise RuntimeError("Could not get a valid moisture reading.") 311 | 312 | return ret 313 | 314 | def _pin_mode_bulk_x(self, capacity, offset, pins, mode): 315 | cmd = bytearray(capacity) 316 | cmd[offset:] = struct.pack(">I", pins) 317 | if mode == self.OUTPUT: 318 | self.write(_GPIO_BASE, _GPIO_DIRSET_BULK, cmd) 319 | elif mode == self.INPUT: 320 | self.write(_GPIO_BASE, _GPIO_DIRCLR_BULK, cmd) 321 | self.write(_GPIO_BASE, _GPIO_PULLENCLR, cmd) 322 | 323 | elif mode == self.INPUT_PULLUP: 324 | self.write(_GPIO_BASE, _GPIO_DIRCLR_BULK, cmd) 325 | self.write(_GPIO_BASE, _GPIO_PULLENSET, cmd) 326 | self.write(_GPIO_BASE, _GPIO_BULK_SET, cmd) 327 | 328 | elif mode == self.INPUT_PULLDOWN: 329 | self.write(_GPIO_BASE, _GPIO_DIRCLR_BULK, cmd) 330 | self.write(_GPIO_BASE, _GPIO_PULLENSET, cmd) 331 | self.write(_GPIO_BASE, _GPIO_BULK_CLR, cmd) 332 | 333 | else: 334 | raise ValueError("Invalid pin mode") 335 | 336 | def pin_mode_bulk(self, pins, mode): 337 | """Set the mode of all the pins on the 'A' port as a bitmask""" 338 | self._pin_mode_bulk_x(4, 0, pins, mode) 339 | 340 | def pin_mode_bulk_b(self, pins, mode): 341 | """Set the mode of all the pins on the 'B' port as a bitmask""" 342 | self._pin_mode_bulk_x(8, 4, pins, mode) 343 | 344 | def digital_write_bulk(self, pins, value): 345 | """Set the mode of pins on the 'A' port as a bitmask""" 346 | cmd = struct.pack(">I", pins) 347 | if value: 348 | self.write(_GPIO_BASE, _GPIO_BULK_SET, cmd) 349 | else: 350 | self.write(_GPIO_BASE, _GPIO_BULK_CLR, cmd) 351 | 352 | def digital_write_bulk_b(self, pins, value): 353 | """Set the mode of pins on the 'B' port as a bitmask""" 354 | cmd = bytearray(8) 355 | cmd[4:] = struct.pack(">I", pins) 356 | if value: 357 | self.write(_GPIO_BASE, _GPIO_BULK_SET, cmd) 358 | else: 359 | self.write(_GPIO_BASE, _GPIO_BULK_CLR, cmd) 360 | 361 | def analog_write(self, pin, value): 362 | """Set the value of an analog output by number""" 363 | if pin not in self.pin_mapping.pwm_pins: 364 | raise ValueError("Invalid PWM pin") 365 | 366 | if self.chip_id == _SAMD09_HW_ID_CODE: 367 | offset = self.pin_mapping.pwm_pins.index(pin) 368 | else: 369 | offset = pin 370 | 371 | if self.pin_mapping.pwm_width == 16: 372 | cmd = bytearray([offset, (value >> 8), value & 0xFF]) 373 | else: 374 | cmd = bytearray([offset, value]) 375 | 376 | self.write(_TIMER_BASE, _TIMER_PWM, cmd) 377 | time.sleep(0.001) 378 | 379 | def get_temp(self): 380 | """Read the temperature""" 381 | buf = bytearray(4) 382 | self.read(_STATUS_BASE, _STATUS_TEMP, buf, 0.005) 383 | buf[0] = buf[0] & 0x3F 384 | ret = struct.unpack(">I", buf)[0] 385 | return 0.00001525878 * ret 386 | 387 | def set_pwm_freq(self, pin, freq): 388 | """Set the PWM frequency of a pin by number""" 389 | if pin not in self.pin_mapping.pwm_pins: 390 | raise ValueError("Invalid PWM pin") 391 | 392 | if self.chip_id == _SAMD09_HW_ID_CODE: 393 | offset = self.pin_mapping.pwm_pins.index(pin) 394 | else: 395 | offset = pin 396 | 397 | cmd = bytearray([offset, (freq >> 8), freq & 0xFF]) 398 | self.write(_TIMER_BASE, _TIMER_FREQ, cmd) 399 | 400 | def encoder_position(self, encoder=0): 401 | """The current position of the encoder""" 402 | buf = bytearray(4) 403 | self.read(_ENCODER_BASE, _ENCODER_POSITION + encoder, buf) 404 | return struct.unpack(">i", buf)[0] 405 | 406 | def set_encoder_position(self, pos, encoder=0): 407 | """Set the current position of the encoder""" 408 | cmd = struct.pack(">i", pos) 409 | self.write(_ENCODER_BASE, _ENCODER_POSITION + encoder, cmd) 410 | 411 | def encoder_delta(self, encoder=0): 412 | """The change in encoder position since it was last read""" 413 | buf = bytearray(4) 414 | self.read(_ENCODER_BASE, _ENCODER_DELTA + encoder, buf) 415 | return struct.unpack(">i", buf)[0] 416 | 417 | def enable_encoder_interrupt(self, encoder=0): 418 | """Enable the interrupt to fire when the encoder changes position""" 419 | self.write8(_ENCODER_BASE, _ENCODER_INTENSET + encoder, 0x01) 420 | 421 | def disable_encoder_interrupt(self, encoder=0): 422 | """Disable the interrupt from firing when the encoder changes""" 423 | self.write8(_ENCODER_BASE, _ENCODER_INTENCLR + encoder, 0x01) 424 | 425 | # def enable_sercom_data_rdy_interrupt(self, sercom): 426 | # 427 | # _sercom_inten.DATA_RDY = 1 428 | # self.write8(SEESAW_SERCOM0_BASE + sercom, SEESAW_SERCOM_INTEN, _sercom_inten.get()) 429 | # 430 | # 431 | # def disable_sercom_data_rdy_interrupt(self, sercom): 432 | # 433 | # _sercom_inten.DATA_RDY = 0 434 | # self.write8(SEESAW_SERCOM0_BASE + sercom, SEESAW_SERCOM_INTEN, _sercom_inten.get()) 435 | # 436 | # 437 | # def read_sercom_data(self, sercom): 438 | # 439 | # return self.read8(SEESAW_SERCOM0_BASE + sercom, SEESAW_SERCOM_DATA) 440 | 441 | def _get_eeprom_i2c_addr(self): 442 | """Return the EEPROM address used to store I2C address.""" 443 | chip_id = self.chip_id 444 | if chip_id in { 445 | _ATTINY806_HW_ID_CODE, 446 | _ATTINY807_HW_ID_CODE, 447 | _ATTINY816_HW_ID_CODE, 448 | _ATTINY817_HW_ID_CODE, 449 | }: 450 | return 0x7F 451 | if chip_id in { 452 | _ATTINY1616_HW_ID_CODE, 453 | _ATTINY1617_HW_ID_CODE, 454 | }: 455 | return 0xFF 456 | if chip_id in {_SAMD09_HW_ID_CODE}: 457 | return 0x3F 458 | return None 459 | 460 | def set_i2c_addr(self, addr): 461 | """Store a new address in the device's EEPROM and reboot it.""" 462 | self.eeprom_write8(self._get_eeprom_i2c_addr(), addr) 463 | 464 | def get_i2c_addr(self): 465 | """Return the device's I2C address stored in its EEPROM""" 466 | return self.read8(_EEPROM_BASE, self._get_eeprom_i2c_addr()) 467 | 468 | def eeprom_write8(self, addr, val): 469 | """Write a single byte directly to the device's EEPROM""" 470 | self.eeprom_write(addr, bytearray([val])) 471 | 472 | def eeprom_write(self, addr, buf): 473 | """Write multiple bytes directly to the device's EEPROM""" 474 | self.write(_EEPROM_BASE, addr, buf) 475 | 476 | def eeprom_read8(self, addr): 477 | """Read a single byte directly to the device's EEPROM""" 478 | return self.read8(_EEPROM_BASE, addr) 479 | 480 | def uart_set_baud(self, baud): 481 | """Set the serial baudrate of the device""" 482 | cmd = struct.pack(">I", baud) 483 | self.write(_SERCOM0_BASE, _SERCOM_BAUD, cmd) 484 | 485 | def write8(self, reg_base, reg, value): 486 | """Write an arbitrary I2C byte register on the device""" 487 | self.write(reg_base, reg, bytearray([value])) 488 | 489 | def read8(self, reg_base, reg): 490 | """Read an arbitrary I2C byte register on the device""" 491 | ret = bytearray(1) 492 | self.read(reg_base, reg, ret) 493 | return ret[0] 494 | 495 | def read(self, reg_base, reg, buf, delay=0.008): 496 | """Read an arbitrary I2C register range on the device""" 497 | self.write(reg_base, reg) 498 | if self._drdy is not None: 499 | while self._drdy.value is False: 500 | pass 501 | else: 502 | time.sleep(delay) 503 | with self.i2c_device as i2c: 504 | i2c.readinto(buf) 505 | 506 | def write(self, reg_base, reg, buf=None): 507 | """Write an arbitrary I2C register range on the device""" 508 | full_buffer = bytearray([reg_base, reg]) 509 | if buf is not None: 510 | full_buffer += buf 511 | 512 | if self._drdy is not None: 513 | while self._drdy.value is False: 514 | pass 515 | with self.i2c_device as i2c: 516 | i2c.write(full_buffer) 517 | -------------------------------------------------------------------------------- /adafruit_seesaw/tftshield18.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2018 Dean Miller for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | 6 | """ 7 | `adafruit_seesaw.tftshield18` - Pin definitions for 1.8" TFT Shield V2 8 | ====================================================================== 9 | """ 10 | 11 | from collections import namedtuple 12 | 13 | import board 14 | 15 | try: 16 | from micropython import const 17 | except ImportError: 18 | 19 | def const(x): 20 | return x 21 | 22 | 23 | from adafruit_seesaw.seesaw import Seesaw 24 | 25 | __version__ = "0.0.0+auto.0" 26 | __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw.git" 27 | 28 | _TIMER_BASE = const(0x08) 29 | _TIMER_PWM = const(0x01) 30 | _TIMER_FREQ = const(0x02) 31 | 32 | _TFTSHIELD_RESET_PIN = const(3) 33 | 34 | _BUTTON_UP = const(5) 35 | _BUTTON_DOWN = const(8) 36 | _BUTTON_LEFT = const(6) 37 | _BUTTON_RIGHT = const(9) 38 | _BUTTON_SELECT = const(7) 39 | _BUTTON_A = const(10) 40 | _BUTTON_B = const(11) 41 | _BUTTON_C = const(14) 42 | 43 | Buttons = namedtuple("Buttons", "right down left up select a b c") 44 | 45 | 46 | class TFTShield18(Seesaw): 47 | _BACKLIGHT_ON = b"\xff\xff" 48 | _BACKLIGHT_OFF = b"\x00\x00" 49 | 50 | try: 51 | _button_mask = ( 52 | (1 << _BUTTON_RIGHT) 53 | | (1 << _BUTTON_DOWN) 54 | | (1 << _BUTTON_LEFT) 55 | | (1 << _BUTTON_UP) 56 | | (1 << _BUTTON_SELECT) 57 | | (1 << _BUTTON_A) 58 | | (1 << _BUTTON_B) 59 | | (1 << _BUTTON_C) 60 | ) 61 | except TypeError: 62 | # During Sphinx build, the following error occurs: 63 | # File ".../tftshield18.py", line 60, in TFTShield18 64 | # (1 << _BUTTON_B) | 65 | # TypeError: unsupported operand type(s) for <<: 'int' and '_MockObject' 66 | _button_mask = 0xFF 67 | 68 | def __init__(self, i2c_bus=None, addr=0x2E): 69 | if i2c_bus is None: 70 | try: 71 | i2c_bus = board.I2C() 72 | except AttributeError as attrError: 73 | raise ValueError("Board has no default I2C bus.") from attrError 74 | super().__init__(i2c_bus, addr) 75 | self.pin_mode(_TFTSHIELD_RESET_PIN, self.OUTPUT) 76 | self.pin_mode_bulk(self._button_mask, self.INPUT_PULLUP) 77 | 78 | def set_backlight(self, value): 79 | """ 80 | Set the backlight on 81 | """ 82 | if not isinstance(value, bool): 83 | raise ValueError("Value must be of boolean type") 84 | command = self._BACKLIGHT_ON if value else self._BACKLIGHT_OFF 85 | self.write(_TIMER_BASE, _TIMER_PWM, b"\x00" + command) 86 | 87 | def set_backlight_freq(self, freq): 88 | """ 89 | Set the backlight frequency of the TFT Display 90 | """ 91 | if not isinstance(freq, int): 92 | raise ValueError("Value must be of integer type") 93 | value = b"\x00" + bytearray((freq >> 8) & 0xFF, freq & 0xFF) 94 | self.write(_TIMER_BASE, _TIMER_FREQ, value) 95 | 96 | def tft_reset(self, rst=True): 97 | """ 98 | Reset the TFT Display 99 | """ 100 | self.digital_write(_TFTSHIELD_RESET_PIN, rst) 101 | 102 | @property 103 | def buttons(self): 104 | """ 105 | Return a set of buttons with current push values 106 | """ 107 | button_values = self.digital_read_bulk(self._button_mask) 108 | return Buttons( 109 | *[ 110 | not button_values & (1 << button) 111 | for button in ( 112 | _BUTTON_RIGHT, 113 | _BUTTON_DOWN, 114 | _BUTTON_LEFT, 115 | _BUTTON_UP, 116 | _BUTTON_SELECT, 117 | _BUTTON_A, 118 | _BUTTON_B, 119 | _BUTTON_C, 120 | ) 121 | ] 122 | ) 123 | -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adafruit/Adafruit_CircuitPython_seesaw/5a4cd087cfe50e5fdcf2475c2023c41a2449711c/docs/_static/favicon.ico -------------------------------------------------------------------------------- /docs/_static/favicon.ico.license: -------------------------------------------------------------------------------- 1 | SPDX-FileCopyrightText: 2018 Phillip Torrone for Adafruit Industries 2 | 3 | SPDX-License-Identifier: CC-BY-4.0 4 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | 2 | .. If you created a package, create one automodule per module in the package. 3 | 4 | API Reference 5 | ############# 6 | 7 | .. automodule:: adafruit_seesaw 8 | :members: 9 | 10 | .. automodule:: adafruit_seesaw.seesaw 11 | :members: 12 | 13 | .. automodule:: adafruit_seesaw.crickit 14 | :members: 15 | 16 | .. automodule:: adafruit_seesaw.analoginput 17 | :members: 18 | 19 | .. automodule:: adafruit_seesaw.digitalio 20 | :members: 21 | 22 | .. automodule:: adafruit_seesaw.__init__ 23 | :members: 24 | 25 | .. automodule:: adafruit_seesaw.keypad 26 | :members: 27 | 28 | .. automodule:: adafruit_seesaw.neopixel 29 | :members: 30 | 31 | .. automodule:: adafruit_seesaw.pwmout 32 | :members: 33 | 34 | .. automodule:: adafruit_seesaw.robohat 35 | :members: 36 | 37 | .. automodule:: adafruit_seesaw.rotaryio 38 | :members: 39 | 40 | .. automodule:: adafruit_seesaw.samd09 41 | :members: 42 | 43 | .. automodule:: adafruit_seesaw.tftshield18 44 | :members: 45 | -------------------------------------------------------------------------------- /docs/api.rst.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | import datetime 6 | import os 7 | import sys 8 | 9 | sys.path.insert(0, os.path.abspath("..")) 10 | 11 | # -- General configuration ------------------------------------------------ 12 | 13 | # Add any Sphinx extension module names here, as strings. They can be 14 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 15 | # ones. 16 | extensions = [ 17 | "sphinx.ext.autodoc", 18 | "sphinxcontrib.jquery", 19 | "sphinx.ext.intersphinx", 20 | "sphinx.ext.viewcode", 21 | ] 22 | 23 | # Uncomment the below if you use native CircuitPython modules such as 24 | # digitalio, micropython and busio. List the modules you use. Without it, the 25 | # autodoc module docs will fail to generate with a warning. 26 | autodoc_mock_imports = [ 27 | "adafruit_bus_device", 28 | "adafruit_pixelbuf", 29 | "board", 30 | "digitalio", 31 | ] 32 | 33 | autodoc_default_flags = ["special-members", "members"] 34 | 35 | autodoc_default_options = { 36 | "member-order": "bysource", 37 | "exclude-members": "__weakref__,__getnewargs__,__dict__,__module__,__init__", 38 | } 39 | 40 | intersphinx_mapping = { 41 | "python": ("https://docs.python.org/3", None), 42 | "BusDevice": ( 43 | "https://docs.circuitpython.org/projects/busdevice/en/latest/", 44 | None, 45 | ), 46 | "Register": ( 47 | "https://docs.circuitpython.org/projects/register/en/latest/", 48 | None, 49 | ), 50 | "CircuitPython": ("https://docs.circuitpython.org/en/latest/", None), 51 | } 52 | 53 | # Add any paths that contain templates here, relative to this directory. 54 | templates_path = ["_templates"] 55 | 56 | source_suffix = ".rst" 57 | 58 | # The master toctree document. 59 | master_doc = "index" 60 | 61 | # General information about the project. 62 | project = "Adafruit seesaw Library" 63 | creation_year = "2017" 64 | current_year = str(datetime.datetime.now().year) 65 | year_duration = ( 66 | current_year if current_year == creation_year else creation_year + " - " + current_year 67 | ) 68 | copyright = year_duration + " Dean Miller" 69 | author = "Dean Miller" 70 | 71 | # The version info for the project you're documenting, acts as replacement for 72 | # |version| and |release|, also used in various other places throughout the 73 | # built documents. 74 | # 75 | # The short X.Y version. 76 | version = "1.0" 77 | # The full version, including alpha/beta/rc tags. 78 | release = "1.0" 79 | 80 | # The language for content autogenerated by Sphinx. Refer to documentation 81 | # for a list of supported languages. 82 | # 83 | # This is also used if you do content translation via gettext catalogs. 84 | # Usually you set "language" from the command line for these cases. 85 | language = "en" 86 | 87 | # List of patterns, relative to source directory, that match files and 88 | # directories to ignore when looking for source files. 89 | # This patterns also effect to html_static_path and html_extra_path 90 | exclude_patterns = ["_build", "Thumbs.db", ".DS_Store", ".env", "CODE_OF_CONDUCT.md"] 91 | 92 | # The reST default role (used for this markup: `text`) to use for all 93 | # documents. 94 | # 95 | default_role = "any" 96 | 97 | # If true, '()' will be appended to :func: etc. cross-reference text. 98 | # 99 | add_function_parentheses = True 100 | 101 | # The name of the Pygments (syntax highlighting) style to use. 102 | pygments_style = "sphinx" 103 | 104 | # If true, `todo` and `todoList` produce output, else they produce nothing. 105 | todo_include_todos = False 106 | 107 | # If this is True, todo emits a warning for each TODO entries. The default is False. 108 | todo_emit_warnings = True 109 | 110 | 111 | # -- Options for HTML output ---------------------------------------------- 112 | 113 | # The theme to use for HTML and HTML Help pages. See the documentation for 114 | # a list of builtin themes. 115 | # 116 | import sphinx_rtd_theme 117 | 118 | html_theme = "sphinx_rtd_theme" 119 | 120 | # Add any paths that contain custom static files (such as style sheets) here, 121 | # relative to this directory. They are copied after the builtin static files, 122 | # so a file named "default.css" will overwrite the builtin "default.css". 123 | html_static_path = ["_static"] 124 | 125 | # The name of an image file (relative to this directory) to use as a favicon of 126 | # the docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 127 | # pixels large. 128 | # 129 | html_favicon = "_static/favicon.ico" 130 | 131 | # Output file base name for HTML help builder. 132 | htmlhelp_basename = "AdafruitseesawLibrarydoc" 133 | 134 | # -- Options for LaTeX output --------------------------------------------- 135 | 136 | latex_elements = { 137 | # The paper size ('letterpaper' or 'a4paper'). 138 | # 139 | # 'papersize': 'letterpaper', 140 | # The font size ('10pt', '11pt' or '12pt'). 141 | # 142 | # 'pointsize': '10pt', 143 | # Additional stuff for the LaTeX preamble. 144 | # 145 | # 'preamble': '', 146 | # Latex figure (float) alignment 147 | # 148 | # 'figure_align': 'htbp', 149 | } 150 | 151 | # Grouping the document tree into LaTeX files. List of tuples 152 | # (source start file, target name, title, 153 | # author, documentclass [howto, manual, or own class]). 154 | latex_documents = [ 155 | ( 156 | master_doc, 157 | "Adafruitseesawibrary.tex", 158 | "Adafruit seesaw Library Documentation", 159 | author, 160 | "manual", 161 | ), 162 | ] 163 | 164 | # -- Options for manual page output --------------------------------------- 165 | 166 | # One entry per manual page. List of tuples 167 | # (source start file, name, description, authors, manual section). 168 | man_pages = [ 169 | ( 170 | master_doc, 171 | "adafruitseesawlibrary", 172 | "Adafruit seesaw Library Documentation", 173 | [author], 174 | 1, 175 | ) 176 | ] 177 | 178 | # -- Options for Texinfo output ------------------------------------------- 179 | 180 | # Grouping the document tree into Texinfo files. List of tuples 181 | # (source start file, target name, title, author, 182 | # dir menu entry, description, category) 183 | texinfo_documents = [ 184 | ( 185 | master_doc, 186 | "AdafruitSEESAWLibrary", 187 | "Adafruit SEESAW Library Documentation", 188 | author, 189 | "AdafruitSEESAWLibrary", 190 | "One line description of project.", 191 | "Miscellaneous", 192 | ), 193 | ] 194 | -------------------------------------------------------------------------------- /docs/examples.rst: -------------------------------------------------------------------------------- 1 | Simple test 2 | ------------ 3 | 4 | Ensure your device works with this simple test. 5 | 6 | .. literalinclude:: ../examples/seesaw_simpletest.py 7 | :caption: examples/seesaw_simpletest.py 8 | :linenos: 9 | 10 | Other Examples 11 | --------------- 12 | 13 | Here are some other examples using the Seesaw library 14 | 15 | .. literalinclude:: ../examples/seesaw_crickit_test.py 16 | :caption: examples/seesaw_crickit_test.py 17 | :linenos: 18 | 19 | .. literalinclude:: ../examples/seesaw_joy_featherwing.py 20 | :caption: examples/seesaw_joy_featherwing.py 21 | :linenos: 22 | 23 | .. literalinclude:: ../examples/seesaw_soil_simpletest.py 24 | :caption: examples/seesaw_soil_simpletest.py 25 | :linenos: 26 | 27 | .. literalinclude:: ../examples/seesaw_minitft_featherwing.py 28 | :caption: examples/seesaw_minitft_featherwing.py 29 | :linenos: 30 | 31 | .. literalinclude:: ../examples/seesaw_rotary_simpletest.py 32 | :caption: examples/seesaw_rotary_simpletest.py 33 | :linenos: 34 | 35 | .. literalinclude:: ../examples/seesaw_rotary_neopixel.py 36 | :caption: examples/seesaw_rotary_neopixel.py 37 | :linenos: 38 | -------------------------------------------------------------------------------- /docs/examples.rst.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../README.rst 2 | 3 | Table of Contents 4 | ================= 5 | 6 | .. toctree:: 7 | :maxdepth: 4 8 | :hidden: 9 | 10 | self 11 | 12 | .. toctree:: 13 | :caption: Examples 14 | 15 | examples 16 | 17 | .. toctree:: 18 | :caption: API Reference 19 | :maxdepth: 3 20 | 21 | api 22 | 23 | .. toctree:: 24 | :caption: Tutorials 25 | 26 | Adafruit seesaw 27 | 28 | Make it Move with Crickit 29 | 30 | Joy Featherwing 31 | 32 | Adafruit Mini TFT with Joystick Featherwing 33 | 34 | Adafruit I2C QT Rotary Encoder 35 | 36 | Adafruit STEMMA Soil Sensor - I2C Capacitive Moisture Sensor 37 | 38 | Discord and Slack Connected Smart Plant with Adafruit IO Triggers 39 | 40 | .. toctree:: 41 | :caption: Related Products 42 | 43 | Adafruit ATSAMD09 Breakout with seesaw 44 | 45 | Adafruit CRICKIT for Circuit Playground Express 46 | 47 | Adafruit Joy FeatherWing for all Feathers 48 | 49 | Adafruit Mini Color TFT with Joystick FeatherWing 50 | 51 | Adafruit I2C QT Rotary Encoder with NeoPixel 52 | 53 | Adafruit STEMMA Soil Sensor - I2C Capacitive Moisture Sensor 54 | 55 | .. toctree:: 56 | :caption: Other Links 57 | 58 | Download from GitHub 59 | Download Library Bundle 60 | CircuitPython Reference Documentation 61 | CircuitPython Support Forum 62 | Discord Chat 63 | Adafruit Learning System 64 | Adafruit Blog 65 | Adafruit Store 66 | 67 | Indices and tables 68 | ================== 69 | 70 | * :ref:`genindex` 71 | * :ref:`modindex` 72 | * :ref:`search` 73 | -------------------------------------------------------------------------------- /docs/index.rst.license: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2020 ladyada for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | sphinx 6 | sphinxcontrib-jquery 7 | sphinx-rtd-theme 8 | -------------------------------------------------------------------------------- /examples/seesaw_analogin_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test reading analog value 5 | # on SAMD09, analog in can be pins 2, 3, or 4 6 | # on Attiny8x7, analog in can be pins 0, 1, 2, 3, 6, 7, 18, 19, 20 7 | 8 | import time 9 | 10 | import board 11 | 12 | from adafruit_seesaw.analoginput import AnalogInput 13 | from adafruit_seesaw.seesaw import Seesaw 14 | 15 | i2c = board.I2C() # uses board.SCL and board.SDA 16 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 17 | ss = Seesaw(i2c) 18 | 19 | analogin_pin = 2 20 | analog_in = AnalogInput(ss, analogin_pin) 21 | 22 | while True: 23 | print(analog_in.value) 24 | time.sleep(0.1) 25 | -------------------------------------------------------------------------------- /examples/seesaw_ano_rotary_7segment_demo.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 John Furcean 2 | # SPDX-License-Identifier: MIT 3 | 4 | """I2C ANO rotary encoder with 7 segment display example.""" 5 | 6 | import board 7 | from adafruit_ht16k33 import segments 8 | 9 | from adafruit_seesaw import digitalio, rotaryio, seesaw 10 | 11 | # For use with the STEMMA connector on QT Py RP2040 12 | # import busio 13 | # i2c = busio.I2C(board.SCL1, board.SDA1) 14 | # seesaw = seesaw.Seesaw(i2c, 0x49) 15 | 16 | i2c = board.I2C() # uses board.SCL and board.SDA 17 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 18 | seesaw = seesaw.Seesaw(i2c, addr=0x49) 19 | display = segments.Seg14x4(i2c, address=0x70) 20 | 21 | seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF 22 | print(f"Found product {seesaw_product}") 23 | if seesaw_product != 5740: 24 | print("Wrong firmware loaded? Expected 5740") 25 | 26 | seesaw.pin_mode(1, seesaw.INPUT_PULLUP) 27 | seesaw.pin_mode(2, seesaw.INPUT_PULLUP) 28 | seesaw.pin_mode(3, seesaw.INPUT_PULLUP) 29 | seesaw.pin_mode(4, seesaw.INPUT_PULLUP) 30 | seesaw.pin_mode(5, seesaw.INPUT_PULLUP) 31 | 32 | select = digitalio.DigitalIO(seesaw, 1) 33 | select_held = False 34 | up = digitalio.DigitalIO(seesaw, 2) 35 | up_held = False 36 | left = digitalio.DigitalIO(seesaw, 3) 37 | left_held = False 38 | down = digitalio.DigitalIO(seesaw, 4) 39 | down_held = False 40 | right = digitalio.DigitalIO(seesaw, 5) 41 | right_held = False 42 | 43 | encoder = rotaryio.IncrementalEncoder(seesaw) 44 | last_position = None 45 | 46 | buttons = [select, up, left, down, right] 47 | button_names = ["Select", "Up", "Left", "Down", "Right"] 48 | button_states = [select_held, up_held, left_held, down_held, right_held] 49 | seven_segment_names = ["SELE", " UP ", "LEFT", "DOWN", "RIGH"] 50 | 51 | while True: 52 | position = encoder.position 53 | 54 | if position != last_position: 55 | last_position = position 56 | display.print(f" {position}") 57 | print(f"Position: {position}") 58 | 59 | for b in range(5): 60 | if not buttons[b].value and button_states[b] is False: 61 | button_states[b] = True 62 | display.print(seven_segment_names[b]) 63 | print(f"{button_names[b]} button pressed") 64 | 65 | if buttons[b].value and button_states[b] is True: 66 | button_states[b] = False 67 | display.print(" ") 68 | print(f"{button_names[b]} button released") 69 | -------------------------------------------------------------------------------- /examples/seesaw_ano_rotary_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 John Furcean 2 | # SPDX-License-Identifier: MIT 3 | 4 | """I2C ANO rotary encoder simple test example.""" 5 | 6 | import board 7 | 8 | from adafruit_seesaw import digitalio, rotaryio, seesaw 9 | 10 | # For use with the STEMMA connector on QT Py RP2040 11 | # import busio 12 | # i2c = busio.I2C(board.SCL1, board.SDA1) 13 | # seesaw = seesaw.Seesaw(i2c, 0x49) 14 | 15 | i2c = board.I2C() # uses board.SCL and board.SDA 16 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 17 | seesaw = seesaw.Seesaw(i2c, addr=0x49) 18 | 19 | seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF 20 | print(f"Found product {seesaw_product}") 21 | if seesaw_product != 5740: 22 | print("Wrong firmware loaded? Expected 5740") 23 | 24 | seesaw.pin_mode(1, seesaw.INPUT_PULLUP) 25 | seesaw.pin_mode(2, seesaw.INPUT_PULLUP) 26 | seesaw.pin_mode(3, seesaw.INPUT_PULLUP) 27 | seesaw.pin_mode(4, seesaw.INPUT_PULLUP) 28 | seesaw.pin_mode(5, seesaw.INPUT_PULLUP) 29 | 30 | select = digitalio.DigitalIO(seesaw, 1) 31 | select_held = False 32 | up = digitalio.DigitalIO(seesaw, 2) 33 | up_held = False 34 | left = digitalio.DigitalIO(seesaw, 3) 35 | left_held = False 36 | down = digitalio.DigitalIO(seesaw, 4) 37 | down_held = False 38 | right = digitalio.DigitalIO(seesaw, 5) 39 | right_held = False 40 | 41 | encoder = rotaryio.IncrementalEncoder(seesaw) 42 | last_position = None 43 | 44 | buttons = [select, up, left, down, right] 45 | button_names = ["Select", "Up", "Left", "Down", "Right"] 46 | button_states = [select_held, up_held, left_held, down_held, right_held] 47 | 48 | while True: 49 | position = encoder.position 50 | 51 | if position != last_position: 52 | last_position = position 53 | print(f"Position: {position}") 54 | 55 | for b in range(5): 56 | if not buttons[b].value and button_states[b] is False: 57 | button_states[b] = True 58 | print(f"{button_names[b]} button pressed") 59 | 60 | if buttons[b].value and button_states[b] is True: 61 | button_states[b] = False 62 | print(f"{button_names[b]} button released") 63 | -------------------------------------------------------------------------------- /examples/seesaw_arcade_qt_multi_board.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | """Arcade QT example for multiple boards that turns on button LED when button is pressed""" 4 | 5 | import board 6 | import digitalio 7 | 8 | from adafruit_seesaw.digitalio import DigitalIO 9 | from adafruit_seesaw.seesaw import Seesaw 10 | 11 | # For most boards. 12 | i2c = board.I2C() # uses board.SCL and board.SDA 13 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 14 | 15 | # For the QT Py RP2040, QT Py ESP32-S2, other boards that have SCL1/SDA1 as the STEMMA QT port. 16 | # import busio 17 | # i2c = busio.I2C(board.SCL1, board.SDA1) 18 | arcade_qt_one = Seesaw(i2c, addr=0x3A) 19 | arcade_qt_two = Seesaw(i2c, addr=0x3B) 20 | 21 | arcade_qts = (arcade_qt_one, arcade_qt_two) 22 | 23 | # Button pins in order (1, 2, 3, 4) 24 | button_pins = (18, 19, 20, 2) 25 | buttons = [] 26 | for arcade_qt in arcade_qts: 27 | for button_pin in button_pins: 28 | button = DigitalIO(arcade_qt, button_pin) 29 | button.direction = digitalio.Direction.INPUT 30 | button.pull = digitalio.Pull.UP 31 | buttons.append(button) 32 | 33 | # LED pins in order (1, 2, 3, 4) 34 | led_pins = (12, 13, 0, 1) 35 | leds = [] 36 | for arcade_qt in arcade_qts: 37 | for led_pin in led_pins: 38 | led = DigitalIO(arcade_qt, led_pin) 39 | led.direction = digitalio.Direction.OUTPUT 40 | leds.append(led) 41 | 42 | while True: 43 | for led_number, button in enumerate(buttons): 44 | leds[led_number].value = not button.value 45 | -------------------------------------------------------------------------------- /examples/seesaw_arcade_qt_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Kattni Rembor for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | """Arcade QT example that pulses the button LED on button press""" 4 | 5 | import time 6 | 7 | import board 8 | import digitalio 9 | 10 | from adafruit_seesaw.digitalio import DigitalIO 11 | from adafruit_seesaw.pwmout import PWMOut 12 | from adafruit_seesaw.seesaw import Seesaw 13 | 14 | # The delay on the PWM cycles. Increase to slow down the LED pulsing, decrease to speed it up. 15 | delay = 0.01 16 | 17 | # For most boards. 18 | i2c = board.I2C() # uses board.SCL and board.SDA 19 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 20 | 21 | # For the QT Py RP2040, QT Py ESP32-S2, other boards that have SCL1/SDA1 as the STEMMA QT port. 22 | # import busio 23 | # i2c = busio.I2C(board.SCL1, board.SDA1) 24 | arcade_qt = Seesaw(i2c, addr=0x3A) 25 | 26 | # Button pins in order (1, 2, 3, 4) 27 | button_pins = (18, 19, 20, 2) 28 | buttons = [] 29 | for button_pin in button_pins: 30 | button = DigitalIO(arcade_qt, button_pin) 31 | button.direction = digitalio.Direction.INPUT 32 | button.pull = digitalio.Pull.UP 33 | buttons.append(button) 34 | 35 | # LED pins in order (1, 2, 3, 4) 36 | led_pins = (12, 13, 0, 1) 37 | leds = [] 38 | for led_pin in led_pins: 39 | led = PWMOut(arcade_qt, led_pin) 40 | leds.append(led) 41 | 42 | while True: 43 | for led_number, button in enumerate(buttons): 44 | if not button.value: 45 | for cycle in range(0, 65535, 8000): 46 | leds[led_number].duty_cycle = cycle 47 | time.sleep(delay) 48 | for cycle in range(65534, 0, -8000): 49 | leds[led_number].duty_cycle = cycle 50 | time.sleep(delay) 51 | -------------------------------------------------------------------------------- /examples/seesaw_attiny_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | """ 4 | Simple seesaw test for ATtiny8x7 breakout using built-in LED on pin 5. 5 | """ 6 | 7 | import time 8 | 9 | import board 10 | 11 | from adafruit_seesaw.seesaw import Seesaw 12 | 13 | i2c = board.I2C() # uses board.SCL and board.SDA 14 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 15 | ss = Seesaw(i2c) 16 | 17 | ss.pin_mode(5, ss.OUTPUT) 18 | 19 | while True: 20 | ss.digital_write(5, False) # Turn the LED on (the built-in LED is active low!) 21 | time.sleep(1) # Wait for one second 22 | ss.digital_write(5, True) # Turn the LED off 23 | time.sleep(1) # Wait for one second 24 | -------------------------------------------------------------------------------- /examples/seesaw_crickit_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | import board 5 | from adafruit_motor import servo 6 | 7 | from adafruit_seesaw.pwmout import PWMOut 8 | from adafruit_seesaw.seesaw import Seesaw 9 | 10 | # from analogio import AnalogOut 11 | # import board 12 | 13 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 14 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 15 | ss = Seesaw(i2c_bus) 16 | pwm1 = PWMOut(ss, 17) 17 | pwm2 = PWMOut(ss, 16) 18 | pwm3 = PWMOut(ss, 15) 19 | pwm4 = PWMOut(ss, 14) 20 | 21 | pwm1.frequency = 50 22 | pwm2.frequency = 50 23 | pwm3.frequency = 50 24 | pwm4.frequency = 50 25 | 26 | S1 = servo.Servo(pwm1) 27 | S2 = servo.Servo(pwm2) 28 | S3 = servo.Servo(pwm3) 29 | S4 = servo.Servo(pwm4) 30 | 31 | servos = (S1, S2, S3, S4) 32 | 33 | CRCKIT_NUM_ADC = 8 34 | CRCKit_adc = (2, 3, 40, 41, 11, 10, 9, 8) 35 | 36 | CRCKIT_NUM_DRIVE = 4 37 | CRCKit_drive = (42, 43, 12, 13) 38 | 39 | CAPTOUCH_THRESH = 500 40 | 41 | _CRCKIT_M1_A1 = 18 42 | _CRCKIT_M1_A2 = 19 43 | _CRCKIT_M1_B1 = 22 44 | _CRCKIT_M1_B2 = 23 45 | 46 | cap_state = [False, False, False, False] 47 | cap_justtouched = [False, False, False, False] 48 | cap_justreleased = [False, False, False, False] 49 | 50 | motor1_dir = False 51 | motor2_dir = True 52 | 53 | test_servos = False 54 | test_motors = False 55 | test_drives = False 56 | test_speaker = False 57 | 58 | counter = 0 59 | 60 | # analog_out = AnalogOut(board.A0) 61 | # analog_out.value = 512 62 | 63 | while True: 64 | counter = (counter + 1) % 256 65 | 66 | if counter % 32 == 0: 67 | print("-------------------- analog -----------------------") 68 | str_out = "" 69 | for i in range(8): 70 | val = ss.analog_read(CRCKit_adc[i]) * 3.3 / 1024 71 | str_out = str_out + str(round(val, 2)) + "\t" 72 | 73 | print(str_out + "\n") 74 | 75 | for i in range(4): 76 | val = ss.touch_read(i) 77 | cap_justtouched[i] = False 78 | cap_justreleased[i] = False 79 | 80 | if val > CAPTOUCH_THRESH: 81 | print("CT" + str(i + 1) + " touched! value: " + str(val)) 82 | 83 | if not cap_state[i]: 84 | cap_justtouched[i] = True 85 | 86 | cap_state[i] = True 87 | 88 | else: 89 | if cap_state[i]: 90 | cap_justreleased[i] = True 91 | 92 | cap_state[i] = False 93 | 94 | if cap_justtouched[0]: 95 | test_servos = not test_servos 96 | if test_servos: 97 | print("Testing servos") 98 | else: 99 | print("Stopping servos") 100 | 101 | if cap_justtouched[1]: 102 | test_drives = not test_drives 103 | if test_drives: 104 | print("Testing drives") 105 | else: 106 | print("Stopping drives") 107 | 108 | if cap_justtouched[2]: 109 | test_motors = not test_motors 110 | if test_motors: 111 | print("Testing motors") 112 | else: 113 | print("Stopping motors") 114 | 115 | if cap_justtouched[3]: 116 | test_speaker = not test_speaker 117 | if test_speaker: 118 | print("Testing speaker") 119 | else: 120 | print("Stopping speaker") 121 | 122 | if test_servos: 123 | if counter % 32 == 0: 124 | print("-------------------- servos -----------------------") 125 | servonum = int(counter / 32) % 4 126 | 127 | if counter < 128: 128 | print("SER" + str(servonum) + " LEFT") 129 | servos[servonum].angle = 0 130 | else: 131 | print("SER" + str(servonum) + " RIGHT") 132 | servos[servonum].angle = 180 133 | 134 | if test_drives: 135 | if counter % 32 == 0: 136 | print("-------------------- drives -----------------------") 137 | drivenum = int(counter / 64) % 4 138 | 139 | if counter % 64 == 0: 140 | print("DRIVE" + str(drivenum) + " ON") 141 | ss.analog_write(CRCKit_drive[drivenum], 65535) 142 | 143 | else: 144 | print("DRIVE" + str(drivenum) + " OFF") 145 | ss.analog_write(CRCKit_drive[drivenum], 0) 146 | 147 | if test_motors: 148 | if counter < 128: 149 | if motor1_dir: 150 | ss.analog_write(_CRCKIT_M1_A1, 0) 151 | ss.analog_write(_CRCKIT_M1_A2, counter * 512) 152 | else: 153 | ss.analog_write(_CRCKIT_M1_A2, 0) 154 | ss.analog_write(_CRCKIT_M1_A1, counter * 512) 155 | elif motor1_dir: 156 | ss.analog_write(_CRCKIT_M1_A1, 0) 157 | ss.analog_write(_CRCKIT_M1_A2, (255 - counter) * 512) 158 | else: 159 | ss.analog_write(_CRCKIT_M1_A2, 0) 160 | ss.analog_write(_CRCKIT_M1_A1, (255 - counter) * 512) 161 | if counter == 255: 162 | print("-------------------- motor 1 -----------------------") 163 | motor1_dir = not motor1_dir 164 | 165 | if counter < 128: 166 | if motor2_dir: 167 | ss.analog_write(_CRCKIT_M1_B1, 0) 168 | ss.analog_write(_CRCKIT_M1_B2, counter * 512) 169 | else: 170 | ss.analog_write(_CRCKIT_M1_B2, 0) 171 | ss.analog_write(_CRCKIT_M1_B1, counter * 512) 172 | elif motor2_dir: 173 | ss.analog_write(_CRCKIT_M1_B1, 0) 174 | ss.analog_write(_CRCKIT_M1_B2, (255 - counter) * 512) 175 | else: 176 | ss.analog_write(_CRCKIT_M1_B2, 0) 177 | ss.analog_write(_CRCKIT_M1_B1, (255 - counter) * 512) 178 | if counter == 255: 179 | print("-------------------- motor 2 -----------------------") 180 | motor2_dir = not motor2_dir 181 | -------------------------------------------------------------------------------- /examples/seesaw_digitalio_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test using an LED attached to Pin 5 and a button on pin 2 5 | # 6 | # See the seesaw Learn Guide for wiring details. 7 | # For SAMD09: 8 | # https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test 9 | # For ATtiny8x7: 10 | # https://learn.adafruit.com/adafruit-attiny817-seesaw/digital-input 11 | 12 | import time 13 | 14 | import board 15 | import digitalio 16 | 17 | from adafruit_seesaw.digitalio import DigitalIO 18 | from adafruit_seesaw.seesaw import Seesaw 19 | 20 | i2c = board.I2C() # uses board.SCL and board.SDA 21 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 22 | ss = Seesaw(i2c) 23 | 24 | button_pin = 2 25 | led_pin = 5 26 | 27 | button = DigitalIO(ss, button_pin) 28 | button.direction = digitalio.Direction.INPUT 29 | button.pull = digitalio.Pull.UP 30 | 31 | led = DigitalIO(ss, led_pin) 32 | led.direction = digitalio.Direction.OUTPUT 33 | 34 | while True: 35 | # simply set the LED to the same 'value' as the button pin 36 | led.value = button.value 37 | time.sleep(0.1) 38 | -------------------------------------------------------------------------------- /examples/seesaw_eeprom_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test reading and writing the internal EEPROM 5 | # The ATtiny8xx series has a true 128 byte EEPROM, the SAMD09 mimics it in flash with 64 bytes 6 | # THE LAST BYTE IS USED FOR I2C ADDRESS CHANGE! 7 | 8 | import time 9 | 10 | import board 11 | 12 | from adafruit_seesaw import seesaw 13 | 14 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 15 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 16 | ss = seesaw.Seesaw(i2c_bus) 17 | 18 | value = ss.eeprom_read8(0x02) # Read from address 2 19 | print("Read 0x%02x from EEPROM address 0x02" % value) 20 | 21 | print("Incrementing value") 22 | ss.eeprom_write8(0x02, (value + 1) % 0xFF) 23 | 24 | value = ss.eeprom_read8(0x02) # Read from address 2 25 | print("Second read 0x%02x from EEPROM address 0x02" % value) 26 | 27 | while True: 28 | # Do not write EEPROM in a loop, it has 100k cycle life 29 | time.sleep(1) 30 | -------------------------------------------------------------------------------- /examples/seesaw_gamepad_qt.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-FileCopyrightText: 2023 Kattni Rembor for Adafruit Industries 3 | 4 | # SPDX-License-Identifier: MIT 5 | 6 | import time 7 | 8 | import board 9 | from micropython import const 10 | 11 | from adafruit_seesaw.seesaw import Seesaw 12 | 13 | BUTTON_X = const(6) 14 | BUTTON_Y = const(2) 15 | BUTTON_A = const(5) 16 | BUTTON_B = const(1) 17 | BUTTON_SELECT = const(0) 18 | BUTTON_START = const(16) 19 | button_mask = const( 20 | (1 << BUTTON_X) 21 | | (1 << BUTTON_Y) 22 | | (1 << BUTTON_A) 23 | | (1 << BUTTON_B) 24 | | (1 << BUTTON_SELECT) 25 | | (1 << BUTTON_START) 26 | ) 27 | 28 | i2c_bus = board.STEMMA_I2C() # The built-in STEMMA QT connector on the microcontroller 29 | # i2c_bus = board.I2C() # Uses board.SCL and board.SDA. Use with breadboard. 30 | 31 | seesaw = Seesaw(i2c_bus, addr=0x50) 32 | 33 | seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP) 34 | 35 | last_x = 0 36 | last_y = 0 37 | 38 | while True: 39 | x = 1023 - seesaw.analog_read(14) 40 | y = 1023 - seesaw.analog_read(15) 41 | 42 | if (abs(x - last_x) > 3) or (abs(y - last_y) > 3): 43 | print(x, y) 44 | last_x = x 45 | last_y = y 46 | 47 | buttons = seesaw.digital_read_bulk(button_mask) 48 | 49 | if not buttons & (1 << BUTTON_X): 50 | print("Button x pressed") 51 | 52 | if not buttons & (1 << BUTTON_Y): 53 | print("Button Y pressed") 54 | 55 | if not buttons & (1 << BUTTON_A): 56 | print("Button A pressed") 57 | 58 | if not buttons & (1 << BUTTON_B): 59 | print("Button B pressed") 60 | 61 | if not buttons & (1 << BUTTON_SELECT): 62 | print("Button Select pressed") 63 | 64 | if not buttons & (1 << BUTTON_START): 65 | print("Button Start pressed") 66 | 67 | time.sleep(0.01) 68 | -------------------------------------------------------------------------------- /examples/seesaw_joy_featherwing.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | import time 5 | 6 | import board 7 | from micropython import const 8 | 9 | from adafruit_seesaw.seesaw import Seesaw 10 | 11 | BUTTON_RIGHT = const(6) 12 | BUTTON_DOWN = const(7) 13 | BUTTON_LEFT = const(9) 14 | BUTTON_UP = const(10) 15 | BUTTON_SEL = const(14) 16 | button_mask = const( 17 | (1 << BUTTON_RIGHT) 18 | | (1 << BUTTON_DOWN) 19 | | (1 << BUTTON_LEFT) 20 | | (1 << BUTTON_UP) 21 | | (1 << BUTTON_SEL) 22 | ) 23 | 24 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 25 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 26 | 27 | ss = Seesaw(i2c_bus) 28 | 29 | ss.pin_mode_bulk(button_mask, ss.INPUT_PULLUP) 30 | 31 | last_x = 0 32 | last_y = 0 33 | 34 | while True: 35 | x = ss.analog_read(2) 36 | y = ss.analog_read(3) 37 | 38 | if (abs(x - last_x) > 3) or (abs(y - last_y) > 3): 39 | print(x, y) 40 | last_x = x 41 | last_y = y 42 | 43 | buttons = ss.digital_read_bulk(button_mask) 44 | if not buttons & (1 << BUTTON_RIGHT): 45 | print("Button A pressed") 46 | 47 | if not buttons & (1 << BUTTON_DOWN): 48 | print("Button B pressed") 49 | 50 | if not buttons & (1 << BUTTON_LEFT): 51 | print("Button Y pressed") 52 | 53 | if not buttons & (1 << BUTTON_UP): 54 | print("Button x pressed") 55 | 56 | if not buttons & (1 << BUTTON_SEL): 57 | print("Button SEL pressed") 58 | 59 | time.sleep(0.01) 60 | -------------------------------------------------------------------------------- /examples/seesaw_minitft_featherwing.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | import time 5 | 6 | import board 7 | from micropython import const 8 | 9 | from adafruit_seesaw.seesaw import Seesaw 10 | 11 | BUTTON_RIGHT = const(7) 12 | BUTTON_DOWN = const(4) 13 | BUTTON_LEFT = const(3) 14 | BUTTON_UP = const(2) 15 | BUTTON_SEL = const(11) 16 | BUTTON_A = const(10) 17 | BUTTON_B = const(9) 18 | 19 | button_mask = const( 20 | (1 << BUTTON_RIGHT) 21 | | (1 << BUTTON_DOWN) 22 | | (1 << BUTTON_LEFT) 23 | | (1 << BUTTON_UP) 24 | | (1 << BUTTON_SEL) 25 | | (1 << BUTTON_A) 26 | | (1 << BUTTON_B) 27 | ) 28 | 29 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 30 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 31 | 32 | ss = Seesaw(i2c_bus, 0x5E) 33 | 34 | ss.pin_mode_bulk(button_mask, ss.INPUT_PULLUP) 35 | 36 | while True: 37 | buttons = ss.digital_read_bulk(button_mask) 38 | if not buttons & (1 << BUTTON_RIGHT): 39 | print("Button RIGHT pressed") 40 | 41 | if not buttons & (1 << BUTTON_DOWN): 42 | print("Button DOWN pressed") 43 | 44 | if not buttons & (1 << BUTTON_LEFT): 45 | print("Button LEFT pressed") 46 | 47 | if not buttons & (1 << BUTTON_UP): 48 | print("Button UP pressed") 49 | 50 | if not buttons & (1 << BUTTON_SEL): 51 | print("Button SEL pressed") 52 | 53 | if not buttons & (1 << BUTTON_A): 54 | print("Button A pressed") 55 | 56 | if not buttons & (1 << BUTTON_B): 57 | print("Button B pressed") 58 | 59 | time.sleep(0.01) 60 | -------------------------------------------------------------------------------- /examples/seesaw_neopixel_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test writing NeoPixels 5 | # Can use any valid GPIO pin, up to 60 pixels! 6 | # 7 | # See the seesaw Learn Guide for wiring details. 8 | # For SAMD09: 9 | # https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test 10 | # For ATtiny8x7: 11 | # https://learn.adafruit.com/adafruit-attiny817-seesaw/neopixel 12 | 13 | import time 14 | 15 | import board 16 | from rainbowio import colorwheel 17 | 18 | from adafruit_seesaw import neopixel, seesaw 19 | 20 | i2c = board.I2C() # uses board.SCL and board.SDA 21 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 22 | ss = seesaw.Seesaw(i2c) 23 | 24 | NEOPIXEL_PIN = 19 # Can be any pin 25 | NEOPIXEL_NUM = 12 # No more than 60 pixels! 26 | 27 | pixels = neopixel.NeoPixel(ss, NEOPIXEL_PIN, NEOPIXEL_NUM) 28 | pixels.brightness = 0.3 # Not so bright! 29 | 30 | color_offset = 0 # Start at red 31 | 32 | # Cycle through all colors along the ring 33 | while True: 34 | for i in range(NEOPIXEL_NUM): 35 | rc_index = (i * 256 // NEOPIXEL_NUM) + color_offset 36 | pixels[i] = colorwheel(rc_index & 255) 37 | color_offset += 1 38 | time.sleep(0.01) 39 | -------------------------------------------------------------------------------- /examples/seesaw_pc_joystick.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 Limor Fried for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | import time 6 | 7 | import board 8 | from micropython import const 9 | 10 | from adafruit_seesaw.seesaw import Seesaw 11 | 12 | BUTTON_1 = const(3) 13 | BUTTON_2 = const(13) 14 | BUTTON_3 = const(2) 15 | BUTTON_4 = const(14) 16 | 17 | JOY1_X = const(1) 18 | JOY1_Y = const(15) 19 | JOY2_X = const(0) 20 | JOY2_Y = const(16) 21 | 22 | button_mask = const((1 << BUTTON_1) | (1 << BUTTON_2) | (1 << BUTTON_3) | (1 << BUTTON_4)) 23 | 24 | i2c_bus = board.STEMMA_I2C() # The built-in STEMMA QT connector on the microcontroller 25 | # i2c_bus = board.I2C() # Uses board.SCL and board.SDA. Use with breadboard. 26 | 27 | seesaw = Seesaw(i2c_bus, addr=0x49) 28 | 29 | seesaw.pin_mode_bulk(button_mask, seesaw.INPUT_PULLUP) 30 | 31 | last_x = 0 32 | last_y = 0 33 | x = 0 34 | y = 0 35 | 36 | while True: 37 | # These joysticks are really jittery so let's take 4 samples of each axis 38 | for i in range(4): 39 | x += seesaw.analog_read(JOY1_X) 40 | y += seesaw.analog_read(JOY1_Y) 41 | 42 | # take average reading 43 | x /= 4 44 | y /= 4 45 | 46 | # PC joysticks aren't true voltage divider because we have a fixed 10K 47 | # we dont know the normalized value so we're just going to give you 48 | # the result in 'Kohms' for easier printing 49 | 50 | x = 1024 / x - 1 51 | y = 1024 / y - 1 52 | 53 | if (abs(x - last_x) > 3) or (abs(y - last_y) > 3): 54 | print(x, y) 55 | last_x = x 56 | last_y = y 57 | 58 | buttons = seesaw.digital_read_bulk(button_mask) 59 | 60 | if not buttons & (1 << BUTTON_1): 61 | print("Button 1 pressed") 62 | 63 | if not buttons & (1 << BUTTON_2): 64 | print("Button 2 pressed") 65 | 66 | if not buttons & (1 << BUTTON_3): 67 | print("Button 3 pressed") 68 | 69 | if not buttons & (1 << BUTTON_4): 70 | print("Button 4 pressed") 71 | 72 | time.sleep(0.01) 73 | -------------------------------------------------------------------------------- /examples/seesaw_pwmout_test.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test for writing PWM outputs 5 | # On the SAMD09 breakout these are pins 5, 6, and 7 6 | # On the ATtiny8x7 breakout these are pins 0, 1, 9, 12, 13 7 | # 8 | # See the seesaw Learn Guide for wiring details. 9 | # For SAMD09: 10 | # https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test 11 | # For ATtiny8x7: 12 | # https://learn.adafruit.com/adafruit-attiny817-seesaw/pwmout 13 | 14 | import time 15 | 16 | import board 17 | 18 | from adafruit_seesaw import pwmout, seesaw 19 | 20 | i2c = board.I2C() # uses board.SCL and board.SDA 21 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 22 | ss = seesaw.Seesaw(i2c) 23 | 24 | PWM_PIN = 12 # If desired, change to any valid PWM output! 25 | led = pwmout.PWMOut(ss, PWM_PIN) 26 | 27 | delay = 0.01 28 | while True: 29 | # The API PWM range is 0 to 65535, but we increment by 256 since our 30 | # resolution is often only 8 bits underneath 31 | for cycle in range(0, 65535, 256): 32 | led.duty_cycle = cycle 33 | time.sleep(delay) 34 | for cycle in range(65534, 0, -256): 35 | led.duty_cycle = cycle 36 | time.sleep(delay) 37 | -------------------------------------------------------------------------------- /examples/seesaw_quadrotary.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2023 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | """Quad I2C rotary encoder NeoPixel color picker example.""" 5 | 6 | import board 7 | import digitalio 8 | from rainbowio import colorwheel 9 | 10 | import adafruit_seesaw.digitalio 11 | import adafruit_seesaw.neopixel 12 | import adafruit_seesaw.rotaryio 13 | import adafruit_seesaw.seesaw 14 | 15 | # For boards/chips that don't handle clock-stretching well, try running I2C at 50KHz 16 | # import busio 17 | # i2c = busio.I2C(board.SCL, board.SDA, frequency=50000) 18 | # For using the built-in STEMMA QT connector on a microcontroller 19 | i2c = board.STEMMA_I2C() 20 | seesaw = adafruit_seesaw.seesaw.Seesaw(i2c, 0x49) 21 | 22 | encoders = [adafruit_seesaw.rotaryio.IncrementalEncoder(seesaw, n) for n in range(4)] 23 | switches = [adafruit_seesaw.digitalio.DigitalIO(seesaw, pin) for pin in (12, 14, 17, 9)] 24 | for switch in switches: 25 | switch.switch_to_input(digitalio.Pull.UP) # input & pullup! 26 | 27 | # four neopixels per PCB 28 | pixels = adafruit_seesaw.neopixel.NeoPixel(seesaw, 18, 4) 29 | pixels.brightness = 0.5 30 | 31 | last_positions = [-1, -1, -1, -1] 32 | colors = [0, 0, 0, 0] # start at red 33 | 34 | while True: 35 | # negate the position to make clockwise rotation positive 36 | positions = [encoder.position for encoder in encoders] 37 | print(positions) 38 | for n, rotary_pos in enumerate(positions): 39 | if rotary_pos != last_positions[n]: 40 | if switches[n].value: # Change the LED color if switch is not pressed 41 | if rotary_pos > last_positions[n]: # Advance forward through the colorwheel. 42 | colors[n] += 8 43 | else: 44 | colors[n] -= 8 # Advance backward through the colorwheel. 45 | colors[n] = (colors[n] + 256) % 256 # wrap around to 0-256 46 | # Set last position to current position after evaluating 47 | print(f"Rotary #{n}: {rotary_pos}") 48 | last_positions[n] = rotary_pos 49 | 50 | # if switch is pressed, light up white, otherwise use the stored color 51 | if not switches[n].value: 52 | pixels[n] = 0xFFFFFF 53 | else: 54 | pixels[n] = colorwheel(colors[n]) 55 | -------------------------------------------------------------------------------- /examples/seesaw_rotary_multiples.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 John Park 2 | # SPDX-License-Identifier: MIT 3 | 4 | # I2C rotary encoder multiple test example. 5 | # solder the A0 jumper on the second QT Rotary Encoder board 6 | 7 | import board 8 | 9 | from adafruit_seesaw import digitalio, neopixel, rotaryio, seesaw 10 | 11 | i2c = board.I2C() # uses board.SCL and board.SDA 12 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 13 | 14 | qt_enc1 = seesaw.Seesaw(i2c, addr=0x36) 15 | qt_enc2 = seesaw.Seesaw(i2c, addr=0x37) 16 | 17 | qt_enc1.pin_mode(24, qt_enc1.INPUT_PULLUP) 18 | button1 = digitalio.DigitalIO(qt_enc1, 24) 19 | button_held1 = False 20 | 21 | qt_enc2.pin_mode(24, qt_enc2.INPUT_PULLUP) 22 | button2 = digitalio.DigitalIO(qt_enc2, 24) 23 | button_held2 = False 24 | 25 | encoder1 = rotaryio.IncrementalEncoder(qt_enc1) 26 | last_position1 = None 27 | 28 | encoder2 = rotaryio.IncrementalEncoder(qt_enc2) 29 | last_position2 = None 30 | 31 | pixel1 = neopixel.NeoPixel(qt_enc1, 6, 1) 32 | pixel1.brightness = 0.2 33 | pixel1.fill(0xFF0000) 34 | 35 | pixel2 = neopixel.NeoPixel(qt_enc2, 6, 1) 36 | pixel2.brightness = 0.2 37 | pixel2.fill(0x0000FF) 38 | 39 | 40 | while True: 41 | # negate the position to make clockwise rotation positive 42 | position1 = -encoder1.position 43 | position2 = -encoder2.position 44 | 45 | if position1 != last_position1: 46 | last_position1 = position1 47 | print(f"Position 1: {position1}") 48 | 49 | if not button1.value and not button_held1: 50 | button_held1 = True 51 | pixel1.brightness = 0.5 52 | print("Button 1 pressed") 53 | 54 | if button1.value and button_held1: 55 | button_held1 = False 56 | pixel1.brightness = 0.2 57 | print("Button 1 released") 58 | 59 | if position2 != last_position2: 60 | last_position2 = position2 61 | print(f"Position 2: {position2}") 62 | 63 | if not button2.value and not button_held2: 64 | button_held2 = True 65 | pixel2.brightness = 0.5 66 | print("Button 2 pressed") 67 | 68 | if button2.value and button_held2: 69 | button_held2 = False 70 | pixel2.brightness = 0.2 71 | print("Button 2 released") 72 | -------------------------------------------------------------------------------- /examples/seesaw_rotary_neopixel.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 Kattni Rembor for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | """I2C rotary encoder NeoPixel color picker and brightness setting example.""" 5 | 6 | import board 7 | from rainbowio import colorwheel 8 | 9 | from adafruit_seesaw import digitalio, neopixel, rotaryio, seesaw 10 | 11 | # For use with the STEMMA connector on QT Py RP2040 12 | # import busio 13 | # i2c = busio.I2C(board.SCL1, board.SDA1) 14 | # seesaw = seesaw.Seesaw(i2c, 0x36) 15 | 16 | i2c = board.I2C() # uses board.SCL and board.SDA 17 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 18 | seesaw = seesaw.Seesaw(i2c, 0x36) 19 | 20 | encoder = rotaryio.IncrementalEncoder(seesaw) 21 | seesaw.pin_mode(24, seesaw.INPUT_PULLUP) 22 | switch = digitalio.DigitalIO(seesaw, 24) 23 | 24 | pixel = neopixel.NeoPixel(seesaw, 6, 1) 25 | pixel.brightness = 0.5 26 | 27 | last_position = -1 28 | color = 0 # start at red 29 | 30 | while True: 31 | # negate the position to make clockwise rotation positive 32 | position = -encoder.position 33 | 34 | if position != last_position: 35 | print(position) 36 | 37 | if switch.value: 38 | # Change the LED color. 39 | if position > last_position: # Advance forward through the colorwheel. 40 | color += 1 41 | else: 42 | color -= 1 # Advance backward through the colorwheel. 43 | color = (color + 256) % 256 # wrap around to 0-256 44 | pixel.fill(colorwheel(color)) 45 | 46 | elif position > last_position: # Increase the brightness. 47 | pixel.brightness = min(1.0, pixel.brightness + 0.1) 48 | else: # Decrease the brightness. 49 | pixel.brightness = max(0, pixel.brightness - 0.1) 50 | 51 | last_position = position 52 | -------------------------------------------------------------------------------- /examples/seesaw_rotary_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 John Furcean 2 | # SPDX-License-Identifier: MIT 3 | 4 | """I2C rotary encoder simple test example.""" 5 | 6 | import board 7 | 8 | from adafruit_seesaw import digitalio, rotaryio, seesaw 9 | 10 | # For use with the STEMMA connector on QT Py RP2040 11 | # import busio 12 | # i2c = busio.I2C(board.SCL1, board.SDA1) 13 | # seesaw = seesaw.Seesaw(i2c, 0x36) 14 | 15 | i2c = board.I2C() # uses board.SCL and board.SDA 16 | # i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 17 | seesaw = seesaw.Seesaw(i2c, addr=0x36) 18 | 19 | seesaw_product = (seesaw.get_version() >> 16) & 0xFFFF 20 | print(f"Found product {seesaw_product}") 21 | if seesaw_product != 4991: 22 | print("Wrong firmware loaded? Expected 4991") 23 | 24 | # Configure seesaw pin used to read knob button presses 25 | # The internal pull up is enabled to prevent floating input 26 | seesaw.pin_mode(24, seesaw.INPUT_PULLUP) 27 | button = digitalio.DigitalIO(seesaw, 24) 28 | 29 | button_held = False 30 | 31 | encoder = rotaryio.IncrementalEncoder(seesaw) 32 | last_position = None 33 | 34 | while True: 35 | # negate the position to make clockwise rotation positive 36 | position = -encoder.position 37 | 38 | if position != last_position: 39 | last_position = position 40 | print(f"Position: {position}") 41 | 42 | if not button.value and not button_held: 43 | button_held = True 44 | print("Button pressed") 45 | 46 | if button.value and button_held: 47 | button_held = False 48 | print("Button released") 49 | -------------------------------------------------------------------------------- /examples/seesaw_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Simple seesaw test using an LED attached to Pin 15. 5 | # 6 | # See the seesaw Learn Guide for wiring details: 7 | # https://learn.adafruit.com/adafruit-seesaw-atsamd09-breakout?view=all#circuitpython-wiring-and-test 8 | import time 9 | 10 | import board 11 | 12 | from adafruit_seesaw.seesaw import Seesaw 13 | 14 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 15 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 16 | 17 | ss = Seesaw(i2c_bus) 18 | 19 | ss.pin_mode(15, ss.OUTPUT) 20 | 21 | while True: 22 | ss.digital_write(15, True) # turn the LED on (True is the voltage level) 23 | time.sleep(1) # wait for a second 24 | ss.digital_write(15, False) # turn the LED off by making the voltage LOW 25 | time.sleep(1) 26 | -------------------------------------------------------------------------------- /examples/seesaw_soil_simpletest.py: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries 2 | # SPDX-License-Identifier: MIT 3 | 4 | import time 5 | 6 | import board 7 | 8 | from adafruit_seesaw.seesaw import Seesaw 9 | 10 | i2c_bus = board.I2C() # uses board.SCL and board.SDA 11 | # i2c_bus = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller 12 | 13 | ss = Seesaw(i2c_bus, addr=0x36) 14 | 15 | while True: 16 | # read moisture level through capacitive touch pad 17 | touch = ss.moisture_read() 18 | 19 | # read temperature from the temperature sensor 20 | temp = ss.get_temp() 21 | 22 | print("temp: " + str(temp) + " moisture: " + str(touch)) 23 | time.sleep(1) 24 | -------------------------------------------------------------------------------- /optional_requirements.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Alec Delaney for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | [build-system] 6 | requires = [ 7 | "setuptools", 8 | "wheel", 9 | "setuptools-scm", 10 | ] 11 | 12 | [project] 13 | name = "adafruit-circuitpython-seesaw" 14 | description = "CircuitPython library for controlling a SeeSaw helper chip." 15 | version = "0.0.0+auto.0" 16 | readme = "README.rst" 17 | authors = [ 18 | {name = "Adafruit Industries", email = "circuitpython@adafruit.com"} 19 | ] 20 | urls = {Homepage = "https://github.com/adafruit/Adafruit_CircuitPython_seesaw"} 21 | keywords = [ 22 | "adafruit", 23 | "seesaw", 24 | "hardware", 25 | "micropython", 26 | "circuitpython", 27 | ] 28 | license = {text = "MIT"} 29 | classifiers = [ 30 | "Intended Audience :: Developers", 31 | "Topic :: Software Development :: Libraries", 32 | "Topic :: Software Development :: Embedded Systems", 33 | "Topic :: System :: Hardware", 34 | "License :: OSI Approved :: MIT License", 35 | "Programming Language :: Python :: 3", 36 | ] 37 | dynamic = ["dependencies", "optional-dependencies"] 38 | 39 | [tool.setuptools] 40 | packages = ["adafruit_seesaw"] 41 | 42 | [tool.setuptools.dynamic] 43 | dependencies = {file = ["requirements.txt"]} 44 | optional-dependencies = {optional = {file = ["optional_requirements.txt"]}} 45 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Alec Delaney, for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: Unlicense 4 | 5 | Adafruit-Blinka 6 | adafruit-circuitpython-busdevice 7 | adafruit-circuitpython-pixelbuf 8 | -------------------------------------------------------------------------------- /ruff.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2024 Tim Cocks for Adafruit Industries 2 | # 3 | # SPDX-License-Identifier: MIT 4 | 5 | target-version = "py38" 6 | line-length = 100 7 | 8 | [lint] 9 | preview = true 10 | select = ["I", "PL", "UP"] 11 | 12 | extend-select = [ 13 | "D419", # empty-docstring 14 | "E501", # line-too-long 15 | "W291", # trailing-whitespace 16 | "PLC0414", # useless-import-alias 17 | "PLC2401", # non-ascii-name 18 | "PLC2801", # unnecessary-dunder-call 19 | "PLC3002", # unnecessary-direct-lambda-call 20 | "E999", # syntax-error 21 | "PLE0101", # return-in-init 22 | "F706", # return-outside-function 23 | "F704", # yield-outside-function 24 | "PLE0116", # continue-in-finally 25 | "PLE0117", # nonlocal-without-binding 26 | "PLE0241", # duplicate-bases 27 | "PLE0302", # unexpected-special-method-signature 28 | "PLE0604", # invalid-all-object 29 | "PLE0605", # invalid-all-format 30 | "PLE0643", # potential-index-error 31 | "PLE0704", # misplaced-bare-raise 32 | "PLE1141", # dict-iter-missing-items 33 | "PLE1142", # await-outside-async 34 | "PLE1205", # logging-too-many-args 35 | "PLE1206", # logging-too-few-args 36 | "PLE1307", # bad-string-format-type 37 | "PLE1310", # bad-str-strip-call 38 | "PLE1507", # invalid-envvar-value 39 | "PLE2502", # bidirectional-unicode 40 | "PLE2510", # invalid-character-backspace 41 | "PLE2512", # invalid-character-sub 42 | "PLE2513", # invalid-character-esc 43 | "PLE2514", # invalid-character-nul 44 | "PLE2515", # invalid-character-zero-width-space 45 | "PLR0124", # comparison-with-itself 46 | "PLR0202", # no-classmethod-decorator 47 | "PLR0203", # no-staticmethod-decorator 48 | "UP004", # useless-object-inheritance 49 | "PLR0206", # property-with-parameters 50 | "PLR0904", # too-many-public-methods 51 | "PLR0911", # too-many-return-statements 52 | "PLR0912", # too-many-branches 53 | "PLR0913", # too-many-arguments 54 | "PLR0914", # too-many-locals 55 | "PLR0915", # too-many-statements 56 | "PLR0916", # too-many-boolean-expressions 57 | "PLR1702", # too-many-nested-blocks 58 | "PLR1704", # redefined-argument-from-local 59 | "PLR1711", # useless-return 60 | "C416", # unnecessary-comprehension 61 | "PLR1733", # unnecessary-dict-index-lookup 62 | "PLR1736", # unnecessary-list-index-lookup 63 | 64 | # ruff reports this rule is unstable 65 | #"PLR6301", # no-self-use 66 | 67 | "PLW0108", # unnecessary-lambda 68 | "PLW0120", # useless-else-on-loop 69 | "PLW0127", # self-assigning-variable 70 | "PLW0129", # assert-on-string-literal 71 | "B033", # duplicate-value 72 | "PLW0131", # named-expr-without-context 73 | "PLW0245", # super-without-brackets 74 | "PLW0406", # import-self 75 | "PLW0602", # global-variable-not-assigned 76 | "PLW0603", # global-statement 77 | "PLW0604", # global-at-module-level 78 | 79 | # fails on the try: import typing used by libraries 80 | #"F401", # unused-import 81 | 82 | "F841", # unused-variable 83 | "E722", # bare-except 84 | "PLW0711", # binary-op-exception 85 | "PLW1501", # bad-open-mode 86 | "PLW1508", # invalid-envvar-default 87 | "PLW1509", # subprocess-popen-preexec-fn 88 | "PLW2101", # useless-with-lock 89 | "PLW3301", # nested-min-max 90 | ] 91 | 92 | ignore = [ 93 | "PLR2004", # magic-value-comparison 94 | "UP030", # format literals 95 | "PLW1514", # unspecified-encoding 96 | "PLR0913", # too-many-arguments 97 | "PLR0915", # too-many-statements 98 | "PLR0917", # too-many-positional-arguments 99 | "PLR0904", # too-many-public-methods 100 | "PLR0912", # too-many-branches 101 | "PLR0916", # too-many-boolean-expressions 102 | ] 103 | 104 | [format] 105 | line-ending = "lf" 106 | --------------------------------------------------------------------------------