kopia lustrzana https://github.com/pimoroni/pimoroni-pico
Porównaj commity
415 Commity
Autor | SHA1 | Data |
---|---|---|
Philip Howard | 7a2ebe5c0d | |
Phil Howard | 48f2446f6c | |
Phil Howard | 6eef96d9c9 | |
Philip Howard | 9771274e90 | |
Phil Howard | 7c05770a44 | |
Philip Howard | 3440ab232c | |
Phil Howard | 7d0bb04d6d | |
Phil Howard | 392890e99b | |
Phil Howard | 7b7d9fe383 | |
Phil Howard | ccd00f6289 | |
Philip Howard | 10fed7edaf | |
Phil Howard | 517f8ae1cd | |
thirdr | 5b6903ce72 | |
Phil Howard | 84cabe077d | |
Phil Howard | 64e26dc6f4 | |
Phil Howard | 47e3aed88f | |
Philip Howard | bf6fa4bc45 | |
Philip Howard | 0b133c750e | |
Philip Howard | 5691573f89 | |
Philip Howard | b41bb4abf7 | |
Philip Howard | 8b928d8891 | |
Philip Howard | 56e6d66c9b | |
thirdr | ffa12c2165 | |
thirdr | b9f3990995 | |
thirdr | cca4f3f7f1 | |
Philip Howard | 981a38b989 | |
Philip Howard | 25786def35 | |
thirdr | a387e45098 | |
thirdr | 452d700ba1 | |
Hel Gibbons | 9d7d651565 | |
Scott Dutton | b3a0c4fb9d | |
thirdr | f962c3cd3c | |
thirdr | b5a040f6cc | |
thirdr | d790d3d344 | |
thirdr | ba7b8388bf | |
thirdr | 829f688285 | |
thirdr | 8fb17a3c26 | |
thirdr | 4db7cc61ab | |
thirdr | c510a3c875 | |
thirdr | 425f132096 | |
thirdr | 76683acb0d | |
thirdr | 7c287192de | |
thirdr | f15c657b44 | |
Philip Howard | f3b53b6b5f | |
coadkins | 37c4d22527 | |
Philip Howard | 616b1cc8d6 | |
Phil Howard | 45a9925072 | |
thirdr | 3998b0c8bf | |
Connor Linfoot | 32c10482d9 | |
Phil Howard | 6ed743b32c | |
Phil Howard | 17d59f4729 | |
Philip Howard | 4c44b77193 | |
Phil Howard | 5510c82564 | |
Philip Howard | 3a10b29f54 | |
Phil Howard | 8cf276b992 | |
Phil Howard | 8bb17087d9 | |
Phil Howard | 6fcbaf5616 | |
Phil Howard | 6803f00b31 | |
Phil Howard | 6e71a62c65 | |
Philip Howard | f1ea35fbbf | |
Philip Howard | c066325ca0 | |
Philip Howard | fd4eb165f8 | |
Phil Howard | 8fc8a8ee06 | |
Phil Howard | 3bfb548686 | |
Philip Howard | 9edcdcc126 | |
Philip Howard | e8e550b18b | |
thirdr | cdb7b4bf2c | |
Philip Howard | 4fc3095433 | |
Phil Howard | 9c5b529754 | |
ZodiusInfuser | a87d5581aa | |
ZodiusInfuser | 44d7875f7e | |
ZodiusInfuser | a90c31fb3b | |
ZodiusInfuser | 458b0ac209 | |
Phil Howard | a537672dd4 | |
Phil Howard | d34e692f51 | |
Phil Howard | 27b913124c | |
Phil Howard | c7b788cd1d | |
Philip Howard | c386b3e9cf | |
thirdr | b499296867 | |
thirdr | 193adaca72 | |
Philip Howard | a7a2e2bee0 | |
thirdr | b0babcfe9f | |
Phil Howard | 19fa8864cf | |
thirdr | e34b2420c6 | |
Phil Howard | 964cf5eedf | |
Phil Howard | eab1595352 | |
Phil Howard | 5dd76ed31b | |
Philip Howard | 6eb0f90e53 | |
Phil Howard | b0d53dadb3 | |
Phil Howard | ad518064e9 | |
Philip Howard | d83107474e | |
Phil Howard | c4f70df1cf | |
Phil Howard | 10221066dd | |
Philip Howard | ab64fcaccc | |
Hel Gibbons | 32c63c343d | |
Hel Gibbons | 8d964bce2c | |
ZodiusInfuser | 8ca47d6405 | |
Skyler Mansfield | b23a71b889 | |
Philip Howard | 6b23c1526d | |
Phil Howard | c19b2276f1 | |
Philip Howard | 392d75b00d | |
Philip Howard | 911cbb710e | |
Philip Howard | 4e3e2c836d | |
Philip Howard | 5bd5334379 | |
Philip Howard | 9ddbb17a82 | |
Phil Howard | 5126263f91 | |
Philip Howard | 0d3fce9b9d | |
Rob Berwick | 9e6a0725c0 | |
Rob Berwick | 3e81b245a1 | |
Phil Howard | bd6bd289d1 | |
Phil Howard | b6953c25a1 | |
Phil Howard | b5df0ac277 | |
Phil Howard | 116bbb1296 | |
Phil Howard | 6154116662 | |
Phil Howard | d45daef654 | |
Phil Howard | 1b3d9d9fb2 | |
Phil Howard | 4dd76525f6 | |
Phil Howard | 3bac13fcc8 | |
Hel Gibbons | bff245324b | |
Hel Gibbons | 400347b862 | |
Ray Bellis | da0ac1821f | |
Rob Berwick | 6dcc0d4fa0 | |
Erin Sparling | fc3f8e5654 | |
Erin Sparling | c001f9bb59 | |
Erin Sparling | 59fa0a1ff8 | |
Stefan Werder | a803c3cee4 | |
Ray Bellis | 6fd667b1ca | |
Paco Hope | 078d81312f | |
Hel Gibbons | a60c856ea8 | |
Philip Howard | b4451c3bdc | |
Phil Howard | ce42d814a7 | |
Philip Howard | ee7f2758dd | |
Phil Howard | 388d8af3dc | |
Phil Howard | 0f75a2839f | |
Phil Howard | e691628723 | |
Phil Howard | 08ce4fbb81 | |
Phil Howard | 20de8a3198 | |
Philip Howard | 9499b7e908 | |
Philip Howard | 65fd3b1c5a | |
Phil Howard | 4b3e83f2ff | |
Philip Howard | fc777ff0ca | |
Hel Gibbons | 5345cc42d2 | |
Hel Gibbons | 169ed9c763 | |
Philip Howard | 8eac60afc6 | |
Phil Howard | 93525a422f | |
Hel Gibbons | 36f3e3a69f | |
Hel Gibbons | 29a13305d2 | |
Philip Howard | 1f4704afdb | |
Phil Howard | ae7e6e8c6c | |
Phil Howard | 5f730ff400 | |
Philip Howard | c3919bd648 | |
Philip Howard | ed3ce45f00 | |
Philip Howard | 1a7deaab71 | |
Philip Howard | 9735402ee3 | |
Philip Howard | c045c405c3 | |
Mike Bell | 80e1e16782 | |
Mike Bell | cdd648f3f6 | |
Mike Bell | 81f42f25b6 | |
Mike Bell | 841c141ebf | |
Mike Bell | c812eec432 | |
Mike Bell | 41eb2b503e | |
Mike Bell | 581481c2ef | |
Mike Bell | e908d5e53e | |
Mike Bell | 34b8ac9f0c | |
Philip Howard | 9124b376d2 | |
Phil Howard | c725b4eee0 | |
Philip Howard | a334899b61 | |
Phil Howard | cca2d569e4 | |
Philip Howard | 3d8f8c9a83 | |
Phil Howard | 788f6c3232 | |
Phil Howard | 231ceb70f2 | |
Phil Howard | c9fd68ec58 | |
Hel Gibbons | b82429caf0 | |
Hel Gibbons | 386a3594c0 | |
Hel Gibbons | 9e0b3adc0c | |
Pete Favelle | 8c3a21ec1a | |
Pete Favelle | 2f44e85431 | |
Phil Howard | 5a92a9c735 | |
Pete Favelle | 8a9ef39158 | |
Phil Howard | c443f8d206 | |
Phil Howard | 591058fb12 | |
Phil Howard | cfe8b3c096 | |
Phil Howard | 9d0501a43c | |
Phil Howard | 7c5ebfce8c | |
Phil Howard | 61c9d7e9b6 | |
Phil Howard | c7d9fe411a | |
Phil Howard | 4671607b3a | |
Phil Howard | 95ab839ba5 | |
Phil Howard | 9e430fd68c | |
Phil Howard | c9a8d5ef49 | |
Phil Howard | 38aaa04c5d | |
Phil Howard | e8dba75aff | |
Phil Howard | 09a58b269f | |
Phil Howard | cc7219b44a | |
Philip Howard | 57042bfed3 | |
Hel Gibbons | dc4ee0d459 | |
Hel Gibbons | 157180c476 | |
Hel Gibbons | 7344e4d1a4 | |
Phil Howard | 1157e605a1 | |
Philip Howard | b82d16e8ae | |
Hel Gibbons | 095122c606 | |
Mike Bell | 211e0aa618 | |
Mike Bell | b8116fc371 | |
Mike Bell | 0cfcb22aa4 | |
Mike Bell | 3cdfe558e8 | |
Mike Bell | 103228a88d | |
Mike Bell | 3a5f069ec1 | |
Mike Bell | 765b8a6226 | |
Mike Bell | 3c2c7ccc94 | |
Mike Bell | b9cd998709 | |
Mike Bell | 1a54f7b77d | |
Mike Bell | 8f78e3d6bc | |
Mike Bell | a396512e7f | |
Mike Bell | 9a0b21d417 | |
Mike Bell | e9779fc0e7 | |
Mike Bell | 559ce08e04 | |
Phil Howard | cbc05863c0 | |
Phil Howard | 7d8bbf5c08 | |
Mike Bell | 7e9f16d80c | |
Mike Bell | 4b57162c06 | |
Phil Howard | de4aaa80b6 | |
Phil Howard | 4afe062d19 | |
Mike Bell | 3bc215074c | |
Mike Bell | a6bd626334 | |
Mike Bell | 575e806cc8 | |
Mike Bell | be943bd5a0 | |
Mike Bell | daf7232024 | |
Mike Bell | a7435c6a5e | |
Mike Bell | 5a6aa0186c | |
Mike Bell | 360588ff67 | |
Mike Bell | 4ed1d61336 | |
Mike Bell | 31b480d138 | |
Mike Bell | c7049f4ff1 | |
Mike Bell | 1d8c836635 | |
Mike Bell | e295e69c72 | |
Mike Bell | 5971bc9ad8 | |
Mike Bell | a1caa9495c | |
Mike Bell | f4b8bc9025 | |
Mike Bell | 2e8632f2b6 | |
Mike Bell | da36b0ad32 | |
Mike Bell | 9acc270418 | |
Mike Bell | 5f8e7556f0 | |
Philip Howard | a7efef0049 | |
Hel Gibbons | 5a5786d066 | |
Simon Prickett | 710863099d | |
Simon Prickett | 316957c263 | |
Simon Prickett | 9b18ed2594 | |
Simon Prickett | 658025a99b | |
Hel Gibbons | fef22530ea | |
Angus Logan | fc28845fb9 | |
Andrew Wilkinson | 14c7f6c9c8 | |
Simon Prickett | 14eabf360f | |
Simon Prickett | fe805a711a | |
Philip Howard | d93839d56a | |
Philip Howard | e1527c44d5 | |
Phil Howard | 4ad6df5cc3 | |
Phil Howard | 004c8de8eb | |
Philip Howard | 3639b46881 | |
Phil Howard | b744f78a46 | |
Philip Howard | 5bc85c0e6d | |
ZodiusInfuser | 6bd5a445ba | |
Irvin | 6306d5e753 | |
Irvin | f0bfc7c13b | |
Irvin | e1e467185a | |
Irvin | 7e65c15cfb | |
Irvin Makosa | 462724210c | |
Irvin Makosa | 0b0474e062 | |
Irvin Makosa | 90a2076b7b | |
Irvin Makosa | e14903dd27 | |
Irvin Makosa | f06d1035a4 | |
Hel Gibbons | d0c40af766 | |
Hel Gibbons | 439b97d96e | |
Irvin Makosa | 8bb5e17e65 | |
Irvin | b8cdff8f4f | |
Hel Gibbons | eb31f9b043 | |
Phil Howard | b368950f02 | |
Philip Howard | 51574f839d | |
Hel Gibbons | 03232bbeb5 | |
Phil Howard | 5ec6903f7f | |
helgibbons | c696cd5e2d | |
Phil Howard | 6db7a9a0a6 | |
Phil Howard | 1630ddbbb2 | |
Hel Gibbons | 25237c54ce | |
Alexander Wilde | 16c2dc0356 | |
Hel Gibbons | 8f5a94482b | |
thinkier | aa8b158ba3 | |
Hel Gibbons | 52df18e550 | |
Hel Gibbons | 1d1b521dfb | |
Hel Gibbons | 3786cbdfe6 | |
Hel Gibbons | 58cdc85b1f | |
helgibbons | 6b67f652c7 | |
helgibbons | 37638172ae | |
helgibbons | 3236503805 | |
helgibbons | ce24330842 | |
helgibbons | 130685eeeb | |
Hel Gibbons | 6afdfef45b | |
Angus Logan | 1e6e68356a | |
Angus Logan | d25c6953d0 | |
Angus Logan | 0a0b72701e | |
Hel Gibbons | 40f0554259 | |
Hel Gibbons | d9064f0162 | |
Hel Gibbons | dc1f000134 | |
Hel Gibbons | 32ae70d16d | |
Hel Gibbons | 8a6bb65d73 | |
LionsPhil | a0fe954b7c | |
Hel Gibbons | 951fe4d8b8 | |
Hel Gibbons | cbaf1fa27d | |
Hel Gibbons | 16f8f0ab05 | |
Hel Gibbons | d759522b08 | |
Hel Gibbons | 9307ea1360 | |
Philip Howard | 6fb35df544 | |
Phil Howard | b0d63ef777 | |
Philip Howard | d523eded0b | |
Phil Howard | 090ce9d2c6 | |
Philip Howard | 9d96d061e9 | |
Phil Howard | 70a1b26041 | |
Phil Howard | bff6bd023e | |
Phil Howard | 19c57ebb20 | |
Phil Howard | 94c5d74894 | |
ZodiusInfuser | 67152e32e5 | |
ZodiusInfuser | 7aa75e57a4 | |
ZodiusInfuser | 68f610184f | |
ZodiusInfuser | aabe789f21 | |
ZodiusInfuser | bd4238945d | |
ZodiusInfuser | ae252fbc6e | |
Philip Howard | d4609699ba | |
Philip Howard | 74064407e9 | |
Phil Howard | 0a2e099886 | |
Hel Gibbons | c8d3b6b7d1 | |
Hel Gibbons | 5aa227ff45 | |
Phil Howard | fba7b53c36 | |
Philip Howard | 00d1617947 | |
Phil Howard | 652de85f4d | |
Philip Howard | 8648196cc2 | |
Philip Howard | ec205fb045 | |
Mike Bell | 5b31e018ff | |
ZodiusInfuser | d00185d831 | |
ZodiusInfuser | 0120975b3c | |
ZodiusInfuser | 12e38c1157 | |
Philip Howard | 89699fd78f | |
Phil Howard | 05cad0c157 | |
ZodiusInfuser | 653090c89e | |
Philip Howard | 1c39da4997 | |
Philip Howard | 092fbe472f | |
Philip Howard | ecbd1e66de | |
Ray Bellis | bfb6490ec8 | |
Ray Bellis | 32dfdc6a20 | |
Ray Bellis | 67df015bfe | |
Hel Gibbons | 302d6ae0eb | |
Hel Gibbons | 1be888f397 | |
Philip Howard | 7491ced13b | |
Niko Kotilainen | 1dcad21ed2 | |
ZodiusInfuser | 8966cbf348 | |
Pete Favelle | a59aa35df5 | |
Philip Howard | b6499e71fc | |
ZodiusInfuser | 5619274d3d | |
ZodiusInfuser | 862806f357 | |
Phil Howard | 7951ef9668 | |
ZodiusInfuser | 4dadeb0d4d | |
Phil Howard | b30d9ca554 | |
ZodiusInfuser | e0a405739c | |
ZodiusInfuser | 9f925b5259 | |
Phil Howard | 8648597134 | |
ZodiusInfuser | e3f9f14dcf | |
ZodiusInfuser | 226e7507dd | |
ZodiusInfuser | 1cfae8b5f8 | |
ZodiusInfuser | 387df3bd12 | |
Phil Howard | 45a2e0f5b1 | |
Phil Howard | e90ae33a99 | |
ZodiusInfuser | d4d6cd1936 | |
Phil Howard | dd4347dac3 | |
ZodiusInfuser | 928c28b677 | |
ZodiusInfuser | 2d45ed6ace | |
ZodiusInfuser | 178afd1469 | |
ZodiusInfuser | 6464f44437 | |
ZodiusInfuser | cd83a51e8a | |
ZodiusInfuser | f353525090 | |
ZodiusInfuser | 7c11593f7c | |
ZodiusInfuser | e3c3692e31 | |
ZodiusInfuser | 15978e5ddc | |
ZodiusInfuser | 59d57a193b | |
Philip Howard | 56dba370c6 | |
Phil Howard | 22a659a559 | |
Phil Howard | 70f133dd62 | |
Philip Howard | f0975778f6 | |
Phil Howard | c885789ada | |
Phil Howard | 8e0fe155c5 | |
Hel Gibbons | b512bdcea1 | |
andrewmk | 49e0b25557 | |
Phil Howard | c25de67247 | |
Philip Howard | 334283a8f6 | |
Phil Howard | af99d6d5f8 | |
Philip Howard | 5bfc0eba4c | |
Phil Howard | 1d003a80c2 | |
Phil Howard | a19f5943c3 | |
Hel Gibbons | cb5dcb965e | |
Hel Gibbons | f48c17ae1f | |
phennessey7 | d78fffcd54 | |
phennessey7 | 7b7959ef20 | |
Hel Gibbons | 39eae8d42c | |
Quitsoon | f6206876b7 | |
mutatrum | 7bdd85d677 | |
Philip Howard | 7b7352130f | |
Philip Howard | 40d4774cf6 | |
Phil Howard | 3a35013667 | |
Phil Howard | 3bdb27458f | |
Phil Howard | cce02feabd | |
Phil Howard | aeca08f275 | |
Phil Howard | d69797689a | |
Phil Howard | af352ff33f | |
Phil Howard | 883d751f52 | |
Hel Gibbons | 5fa99c0690 | |
Hel Gibbons | 75602b3fbb | |
Hel Gibbons | 6e7ec899eb | |
Phil Howard | acf0e568bd |
|
@ -25,7 +25,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Compiler Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /home/runner/.ccache
|
||||
key: ccache-cmake-${{github.ref}}-${{matrix.board}}-${{github.sha}}
|
||||
|
@ -34,13 +34,13 @@ jobs:
|
|||
ccache-cmake-${{github.ref}}
|
||||
ccache-cmake
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
|
||||
# Check out the Pico SDK
|
||||
- name: Checkout Pico SDK
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: raspberrypi/pico-sdk
|
||||
path: pico-sdk
|
||||
|
@ -48,7 +48,7 @@ jobs:
|
|||
|
||||
# Check out the Pico Extras
|
||||
- name: Checkout Pico Extras
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: raspberrypi/pico-extras
|
||||
path: pico-extras
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
name: MicroPython
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
release:
|
||||
types: [created]
|
||||
|
||||
env:
|
||||
MICROPYTHON_VERSION: 38e7b842c6bc8122753cbf0845eb141f28fbcb72
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Dependencies
|
||||
steps:
|
||||
- name: Workspace Cache
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{runner.workspace}}
|
||||
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}-with-libs
|
||||
restore-keys: |
|
||||
workspace-micropython-${{env.MICROPYTHON_VERSION}}-with-libs
|
||||
|
||||
# Check out MicroPython
|
||||
- name: Checkout MicroPython
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: micropython/micropython
|
||||
ref: ${{env.MICROPYTHON_VERSION}}
|
||||
submodules: false # MicroPython submodules are hideously broken
|
||||
path: micropython
|
||||
|
||||
# Check out MicroPython Libs
|
||||
- name: Checkout MicroPython Libs
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: micropython/micropython-lib
|
||||
path: micropython-lib
|
||||
|
||||
- name: Fetch base MicroPython submodules
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Fetch Pico SDK submodules
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython/lib/pico-sdk
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Build mpy-cross
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython/mpy-cross
|
||||
run: make
|
||||
|
||||
build:
|
||||
needs: deps
|
||||
name: Build ${{matrix.name}} (${{matrix.board}})
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: picow
|
||||
board: PICO_W
|
||||
- name: picow_enviro
|
||||
board: PICO_W_ENVIRO
|
||||
- name: picow_galactic_unicorn
|
||||
board: PICO_W
|
||||
- name: picow_cosmic_unicorn
|
||||
board: PICO_W
|
||||
- name: picow_inky_frame
|
||||
board: PICO_W_INKY
|
||||
|
||||
env:
|
||||
# MicroPython version will be contained in github.event.release.tag_name for releases
|
||||
RELEASE_FILE: pimoroni-${{matrix.name}}-${{github.event.release.tag_name || github.sha}}-micropython
|
||||
|
||||
steps:
|
||||
- name: Compiler Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: /home/runner/.ccache
|
||||
key: ccache-micropython-${{matrix.name}}-${{github.ref}}-${{github.sha}}
|
||||
restore-keys: |
|
||||
ccache-micropython-${{matrix.name}}-${{github.ref}}
|
||||
ccache-micropython-${{matrix.name}}-
|
||||
|
||||
- name: Workspace Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{runner.workspace}}
|
||||
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}-with-libs
|
||||
restore-keys: |
|
||||
workspace-micropython-${{env.MICROPYTHON_VERSION}}-with-libs
|
||||
|
||||
- name: Install Compiler & CCache
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt update && sudo apt install ccache gcc-arm-none-eabi
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: true
|
||||
path: pimoroni-pico-${{ github.sha }}
|
||||
|
||||
- name: "HACK: MicroPython Board Fixups"
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
run: |
|
||||
../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh ${{matrix.name}} ${{matrix.board}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board
|
||||
|
||||
- name: Configure MicroPython
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
run: |
|
||||
cmake -S . -B build-${{matrix.board}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-${{matrix.name}}.cmake -DMICROPY_BOARD=${{matrix.board}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
|
||||
- name: Build MicroPython
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
run: |
|
||||
ccache --zero-stats || true
|
||||
cmake --build build-${{matrix.board}} -j 2
|
||||
ccache --show-stats || true
|
||||
|
||||
- name: Rename .uf2 for artifact
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2/build-${{matrix.board}}
|
||||
run: |
|
||||
cp firmware.uf2 $RELEASE_FILE.uf2
|
||||
|
||||
- name: Store .uf2 as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{env.RELEASE_FILE}}.uf2
|
||||
path: micropython/ports/rp2/build-${{matrix.board}}/${{env.RELEASE_FILE}}.uf2
|
||||
|
||||
- name: Upload .uf2
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
with:
|
||||
asset_path: micropython/ports/rp2/build-${{matrix.board}}/firmware.uf2
|
||||
upload_url: ${{github.event.release.upload_url}}
|
||||
asset_name: ${{env.RELEASE_FILE}}.uf2
|
||||
asset_content_type: application/octet-stream
|
|
@ -7,60 +7,23 @@ on:
|
|||
types: [created]
|
||||
|
||||
env:
|
||||
MICROPYTHON_VERSION: 38e7b842c6bc8122753cbf0845eb141f28fbcb72
|
||||
MICROPYTHON_VERSION: v1.23.0
|
||||
|
||||
jobs:
|
||||
deps:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Dependencies
|
||||
steps:
|
||||
- name: Workspace Cache
|
||||
id: cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{runner.workspace}}
|
||||
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
|
||||
restore-keys: |
|
||||
workspace-micropython-${{env.MICROPYTHON_VERSION}}
|
||||
|
||||
# Check out MicroPython
|
||||
- name: Checkout MicroPython
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: micropython/micropython
|
||||
ref: ${{env.MICROPYTHON_VERSION}}
|
||||
submodules: false # MicroPython submodules are hideously broken
|
||||
path: micropython
|
||||
|
||||
- name: Fetch base MicroPython submodules
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Fetch Pico SDK submodules
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython/lib/pico-sdk
|
||||
run: git submodule update --init
|
||||
|
||||
- name: Build mpy-cross
|
||||
if: steps.cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
working-directory: micropython/mpy-cross
|
||||
run: make
|
||||
|
||||
build:
|
||||
needs: deps
|
||||
name: Build ${{matrix.board}}
|
||||
name: ${{ matrix.name }} (${{ matrix.board }})
|
||||
runs-on: ubuntu-20.04
|
||||
continue-on-error: true
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- name: pico
|
||||
board: PICO
|
||||
- name: tiny2040
|
||||
board: RPI_PICO
|
||||
- name: pico_usb
|
||||
board: RPI_PICO_USB
|
||||
- name: picow
|
||||
board: RPI_PICO_W
|
||||
- name: tiny2040_8mb
|
||||
board: PIMORONI_TINY2040
|
||||
- name: picolipo_4mb
|
||||
board: PIMORONI_PICOLIPO_4MB
|
||||
|
@ -68,77 +31,113 @@ jobs:
|
|||
board: PIMORONI_PICOLIPO_16MB
|
||||
- name: tufty2040
|
||||
board: PIMORONI_TUFTY2040
|
||||
- name: enviro
|
||||
board: PICO_W_ENVIRO
|
||||
- name: galactic_unicorn
|
||||
board: RPI_PICO_W
|
||||
- name: cosmic_unicorn
|
||||
board: RPI_PICO_W
|
||||
- name: stellar_unicorn
|
||||
board: RPI_PICO_W
|
||||
- name: inky_frame
|
||||
board: PICO_W_INKY
|
||||
|
||||
env:
|
||||
# MicroPython version will be contained in github.event.release.tag_name for releases
|
||||
RELEASE_FILE: pimoroni-${{matrix.name}}-${{github.event.release.tag_name || github.sha}}-micropython.uf2
|
||||
RELEASE_FILE: ${{ matrix.name }}-${{ github.event.release.tag_name || github.sha }}-pimoroni-micropython
|
||||
PIMORONI_PICO_DIR: "${{ github.workspace }}/pimoroni-pico-${{ github.sha }}"
|
||||
MICROPY_BOARD_DIR: "${{ github.workspace }}/pimoroni-pico-${{ github.sha }}/micropython/board/${{ matrix.BOARD }}"
|
||||
USER_C_MODULES: "${{ github.workspace }}/pimoroni-pico-${{ github.sha }}/micropython/modules/micropython-${{ matrix.name }}.cmake"
|
||||
TAG_OR_SHA: ${{ github.event.release.tag_name || github.sha }}
|
||||
MICROPY_BOARD: ${{ matrix.board }}
|
||||
BOARD_NAME: ${{ matrix.name }}
|
||||
BUILD_TOOLS: pimoroni-pico-${{ github.sha }}/ci/micropython.sh
|
||||
|
||||
steps:
|
||||
- name: Compiler Cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /home/runner/.ccache
|
||||
key: ccache-micropython-${{matrix.name}}-${{github.ref}}-${{github.sha}}
|
||||
key: ccache-micropython-${{ matrix.name }}-${{ github.ref }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
ccache-micropython-${{matrix.name}}-${{github.ref}}
|
||||
ccache-micropython-${{matrix.name}}-
|
||||
|
||||
- name: Workspace Cache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{runner.workspace}}
|
||||
key: workspace-micropython-${{env.MICROPYTHON_VERSION}}
|
||||
restore-keys: |
|
||||
workspace-micropython-${{env.MICROPYTHON_VERSION}}
|
||||
ccache-micropython-${{ matrix.name }}-${{ github.ref }}
|
||||
ccache-micropython-${{ matrix.name }}-
|
||||
|
||||
- name: Install Compiler & CCache
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt update && sudo apt install ccache gcc-arm-none-eabi
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: true
|
||||
path: pimoroni-pico-${{ github.sha }}
|
||||
|
||||
- name: "HACK: MicroPython Board Fixups"
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
|
||||
- name: Install Arm GNU Toolchain (arm-none-eabi-gcc)
|
||||
uses: carlosperate/arm-none-eabi-gcc-action@v1
|
||||
with:
|
||||
release: '9-2020-q2'
|
||||
|
||||
- name: Install CCache
|
||||
run: |
|
||||
../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board/board-fixup.sh ${{matrix.name}} ${{matrix.board}} ../../../pimoroni-pico-${GITHUB_SHA}/micropython/_board
|
||||
source $BUILD_TOOLS
|
||||
apt_install_build_deps
|
||||
|
||||
- name: Checkout MicroPython & Submodules
|
||||
run: |
|
||||
source $BUILD_TOOLS
|
||||
micropython_clone
|
||||
|
||||
- name: "Py_Decl: Checkout py_decl"
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: gadgetoid/py_decl
|
||||
ref: v0.0.1
|
||||
path: py_decl
|
||||
|
||||
- name: Build MPY Cross
|
||||
run: |
|
||||
source $BUILD_TOOLS
|
||||
micropython_build_mpy_cross
|
||||
|
||||
- name: "HACK: CMakeLists.txt Disable C++ Exceptions Patch"
|
||||
shell: bash
|
||||
run: |
|
||||
source $BUILD_TOOLS
|
||||
hack_patch_micropython_disable_exceptions
|
||||
|
||||
- name: "HACK: Pico SDK Patch"
|
||||
shell: bash
|
||||
run: |
|
||||
source $BUILD_TOOLS
|
||||
hack_patch_pico_sdk
|
||||
|
||||
- name: Configure MicroPython
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
run: |
|
||||
cmake -S . -B build-${{matrix.board}} -DPICO_BUILD_DOCS=0 -DUSER_C_MODULES=../../../pimoroni-pico-${GITHUB_SHA}/micropython/modules/micropython-${{matrix.name}}.cmake -DMICROPY_BOARD=${{matrix.board}} -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
source $BUILD_TOOLS
|
||||
micropython_version
|
||||
cmake_configure
|
||||
|
||||
- name: Build MicroPython
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2
|
||||
run: |
|
||||
ccache --zero-stats || true
|
||||
cmake --build build-${{matrix.board}} -j 2
|
||||
ccache --show-stats || true
|
||||
source $BUILD_TOOLS
|
||||
cmake_build
|
||||
|
||||
- name: Rename .uf2 for artifact
|
||||
- name: "Py_Decl: Verify UF2"
|
||||
shell: bash
|
||||
working-directory: micropython/ports/rp2/build-${{matrix.board}}
|
||||
run: cp firmware.uf2 $RELEASE_FILE
|
||||
run: |
|
||||
python3 py_decl/py_decl.py --to-json --verify build-${{ matrix.name }}/${{ env.RELEASE_FILE }}.uf2
|
||||
|
||||
- name: Store .uf2 as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.RELEASE_FILE}}
|
||||
path: micropython/ports/rp2/build-${{matrix.board}}/${{env.RELEASE_FILE}}
|
||||
name: ${{ env.RELEASE_FILE }}.uf2
|
||||
path: build-${{ matrix.name }}/${{ env.RELEASE_FILE }}.uf2
|
||||
|
||||
- name: Upload .uf2
|
||||
if: github.event_name == 'release'
|
||||
uses: actions/upload-release-asset@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
asset_path: micropython/ports/rp2/build-${{matrix.board}}/firmware.uf2
|
||||
upload_url: ${{github.event.release.upload_url}}
|
||||
asset_name: ${{env.RELEASE_FILE}}
|
||||
asset_path: build-${{ matrix.name }}/firmware.uf2
|
||||
upload_url: ${{ github.event.release.upload_url }}
|
||||
asset_name: ${{ env.RELEASE_FILE }}.uf2
|
||||
asset_content_type: application/octet-stream
|
||||
|
|
|
@ -9,7 +9,7 @@ jobs:
|
|||
name: Python Linting
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install Python Deps
|
||||
run: python3 -m pip install flake8
|
||||
|
|
|
@ -10,6 +10,8 @@ set(CMAKE_CXX_STANDARD 17)
|
|||
# Initialize the SDK
|
||||
pico_sdk_init()
|
||||
|
||||
pico_find_compiler(PICO_COMPILER_LD ${PICO_GCC_TRIPLE}-ld)
|
||||
|
||||
function(add_resource target file)
|
||||
get_filename_component(NAME ${ARGV1} NAME_WE)
|
||||
set(FILENAME ${ARGV1})
|
||||
|
@ -21,7 +23,7 @@ function(add_resource target file)
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/${FILENAME}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
|
||||
COMMAND arm-none-eabi-ld -r -b binary -o ${NAME}.o ${FILENAME}
|
||||
COMMAND ${PICO_COMPILER_LD} -r -b binary -o ${NAME}.o ${FILENAME}
|
||||
DEPENDS ${FILENAME}
|
||||
)
|
||||
|
||||
|
|
|
@ -44,6 +44,10 @@ You can find MicroPython examples for supported sensors, packs and bases in the
|
|||
|
||||
* [MicroPython Examples](micropython/examples)
|
||||
|
||||
You can also install MicroPython stubs into Visual Studio Code to give you auto-complete, see:
|
||||
|
||||
* [MicroPython Stubs](https://github.com/pimoroni/pimoroni-pico-stubs)
|
||||
|
||||
# C/C++
|
||||
|
||||
Advanced users that want to unleash the full power of Pico can use our C++ libraries. If you know what you're doing and want to build your own Pimoroni Pico project then start with the [Pimoroni Pico SDK Boilerplate](https://github.com/pimoroni/pico-boilerplate).
|
||||
|
@ -116,6 +120,7 @@ We also maintain a C++/CMake boilerplate with GitHub workflows configured for te
|
|||
* MICS6814 - Gas Sensor - https://shop.pimoroni.com/products/mics6814-gas-sensor-breakout
|
||||
* RGB Potentiometer - https://shop.pimoroni.com/products/rgb-potentiometer-breakout
|
||||
* RGB Encoder - https://shop.pimoroni.com/products/rgb-encoder-breakout
|
||||
* RGB Encoder Wheel - https://shop.pimoroni.com/products/rgb-encoder-wheel-breakout
|
||||
* IO Expander - https://shop.pimoroni.com/products/io-expander
|
||||
* RV3028 - Real-Time Clock (RTC) - https://shop.pimoroni.com/products/rv3028-real-time-clock-rtc-breakout
|
||||
* ST7735 - 0.96" LCD - https://shop.pimoroni.com/products/0-96-spi-colour-lcd-160x80-breakout
|
||||
|
@ -139,6 +144,7 @@ We also maintain a C++/CMake boilerplate with GitHub workflows configured for te
|
|||
* ICP10125 - High Accuracy Pressure / Altitude / Temperature Sensor - https://shop.pimoroni.com/products/icp10125-air-pressure-breakout
|
||||
* SCD41 CO2 Sensor (Carbon Dioxide / Temperature / Humidity) - https://shop.pimoroni.com/products/scd41-co2-sensor-breakout
|
||||
* VL53L5CX 8x8 Time of Flight Array Sensor - https://shop.pimoroni.com/products/vl53l5cx-time-of-flight-tof-sensor-breakout
|
||||
* RGB Encoder Wheel - https://shop.pimoroni.com/products/rgb-encoder-wheel-breakout
|
||||
|
||||
## Kits
|
||||
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
export TERM=${TERM:="xterm-256color"}
|
||||
|
||||
function log_success {
|
||||
echo -e "$(tput setaf 2)$1$(tput sgr0)"
|
||||
}
|
||||
|
||||
function log_inform {
|
||||
echo -e "$(tput setaf 6)$1$(tput sgr0)"
|
||||
}
|
||||
|
||||
function log_warning {
|
||||
echo -e "$(tput setaf 1)$1$(tput sgr0)"
|
||||
}
|
||||
|
||||
function micropython_clone {
|
||||
log_inform "Using MicroPython $MICROPYTHON_VERSION"
|
||||
git clone https://github.com/micropython/micropython
|
||||
cd micropython
|
||||
git checkout $MICROPYTHON_VERSION
|
||||
git cherry-pick -n 932f76c6ba64c5a3e68de3324556d9979f09303b
|
||||
git submodule update --init lib/pico-sdk
|
||||
git submodule update --init lib/cyw43-driver
|
||||
git submodule update --init lib/lwip
|
||||
git submodule update --init lib/mbedtls
|
||||
git submodule update --init lib/micropython-lib
|
||||
git submodule update --init lib/tinyusb
|
||||
git submodule update --init lib/btstack
|
||||
cd ../
|
||||
}
|
||||
|
||||
function micropython_build_mpy_cross {
|
||||
cd micropython/mpy-cross
|
||||
ccache --zero-stats || true
|
||||
CROSS_COMPILE="ccache " make
|
||||
ccache --show-stats || true
|
||||
cd ../../
|
||||
}
|
||||
|
||||
function apt_install_build_deps {
|
||||
sudo apt update && sudo apt install ccache
|
||||
}
|
||||
|
||||
function micropython_version {
|
||||
echo "MICROPY_GIT_TAG=$MICROPYTHON_VERSION, $BOARD_NAME $TAG_OR_SHA" >> $GITHUB_ENV
|
||||
echo "MICROPY_GIT_HASH=$MICROPYTHON_VERSION-$TAG_OR_SHA" >> $GITHUB_ENV
|
||||
}
|
||||
|
||||
function hack_patch_micropython_disable_exceptions {
|
||||
cd micropython
|
||||
git apply $PIMORONI_PICO_DIR/micropython/micropython_nano_specs.patch
|
||||
cd ../
|
||||
}
|
||||
|
||||
function hack_patch_pico_sdk {
|
||||
# pico-sdk-patch.sh will apply the patch if it exists
|
||||
cd micropython
|
||||
$PIMORONI_PICO_DIR/micropython/board/pico-sdk-patch.sh $MICROPY_BOARD
|
||||
cd ../
|
||||
}
|
||||
|
||||
function cmake_configure {
|
||||
cmake -S micropython/ports/rp2 -B build-$BOARD_NAME \
|
||||
-DPICO_BUILD_DOCS=0 \
|
||||
-DUSER_C_MODULES=$USER_C_MODULES \
|
||||
-DMICROPY_BOARD_DIR=$MICROPY_BOARD_DIR \
|
||||
-DMICROPY_BOARD=$MICROPY_BOARD \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache
|
||||
}
|
||||
|
||||
function cmake_build {
|
||||
ccache --zero-stats || true
|
||||
cmake --build build-$BOARD_NAME -j 2
|
||||
ccache --show-stats || true
|
||||
cd build-$BOARD_NAME
|
||||
cp firmware.uf2 $RELEASE_FILE.uf2
|
||||
}
|
Plik binarny nie jest wyświetlany.
|
@ -78,7 +78,7 @@ namespace pimoroni {
|
|||
return to_ms_since_boot(get_absolute_time());
|
||||
}
|
||||
|
||||
constexpr uint8_t GAMMA_8BIT[256] = {
|
||||
inline constexpr uint8_t GAMMA_8BIT[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
|
||||
2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5,
|
||||
|
@ -98,7 +98,7 @@ namespace pimoroni {
|
|||
|
||||
/* Moved from pico_unicorn.cpp
|
||||
v = (uint16_t)(powf((float)(n) / 255.0f, 2.2) * 16383.0f + 0.5f) */
|
||||
constexpr uint16_t GAMMA_14BIT[256] = {
|
||||
inline constexpr uint16_t GAMMA_14BIT[256] = {
|
||||
0, 0, 0, 1, 2, 3, 4, 6, 8, 10, 13, 16, 20, 23, 28, 32,
|
||||
37, 42, 48, 54, 61, 67, 75, 82, 90, 99, 108, 117, 127, 137, 148, 159,
|
||||
170, 182, 195, 207, 221, 234, 249, 263, 278, 294, 310, 326, 343, 361, 379, 397,
|
||||
|
|
|
@ -40,6 +40,15 @@ namespace pimoroni {
|
|||
i2c_write_blocking(i2c, address, buffer, 2, false);
|
||||
}
|
||||
|
||||
void I2C::reg_write_uint16(uint8_t address, uint8_t reg, uint16_t value) {
|
||||
uint8_t buffer[3] = {
|
||||
reg,
|
||||
(uint8_t)((value & 0xff00) >> 8),
|
||||
(uint8_t)(value & 0x00ff)
|
||||
};
|
||||
i2c_write_blocking(i2c, address, buffer, 3, false);
|
||||
}
|
||||
|
||||
uint8_t I2C::reg_read_uint8(uint8_t address, uint8_t reg) {
|
||||
uint8_t value;
|
||||
i2c_write_blocking(i2c, address, ®, 1, false);
|
||||
|
|
|
@ -63,6 +63,7 @@ namespace pimoroni {
|
|||
i2c_inst_t* pin_to_inst(uint pin);
|
||||
|
||||
void reg_write_uint8(uint8_t address, uint8_t reg, uint8_t value);
|
||||
void reg_write_uint16(uint8_t address, uint8_t reg, uint16_t value);
|
||||
uint8_t reg_read_uint8(uint8_t address, uint8_t reg);
|
||||
uint16_t reg_read_uint16(uint8_t address, uint8_t reg);
|
||||
int16_t reg_read_int16(uint8_t address, uint8_t reg);
|
||||
|
|
|
@ -16,6 +16,7 @@ add_subdirectory(is31fl3731)
|
|||
add_subdirectory(fatfs)
|
||||
add_subdirectory(sdcard)
|
||||
add_subdirectory(as7262)
|
||||
add_subdirectory(as7343)
|
||||
add_subdirectory(bh1745)
|
||||
add_subdirectory(bme68x)
|
||||
add_subdirectory(bmp280)
|
||||
|
@ -41,6 +42,6 @@ add_subdirectory(pms5003)
|
|||
add_subdirectory(sh1107)
|
||||
add_subdirectory(st7567)
|
||||
add_subdirectory(psram_display)
|
||||
add_subdirectory(inky73)
|
||||
add_subdirectory(shiftregister)
|
||||
add_subdirectory(mlx90640)
|
||||
add_subdirectory(inky73)
|
||||
add_subdirectory(mlx90640)
|
|
@ -11,7 +11,7 @@ namespace pimoroni {
|
|||
public:
|
||||
Analog(uint pin, float amplifier_gain = 1.0f, float resistor = 0.0f, float offset = 0.0f) :
|
||||
pin(pin), amplifier_gain(amplifier_gain), resistor(resistor), offset(offset) {
|
||||
adc_init();
|
||||
if (!(adc_hw->cs & ADC_CS_EN_BITS)) adc_init();
|
||||
|
||||
//Make sure GPIO is high-impedance, no pullups etc
|
||||
adc_gpio_init(pin);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(as7343.cmake)
|
|
@ -0,0 +1,10 @@
|
|||
set(DRIVER_NAME as7343)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
target_sources(${DRIVER_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${DRIVER_NAME}.cpp)
|
||||
|
||||
target_include_directories(${DRIVER_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${DRIVER_NAME} INTERFACE pico_stdlib hardware_i2c pimoroni_i2c)
|
|
@ -0,0 +1,160 @@
|
|||
#include <cstdlib>
|
||||
#include <math.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
|
||||
#include "as7343.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
bool AS7343::init() {
|
||||
if(interrupt != PIN_UNUSED) {
|
||||
gpio_set_function(interrupt, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(interrupt, GPIO_IN);
|
||||
gpio_pull_up(interrupt);
|
||||
}
|
||||
|
||||
uint8_t aux_id, revision_id, hardware_id;
|
||||
get_version(aux_id, revision_id, hardware_id);
|
||||
|
||||
if(hardware_id != HARDWARE_ID) {
|
||||
return false;
|
||||
}
|
||||
|
||||
reset();
|
||||
|
||||
bank_select(0);
|
||||
|
||||
// Enable all 7 channels in output FIFO
|
||||
i2c->set_bits(address, reg::FIFO_MAP, 0, FIFO_MAP_CH5 | FIFO_MAP_CH4 | FIFO_MAP_CH3 | FIFO_MAP_CH2 | FIFO_MAP_CH1 | FIFO_MAP_CH0 | FIFO_MAP_ASTATUS);
|
||||
|
||||
// Set the PON bit
|
||||
i2c->reg_write_uint8(address, reg::ENABLE, ENABLE_WEN | ENABLE_SMUXEN | ENABLE_SP_EN | ENABLE_PON);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void AS7343::reset() {
|
||||
i2c->reg_write_uint8(address, reg::CONTROL, CONTROL_SW_RESET);
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
i2c_inst_t* AS7343::get_i2c() const {
|
||||
return i2c->get_i2c();
|
||||
}
|
||||
|
||||
int AS7343::get_sda() const {
|
||||
return i2c->get_sda();
|
||||
}
|
||||
|
||||
int AS7343::get_scl() const {
|
||||
return i2c->get_scl();
|
||||
}
|
||||
|
||||
int AS7343::get_int() const {
|
||||
return interrupt;
|
||||
}
|
||||
|
||||
void AS7343::bank_select(uint8_t bank) {
|
||||
if(bank == 1) {
|
||||
i2c->set_bits(address, reg::CFG0, 0, CFG0_BANK);
|
||||
} else {
|
||||
i2c->clear_bits(address, reg::CFG0, 0, CFG0_BANK);
|
||||
}
|
||||
}
|
||||
|
||||
void AS7343::get_version(uint8_t &auxid, uint8_t &revid, uint8_t &hwid) {
|
||||
bank_select(1);
|
||||
auxid = i2c->reg_read_uint8(address, reg::AUXID) & 0b00001111;
|
||||
revid = i2c->reg_read_uint8(address, reg::REVID) & 0b00000111;
|
||||
hwid = i2c->reg_read_uint8(address, reg::ID);
|
||||
bank_select(0);
|
||||
}
|
||||
|
||||
void AS7343::set_gain(float gain) {
|
||||
if(gain == 0.5f) {
|
||||
i2c->reg_write_uint8(address, reg::CFG1, 0);
|
||||
} else {
|
||||
uint16_t ugain = (uint16_t)gain;
|
||||
uint16_t bitlength = 0;
|
||||
while(ugain > 0) {
|
||||
bitlength++;
|
||||
ugain >>= 1;
|
||||
}
|
||||
i2c->reg_write_uint8(address, reg::CFG1, bitlength & 0x1f);
|
||||
}
|
||||
}
|
||||
|
||||
void AS7343::set_channels(channel_count channel_count) {
|
||||
this->read_cycles = uint8_t(channel_count) / 6;
|
||||
this->ch_count = (uint8_t)channel_count;
|
||||
uint8_t temp = i2c->reg_read_uint8(address, reg::CFG20) & ~CFG20_18_CH;
|
||||
switch(channel_count) {
|
||||
case channel_count::SIX_CHANNEL:
|
||||
temp |= CFG20_6_CH;
|
||||
break;
|
||||
case channel_count::TWELVE_CHANNEL:
|
||||
temp |= CFG20_12_CH;
|
||||
break;
|
||||
case channel_count::EIGHTEEN_CHANNEL:
|
||||
temp |= CFG20_18_CH;
|
||||
break;
|
||||
}
|
||||
i2c->reg_write_uint8(address, reg::CFG20, temp);
|
||||
}
|
||||
|
||||
void AS7343::set_illumination_current(float current) {
|
||||
current -= 4;
|
||||
current /= 2.0f;
|
||||
uint8_t temp = i2c->reg_read_uint8(address, reg::LED) & 0b10000000;
|
||||
temp |= (uint8_t)current;
|
||||
i2c->reg_write_uint8(address, reg::LED, temp);
|
||||
}
|
||||
|
||||
void AS7343::set_illumination_led(bool state) {
|
||||
uint8_t temp = i2c->reg_read_uint8(address, reg::LED) & 0b01111111;
|
||||
temp |= state ? 0x80 : 0x00;
|
||||
i2c->reg_write_uint8(address, reg::LED, temp);
|
||||
}
|
||||
|
||||
void AS7343::set_measurement_time(float measurement_time_ms) {
|
||||
constexpr float resolution = 2.78f;
|
||||
i2c->reg_write_uint8(address, reg::WTIME, (uint8_t)((measurement_time_ms - resolution) / resolution));
|
||||
}
|
||||
|
||||
void AS7343::set_integration_time(float integration_time_us, uint8_t repeat) {
|
||||
constexpr float resolution = 2.78f;
|
||||
constexpr float max_astep = (65534 + 1) * resolution;
|
||||
|
||||
if (integration_time_us <= max_astep) {
|
||||
i2c->reg_write_uint8(address, reg::ATIME, repeat - 1);
|
||||
i2c->reg_write_uint16(address, reg::ASTEP, (uint16_t)((integration_time_us - resolution) / resolution) & 0xfffe);
|
||||
} else {
|
||||
// Time out of range...
|
||||
}
|
||||
}
|
||||
|
||||
void AS7343::read_fifo(uint16_t *buf) {
|
||||
uint16_t expected_results = read_cycles * 7;
|
||||
uint16_t result_slot = 0;
|
||||
|
||||
while (i2c->reg_read_uint8(address, reg::FIFO_LVL) < expected_results) {
|
||||
sleep_ms(1);
|
||||
}
|
||||
|
||||
while (i2c->reg_read_uint8(address, reg::FIFO_LVL) > 0 && expected_results > 0) {
|
||||
buf[result_slot] = i2c->reg_read_uint16(address, reg::FDATA);
|
||||
expected_results--;
|
||||
result_slot++;
|
||||
}
|
||||
}
|
||||
|
||||
AS7343::reading AS7343::read() {
|
||||
reading result;
|
||||
read_fifo((uint16_t *)&result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,139 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "hardware/i2c.h"
|
||||
#include "hardware/gpio.h"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
#include "common/pimoroni_i2c.hpp"
|
||||
#include "as7343_regs.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
|
||||
class AS7343 {
|
||||
//--------------------------------------------------
|
||||
// Constants
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
static const uint8_t DEFAULT_I2C_ADDRESS = 0x39;
|
||||
|
||||
//--------------------------------------------------
|
||||
// Enums
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
enum class channel_count : uint8_t {
|
||||
SIX_CHANNEL = 6,
|
||||
TWELVE_CHANNEL = 12,
|
||||
EIGHTEEN_CHANNEL = 18
|
||||
};
|
||||
/*
|
||||
enum class COMPENSATION_GAIN : float {
|
||||
F1 = 1.84f,
|
||||
F2 = 6.03f,
|
||||
FZ = 4.88f,
|
||||
F3 = 13.74f,
|
||||
F4 = 3.37f,
|
||||
FY = 2.82f,
|
||||
F5 = 6.72f,
|
||||
FXL = 2.22f,
|
||||
F6 = 3.17f,
|
||||
F7 = 1.95f,
|
||||
F8 = 12.25f,
|
||||
NIR = 1.00f,
|
||||
};
|
||||
*/
|
||||
|
||||
//--------------------------------------------------
|
||||
// Substructures
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
struct reading {
|
||||
// Cycle 1
|
||||
uint16_t FZ = 0; // 428-480 nm
|
||||
uint16_t FY = 0; // 534-593 nm
|
||||
uint16_t FXL = 0; // 593-628 nm
|
||||
uint16_t NIR = 0; // 849-903 nm
|
||||
|
||||
uint16_t c1_vis_tl = 0; // Visible top-left
|
||||
uint16_t c1_vis_br = 0; // Visible bottom-right
|
||||
uint16_t c1_astatus = 0; // (c1_astatus >> 8) & 0b10001111
|
||||
// 0b10000000 = saturated
|
||||
// 0b00001111 = gain lowest nibble
|
||||
|
||||
// Cycle 2
|
||||
uint16_t F2 = 0; // 408-448 nm
|
||||
uint16_t F3 = 0; // 448-500 mn
|
||||
uint16_t F4 = 0; // 500-534 nm
|
||||
uint16_t F6 = 0; // 618-665 nm
|
||||
|
||||
uint16_t c2_vis_tl = 0;
|
||||
uint16_t c2_vis_br = 0;
|
||||
uint16_t c2_astatus = 0;
|
||||
|
||||
// Cycle 3
|
||||
uint16_t F1 = 0; // 396-408 nm
|
||||
uint16_t F5 = 0; // 531-594 nm
|
||||
uint16_t F7 = 0; // 685-715 nm
|
||||
uint16_t F8 = 0; // 715-766 nm
|
||||
|
||||
uint16_t c3_vis_tl = 0;
|
||||
uint16_t c3_vis_br = 0;
|
||||
uint16_t c3_astatus = 0;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
I2C *i2c;
|
||||
|
||||
// interface pins with our standard defaults where appropriate
|
||||
int8_t address = DEFAULT_I2C_ADDRESS;
|
||||
uint interrupt = PIN_UNUSED;
|
||||
|
||||
uint8_t read_cycles = 1;
|
||||
uint8_t ch_count = (uint8_t)channel_count::SIX_CHANNEL;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constructors/Destructor
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
AS7343(uint interrupt = PIN_UNUSED) : AS7343(new I2C(), interrupt) {};
|
||||
|
||||
AS7343(I2C *i2c, uint interrupt = PIN_UNUSED) : i2c(i2c), interrupt(interrupt) {}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
bool init();
|
||||
void reset();
|
||||
|
||||
// For print access in micropython
|
||||
i2c_inst_t* get_i2c() const;
|
||||
int get_sda() const;
|
||||
int get_scl() const;
|
||||
int get_int() const;
|
||||
|
||||
void get_version(uint8_t &auxid, uint8_t &revid, uint8_t &hwid);
|
||||
|
||||
reading read();
|
||||
|
||||
void read_fifo(uint16_t *buf);
|
||||
|
||||
void set_gain(float gain);
|
||||
void set_illumination_current(float current);
|
||||
void set_illumination_led(bool state);
|
||||
void set_measurement_time(float measurement_time_ms);
|
||||
void set_integration_time(float integration_time_us, uint8_t repeat=1);
|
||||
|
||||
void set_channels(channel_count channel_count);
|
||||
|
||||
private:
|
||||
void bank_select(uint8_t bank=0);
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace pimoroni {
|
||||
/***** Device registers and masks here *****/
|
||||
|
||||
enum reg {
|
||||
// Bank 1
|
||||
AUXID = 0x58, // AUXID = 0b00001111
|
||||
REVID = 0x59, // REVID = 0b00000111
|
||||
ID = 0x5A, // ID = 0b11111111
|
||||
CFG12 = 0x66, // SP_TH_CH = 0b00000111
|
||||
|
||||
// Bank 0
|
||||
ENABLE = 0x80, // FDEN = 0b01000000
|
||||
// SMUXEN = 0b00010000
|
||||
// WEN = 0b00001000
|
||||
// SP_EN = 0b00000010
|
||||
// PON = 0b00000001
|
||||
ATIME = 0x81, // ATIME = 0b11111111
|
||||
// Integration Time Step Size
|
||||
// 0 = 2.87us
|
||||
// n 2.87us x (n + 1)
|
||||
ASTEP = 0xD4, // STEP = 0xFFFF
|
||||
// Spectral Measurement Wait Time
|
||||
// 0 = 1 cycle = 2.78ms
|
||||
// n = 2.78ms x (n + 1)
|
||||
WTIME = 0x83, // WTIME = 0b11111111
|
||||
SP_TH = 0x84, // SP_TH_L = 0xFFFF0000 Spectral Low Threshold
|
||||
// SP_TH_H = 0x0000FFFF Spectral High Threshold
|
||||
STATUS = 0x93, // ASAT = 0b10000000 Spectral Saturation (if ASIEN set)
|
||||
// AINT = 0b00001000 Spectral Channel Interrupt (if SP_IEN set)
|
||||
// FINT = 0b00000100 FIFO Buffer Interrupt
|
||||
// SINT = 0b00000001 System Interrupt
|
||||
ASTATUS = 0x94,// ASAT = 0b10000000 Saturation Status
|
||||
// AGAIN = 0b00000111 Gain Status
|
||||
DATA = 0x95, // 36 bytes, fields 0 to 17 (2 bytes eac)
|
||||
STATUS2 = 0x90,// AVALID = 0b01000000 Spectral Data Valid
|
||||
// ASAT_DIG = 0b00010000 Digital Saturation
|
||||
// ASAT_ANA = 0b00001000 Analog Saturation
|
||||
// FDSAT_ANA= 0b00000010 Flicker Analog Saturation
|
||||
// FDSAT_DIG= 0b00000001 Flicker Digital Saturation
|
||||
STATUS3 = 0x91,// INT_SP_H = 0b00100000 Spectral Above High Threshold
|
||||
// INT_SP_L = 0b00010000 Spectral Below Low Threshold
|
||||
STATUS5 = 0xBB,// SINT_FD = 0b00001000 Flicker Detect Interrupt (if SIEN_FD set)
|
||||
// SINT_SMUX= 0b00000100 SMUS Operation Interrupt (SMUX exec finished)
|
||||
STATUS4 = 0xBC,// FIFO_OV = 0b10000000 FIFO Buffer Overflow
|
||||
// OVTEMP = 0b00100000 Over Temperature
|
||||
// FD_TRIG = 0b00010000 Flicker Detect Trigger Error
|
||||
// SD_TRIG = 0b00000100 Spectral Trigger Error
|
||||
// SAI_ACT = 0b00000010 Sleep After Interrupt Active
|
||||
// INT_BUSY = 0b00000001 Initialization busy (1 for ~300us after power on)
|
||||
CFG0 = 0xBF, // LOW_POWER= 0b00100000
|
||||
// REG_BANK = 0b00010000 0 - Register 0x80 and above
|
||||
// 1 - Register 0x20 to 0x7f
|
||||
// WLONG = 0b00000100 Increase WTIME by factor of 16
|
||||
// Spectral Engines Gain Setting
|
||||
// 0 = 0.5x, # 1 = 1x, 2 = 2x, 12 = 2048x
|
||||
// GAINx = 1 << (n - 1)
|
||||
CFG1 = 0xC6,
|
||||
CFG3 = 0xC7, // SAI = 0b00100000 Sleep after interrupt
|
||||
CFG6 = 0xF5, // SMUS_CMD = 0b00011000 0 - ROM_init
|
||||
// 1 - Read_SMUX
|
||||
// 2 - Write_SMUX
|
||||
CFG8 = 0xC9, // FIFO_TH = 0b11000000 0b00, 0b01, 0b10, 0b11
|
||||
CFG9 = 0xCA, // SIEN_FD = 0b01000000 System Interrupt Flicker Detection
|
||||
// SIEN_SMUX= 0b00010000 System Interrupt SMUX Operation
|
||||
CFG10 = 0x65, // FD_PERS = 0b00000111 Flicker Detect Persistence
|
||||
// Number of results that must differ before status change
|
||||
PERS = 0xCF, // APERS = 0b00001111
|
||||
GPIO = 0x6B, // GPIO_INV = 0b00001000 Invert GPIO output
|
||||
// GPIO_IN_EN=0b00000100 Enable GPIO input
|
||||
// GPIO_OUT = 0b00000010 GPIO Output
|
||||
// GPIO_IN = 0b00000001 GPIO Input
|
||||
CFG20 = 0xD6, // FD_FIFO_8b=0b10000000 Enable 8bit FIFO mode for Flicker Detect (FD_TIME < 256)
|
||||
// auto_SMUX= 0b01100000 Auto channel read-out
|
||||
LED = 0xCD, // LED_ACT = 0b10000000 External LED (LDR) Control
|
||||
// LED_DRIVE= 0b01111111 External LED drive strength (N - 4) >> 1
|
||||
// Flicker Detection AGC Gain Max
|
||||
// Max = 2^N (0 = 0.5x)
|
||||
AGC_GAIN_MAX = 0xD7, // ADC_FD_GAIN_MAX = 0b11110000
|
||||
AZ_CONFIG = 0xDE, // AT_NTH_ITERATION = 0b11111111 Auto-zero Frequency
|
||||
// 0 - Never (Not Recommended)
|
||||
// n - Every n integration cycles
|
||||
// 255 - only before first measurement cycle
|
||||
FD_TIME_1 = 0xE0, // FD_TIME=0b11111111 Flicker Detection Integration Time (Do not change if FDEN = 1 & PON = 1)
|
||||
FD_TIME_2 = 0xE2, // FD_GAIN=0b11111000 Flicker Detection Gain (0 = 0.5x, 1 = 1x, 2 = 2x, 12 = 2048x)
|
||||
// FD_TIME=0b00000111 Flicker Detection Time (Do not change if FDEN = 1 & PON = 1)
|
||||
FD_CFG0 = 0xDF, // FIFO_WRITE_FD = 0b10000000 Write flicker raw data to FIFO (1 byte per sample)
|
||||
FD_STATUS = 0xE3, // FD_VALID=0b00100000
|
||||
// FD_SAT = 0b00010000
|
||||
// FD_120HZ_VALID = 0b00001000
|
||||
// FD_100HZ_VALID = 0b00000100
|
||||
// FD_120HZ = 0b00000010
|
||||
// FD_100HZ = 0b00000001
|
||||
INTERNAB = 0xF9, // ASIEN = 0b10000000 Saturation Interrupt Enable
|
||||
// SP_IEN = 0b00001000 Spectral Interrupt Enable
|
||||
// FIEN = 0b00000100 FIFO Buffer Interrupt Enable
|
||||
// SIEN = 0b00000001 System Interrupt Enable
|
||||
CONTROL = 0xFA, // SW_RESET = 0b00001000 Software Reset
|
||||
// SP_MAN_AZ= 0b00000100 Spectral Manual Auto-zero
|
||||
// FIFO_CLR = 0b00000010 FIFO Buffer Clear
|
||||
// CLEAR_SAI_ACT = 0b00000001 Clear sleep-after-interrupt
|
||||
FIFO_MAP = 0xFC, // CH5 = 0b01000000
|
||||
// CH4 = 0b00100000
|
||||
// CH3 = 0b00010000
|
||||
// CH2 = 0b00001000
|
||||
// CH1 = 0b00000100
|
||||
// CH0 = 0b00000010
|
||||
// ASTATUS = 0b00000001
|
||||
FIFO_LVL = 0xFD,
|
||||
FDATA = 0xFE // 0xFFFF
|
||||
};
|
||||
|
||||
constexpr uint8_t HARDWARE_ID = 0b10000001;
|
||||
|
||||
constexpr uint8_t CFG0_LOW_POWER = 0b00100000;
|
||||
constexpr uint8_t CFG0_BANK = 0b00010000;
|
||||
constexpr uint8_t CFG0_WLONG = 0b00000100;
|
||||
|
||||
constexpr uint8_t CFG20_6_CH = 0b00000000;
|
||||
constexpr uint8_t CFG20_12_CH = 0b01000000;
|
||||
constexpr uint8_t CFG20_18_CH = 0b01100000;
|
||||
|
||||
constexpr uint8_t ENABLE_FDEN = 0b01000000;
|
||||
constexpr uint8_t ENABLE_SMUXEN = 0b00010000;
|
||||
constexpr uint8_t ENABLE_WEN = 0b00001000;
|
||||
constexpr uint8_t ENABLE_SP_EN = 0b00000010;
|
||||
constexpr uint8_t ENABLE_PON = 0b00000001;
|
||||
|
||||
constexpr uint8_t FD_CFG0_FIFO_WRITE = 0b10000000;
|
||||
|
||||
constexpr uint8_t FD_VALID = 0b00100000;
|
||||
constexpr uint8_t FD_SAT = 0b00010000;
|
||||
constexpr uint8_t FD_120HZ_VALID = 0b00001000;
|
||||
constexpr uint8_t FD_100HZ_VALID = 0b00000100;
|
||||
constexpr uint8_t FD_120HZ = 0b00000010;
|
||||
constexpr uint8_t FD_100HZ = 0b00000001;
|
||||
|
||||
constexpr uint8_t INTERNAB_ASIEN = 0b10000000;
|
||||
constexpr uint8_t INTERNAB_SP_IEN = 0b00001000;
|
||||
constexpr uint8_t INTERNAB_FIEN = 0b00000100;
|
||||
constexpr uint8_t INTERNAB_SIEN = 0b00000001;
|
||||
|
||||
constexpr uint8_t CONTROL_SW_RESET = 0b00001000;
|
||||
constexpr uint8_t CONTROL_SP_MAN_AZ = 0b00000100;
|
||||
constexpr uint8_t CONTROL_FIFO_CLR = 0b00000010;
|
||||
constexpr uint8_t CONTROL_CLEAR_SAI_ACT = 0b00000001;
|
||||
|
||||
constexpr uint8_t FIFO_MAP_CH5 = 0b01000000;
|
||||
constexpr uint8_t FIFO_MAP_CH4 = 0b00100000;
|
||||
constexpr uint8_t FIFO_MAP_CH3 = 0b00010000;
|
||||
constexpr uint8_t FIFO_MAP_CH2 = 0b00001000;
|
||||
constexpr uint8_t FIFO_MAP_CH1 = 0b00000100;
|
||||
constexpr uint8_t FIFO_MAP_CH0 = 0b00000010;
|
||||
constexpr uint8_t FIFO_MAP_ASTATUS = 0b00000001;
|
||||
}
|
|
@ -4,7 +4,10 @@
|
|||
#include "hardware/irq.h"
|
||||
#include "hardware/clocks.h"
|
||||
#include "encoder.hpp"
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "encoder.pio.h"
|
||||
#endif
|
||||
|
||||
#define LAST_STATE(state) ((state) & 0b0011)
|
||||
#define CURR_STATE(state) (((state) & 0b1100) >> 2)
|
||||
|
|
|
@ -113,12 +113,6 @@ void Hub75::FM6126A_setup() {
|
|||
|
||||
void Hub75::start(irq_handler_t handler) {
|
||||
if(handler) {
|
||||
dma_channel = 0;
|
||||
|
||||
// Try as I might, I can't seem to coax MicroPython into leaving PIO in a known state upon soft reset
|
||||
// check for claimed PIO and prepare a clean slate.
|
||||
stop(handler);
|
||||
|
||||
if (panel_type == PANEL_FM6126A) {
|
||||
FM6126A_setup();
|
||||
}
|
||||
|
@ -139,7 +133,7 @@ void Hub75::start(irq_handler_t handler) {
|
|||
// Prevent flicker in Python caused by the smaller dataset just blasting through the PIO too quickly
|
||||
pio_sm_set_clkdiv(pio, sm_data, width <= 32 ? 2.0f : 1.0f);
|
||||
|
||||
dma_channel_claim(dma_channel);
|
||||
dma_channel = dma_claim_unused_channel(true);
|
||||
dma_channel_config config = dma_channel_get_default_config(dma_channel);
|
||||
channel_config_set_transfer_data_size(&config, DMA_SIZE_32);
|
||||
channel_config_set_bswap(&config, false);
|
||||
|
@ -148,15 +142,13 @@ void Hub75::start(irq_handler_t handler) {
|
|||
|
||||
|
||||
// Same handler for both DMA channels
|
||||
irq_set_exclusive_handler(DMA_IRQ_0, handler);
|
||||
irq_set_exclusive_handler(DMA_IRQ_1, handler);
|
||||
irq_add_shared_handler(DMA_IRQ_0, handler, PICO_SHARED_IRQ_HANDLER_DEFAULT_ORDER_PRIORITY);
|
||||
|
||||
dma_channel_set_irq0_enabled(dma_channel, true);
|
||||
|
||||
irq_set_enabled(pio_get_dreq(pio, sm_data, true), true);
|
||||
irq_set_enabled(DMA_IRQ_0, true);
|
||||
|
||||
|
||||
row = 0;
|
||||
bit = 0;
|
||||
|
||||
|
@ -169,10 +161,9 @@ void Hub75::start(irq_handler_t handler) {
|
|||
void Hub75::stop(irq_handler_t handler) {
|
||||
|
||||
irq_set_enabled(DMA_IRQ_0, false);
|
||||
irq_set_enabled(DMA_IRQ_1, false);
|
||||
irq_set_enabled(pio_get_dreq(pio, sm_data, true), false);
|
||||
|
||||
if(dma_channel_is_claimed(dma_channel)) {
|
||||
if(dma_channel != -1 && dma_channel_is_claimed(dma_channel)) {
|
||||
dma_channel_set_irq0_enabled(dma_channel, false);
|
||||
irq_remove_handler(DMA_IRQ_0, handler);
|
||||
//dma_channel_wait_for_finish_blocking(dma_channel);
|
||||
|
@ -184,17 +175,21 @@ void Hub75::stop(irq_handler_t handler) {
|
|||
if(pio_sm_is_claimed(pio, sm_data)) {
|
||||
pio_sm_set_enabled(pio, sm_data, false);
|
||||
pio_sm_drain_tx_fifo(pio, sm_data);
|
||||
pio_remove_program(pio, &hub75_data_rgb888_program, data_prog_offs);
|
||||
pio_sm_unclaim(pio, sm_data);
|
||||
}
|
||||
|
||||
if(pio_sm_is_claimed(pio, sm_row)) {
|
||||
pio_sm_set_enabled(pio, sm_row, false);
|
||||
pio_sm_drain_tx_fifo(pio, sm_row);
|
||||
if (inverted_stb) {
|
||||
pio_remove_program(pio, &hub75_row_inverted_program, row_prog_offs);
|
||||
} else {
|
||||
pio_remove_program(pio, &hub75_row_program, row_prog_offs);
|
||||
}
|
||||
pio_sm_unclaim(pio, sm_row);
|
||||
}
|
||||
|
||||
pio_clear_instruction_memory(pio);
|
||||
|
||||
// Make sure the GPIO is in a known good state
|
||||
// since we don't know what the PIO might have done with it
|
||||
gpio_put_masked(0b111111 << pin_r0, 0);
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "hub75.pio.h"
|
||||
#endif
|
||||
|
||||
namespace pimoroni {
|
||||
const uint DATA_BASE_PIN = 0;
|
||||
|
@ -70,7 +73,7 @@ class Hub75 {
|
|||
Pixel background = 0;
|
||||
|
||||
// DMA & PIO
|
||||
uint dma_channel = 0;
|
||||
int dma_channel = -1;
|
||||
uint bit = 0;
|
||||
uint row = 0;
|
||||
|
||||
|
|
|
@ -4,7 +4,10 @@
|
|||
#include "hardware/pio.h"
|
||||
#include "hardware/dma.h"
|
||||
#include "hardware/irq.h"
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "hub75.pio.h"
|
||||
#endif
|
||||
|
||||
const uint DATA_BASE_PIN = 0;
|
||||
const uint DATA_N_PINS = 6;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET shiftregister)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../shiftregister/shiftregister.cmake)
|
||||
endif()
|
||||
|
||||
set(DRIVER_NAME inky73)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -47,8 +47,9 @@ namespace pimoroni {
|
|||
return !(sr.read() & 128);
|
||||
}
|
||||
|
||||
void Inky73::busy_wait() {
|
||||
while(is_busy()) {
|
||||
void Inky73::busy_wait(uint timeout_ms) {
|
||||
absolute_time_t timeout = make_timeout_time_ms(timeout_ms);
|
||||
while(is_busy() && !time_reached(timeout)) {
|
||||
tight_loop_contents();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace pimoroni {
|
|||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
void busy_wait();
|
||||
void busy_wait(uint timeout_ms=45000);
|
||||
void reset();
|
||||
void power_off();
|
||||
|
||||
|
|
|
@ -320,8 +320,21 @@ namespace pimoroni {
|
|||
Pin::adc(1, 7, 0)}
|
||||
{}
|
||||
|
||||
bool IOExpander::init(bool skipChipIdCheck) {
|
||||
bool succeeded = true;
|
||||
bool IOExpander::init(bool skipChipIdCheck, bool perform_reset) {
|
||||
if(!skipChipIdCheck) {
|
||||
uint16_t chip_id = get_chip_id();
|
||||
if(chip_id != CHIP_ID) {
|
||||
if(debug) {
|
||||
printf("Chip ID invalid: %04x expected: %04x\n", chip_id, CHIP_ID);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the chip if requested, to put it into a known state
|
||||
if(perform_reset && !reset()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if(interrupt != PIN_UNUSED) {
|
||||
gpio_set_function(interrupt, GPIO_FUNC_SIO);
|
||||
|
@ -331,17 +344,36 @@ namespace pimoroni {
|
|||
enable_interrupt_out(true);
|
||||
}
|
||||
|
||||
if(!skipChipIdCheck) {
|
||||
uint16_t chip_id = get_chip_id();
|
||||
if(chip_id != CHIP_ID) {
|
||||
if(debug) {
|
||||
printf("Chip ID invalid: %04x expected: %04x\n", chip_id, CHIP_ID);
|
||||
}
|
||||
succeeded = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t IOExpander::check_reset() {
|
||||
uint8_t user_flash_reg = reg::USER_FLASH;
|
||||
uint8_t value;
|
||||
if(i2c_write_blocking(i2c->get_i2c(), address, &user_flash_reg, 1, false) == PICO_ERROR_GENERIC) {
|
||||
return 0x00;
|
||||
}
|
||||
if(i2c_read_blocking(i2c->get_i2c(), address, (uint8_t *)&value, sizeof(uint8_t), false) == PICO_ERROR_GENERIC) {
|
||||
return 0x00;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
bool IOExpander::reset() {
|
||||
uint32_t start_time = millis();
|
||||
set_bits(reg::CTRL, ctrl_mask::RESET);
|
||||
// Wait for a register to read its initialised value
|
||||
while(check_reset() != 0x78) {
|
||||
sleep_ms(1);
|
||||
if(millis() - start_time >= RESET_TIMEOUT_MS) {
|
||||
if(debug)
|
||||
printf("Timed out waiting for Reset!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return succeeded;
|
||||
return true;
|
||||
}
|
||||
|
||||
i2c_inst_t* IOExpander::get_i2c() const {
|
||||
|
@ -370,7 +402,7 @@ namespace pimoroni {
|
|||
|
||||
void IOExpander::set_address(uint8_t address) {
|
||||
set_bit(reg::CTRL, 4);
|
||||
i2c->reg_write_uint8(address, reg::ADDR, address);
|
||||
i2c->reg_write_uint8(this->address, reg::ADDR, address);
|
||||
this->address = address;
|
||||
sleep_ms(250); //TODO Handle addr change IOError better
|
||||
//wait_for_flash()
|
||||
|
@ -491,13 +523,35 @@ namespace pimoroni {
|
|||
return divider_good;
|
||||
}
|
||||
|
||||
void IOExpander::set_pwm_period(uint16_t value, bool load) {
|
||||
void IOExpander::set_pwm_period(uint16_t value, bool load, bool wait_for_load) {
|
||||
value &= 0xffff;
|
||||
i2c->reg_write_uint8(address, reg::PWMPL, (uint8_t)(value & 0xff));
|
||||
i2c->reg_write_uint8(address, reg::PWMPH, (uint8_t)(value >> 8));
|
||||
|
||||
if(load)
|
||||
pwm_load();
|
||||
pwm_load(wait_for_load);
|
||||
}
|
||||
|
||||
uint16_t IOExpander::set_pwm_frequency(float frequency, bool load, bool wait_for_load) {
|
||||
uint32_t period = (uint32_t)(CLOCK_FREQ / frequency);
|
||||
if (period / 128 > MAX_PERIOD) {
|
||||
return MAX_PERIOD;
|
||||
}
|
||||
if (period < 2) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
uint8_t divider = 1;
|
||||
while ((period > MAX_PERIOD) && (divider < MAX_DIVIDER)) {
|
||||
period >>= 1;
|
||||
divider <<= 1;
|
||||
}
|
||||
|
||||
period = MIN(period, MAX_PERIOD); // Should be unnecessary because of earlier raised errors, but kept in case
|
||||
set_pwm_control(divider);
|
||||
set_pwm_period((uint16_t)(period - 1), load, wait_for_load);
|
||||
|
||||
return (uint16_t)period;
|
||||
}
|
||||
|
||||
uint8_t IOExpander::get_mode(uint8_t pin) {
|
||||
|
@ -669,7 +723,7 @@ namespace pimoroni {
|
|||
}
|
||||
}
|
||||
|
||||
void IOExpander::output(uint8_t pin, uint16_t value, bool load) {
|
||||
void IOExpander::output(uint8_t pin, uint16_t value, bool load, bool wait_for_load) {
|
||||
if(pin < 1 || pin > NUM_PINS) {
|
||||
printf("Pin should be in range 1-14.");
|
||||
return;
|
||||
|
@ -685,7 +739,7 @@ namespace pimoroni {
|
|||
i2c->reg_write_uint8(address, io_pin.reg_pwml, (uint8_t)(value & 0xff));
|
||||
i2c->reg_write_uint8(address, io_pin.reg_pwmh, (uint8_t)(value >> 8));
|
||||
if(load)
|
||||
pwm_load();
|
||||
pwm_load(wait_for_load);
|
||||
}
|
||||
else {
|
||||
if(value == LOW) {
|
||||
|
|
|
@ -26,6 +26,8 @@ namespace pimoroni {
|
|||
static const uint8_t PIN_MODE_PWM = 0b00101; // PWM, Output, Push-Pull mode
|
||||
static const uint8_t PIN_MODE_ADC = 0b01010; // ADC, Input-only (high-impedance)
|
||||
|
||||
static const uint32_t RESET_TIMEOUT_MS = 1000;
|
||||
|
||||
public:
|
||||
static const uint8_t DEFAULT_I2C_ADDRESS = 0x18;
|
||||
|
||||
|
@ -45,6 +47,10 @@ namespace pimoroni {
|
|||
static const uint16_t LOW = 0;
|
||||
static const uint16_t HIGH = 1;
|
||||
|
||||
static const uint32_t CLOCK_FREQ = 24000000;
|
||||
static const uint32_t MAX_PERIOD = (1 << 16) - 1;
|
||||
static const uint32_t MAX_DIVIDER = (1 << 7);
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Subclasses
|
||||
|
@ -171,7 +177,12 @@ namespace pimoroni {
|
|||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
bool init(bool skip_chip_id_check = false);
|
||||
bool init(bool skip_chip_id_check = false, bool perform_reset = false);
|
||||
|
||||
private:
|
||||
uint8_t check_reset();
|
||||
public:
|
||||
bool reset();
|
||||
|
||||
// For print access in micropython
|
||||
i2c_inst_t* get_i2c() const;
|
||||
|
@ -198,7 +209,8 @@ namespace pimoroni {
|
|||
void pwm_clear(bool wait_for_clear = true);
|
||||
bool pwm_clearing();
|
||||
bool set_pwm_control(uint8_t divider);
|
||||
void set_pwm_period(uint16_t value, bool load = true);
|
||||
void set_pwm_period(uint16_t value, bool load = true, bool wait_for_load = true);
|
||||
uint16_t set_pwm_frequency(float frequency, bool load = true, bool wait_for_load = true);
|
||||
|
||||
uint8_t get_mode(uint8_t pin);
|
||||
void set_mode(uint8_t pin, uint8_t mode, bool schmitt_trigger = false, bool invert = false);
|
||||
|
@ -206,7 +218,7 @@ namespace pimoroni {
|
|||
int16_t input(uint8_t pin, uint32_t adc_timeout = 1);
|
||||
float input_as_voltage(uint8_t pin, uint32_t adc_timeout = 1);
|
||||
|
||||
void output(uint8_t pin, uint16_t value, bool load = true);
|
||||
void output(uint8_t pin, uint16_t value, bool load = true, bool wait_for_load = true);
|
||||
|
||||
void setup_rotary_encoder(uint8_t channel, uint8_t pin_a, uint8_t pin_b, uint8_t pin_c = 0, bool count_microsteps = false);
|
||||
int16_t read_rotary_encoder(uint8_t channel);
|
||||
|
|
|
@ -64,8 +64,8 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void LTP305::set_character(uint8_t x, uint16_t ch) {
|
||||
uint8_t *data = nullptr;
|
||||
for(auto c : dotfont) {
|
||||
const uint8_t *data = nullptr;
|
||||
for(const auto& c : dotfont) {
|
||||
if(c.code == ch) {
|
||||
data = &c.data[0];
|
||||
break;
|
||||
|
@ -128,4 +128,4 @@ namespace pimoroni {
|
|||
i2c->reg_write_uint8(address, CMD_BRIGHTNESS, brightness);
|
||||
i2c->reg_write_uint8(address, CMD_UPDATE, 0x01);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET pwm)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../pwm/pwm.cmake)
|
||||
endif()
|
||||
|
||||
set(DRIVER_NAME motor)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET pwm_cluster)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../pwm/pwm_cluster.cmake)
|
||||
endif()
|
||||
|
||||
set(DRIVER_NAME motor_cluster)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -14,7 +14,9 @@ found here: https://github.com/raspberrypi/pico-examples/tree/master/pio/apa102
|
|||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "apa102.pio.h"
|
||||
#endif
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pio.h"
|
||||
|
|
|
@ -14,7 +14,9 @@ found here: https://github.com/raspberrypi/pico-examples/tree/master/pio/ws2812
|
|||
#include <math.h>
|
||||
#include <cstdint>
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "ws2812.pio.h"
|
||||
#endif
|
||||
|
||||
#include "pico/stdlib.h"
|
||||
#include "hardware/pio.h"
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
#include "pwm_cluster.hpp"
|
||||
#include "hardware/gpio.h"
|
||||
#include "hardware/clocks.h"
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "pwm_cluster.pio.h"
|
||||
#endif
|
||||
|
||||
// Uncomment the below line to enable debugging
|
||||
//#define DEBUG_MULTI_PWM
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
#define _PIO_SPI_H
|
||||
|
||||
#include "hardware/pio.h"
|
||||
#ifndef NO_QSTR
|
||||
#include "spi.pio.h"
|
||||
#endif
|
||||
|
||||
typedef struct pio_spi_inst {
|
||||
PIO pio;
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET pwm)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../pwm/pwm.cmake)
|
||||
endif()
|
||||
|
||||
set(DRIVER_NAME servo)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET pwm_cluster)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../pwm/pwm_cluster.cmake)
|
||||
endif()
|
||||
|
||||
set(DRIVER_NAME servo_cluster)
|
||||
add_library(${DRIVER_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -89,11 +89,19 @@ namespace pimoroni {
|
|||
if(width == 320 && height == 240) {
|
||||
command(reg::GCTRL, 1, "\x35");
|
||||
command(reg::VCOMS, 1, "\x1f");
|
||||
command(0xd6, 1, "\xa1"); // ???
|
||||
command(reg::GMCTRP1, 14, "\xD0\x08\x11\x08\x0C\x15\x39\x33\x50\x36\x13\x14\x29\x2D");
|
||||
command(reg::GMCTRN1, 14, "\xD0\x08\x10\x08\x06\x06\x39\x44\x51\x0B\x16\x14\x2F\x31");
|
||||
}
|
||||
|
||||
if(width == 240 && height == 135) { // Pico Display Pack (1.14" 240x135)
|
||||
command(reg::VRHS, 1, "\x00"); // VRH Voltage setting
|
||||
command(reg::GCTRL, 1, "\x75"); // VGH and VGL voltages
|
||||
command(reg::VCOMS, 1, "\x3D"); // VCOM voltage
|
||||
command(0xd6, 1, "\xa1"); // ???
|
||||
command(reg::GMCTRP1, 14, "\x70\x04\x08\x09\x09\x05\x2A\x33\x41\x07\x13\x13\x29\x2f");
|
||||
command(reg::GMCTRN1, 14, "\x70\x03\x09\x0A\x09\x06\x2B\x34\x41\x07\x12\x14\x28\x2E");
|
||||
}
|
||||
|
||||
command(reg::INVON); // set inversion mode
|
||||
command(reg::SLPOUT); // leave sleep mode
|
||||
command(reg::DISPON); // turn display on
|
||||
|
@ -125,8 +133,6 @@ namespace pimoroni {
|
|||
|
||||
void ST7789::configure_display(Rotation rotate) {
|
||||
|
||||
bool rotate180 = rotate == ROTATE_180 || rotate == ROTATE_90;
|
||||
|
||||
if(rotate == ROTATE_90 || rotate == ROTATE_270) {
|
||||
std::swap(width, height);
|
||||
}
|
||||
|
@ -177,20 +183,30 @@ namespace pimoroni {
|
|||
// Pico Display
|
||||
if(width == 240 && height == 135) {
|
||||
caset[0] = 40; // 240 cols
|
||||
caset[1] = 279;
|
||||
raset[0] = 53; // 135 rows
|
||||
raset[1] = 187;
|
||||
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
caset[1] = 40 + width - 1;
|
||||
raset[0] = 52; // 135 rows
|
||||
raset[1] = 52 + height - 1;
|
||||
if (rotate == ROTATE_0) {
|
||||
raset[0] += 1;
|
||||
raset[1] += 1;
|
||||
}
|
||||
madctl = rotate == ROTATE_180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
|
||||
}
|
||||
|
||||
// Pico Display at 90 degree rotation
|
||||
if(width == 135 && height == 240) {
|
||||
caset[0] = 52; // 135 cols
|
||||
caset[1] = 186;
|
||||
caset[1] = 52 + width - 1;
|
||||
raset[0] = 40; // 240 rows
|
||||
raset[1] = 279;
|
||||
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
raset[1] = 40 + height - 1;
|
||||
madctl = 0;
|
||||
if (rotate == ROTATE_90) {
|
||||
caset[0] += 1;
|
||||
caset[1] += 1;
|
||||
madctl = MADCTL::COL_ORDER | MADCTL::ROW_ORDER;
|
||||
}
|
||||
madctl = rotate == ROTATE_90 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
}
|
||||
|
||||
// Pico Display 2.0
|
||||
|
@ -199,7 +215,7 @@ namespace pimoroni {
|
|||
caset[1] = 319;
|
||||
raset[0] = 0;
|
||||
raset[1] = 239;
|
||||
madctl = rotate180 ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
madctl = (rotate == ROTATE_180 || rotate == ROTATE_90) ? MADCTL::ROW_ORDER : MADCTL::COL_ORDER;
|
||||
madctl |= MADCTL::SWAP_XY | MADCTL::SCAN_ORDER;
|
||||
}
|
||||
|
||||
|
@ -209,7 +225,7 @@ namespace pimoroni {
|
|||
caset[1] = 239;
|
||||
raset[0] = 0;
|
||||
raset[1] = 319;
|
||||
madctl = rotate180 ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
madctl = (rotate == ROTATE_180 || rotate == ROTATE_90) ? (MADCTL::COL_ORDER | MADCTL::ROW_ORDER) : 0;
|
||||
}
|
||||
|
||||
// Byte swap the 16bit rows/cols values
|
||||
|
@ -231,29 +247,13 @@ namespace pimoroni {
|
|||
}
|
||||
|
||||
void ST7789::write_blocking_parallel(const uint8_t *src, size_t len) {
|
||||
const uint8_t *p = src;
|
||||
while(len--) {
|
||||
// Does not byte align correctly
|
||||
//pio_sm_put_blocking(parallel_pio, parallel_sm, *p);
|
||||
while (pio_sm_is_tx_fifo_full(parallel_pio, parallel_sm))
|
||||
;
|
||||
*(volatile uint8_t*)¶llel_pio->txf[parallel_sm] = *p;
|
||||
p++;
|
||||
}
|
||||
write_blocking_dma(src, len);
|
||||
dma_channel_wait_for_finish_blocking(st_dma);
|
||||
|
||||
uint32_t sm_stall_mask = 1u << (parallel_sm + PIO_FDEBUG_TXSTALL_LSB);
|
||||
parallel_pio->fdebug = sm_stall_mask;
|
||||
while (!(parallel_pio->fdebug & sm_stall_mask))
|
||||
;
|
||||
/*uint32_t mask = 0xff << d0;
|
||||
while(len--) {
|
||||
gpio_put(wr_sck, false);
|
||||
uint8_t v = *src++;
|
||||
gpio_put_masked(mask, v << d0);
|
||||
//asm("nop;");
|
||||
gpio_put(wr_sck, true);
|
||||
asm("nop;");
|
||||
}*/
|
||||
// This may cause a race between PIO and the
|
||||
// subsequent chipselect deassert for the last pixel
|
||||
while(!pio_sm_is_tx_fifo_empty(parallel_pio, parallel_sm))
|
||||
;
|
||||
}
|
||||
|
||||
void ST7789::command(uint8_t command, size_t len, const char *data) {
|
||||
|
|
|
@ -11,7 +11,9 @@
|
|||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "st7789_parallel.pio.h"
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
|
|
@ -217,7 +217,7 @@ namespace pimoroni {
|
|||
i2c->read_blocking(address, (uint8_t *)&value, 4, false);
|
||||
|
||||
// TODO do we need to bswap this return value?
|
||||
return __bswap32(value);
|
||||
return __builtin_bswap32(value);
|
||||
}
|
||||
|
||||
// set distance mode to Short, Medium, or Long
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
add_subdirectory(breakout_dotmatrix)
|
||||
add_subdirectory(breakout_encoder)
|
||||
add_subdirectory(breakout_encoder_wheel)
|
||||
add_subdirectory(breakout_ioexpander)
|
||||
add_subdirectory(breakout_ltr559)
|
||||
add_subdirectory(breakout_colourlcd160x80)
|
||||
|
@ -18,6 +19,7 @@ add_subdirectory(breakout_bme688)
|
|||
add_subdirectory(breakout_bmp280)
|
||||
add_subdirectory(breakout_bme280)
|
||||
add_subdirectory(breakout_as7262)
|
||||
add_subdirectory(as7343)
|
||||
add_subdirectory(breakout_bh1745)
|
||||
add_subdirectory(breakout_icp10125)
|
||||
add_subdirectory(breakout_scd41)
|
||||
|
@ -60,3 +62,4 @@ add_subdirectory(encoder)
|
|||
add_subdirectory(galactic_unicorn)
|
||||
add_subdirectory(gfx_pack)
|
||||
add_subdirectory(cosmic_unicorn)
|
||||
add_subdirectory(stellar_unicorn)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include("${CMAKE_CURRENT_LIST_DIR}/as7343_demo.cmake")
|
|
@ -0,0 +1,16 @@
|
|||
set(OUTPUT_NAME as7343_demo)
|
||||
|
||||
add_executable(
|
||||
${OUTPUT_NAME}
|
||||
as7343_demo.cpp
|
||||
)
|
||||
|
||||
# enable usb output, disable uart output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
pico_enable_stdio_uart(${OUTPUT_NAME} 1)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME} pico_stdlib as7343)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,69 @@
|
|||
#include "pico/stdlib.h"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
|
||||
#include "as7343.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
I2C i2c(6, 7);
|
||||
AS7343 as7343(&i2c);
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
printf("AS7343 Demo\n");
|
||||
as7343.init();
|
||||
printf("Init done...\n");
|
||||
|
||||
uint8_t aux_id;
|
||||
uint8_t revision_id;
|
||||
uint8_t hardware_id;
|
||||
|
||||
as7343.get_version(aux_id, revision_id, hardware_id);
|
||||
|
||||
printf("Aux: %d, Rev: %d, HW: %d\n", aux_id, revision_id, hardware_id);
|
||||
|
||||
printf("set_channels\n");
|
||||
as7343.set_channels(AS7343::channel_count::EIGHTEEN_CHANNEL);
|
||||
|
||||
printf("set_gain\n");
|
||||
as7343.set_gain(1024);
|
||||
|
||||
printf("set_measurement_time\n");
|
||||
as7343.set_measurement_time(500);
|
||||
|
||||
printf("set_integration_time\n");
|
||||
as7343.set_integration_time(27800);
|
||||
|
||||
printf("set_illumination_current\n");
|
||||
as7343.set_illumination_current(4);
|
||||
|
||||
printf("set_illumination_led\n");
|
||||
as7343.set_illumination_led(true);
|
||||
|
||||
printf("start...\n");
|
||||
while(true) {
|
||||
|
||||
AS7343::reading reading = as7343.read();
|
||||
printf("FZ: %d FY: %d FXL: %d NIR: %d F2 %d F3: %d F4: %d F5: %d F1: %d F5: %d F7: %d F8: %d \n",
|
||||
reading.FZ,
|
||||
reading.FY,
|
||||
reading.FXL,
|
||||
reading.NIR,
|
||||
|
||||
reading.F2,
|
||||
reading.F3,
|
||||
reading.F4,
|
||||
reading.F6,
|
||||
|
||||
reading.F1,
|
||||
reading.F5,
|
||||
reading.F7,
|
||||
reading.F8
|
||||
);
|
||||
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -25,7 +25,7 @@ int main() {
|
|||
|
||||
while (1) {
|
||||
BME280::bme280_reading result = bme280.read_forced();
|
||||
printf("%s %0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", result.status == BME280_OK ? "OK" : "ER", result.temperature, result.pressure, result.humidity);
|
||||
printf("%s %0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", result.status ? "OK" : "ER", result.temperature, result.pressure, result.humidity);
|
||||
sleep_ms(1000);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
add_subdirectory(buttons)
|
||||
add_subdirectory(chase_game)
|
||||
add_subdirectory(clock)
|
||||
add_subdirectory(colour_picker)
|
||||
add_subdirectory(encoder)
|
||||
add_subdirectory(gpio_pwm)
|
||||
add_subdirectory(interrupt)
|
||||
add_subdirectory(led_rainbow)
|
||||
add_subdirectory(stop_watch)
|
|
@ -0,0 +1,77 @@
|
|||
# RGB Encoder Wheel Breakout Examples (C++) <!-- omit in toc -->
|
||||
|
||||
- [Function Examples](#function-examples)
|
||||
- [Buttons](#buttons)
|
||||
- [Encoder](#encoder)
|
||||
- [Interrupt](#interrupt)
|
||||
- [LED Examples](#led-examples)
|
||||
- [LED Rainbow](#led-rainbow)
|
||||
- [Clock](#clock)
|
||||
- [Interactive Examples](#interactive-examples)
|
||||
- [Colour Picker](#colour-picker)
|
||||
- [Stop Watch](#stop-watch)
|
||||
- [Chase Game](#chase-game)
|
||||
- [GPIO Examples](#gpio-examples)
|
||||
- [GPIO PWM](#gpio-pwm)
|
||||
|
||||
|
||||
## Function Examples
|
||||
|
||||
### Buttons
|
||||
[buttons/buttons.cpp](buttons/buttons.cpp)
|
||||
|
||||
A demonstration of reading the 5 buttons on Encoder Wheel.
|
||||
|
||||
|
||||
### Encoder
|
||||
[encoder/encoder.cpp](encoder/encoder.cpp)
|
||||
|
||||
A demonstration of reading the rotary dial of the Encoder Wheel breakout.
|
||||
|
||||
|
||||
### Interrupt
|
||||
[interrupt/interrupt.cpp](interrupt/interrupt.cpp)
|
||||
|
||||
How to read the buttons and rotary dial of the Encoder Wheel breakout, only when an interrupt occurs.
|
||||
|
||||
|
||||
## LED Examples
|
||||
|
||||
### LED Rainbow
|
||||
[led_rainbow/led_rainbow.cpp](led_rainbow/led_rainbow.cpp)
|
||||
|
||||
Displays a rotating rainbow pattern on Encoder Wheel's LED ring.
|
||||
|
||||
|
||||
### Clock
|
||||
[clock/clock.cpp](clock/clock.cpp)
|
||||
|
||||
Displays a 12 hour clock on Encoder Wheel's LED ring, getting time from the system.
|
||||
|
||||
|
||||
## Interactive Examples
|
||||
|
||||
### Colour Picker
|
||||
[colour_picker/colour_picker.cpp](colour_picker/colour_picker.cpp)
|
||||
|
||||
Create a colour wheel on the Encoder Wheel's LED ring, and use all functions of the wheel to interact with it.
|
||||
|
||||
|
||||
### Stop Watch
|
||||
[stop_watch/stop_watch.cpp](stop_watch/stop_watch.cpp)
|
||||
|
||||
Display a circular stop-watch on the Encoder Wheel's LED ring.
|
||||
|
||||
|
||||
### Chase Game
|
||||
[chase_game/chase_game.cpp](chase_game/chase_game.cpp)
|
||||
|
||||
A simple alignment game. Use Encoder Wheel's rotary dial to align the coloured band to the white goal. The closer to the goal, the greener your coloured band will be. When you reach the goal, the goal will move to a new random position.
|
||||
|
||||
|
||||
## GPIO Examples
|
||||
|
||||
### GPIO PWM
|
||||
[gpio_pwm/gpio_pwm.cpp](gpio_pwm/gpio_pwm.cpp)
|
||||
|
||||
Output a sine wave PWM sequence on the Encoder Wheel's side GPIO pins.
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_buttons)
|
||||
add_executable(${OUTPUT_NAME} buttons.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,96 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A demonstration of reading the 5 buttons on Encoder Wheel.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
const std::string BUTTON_NAMES[] = {"Up", "Down", "Left", "Right", "Centre"};
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
bool last_pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
bool pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Read all of the encoder wheel's buttons
|
||||
for(int b = 0 ; b < NUM_BUTTONS; b++) {
|
||||
pressed[b] = wheel.pressed(b);
|
||||
if(pressed[b] != last_pressed[b]) {
|
||||
printf("%s %s\n", BUTTON_NAMES[b].c_str(), pressed[b] ? "Pressed" : "Released");
|
||||
}
|
||||
last_pressed[b] = pressed[b];
|
||||
}
|
||||
|
||||
// Clear the LED ring
|
||||
wheel.clear();
|
||||
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
if(i % 6 == 3) {
|
||||
wheel.set_rgb(i, 64, 64, 64);
|
||||
}
|
||||
}
|
||||
|
||||
// If up is pressed, set the top LEDs to yellow
|
||||
if(pressed[UP]) {
|
||||
int mid = NUM_LEDS;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 255, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If right is pressed, set the right LEDs to red
|
||||
if(pressed[RIGHT]) {
|
||||
int mid = NUM_LEDS / 4;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 255, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If down is pressed, set the bottom LEDs to green
|
||||
if(pressed[DOWN]) {
|
||||
int mid = NUM_LEDS / 2;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 0, 255, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// If left is pressed, set the left LEDs to blue
|
||||
if(pressed[LEFT]) {
|
||||
int mid = (NUM_LEDS * 3) / 4;
|
||||
for(int i = mid - 2; i < mid + 3; i++) {
|
||||
wheel.set_rgb(i % NUM_LEDS, 0, 0, 255);
|
||||
}
|
||||
}
|
||||
|
||||
// If centre is pressed, set the diagonal LEDs to half white
|
||||
if(pressed[CENTRE]) {
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
if(i % 6 >= 2 && i % 6 <= 4) {
|
||||
wheel.set_rgb(i, 128, 128, 128);
|
||||
}
|
||||
}
|
||||
}
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_chase_game)
|
||||
add_executable(${OUTPUT_NAME} chase_game.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,148 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A simple alignment game. Use Encoder Wheel's rotary dial to align the coloured band
|
||||
to the white goal. The closer to the goal, the greener your coloured band will be.
|
||||
When you reach the goal, the goal will move to a new random position.
|
||||
*/
|
||||
|
||||
// The band colour hues to show in Angle mode
|
||||
constexpr float GOAL_HUE = 0.333f;
|
||||
constexpr float FAR_HUE = 0.0f;
|
||||
|
||||
// The width and colour settings for the band
|
||||
constexpr float BAND_WIDTH = 5.0f;
|
||||
constexpr float BAND_SATURATION = 1.0f;
|
||||
constexpr float BAND_IN_GOAL_SATURATION = 0.5f;
|
||||
constexpr float BAND_BRIGHTNESS = 1.0f;
|
||||
|
||||
// The width and colour settings for the goal
|
||||
// Goal should be wider than the band by a small amount
|
||||
constexpr float GOAL_MARGIN = 1.0f;
|
||||
constexpr float GOAL_WIDTH = BAND_WIDTH + (2.0f * GOAL_MARGIN);
|
||||
constexpr float GOAL_BRIGHTNESS = 0.4f;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float goal_position = 0.0f;
|
||||
int16_t band_position = 0;
|
||||
|
||||
|
||||
// Maps a value from one range to another
|
||||
float map(float x, float in_min, float in_max, float out_min, float out_max) {
|
||||
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||
}
|
||||
|
||||
// Shows a band and goal with the given widths at the positions on the strip
|
||||
void colour_band(float centre_position, float width, float goal_position, float goal_width, float hue) {
|
||||
if(centre_position >= 0.0f && width > 0.0f && goal_width > 0.0) {
|
||||
float band_start = centre_position - (width / 2);
|
||||
float band_end = centre_position + (width / 2);
|
||||
float band_centre = centre_position;
|
||||
|
||||
float goal_start = goal_position - (goal_width / 2);
|
||||
float goal_end = goal_position + (goal_width / 2);
|
||||
|
||||
// Go through each led in the strip
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Set saturation and brightness values for if the led is inside or outside of the goal
|
||||
float saturation = BAND_SATURATION;
|
||||
float brightness = 0.0f;
|
||||
|
||||
if(i >= goal_start && i < goal_end) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
if(goal_end >= NUM_LEDS && i + NUM_LEDS < goal_end) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
if(goal_start < 0 && i - NUM_LEDS >= goal_start) {
|
||||
saturation = BAND_IN_GOAL_SATURATION;
|
||||
brightness = GOAL_BRIGHTNESS;
|
||||
}
|
||||
|
||||
float val = brightness;
|
||||
float sat = 0.0f;
|
||||
if(i >= band_start && i < band_end) {
|
||||
// Inside the band
|
||||
if(i < band_centre) {
|
||||
// Transition into the band
|
||||
val = map(i, band_centre, band_start, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i, band_centre, band_start, BAND_SATURATION, saturation);
|
||||
}
|
||||
else {
|
||||
val = map(i, band_centre, band_end, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i, band_centre, band_end, BAND_SATURATION, saturation);
|
||||
}
|
||||
}
|
||||
else if(band_end >= NUM_LEDS && i + NUM_LEDS < band_end && i < band_centre) {
|
||||
val = map(i + NUM_LEDS, band_centre, band_end, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i + NUM_LEDS, band_centre, band_end, BAND_SATURATION, saturation);
|
||||
}
|
||||
else if(band_start < 0 && i - NUM_LEDS >= band_start && i >= band_centre) {
|
||||
val = map(i - NUM_LEDS, band_centre, band_start, BAND_BRIGHTNESS, brightness);
|
||||
sat = map(i - NUM_LEDS, band_centre, band_start, BAND_SATURATION, saturation);
|
||||
}
|
||||
//else {
|
||||
// Outside of the band
|
||||
//}
|
||||
wheel.set_hsv(i, hue, sat, val);
|
||||
}
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
band_position = wheel.step();
|
||||
|
||||
// Convert the difference between the band and goal positions into a colour hue
|
||||
float diff1, diff2;
|
||||
if(band_position > goal_position) {
|
||||
diff1 = band_position - goal_position;
|
||||
diff2 = (goal_position + NUM_LEDS) - band_position;
|
||||
}
|
||||
else {
|
||||
diff1 = goal_position - band_position;
|
||||
diff2 = (band_position + NUM_LEDS) - goal_position;
|
||||
}
|
||||
|
||||
float position_diff = MIN(diff1, diff2);
|
||||
float hue = map(position_diff, 0, NUM_LEDS / 2.0f, GOAL_HUE, FAR_HUE);
|
||||
|
||||
// Convert the band and goal positions to positions on the LED strip
|
||||
float strip_band_position = map(band_position, 0, NUM_LEDS, 0.0f, (float)NUM_LEDS);
|
||||
float strip_goal_position = map(goal_position, 0, NUM_LEDS, 0.0f, (float)NUM_LEDS);
|
||||
|
||||
// Draw the band and goal
|
||||
colour_band(strip_band_position, BAND_WIDTH, strip_goal_position, GOAL_WIDTH, hue);
|
||||
|
||||
// Check if the band is within the goal, and if so, set a new goal
|
||||
if(band_position >= goal_position - GOAL_MARGIN && band_position <= goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
if(band_position >= NUM_LEDS && band_position + NUM_LEDS < goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
if(goal_position - GOAL_MARGIN < 0 && band_position - NUM_LEDS >= goal_position + GOAL_MARGIN)
|
||||
goal_position = rand() % NUM_LEDS;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
set(OUTPUT_NAME encoderwheel_clock)
|
||||
add_executable(${OUTPUT_NAME} clock.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
hardware_rtc
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,114 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
#include "hardware/rtc.h"
|
||||
#include "pico/util/datetime.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Displays a 12 hour clock on Encoder Wheel's LED ring, getting time from the system.
|
||||
*/
|
||||
|
||||
// Datetime Indices
|
||||
const uint HOUR = 4;
|
||||
const uint MINUTE = 5;
|
||||
const uint SECOND = 6;
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Handy values for the number of milliseconds
|
||||
constexpr float MILLIS_PER_SECOND = 1000;
|
||||
constexpr float MILLIS_PER_MINUTE = MILLIS_PER_SECOND * 60;
|
||||
constexpr float MILLIS_PER_HOUR = MILLIS_PER_MINUTE * 60;
|
||||
constexpr float MILLIS_PER_HALF_DAY = MILLIS_PER_HOUR * 12;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
|
||||
// Calculates the brightness of an LED based on its index and a position along the LED ring
|
||||
int led_brightness_at(int led, float position, float half_width = 1.0f, float span = 1.0f) {
|
||||
float brightness = 0.0f;
|
||||
float upper = position + half_width;
|
||||
float lower = position - half_width;
|
||||
if(led > position)
|
||||
brightness = CLAMP((upper - led) / span, 0.0f, 1.0f);
|
||||
else
|
||||
brightness = CLAMP((led - lower) / span, 0.0f, 1.0f);
|
||||
|
||||
// Handle the LEDs being in a circle
|
||||
if(upper >= NUM_LEDS)
|
||||
brightness = CLAMP(((upper - NUM_LEDS) - led) / span, brightness, 1.0f);
|
||||
else if(lower < 0.0f)
|
||||
brightness = CLAMP((led - (lower + NUM_LEDS)) / span, brightness, 1.0f);
|
||||
|
||||
return (int)(brightness * BRIGHTNESS * 255);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Start on Thursday 4th of May 2023 14:20:00
|
||||
datetime_t now = {
|
||||
.year = 2023,
|
||||
.month = 05,
|
||||
.day = 04,
|
||||
.dotw = 4, // 0 is Sunday, so 4 is Thursday
|
||||
.hour = 14,
|
||||
.min = 20,
|
||||
.sec = 00
|
||||
};
|
||||
|
||||
// Start the RTC
|
||||
rtc_init();
|
||||
rtc_set_datetime(&now);
|
||||
|
||||
// clk_sys is >2000x faster than clk_rtc, so datetime is not updated immediately when rtc_get_datetime() is called.
|
||||
// tbe delay is up to 3 RTC clock cycles (which is 64us with the default clock settings)
|
||||
sleep_us(64);
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// Get the current system time
|
||||
rtc_get_datetime(&now);
|
||||
|
||||
// Convert the seconds, minutes, and hours into milliseconds (this is done to give a smoother animation, particularly for the seconds hand)
|
||||
uint sec_as_millis = (now.sec * MILLIS_PER_SECOND);
|
||||
uint min_as_millis = (now.min * MILLIS_PER_MINUTE) + sec_as_millis;
|
||||
uint hour_as_millis = ((now.hour % 12) * MILLIS_PER_HOUR) + min_as_millis;
|
||||
|
||||
// Calculate the position on the LED ring that the, second, minute, and hour hands should be
|
||||
float sec_pos = MIN(sec_as_millis / MILLIS_PER_MINUTE, 1.0f) * NUM_LEDS;
|
||||
float min_pos = MIN(min_as_millis / MILLIS_PER_HOUR, 1.0f) * NUM_LEDS;
|
||||
float hour_pos = MIN(hour_as_millis / MILLIS_PER_HALF_DAY, 1.0f) * NUM_LEDS;
|
||||
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
// Turn on the LEDs close to the position of the current second, minute, and hour
|
||||
int r = led_brightness_at(i, sec_pos);
|
||||
int g = led_brightness_at(i, min_pos);
|
||||
int b = led_brightness_at(i, hour_pos);
|
||||
wheel.set_rgb(i, r, g, b);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_colour_picker)
|
||||
add_executable(${OUTPUT_NAME} colour_picker.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,168 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Create a colour wheel on the Encoder Wheel's LED ring, and use all functions of the wheel to interact with it.
|
||||
|
||||
Rotate the wheel to select a Hue
|
||||
Press the up direction to increase Brightness
|
||||
Press the down direction to decrease Brightness
|
||||
Press the left direction to decrease Saturation
|
||||
Press the right direction to increase Saturation
|
||||
Press the centre to hide the selection marker
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS_STEP = 0.02f; // How much to increase or decrease the brightness each update
|
||||
constexpr float SATURATION_STEP = 0.02f; // How much to increase or decrease the saturation each update
|
||||
const uint UPDATES = 50; // How many times to update the LEDs per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float brightness = 1.0f;
|
||||
float saturation = 1.0f;
|
||||
int position = 0;
|
||||
bool changed = true;
|
||||
bool last_centre_pressed = false;
|
||||
|
||||
// Struct for storing RGB values
|
||||
struct Pixel {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
Pixel() : r(0), g(0), b(0) {};
|
||||
Pixel(uint8_t r, uint8_t g, uint8_t b) : r(r), g(g), b(b) {};
|
||||
};
|
||||
|
||||
// Basic function to convert Hue, Saturation and Value to an RGB colour
|
||||
Pixel hsv_to_rgb(float h, float s, float v) {
|
||||
if(h < 0.0f) {
|
||||
h = 1.0f + fmodf(h, 1.0f);
|
||||
}
|
||||
|
||||
int i = int(h * 6);
|
||||
float f = h * 6 - i;
|
||||
|
||||
v = v * 255.0f;
|
||||
|
||||
float sv = s * v;
|
||||
float fsv = f * sv;
|
||||
|
||||
auto p = uint8_t(-sv + v);
|
||||
auto q = uint8_t(-fsv + v);
|
||||
auto t = uint8_t(fsv - sv + v);
|
||||
|
||||
uint8_t bv = uint8_t(v);
|
||||
|
||||
switch (i % 6) {
|
||||
default:
|
||||
case 0: return Pixel(bv, t, p);
|
||||
case 1: return Pixel(q, bv, p);
|
||||
case 2: return Pixel(p, bv, t);
|
||||
case 3: return Pixel(p, q, bv);
|
||||
case 4: return Pixel(t, p, bv);
|
||||
case 5: return Pixel(bv, p, q);
|
||||
}
|
||||
}
|
||||
|
||||
// Simple function to clamp a value between 0.0 and 1.0
|
||||
float clamp01(float value) {
|
||||
return MAX(MIN(value, 1.0f), 0.0f);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// If up is pressed, increase the brightness
|
||||
if(wheel.pressed(UP)) {
|
||||
brightness += BRIGHTNESS_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If down is pressed, decrease the brightness
|
||||
if(wheel.pressed(DOWN)) {
|
||||
brightness -= BRIGHTNESS_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If right is pressed, increase the saturation
|
||||
if(wheel.pressed(RIGHT)) {
|
||||
saturation += SATURATION_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If left is pressed, decrease the saturation
|
||||
if(wheel.pressed(LEFT)) {
|
||||
saturation -= SATURATION_STEP;
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// Limit the brightness and saturation between 0.0 and 1.0
|
||||
brightness = clamp01(brightness);
|
||||
saturation = clamp01(saturation);
|
||||
|
||||
// Check if the encoder has been turned
|
||||
if(wheel.delta() != 0) {
|
||||
// Update the position based on the count change
|
||||
position = wheel.step();
|
||||
changed = true; // Trigger a change
|
||||
}
|
||||
|
||||
// If centre is pressed, trigger a change
|
||||
bool centre_pressed = wheel.pressed(CENTRE);
|
||||
if(centre_pressed != last_centre_pressed) {
|
||||
changed = true;
|
||||
}
|
||||
last_centre_pressed = centre_pressed;
|
||||
|
||||
// Was a change triggered?
|
||||
if(changed) {
|
||||
// Print the colour at the current hue, saturation, and brightness
|
||||
Pixel pixel = hsv_to_rgb((float)position / NUM_LEDS, saturation, brightness);
|
||||
printf("Colour Code = #%02x%02x%02x\n", pixel.r, pixel.g, pixel.b);
|
||||
|
||||
// Set the LED at the current position to either the actual colour,
|
||||
// or an inverted version to show a "selection marker"
|
||||
if(centre_pressed)
|
||||
wheel.set_rgb(position, pixel.r, pixel.g, pixel.b);
|
||||
else
|
||||
wheel.set_rgb(position, 255 - pixel.r, 255 - pixel.g, 255 - pixel.b);
|
||||
|
||||
// Set the LEDs below the current position
|
||||
for(int i = 0; i < position; i++) {
|
||||
wheel.set_hsv(i, (float)i / NUM_LEDS, saturation, brightness);
|
||||
}
|
||||
|
||||
// Set the LEDs after the current position
|
||||
for(int i = position + 1; i < NUM_LEDS; i++) {
|
||||
wheel.set_hsv(i, (float)i / NUM_LEDS, saturation, brightness);
|
||||
}
|
||||
wheel.show();
|
||||
changed = false;
|
||||
}
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_encoder)
|
||||
add_executable(${OUTPUT_NAME} encoder.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,60 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
A demonstration of reading the rotary dial of the Encoder Wheel breakout.
|
||||
*/
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
int position = 0;
|
||||
float hue = 0.0f;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
|
||||
// Set the first LED
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
|
||||
// Loop forever
|
||||
while(true) {
|
||||
// Has the dial been turned since the last time we checked?
|
||||
int16_t change = wheel.delta();
|
||||
if(change != 0) {
|
||||
// Print out the direction the dial was turned, and the count
|
||||
if(change > 0)
|
||||
printf("Clockwise, Count = %d\n", wheel.count());
|
||||
else
|
||||
printf("Counter Clockwise, Count = %d\n", wheel.count());
|
||||
|
||||
// Record the new position (from 0 to 23)
|
||||
position = wheel.step();
|
||||
|
||||
// Record a colour hue from 0.0 to 1.0
|
||||
hue = fmodf(wheel.revolutions(), 1.0f);
|
||||
|
||||
// Set the LED at the new position to the new hue
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_gpio_pwm)
|
||||
add_executable(${OUTPUT_NAME} gpio_pwm.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,74 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Output a sine wave PWM sequence on the Encoder Wheel's side GPIO pins.
|
||||
|
||||
Press the centre button to stop the program.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float SPEED = 5.0f; // The speed that the LEDs will cycle at
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
constexpr float FREQUENCY = 1000.0f; // The frequency to run the PWM at
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float offset = 0.0f;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
|
||||
// Set the PWM frequency for the GPIOs
|
||||
uint16_t period = wheel.gpio_pwm_frequency(FREQUENCY);
|
||||
|
||||
// Set the GPIO pins to PWM outputs
|
||||
for(int i = 0; i < NUM_GPIOS; i++) {
|
||||
wheel.gpio_pin_mode(GPIOS[i], IOExpander::PIN_PWM);
|
||||
}
|
||||
|
||||
// Loop forever
|
||||
while(!wheel.pressed(CENTRE)) {
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
offset += SPEED / 1000.0f;
|
||||
|
||||
// Update all the PWMs
|
||||
for(int i = 0; i < NUM_GPIOS; i++) {
|
||||
float angle = (((float)i / NUM_GPIOS) + offset) * M_PI;
|
||||
uint16_t duty = (uint16_t)(((sinf(angle) / 2.0f) + 0.5f) * period);
|
||||
|
||||
// Set the GPIO pin to the new duty cycle, but do not load it yet
|
||||
wheel.gpio_pin_value(GPIOS[i], duty, false);
|
||||
}
|
||||
|
||||
// Have all the PWMs load at once
|
||||
wheel.gpio_pwm_load();
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
|
||||
// Turn off the PWM outputs
|
||||
for(int i = 0; i < NUM_GPIOS; i++) {
|
||||
wheel.gpio_pin_value(GPIOS[i], 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_interrupt)
|
||||
add_executable(${OUTPUT_NAME} interrupt.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,84 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
How to read the buttons and rotary dial of the Encoder Wheel breakout, only when an interrupt occurs.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
const std::string BUTTON_NAMES[] = {"Up", "Down", "Left", "Right", "Centre"};
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c,
|
||||
BreakoutEncoderWheel::DEFAULT_IOE_I2C_ADDRESS,
|
||||
BreakoutEncoderWheel::DEFAULT_LED_I2C_ADDRESS,
|
||||
3); // 3 for BG_BASE, 22 for EXPLORER_BASE, or 19 for some RP2040 boards
|
||||
// If wiring the breakout via the qw/st connector, use the below line instead
|
||||
// BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
bool last_pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
bool pressed[NUM_BUTTONS] = {false, false, false, false, false};
|
||||
int position = 0;
|
||||
float hue = 0.0f;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
|
||||
// Set the first LED
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
|
||||
// Clear any left over interrupt from previous code
|
||||
wheel.clear_interrupt_flag();
|
||||
|
||||
// Loop forever
|
||||
while(true) {
|
||||
|
||||
// Check if the interrupt has fired
|
||||
if(wheel.get_interrupt_flag()) {
|
||||
wheel.clear_interrupt_flag();
|
||||
|
||||
// Read all of the encoder wheel's buttons
|
||||
for(int b = 0 ; b < NUM_BUTTONS; b++) {
|
||||
pressed[b] = wheel.pressed(b);
|
||||
if(pressed[b] != last_pressed[b]) {
|
||||
printf("%s %s\n", BUTTON_NAMES[b].c_str(), pressed[b] ? "Pressed" : "Released");
|
||||
}
|
||||
last_pressed[b] = pressed[b];
|
||||
}
|
||||
|
||||
// The interrupt may have come from several sources,
|
||||
// so check if it was a position change
|
||||
int new_position = wheel.step();
|
||||
if(new_position != position) {
|
||||
// Record the new position (from 0 to 23)
|
||||
position = new_position;
|
||||
printf("Position = %d\n", position);
|
||||
|
||||
// Record a colour hue from 0.0 to 1.0
|
||||
hue = fmodf(wheel.revolutions(), 1.0f);
|
||||
|
||||
// Set the LED at the new position to the new hue
|
||||
wheel.clear();
|
||||
wheel.set_hsv(position, hue, 1.0f, 1.0f);
|
||||
wheel.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_led_rainbow)
|
||||
add_executable(${OUTPUT_NAME} led_rainbow.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,54 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Displays a rotating rainbow pattern on Encoder Wheel's LED ring.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float SPEED = 5.0f; // The speed that the LEDs will cycle at
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
float offset = 0.0;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Loop forever
|
||||
while(true) {
|
||||
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
offset += SPEED / 1000.0f;
|
||||
|
||||
// Update all the LEDs
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
float hue = (float)i / NUM_LEDS;
|
||||
wheel.set_hsv(i, hue + offset, 1.0, BRIGHTNESS);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
sleep_until(delayed_by_us(start_time, UPDATE_RATE_US));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
set(OUTPUT_NAME encoderwheel_stop_watch)
|
||||
add_executable(${OUTPUT_NAME} stop_watch.cpp)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${OUTPUT_NAME}
|
||||
pico_stdlib
|
||||
breakout_encoder_wheel
|
||||
)
|
||||
|
||||
# enable usb output
|
||||
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
|
||||
|
||||
pico_add_extra_outputs(${OUTPUT_NAME})
|
|
@ -0,0 +1,151 @@
|
|||
#include <math.h>
|
||||
#include <string>
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
#include "time.h"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
/*
|
||||
Display a circular stop-watch on the Encoder Wheel's LED ring.
|
||||
|
||||
Press the centre button to start the stopwatch, then again to pause and resume.
|
||||
*/
|
||||
|
||||
// Constants
|
||||
constexpr float BRIGHTNESS = 1.0f; // The brightness of the LEDs
|
||||
const uint UPDATES = 50; // How many times the LEDs will be updated per second
|
||||
const uint MINUTE_UPDATES = UPDATES * 60; // How many times the LEDs will be updated per minute
|
||||
const uint HOUR_UPDATES = MINUTE_UPDATES * 60; // How many times the LEDs will be updated per hour
|
||||
const uint UPDATE_RATE_US = 1000000 / UPDATES;
|
||||
|
||||
constexpr float IDLE_PULSE_MIN = 0.2f; // The brightness (between 0.0 and 1.0) that the idle pulse will go down to
|
||||
constexpr float IDLE_PULSE_MAX = 0.5f; // The brightness (between 0.0 and 1.0) that the idle pulse will go up to
|
||||
constexpr float IDLE_PULSE_TIME = 2.0f; // The time (in seconds) to perform a complete idle pulse
|
||||
constexpr uint UPDATES_PER_PULSE = IDLE_PULSE_TIME * UPDATES;
|
||||
|
||||
// The state constants used for program flow
|
||||
enum State {
|
||||
IDLE = 0,
|
||||
COUNTING,
|
||||
PAUSED
|
||||
};
|
||||
|
||||
// Create a new BreakoutEncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Variables
|
||||
State state = IDLE;
|
||||
uint idle_update = 0;
|
||||
uint second_update = 0;
|
||||
uint minute_update = 0;
|
||||
uint hour_update = 0;
|
||||
bool last_centre_pressed = false;
|
||||
|
||||
|
||||
int main() {
|
||||
stdio_init_all();
|
||||
|
||||
// Attempt to initialise the encoder wheel
|
||||
if(wheel.init()) {
|
||||
// Record the current time
|
||||
absolute_time_t current_time = get_absolute_time();
|
||||
|
||||
// Run the update loop forever
|
||||
while(true) {
|
||||
|
||||
// Record the start time of this loop
|
||||
absolute_time_t start_time = get_absolute_time();
|
||||
|
||||
// Read whether or not the wheen centre has been pressed
|
||||
bool centre_pressed = wheel.pressed(CENTRE);
|
||||
if(centre_pressed && centre_pressed != last_centre_pressed) {
|
||||
switch(state) {
|
||||
case IDLE: // If we're currently idle, switch to counting
|
||||
second_update = 0;
|
||||
minute_update = 0;
|
||||
hour_update = 0;
|
||||
state = COUNTING;
|
||||
break;
|
||||
case COUNTING: // If we're counting, switch to paused
|
||||
state = PAUSED;
|
||||
break;
|
||||
case PAUSED: // If we're paused, switch back to counting
|
||||
state = COUNTING;
|
||||
}
|
||||
}
|
||||
last_centre_pressed = centre_pressed;
|
||||
|
||||
switch(state) {
|
||||
// If we're idle, perform a pulsing animation to show the stopwatch is ready to go
|
||||
case IDLE:
|
||||
{
|
||||
float percent_along = MIN((float)idle_update / (float)UPDATES_PER_PULSE, 1.0f);
|
||||
float brightness = ((cosf(percent_along * M_PI * 2.0f) + 1.0f) / 2.0f) * ((IDLE_PULSE_MAX - IDLE_PULSE_MIN)) + IDLE_PULSE_MIN;
|
||||
// Update all the LEDs
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
wheel.set_hsv(i, 0.0, 0.0, brightness);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Advance to the next update, wrapping around to zero if at the end
|
||||
idle_update += 1;
|
||||
if(idle_update >= UPDATES_PER_PULSE) {
|
||||
idle_update = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// If we're counting, perform the stopwatch animation
|
||||
case COUNTING:
|
||||
{
|
||||
// Calculate how many LED channels should light, as a proportion of a second, minute, and hour
|
||||
float r_to_light = MIN((float)second_update / UPDATES, 1.0f) * 24.0f;
|
||||
float g_to_light = MIN((float)minute_update / MINUTE_UPDATES, 1.0f) * 24.0f;
|
||||
float b_to_light = MIN((float)hour_update / HOUR_UPDATES, 1.0f) * 24.0f;
|
||||
|
||||
// Set each LED, such that ones below the current time are fully lit, ones after
|
||||
// are off, and the one at the transition is at a percentage of the brightness
|
||||
for(int i = 0; i < NUM_LEDS; i++) {
|
||||
int r = (int)(CLAMP(r_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
int g = (int)(CLAMP(g_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
int b = (int)(CLAMP(b_to_light - i, 0.0f, 1.0f) * BRIGHTNESS * 255.0f);
|
||||
wheel.set_rgb(i, r, g, b);
|
||||
}
|
||||
wheel.show();
|
||||
|
||||
// Advance the second updates count, wrapping around to zero if at the end
|
||||
second_update += 1;
|
||||
if(second_update >= UPDATES) {
|
||||
second_update = 0;
|
||||
}
|
||||
|
||||
// Advance the minute updates count, wrapping around to zero if at the end
|
||||
minute_update += 1;
|
||||
if(minute_update >= MINUTE_UPDATES) {
|
||||
minute_update = 0;
|
||||
}
|
||||
|
||||
// Advance the hour updates count, wrapping around to zero if at the end
|
||||
hour_update += 1;
|
||||
if(hour_update >= HOUR_UPDATES) {
|
||||
hour_update = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PAUSED:
|
||||
// Do nothing
|
||||
break;
|
||||
}
|
||||
|
||||
// Sleep until the next update, accounting for how long the above operations took to perform
|
||||
current_time = delayed_by_us(start_time, UPDATE_RATE_US);
|
||||
sleep_until(current_time);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -30,7 +30,7 @@ int main() {
|
|||
// }
|
||||
// }
|
||||
|
||||
graphics.set_pen(1);
|
||||
graphics.set_pen(15);
|
||||
graphics.clear();
|
||||
|
||||
float s = (sin(i / 10.0f) * 1.0f) + 1.5f;
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
#include "pico_explorer.hpp"
|
||||
#include "pico/stdlib.h"
|
||||
#include "encoder.hpp"
|
||||
|
||||
#ifndef NO_QSTR
|
||||
#include "quadrature_out.pio.h"
|
||||
#endif
|
||||
|
||||
#include "drivers/st7789/st7789.hpp"
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "button.hpp"
|
||||
|
|
|
@ -34,10 +34,15 @@ int main() {
|
|||
while(true) {
|
||||
|
||||
offset += float(SPEED) / 2000.0f;
|
||||
if (offset > 1.0) {
|
||||
offset -= 1.0;
|
||||
}
|
||||
|
||||
for(auto i = 0u; i < NUM_LEDS; ++i) {
|
||||
float hue = float(i) / NUM_LEDS;
|
||||
led_strip.set_hsv(i, hue + offset, 1.0f, 1.0f);
|
||||
hue += offset;
|
||||
hue -= floor(hue);
|
||||
led_strip.set_hsv(i, hue, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
sleep_ms(1000 / UPDATES);
|
||||
|
|
|
@ -45,7 +45,7 @@ int main() {
|
|||
|
||||
while(true) {
|
||||
BME280::bme280_reading result = bme.read_forced();
|
||||
printf("%s %0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", result.status == BME280_OK ? "OK" : "ER", result.temperature, result.pressure, result.humidity);
|
||||
printf("%s %0.2lf deg C, %0.2lf hPa, %0.2lf%%\n", result.status ? "OK" : "ER", result.temperature, result.pressure, result.humidity);
|
||||
|
||||
// calculates a colour
|
||||
float hue = HUE_START + ((float)(result.temperature - MIN) * (float)(HUE_END - HUE_START) / (float)(MAX - MIN));
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
add_executable(
|
||||
stellar_rainbow_text
|
||||
stellar_rainbow_text.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_rainbow_text pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_rainbow_text 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_rainbow_text)
|
||||
|
||||
|
||||
|
||||
add_executable(
|
||||
stellar_rainbow
|
||||
stellar_rainbow.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_rainbow pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_rainbow 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_rainbow)
|
||||
|
||||
|
||||
|
||||
|
||||
add_executable(
|
||||
stellar_eighties_super_computer
|
||||
stellar_eighties_super_computer.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_eighties_super_computer pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_eighties_super_computer 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_eighties_super_computer)
|
||||
|
||||
|
||||
|
||||
|
||||
add_executable(
|
||||
stellar_fire_effect
|
||||
stellar_fire_effect.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_fire_effect pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_fire_effect 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_fire_effect)
|
||||
|
||||
|
||||
|
||||
|
||||
add_executable(
|
||||
stellar_scroll_text
|
||||
stellar_scroll_text.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_scroll_text pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_scroll_text 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_scroll_text)
|
||||
|
||||
|
||||
add_executable(
|
||||
stellar_lava_lamp
|
||||
stellar_lava_lamp.cpp
|
||||
)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(stellar_lava_lamp pico_stdlib hardware_pio hardware_adc hardware_dma pico_graphics stellar_unicorn)
|
||||
pico_enable_stdio_usb(stellar_lava_lamp 1)
|
||||
|
||||
# create map/bin/hex file etc.
|
||||
pico_add_extra_outputs(stellar_lava_lamp)
|
||||
|
Plik diff jest za duży
Load Diff
|
@ -0,0 +1,67 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
float lifetime[16][16];
|
||||
float age[16][16];
|
||||
|
||||
int main() {
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
for(int y = 0; y < 16; y++) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
lifetime[x][y] = 1.0f + ((rand() % 10) / 100.0f);
|
||||
age[x][y] = ((rand() % 100) / 100.0f) * lifetime[x][y];
|
||||
}
|
||||
}
|
||||
|
||||
stellar_unicorn.init();
|
||||
|
||||
while(true) {
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
graphics.set_pen(0, 0, 0);
|
||||
graphics.clear();
|
||||
|
||||
for(int y = 0; y < 16; y++) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
if(age[x][y] < lifetime[x][y] * 0.3f) {
|
||||
graphics.set_pen(230, 150, 0);
|
||||
graphics.pixel(Point(x, y));
|
||||
}else if(age[x][y] < lifetime[x][y] * 0.5f) {
|
||||
float decay = (lifetime[x][y] * 0.5f - age[x][y]) * 5.0f;
|
||||
graphics.set_pen(decay * 230, decay * 150, 0);
|
||||
graphics.pixel(Point(x, y));
|
||||
}
|
||||
|
||||
if(age[x][y] >= lifetime[x][y]) {
|
||||
age[x][y] = 0.0f;
|
||||
lifetime[x][y] = 1.0f + ((rand() % 10) / 100.0f);
|
||||
}
|
||||
|
||||
age[x][y] += 0.01f;
|
||||
}
|
||||
}
|
||||
|
||||
stellar_unicorn.update(&graphics);
|
||||
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,115 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
// extra row of pixels for sourcing flames and averaging
|
||||
int width = 16;
|
||||
int height = 17;
|
||||
|
||||
// a buffer that's at least big enough to store 55 x 15 values (to allow for both orientations)
|
||||
float heat[2000] = {0.0f};
|
||||
|
||||
void set(int x, int y, float v) {
|
||||
heat[x + y * width] = v;
|
||||
}
|
||||
|
||||
float get(int x, int y) {
|
||||
/*if(x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return 0.0f;
|
||||
}*/
|
||||
x = x < 0 ? 0 : x;
|
||||
x = x >= width ? width - 1 : x;
|
||||
|
||||
return heat[x + y * width];
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
stellar_unicorn.init();
|
||||
stellar_unicorn.set_brightness(0.2);
|
||||
|
||||
bool landscape = true;
|
||||
/*
|
||||
while(true) {
|
||||
stellar_unicorn.set_pixel(0, 0, 255, 0, 0);
|
||||
stellar_unicorn.set_pixel(1, 1, 0, 255, 0);
|
||||
stellar_unicorn.set_pixel(2, 2, 0, 0, 255);
|
||||
}*/
|
||||
|
||||
while(true) {
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
|
||||
for(int y = 0; y < height; y++) {
|
||||
for(int x = 0; x < width; x++) {
|
||||
float value = get(x, y);
|
||||
|
||||
graphics.set_pen(0, 0, 0);
|
||||
if(value > 0.5f) {
|
||||
graphics.set_pen(255, 255, 180);
|
||||
}else if(value > 0.4f) {
|
||||
graphics.set_pen(220, 160, 0);
|
||||
}else if(value > 0.3f) {
|
||||
graphics.set_pen(180, 30, 0);
|
||||
}else if(value > 0.22f) {
|
||||
graphics.set_pen(20, 20, 20);
|
||||
}
|
||||
|
||||
if(landscape) {
|
||||
graphics.pixel(Point(x, y));
|
||||
}else{
|
||||
graphics.pixel(Point(y, x));
|
||||
}
|
||||
|
||||
// update this pixel by averaging the below pixels
|
||||
float average = (get(x, y) + get(x, y + 2) + get(x, y + 1) + get(x - 1, y + 1) + get(x + 1, y + 1)) / 5.0f;
|
||||
|
||||
// damping factor to ensure flame tapers out towards the top of the displays
|
||||
average *= 0.95f;
|
||||
|
||||
// update the heat map with our newly averaged value
|
||||
set(x, y, average);
|
||||
}
|
||||
}
|
||||
|
||||
stellar_unicorn.update(&graphics);
|
||||
|
||||
// clear the bottom row and then add a new fire seed to it
|
||||
for(int x = 0; x < width; x++) {
|
||||
set(x, height - 1, 0.0f);
|
||||
}
|
||||
|
||||
// add a new random heat source
|
||||
int source_count = landscape ? 5 : 1;
|
||||
for(int c = 0; c < source_count; c++) {
|
||||
int px = (rand() % (width - 4)) + 2;
|
||||
set(px , height - 2, 1.0f);
|
||||
set(px + 1, height - 2, 1.0f);
|
||||
set(px - 1, height - 2, 1.0f);
|
||||
set(px , height - 1, 1.0f);
|
||||
set(px + 1, height - 1, 1.0f);
|
||||
set(px - 1, height - 1, 1.0f);
|
||||
}
|
||||
|
||||
sleep_ms(20);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
struct blob_t {
|
||||
float x, y;
|
||||
float r;
|
||||
float dx, dy;
|
||||
};
|
||||
|
||||
constexpr int blob_count = 20;
|
||||
|
||||
int main() {
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
stellar_unicorn.init();
|
||||
stellar_unicorn.set_brightness(0.5);
|
||||
|
||||
// randomise blob start positions, directions, and size
|
||||
std::array<blob_t, blob_count> blobs;
|
||||
for(auto &blob : blobs) {
|
||||
blob.x = rand() % 16;
|
||||
blob.y = rand() % 16;
|
||||
blob.r = ((rand() % 40) / 10.0f) + 5.0f;
|
||||
blob.dx = ((rand() % 2) / 10.0f) - 0.05f;
|
||||
blob.dy = ((rand() % 3) / 10.0f) - 0.1f;
|
||||
}
|
||||
|
||||
float hue = 0.0f;
|
||||
|
||||
while(true) {
|
||||
// allow user to adjust brightness
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
uint start_ms = to_ms_since_boot(get_absolute_time());
|
||||
|
||||
// calculate the influence of each blob on the liquid based
|
||||
// on their distance to each pixel. this causes blobs to
|
||||
// "merge" into each other when we use fixed thresholds to
|
||||
// determine which colour to draw with
|
||||
float liquid[16][16] = {0.0f};
|
||||
for(auto &blob : blobs) {
|
||||
float r_sq = blob.r * blob.r;
|
||||
for(int y = 0; y < 16; y++) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
float d_sq = (x - blob.x) * (x - blob.x) + (y - blob.y) * (y - blob.y);
|
||||
if(d_sq <= r_sq) {
|
||||
// add this blobs influence to this pixel
|
||||
liquid[x][y] += 1.0f - (d_sq / r_sq);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// update the blob positions
|
||||
for(auto &blob : blobs) {
|
||||
blob.x += blob.dx;
|
||||
blob.y += blob.dy;
|
||||
|
||||
// if we hit the edge then bounce!
|
||||
if(blob.x < 0.0f || blob.x >= 11.0f) {
|
||||
blob.dx *= -1.0f;
|
||||
}
|
||||
if(blob.y < 0.0f || blob.y >= 53.0f) {
|
||||
blob.dy *= -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// rotate the hue
|
||||
hue += 0.001f;
|
||||
|
||||
// calculate dark, medium, and bright shades for rendering the
|
||||
// lava
|
||||
uint8_t dark_r, dark_g, dark_b;
|
||||
from_hsv(hue, 1.0f, 0.3f, dark_r, dark_g, dark_b);
|
||||
uint8_t mid_r, mid_g, mid_b;
|
||||
from_hsv(hue, 1.0f, 0.6f, mid_r, mid_g, mid_b);
|
||||
uint8_t bright_r, bright_g, bright_b;
|
||||
from_hsv(hue, 1.0f, 1.0f, bright_r, bright_g, bright_b);
|
||||
|
||||
// clear the canvas
|
||||
graphics.set_pen(0, 0, 0);
|
||||
graphics.clear();
|
||||
|
||||
// render the lava
|
||||
for(int y = 0; y < 16; y++) {
|
||||
for(int x = 0; x < 16; x++) {
|
||||
float v = liquid[x][y];
|
||||
|
||||
// select a colour for this pixel based on how much
|
||||
// "blobfluence" there is at this position in the liquid
|
||||
if(v >= 1.5f) {
|
||||
graphics.set_pen(bright_r, bright_g, bright_b);
|
||||
graphics.pixel(Point(y, x));
|
||||
}else if(v >= 1.25f) {
|
||||
graphics.set_pen(mid_r, mid_g, mid_b);
|
||||
graphics.pixel(Point(y, x));
|
||||
}else if(v >= 1.0f) {
|
||||
graphics.set_pen(dark_r, dark_g, dark_b);
|
||||
graphics.pixel(Point(y, x));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint end_ms = to_ms_since_boot(get_absolute_time());
|
||||
|
||||
printf("rendering took %dms\n", end_ms - start_ms);
|
||||
|
||||
stellar_unicorn.update(&graphics);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,184 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
void text(std::string t, Point p, float s = 1.0f, float a = 1.0f) {
|
||||
int w = graphics.measure_text(t, s);
|
||||
p.x += (53 / 2) - (w / 2);
|
||||
p.y += (11 / 2);
|
||||
graphics.text(t, Point(p.x, p.y), -1, s, a);
|
||||
//graphics.text(t, Point(p.x + 1, p.y), -1, s, a);
|
||||
//graphics.text(t, Point(p.x + 1, p.y + 1), -1, s, a);
|
||||
//graphics.text(t, Point(p.x, p.y + 1), -1, s, a);
|
||||
}
|
||||
|
||||
struct star_t {
|
||||
float dx, dy, x, y, a;
|
||||
|
||||
uint8_t brightness() {
|
||||
int b = a / 5;
|
||||
return b > 15 ? 15 : b;
|
||||
}
|
||||
};
|
||||
|
||||
void init_star(star_t &s) {
|
||||
s.x = ((rand() % 100) / 5.0f) - 10.0f;
|
||||
s.y = ((rand() % 100) / 10.0f) - 5.0f;
|
||||
|
||||
s.dx = s.x / 10.0f;
|
||||
s.dy = s.y / 10.0f;
|
||||
s.a = 0;
|
||||
}
|
||||
|
||||
void step_star(star_t &s) {
|
||||
s.x += s.dx;
|
||||
s.y += s.dy;
|
||||
s.a++;
|
||||
|
||||
if(s.a > 100) {
|
||||
init_star(s);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
uint8_t hue_map[16][3];
|
||||
for(int i = 0; i < 16; i++) {
|
||||
from_hsv(i / 16.0f, 1.0f, 1.0f, hue_map[i][0], hue_map[i][1], hue_map[i][2]);
|
||||
}
|
||||
|
||||
star_t stars[100];
|
||||
for(int i = 0; i < 100; i++) {
|
||||
init_star(stars[i]);
|
||||
stars[i].a = i;
|
||||
}
|
||||
|
||||
gpio_set_function(28, GPIO_FUNC_SIO);
|
||||
gpio_set_dir(28, GPIO_OUT);
|
||||
|
||||
for(int i = 0; i < 10; i++) {
|
||||
gpio_put(28, !gpio_get(28));
|
||||
sleep_ms(100);
|
||||
}
|
||||
sleep_ms(1000);
|
||||
|
||||
gpio_put(28,true);
|
||||
|
||||
stellar_unicorn.init();
|
||||
|
||||
|
||||
|
||||
float i = 0;
|
||||
|
||||
float hue_offset = 0.0f;
|
||||
|
||||
bool animate = true;
|
||||
|
||||
float stripe_width = 3.0f;
|
||||
float speed = 1.0f;
|
||||
float curve = 0.0f;
|
||||
|
||||
while(true) {
|
||||
|
||||
if(animate) {
|
||||
i += speed;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_VOLUME_UP)) {
|
||||
curve += 0.05;
|
||||
if(hue_offset > 1.0f) hue_offset = 1.0f;
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_VOLUME_DOWN)) {
|
||||
curve -= 0.05;
|
||||
if(hue_offset < 0.0f) hue_offset = 0.0f;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_SLEEP)) {
|
||||
animate = false;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_A)) {
|
||||
speed += 0.05f;
|
||||
speed = speed >= 10.0f ? 10.0f : speed;
|
||||
animate = true;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_B)) {
|
||||
speed -= 0.05f;
|
||||
speed = speed <= 0.0f ? 0.0f : speed;
|
||||
animate = true;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_C)) {
|
||||
stripe_width += 0.05f;
|
||||
stripe_width = stripe_width >= 10.0f ? 10.0f : stripe_width;
|
||||
}
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_D)) {
|
||||
stripe_width -= 0.05f;
|
||||
stripe_width = stripe_width <= 1.0f ? 1.0f : stripe_width;
|
||||
}
|
||||
|
||||
for(int x = 0; x < 16; x++) {
|
||||
for(int y = 0; y < 16; y++) {
|
||||
int v = ((sin((x + y) / stripe_width + (sin((y * 3.1415927f * 2.0f) / 11.0f) * curve) + i / 15.0f) + 1.5f) / 2.5f) * 255.0f;
|
||||
|
||||
uint8_t r = (hue_map[x][0] * v) / 256;
|
||||
uint8_t g = (hue_map[x][1] * v) / 256;
|
||||
uint8_t b = (hue_map[x][2] * v) / 256;
|
||||
|
||||
graphics.set_pen(r, g, b);
|
||||
graphics.pixel(Point(x, y));
|
||||
}
|
||||
}
|
||||
stellar_unicorn.update(&graphics);
|
||||
|
||||
printf("%d\n", stellar_unicorn.light());
|
||||
sleep_ms(20);
|
||||
}
|
||||
|
||||
|
||||
|
||||
printf("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
void text(std::string t, Point p, float s = 1.0f, float a = 1.0f) {
|
||||
int w = graphics.measure_text(t, s);
|
||||
p.x += (16 / 2) - (w / 2);
|
||||
p.y += (16 / 2);
|
||||
graphics.text(t, Point(p.x, p.y), -1, s, a);
|
||||
graphics.text(t, Point(p.x + 1, p.y), -1, s, a);
|
||||
graphics.text(t, Point(p.x + 1, p.y + 1), -1, s, a);
|
||||
graphics.text(t, Point(p.x, p.y + 1), -1, s, a);
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
uint8_t hue_map[16][3];
|
||||
for(int i = 0; i < 16; i++) {
|
||||
from_hsv(i / 16.0f, 1.0f, 0.5f, hue_map[i][0], hue_map[i][1], hue_map[i][2]);
|
||||
}
|
||||
|
||||
stellar_unicorn.init();
|
||||
|
||||
graphics.set_font("sans");
|
||||
uint i = 0;
|
||||
|
||||
while(true) {
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
graphics.set_pen(0, 0, 0);
|
||||
graphics.clear();
|
||||
|
||||
float s = 0.4f;//0.65f + (sin(i / 25.0f) * 0.15f);
|
||||
float a = 1.0f;// (sin(i / 25.0f) * 100.0f);
|
||||
|
||||
float x = (sin((i) / 50.0f) * 45.0f);
|
||||
float y = (cos((i) / 40.0f) * 2.5f);
|
||||
graphics.set_pen(255, 255, 255);
|
||||
text("Galactic Unicorn", Point(x, y), s, a);
|
||||
uint8_t *p = (uint8_t *)graphics.frame_buffer;
|
||||
for(size_t i = 0; i < 16 * 16; i++) {
|
||||
int x = i % 16;
|
||||
int y = i / 16;
|
||||
uint r = *p++;
|
||||
uint g = *p++;
|
||||
uint b = *p++;
|
||||
p++;
|
||||
|
||||
if(r > 0) {
|
||||
r = hue_map[x][0];
|
||||
g = hue_map[x][1];
|
||||
b = hue_map[x][2];
|
||||
}
|
||||
|
||||
graphics.set_pen(r, g, b);
|
||||
graphics.pixel(Point(x, y));
|
||||
}
|
||||
|
||||
stellar_unicorn.update(&graphics);
|
||||
}
|
||||
|
||||
printf("done\n");
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include "pico/stdlib.h"
|
||||
|
||||
#include "libraries/pico_graphics/pico_graphics.hpp"
|
||||
#include "stellar_unicorn.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
|
||||
PicoGraphics_PenRGB888 graphics(16, 16, nullptr);
|
||||
StellarUnicorn stellar_unicorn;
|
||||
|
||||
std::string message = "Pirate. Monkey. Robot. Ninja.";
|
||||
|
||||
// HSV Conversion expects float inputs in the range of 0.00-1.00 for each channel
|
||||
// Outputs are rgb in the range 0-255 for each channel
|
||||
void from_hsv(float h, float s, float v, uint8_t &r, uint8_t &g, uint8_t &b) {
|
||||
float i = floor(h * 6.0f);
|
||||
float f = h * 6.0f - i;
|
||||
v *= 255.0f;
|
||||
uint8_t p = v * (1.0f - s);
|
||||
uint8_t q = v * (1.0f - f * s);
|
||||
uint8_t t = v * (1.0f - (1.0f - f) * s);
|
||||
|
||||
switch (int(i) % 6) {
|
||||
case 0: r = v; g = t; b = p; break;
|
||||
case 1: r = q; g = v; b = p; break;
|
||||
case 2: r = p; g = v; b = t; break;
|
||||
case 3: r = p; g = q; b = v; break;
|
||||
case 4: r = t; g = p; b = v; break;
|
||||
case 5: r = v; g = p; b = q; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
stdio_init_all();
|
||||
|
||||
stellar_unicorn.init();
|
||||
|
||||
float scroll = -16.0f;
|
||||
|
||||
while(true) {
|
||||
//uint time_ms = to_ms_since_boot(get_absolute_time());
|
||||
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_UP)) {
|
||||
stellar_unicorn.adjust_brightness(+0.01);
|
||||
}
|
||||
if(stellar_unicorn.is_pressed(stellar_unicorn.SWITCH_BRIGHTNESS_DOWN)) {
|
||||
stellar_unicorn.adjust_brightness(-0.01);
|
||||
}
|
||||
|
||||
int width = graphics.measure_text(message, 1);
|
||||
scroll += 0.125f;
|
||||
|
||||
if(scroll > width) {
|
||||
scroll = -16.0f;
|
||||
}
|
||||
|
||||
graphics.set_pen(0, 0, 0);
|
||||
graphics.clear();
|
||||
|
||||
uint8_t r = 0, g = 0, b = 0;
|
||||
from_hsv(scroll / 100.0f, 1.0f, 0.5f, r, g, b);
|
||||
graphics.set_pen(r, g, b);
|
||||
graphics.text(message, Point(0 - scroll, 5), -1, 0.55);
|
||||
|
||||
stellar_unicorn.update(&graphics);
|
||||
|
||||
sleep_ms(10);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -32,11 +32,11 @@ ST7789 st7789(
|
|||
|
||||
PicoGraphics_PenRGB332 graphics(st7789.width, st7789.height, nullptr);
|
||||
|
||||
Button button_a(Tufty2040::A);
|
||||
Button button_b(Tufty2040::B);
|
||||
Button button_c(Tufty2040::C);
|
||||
Button button_up(Tufty2040::UP);
|
||||
Button button_down(Tufty2040::DOWN);
|
||||
Button button_a(Tufty2040::A, Polarity::ACTIVE_HIGH);
|
||||
Button button_b(Tufty2040::B, Polarity::ACTIVE_HIGH);
|
||||
Button button_c(Tufty2040::C, Polarity::ACTIVE_HIGH);
|
||||
Button button_up(Tufty2040::UP, Polarity::ACTIVE_HIGH);
|
||||
Button button_down(Tufty2040::DOWN, Polarity::ACTIVE_HIGH);
|
||||
|
||||
uint32_t time() {
|
||||
absolute_time_t t = get_absolute_time();
|
||||
|
|
|
@ -2,6 +2,7 @@ add_subdirectory(hershey_fonts)
|
|||
add_subdirectory(bitmap_fonts)
|
||||
add_subdirectory(breakout_dotmatrix)
|
||||
add_subdirectory(breakout_encoder)
|
||||
add_subdirectory(breakout_encoder_wheel)
|
||||
add_subdirectory(breakout_ioexpander)
|
||||
add_subdirectory(breakout_ltr559)
|
||||
add_subdirectory(breakout_rgbmatrix5x5)
|
||||
|
@ -35,9 +36,11 @@ add_subdirectory(motor2040)
|
|||
add_subdirectory(inventor2040w)
|
||||
add_subdirectory(adcfft)
|
||||
add_subdirectory(jpegdec)
|
||||
add_subdirectory(pngdec)
|
||||
add_subdirectory(inky_frame)
|
||||
add_subdirectory(inky_frame_7)
|
||||
add_subdirectory(galactic_unicorn)
|
||||
add_subdirectory(gfx_pack)
|
||||
add_subdirectory(interstate75)
|
||||
add_subdirectory(cosmic_unicorn)
|
||||
add_subdirectory(stellar_unicorn)
|
||||
|
|
|
@ -47,7 +47,7 @@ void ADCFFT::init() {
|
|||
|
||||
// Initialize the ADC harware
|
||||
// (resets it, enables the clock, spins until the hardware is ready)
|
||||
adc_init();
|
||||
if (!(adc_hw->cs & ADC_CS_EN_BITS)) adc_init();
|
||||
|
||||
// Select analog mux input (0...3 are GPIO 26, 27, 28, 29; 4 is temp sensor)
|
||||
adc_select_input(adc_channel);
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
add_library(automation INTERFACE)
|
||||
|
||||
target_sources(automation INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/automation.cpp
|
||||
)
|
||||
|
||||
target_include_directories(automation INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
#include(${PIMORONI_PICO_PATH}/drivers/analog/analog.cmake)
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(automation INTERFACE pico_stdlib hardware_pwm hardware_i2c pimoroni_i2c analog)
|
||||
if(NOT TARGET analog)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/analog/analog.cmake)
|
||||
endif()
|
||||
|
||||
add_library(automation INTERFACE)
|
||||
|
||||
target_sources(automation INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/automation.cpp
|
||||
)
|
||||
|
||||
target_include_directories(automation INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(automation INTERFACE pico_stdlib hardware_pwm hardware_i2c pimoroni_i2c analog)
|
||||
|
|
|
@ -1,11 +1,23 @@
|
|||
set(LIB_NAME badger2040)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE bitmap_fonts hershey_fonts pico_stdlib hardware_pwm uc8151_legacy)
|
||||
if(NOT TARGET uc8151_legacy)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/uc8151_legacy/uc8151_legacy.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET bitmap_fonts)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../bitmap_fonts/bitmap_fonts.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET hershey_fonts)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../hershey_fonts/hershey_fonts.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME badger2040)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE bitmap_fonts hershey_fonts uc8151_legacy pico_stdlib hardware_pwm)
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
#include "bitmap_fonts.hpp"
|
||||
|
||||
namespace bitmap {
|
||||
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage) {
|
||||
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage, bool fixed_width) {
|
||||
if(c < 32 || c > 127 + 64) { // + 64 char remappings defined in unicode_sorta.hpp
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(fixed_width) {
|
||||
return font->max_width * scale;
|
||||
}
|
||||
|
||||
uint8_t char_index = c;
|
||||
|
||||
if(char_index > 127) {
|
||||
|
@ -21,7 +25,7 @@ namespace bitmap {
|
|||
return font->widths[char_index] * scale;
|
||||
}
|
||||
|
||||
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale, const uint8_t letter_spacing) {
|
||||
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale, const uint8_t letter_spacing, bool fixed_width) {
|
||||
int32_t text_width = 0;
|
||||
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;
|
||||
for(auto c : t) {
|
||||
|
@ -31,14 +35,14 @@ namespace bitmap {
|
|||
} else if (c == unicode_sorta::PAGE_195_START) {
|
||||
continue;
|
||||
}
|
||||
text_width += measure_character(font, c, scale, codepage);
|
||||
text_width += measure_character(font, c, scale, codepage, fixed_width);
|
||||
text_width += letter_spacing * scale;
|
||||
codepage = unicode_sorta::PAGE_195; // Reset back to default
|
||||
}
|
||||
return text_width;
|
||||
}
|
||||
|
||||
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale, unicode_sorta::codepage_t codepage) {
|
||||
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale, int32_t rotation, unicode_sorta::codepage_t codepage) {
|
||||
if(c < 32 || c > 127 + 64) { // + 64 char remappings defined in unicode_sorta.hpp
|
||||
return;
|
||||
}
|
||||
|
@ -85,7 +89,8 @@ namespace bitmap {
|
|||
uint8_t accent_offset = char_index < 65 ? offset_upper : offset_lower;
|
||||
|
||||
// Offset our y position to account for our column canvas being 32 pixels
|
||||
int y_offset = y - (8 * scale);
|
||||
// this gives us 8 "pixels" of headroom above the letters for diacritic marks
|
||||
int font_offset = (8 * scale);
|
||||
|
||||
// Iterate through each horizontal column of font (and accent) data
|
||||
for(uint8_t cx = 0; cx < font->widths[char_index]; cx++) {
|
||||
|
@ -94,6 +99,8 @@ namespace bitmap {
|
|||
// We shift the char down 8 pixels to make room for an accent above.
|
||||
uint32_t data = *d << 8;
|
||||
|
||||
int32_t o_x = cx * scale;
|
||||
|
||||
// For fonts that are taller than 8 pixels (up to 16) they need two bytes
|
||||
if(two_bytes_per_column) {
|
||||
d++;
|
||||
|
@ -109,7 +116,28 @@ namespace bitmap {
|
|||
// Draw the 32 pixel column
|
||||
for(uint8_t cy = 0; cy < 32; cy++) {
|
||||
if((1U << cy) & data) {
|
||||
rectangle(x + (cx * scale), y_offset + (cy * scale), scale, scale);
|
||||
int32_t o_y = cy * scale;
|
||||
int32_t px = 0;
|
||||
int32_t py = 0;
|
||||
switch (rotation) {
|
||||
case 0:
|
||||
px = x + o_x;
|
||||
py = y - font_offset + o_y;
|
||||
break;
|
||||
case 90:
|
||||
px = x + font_offset - o_y;
|
||||
py = y + o_x;
|
||||
break;
|
||||
case 180:
|
||||
px = x - o_x;
|
||||
py = y + font_offset - o_y;
|
||||
break;
|
||||
case 270:
|
||||
px = x - font_offset + o_y;
|
||||
py = y - o_x;
|
||||
break;
|
||||
}
|
||||
rectangle(px, py, scale, scale);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -119,10 +147,14 @@ namespace bitmap {
|
|||
}
|
||||
}
|
||||
|
||||
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing) {
|
||||
uint32_t co = 0, lo = 0; // character and line (if wrapping) offset
|
||||
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale, const uint8_t letter_spacing, bool fixed_width, int32_t rotation) {
|
||||
uint32_t char_offset = 0;
|
||||
uint32_t line_offset = 0; // line (if wrapping) offset
|
||||
unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195;
|
||||
|
||||
int32_t space_width = measure_character(font, ' ', scale, codepage, fixed_width);
|
||||
space_width += letter_spacing * scale;
|
||||
|
||||
size_t i = 0;
|
||||
while(i < t.length()) {
|
||||
// find length of current word
|
||||
|
@ -148,38 +180,53 @@ namespace bitmap {
|
|||
} else if (t[j] == unicode_sorta::PAGE_195_START) {
|
||||
continue;
|
||||
}
|
||||
word_width += measure_character(font, t[j], scale, codepage);
|
||||
word_width += measure_character(font, t[j], scale, codepage, fixed_width);
|
||||
word_width += letter_spacing * scale;
|
||||
codepage = unicode_sorta::PAGE_195;
|
||||
}
|
||||
|
||||
// if this word would exceed the wrap limit then
|
||||
// move to the next line
|
||||
if(co != 0 && co + word_width > (uint32_t)wrap) {
|
||||
co = 0;
|
||||
lo += (font->height + 1) * scale;
|
||||
if(char_offset != 0 && char_offset + word_width > (uint32_t)wrap) {
|
||||
char_offset = 0;
|
||||
line_offset += (font->height + 1) * scale;
|
||||
}
|
||||
|
||||
// draw word
|
||||
for(size_t j = i; j < next_break; j++) {
|
||||
for(size_t j = i; j < std::min(next_break + 1, t.length()); j++) {
|
||||
if (t[j] == unicode_sorta::PAGE_194_START) {
|
||||
codepage = unicode_sorta::PAGE_194;
|
||||
continue;
|
||||
} else if (t[j] == unicode_sorta::PAGE_195_START) {
|
||||
continue;
|
||||
}
|
||||
if (t[j] == '\n') {
|
||||
lo += (font->height + 1) * scale;
|
||||
co = 0;
|
||||
if (t[j] == '\n') { // Linebreak
|
||||
line_offset += (font->height + 1) * scale;
|
||||
char_offset = 0;
|
||||
} else if (t[j] == ' ') { // Space
|
||||
char_offset += space_width;
|
||||
} else {
|
||||
character(font, rectangle, t[j], x + co, y + lo, scale, codepage);
|
||||
co += measure_character(font, t[j], scale, codepage);
|
||||
co += letter_spacing * scale;
|
||||
switch(rotation) {
|
||||
case 0:
|
||||
character(font, rectangle, t[j], x + char_offset, y + line_offset, scale, rotation, codepage);
|
||||
break;
|
||||
case 90:
|
||||
character(font, rectangle, t[j], x - line_offset, y + char_offset, scale, rotation, codepage);
|
||||
break;
|
||||
case 180:
|
||||
character(font, rectangle, t[j], x - char_offset, y - line_offset, scale, rotation, codepage);
|
||||
break;
|
||||
case 270:
|
||||
character(font, rectangle, t[j], x + line_offset, y - char_offset, scale, rotation, codepage);
|
||||
break;
|
||||
}
|
||||
char_offset += measure_character(font, t[j], scale, codepage, fixed_width);
|
||||
char_offset += letter_spacing * scale;
|
||||
}
|
||||
codepage = unicode_sorta::PAGE_195;
|
||||
}
|
||||
|
||||
// move character offset to end of word and add a space
|
||||
co += font->widths[0] * scale;
|
||||
// move character offset
|
||||
i = next_break += 1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,9 @@ namespace bitmap {
|
|||
|
||||
typedef std::function<void(int32_t x, int32_t y, int32_t w, int32_t h)> rect_func;
|
||||
|
||||
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
|
||||
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
|
||||
int32_t measure_character(const font_t *font, const char c, const uint8_t scale, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195, bool fixed_width = false);
|
||||
int32_t measure_text(const font_t *font, const std::string_view &t, const uint8_t scale = 2, const uint8_t letter_spacing = 1, bool fixed_width = false);
|
||||
|
||||
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
|
||||
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1);
|
||||
void character(const font_t *font, rect_func rectangle, const char c, const int32_t x, const int32_t y, const uint8_t scale = 2, int32_t rotation = 0, unicode_sorta::codepage_t codepage = unicode_sorta::PAGE_195);
|
||||
void text(const font_t *font, rect_func rectangle, const std::string_view &t, const int32_t x, const int32_t y, const int32_t wrap, const uint8_t scale = 2, const uint8_t letter_spacing = 1, bool fixed_width = false, int32_t rotation = 0);
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
const bitmap::font_t font8 {
|
||||
.height = 8,
|
||||
.max_width = 6,
|
||||
.max_width = 5,
|
||||
.widths = {
|
||||
3, 1, 3, 5, 4, 4, 4, 1, 3, 3, 3, 3, 2, 3, 2, 4,
|
||||
4, 3, 4, 4, 4, 4, 4, 4, 4, 4, 1, 2, 3, 3, 3, 4,
|
||||
|
@ -17,123 +17,123 @@ const bitmap::font_t font8 {
|
|||
5, 4, 4, 5, 4, 4, 4, 4, 3
|
||||
},
|
||||
.data = {
|
||||
0x00,0x00,0x00,0x00,0x00,0x00, //
|
||||
0x5f,0x00,0x00,0x00,0x00,0x00, // !
|
||||
0x03,0x00,0x03,0x00,0x00,0x00, // "
|
||||
0x28,0x7c,0x28,0x7c,0x28,0x00, // #
|
||||
0x24,0x7a,0x2f,0x12,0x00,0x00, // $
|
||||
0x66,0x10,0x08,0x66,0x00,0x00, // %
|
||||
0x36,0x49,0x49,0x7c,0x00,0x00, // &
|
||||
0x03,0x00,0x00,0x00,0x00,0x00, // '
|
||||
0x1c,0x22,0x41,0x00,0x00,0x00, // (
|
||||
0x41,0x22,0x1c,0x00,0x00,0x00, // )
|
||||
0x54,0x38,0x54,0x00,0x00,0x00, // *
|
||||
0x10,0x38,0x10,0x00,0x00,0x00, // +
|
||||
0x80,0x60,0x00,0x00,0x00,0x00, // ,
|
||||
0x10,0x10,0x10,0x00,0x00,0x00, // -
|
||||
0x60,0x60,0x00,0x00,0x00,0x00, // .
|
||||
0x60,0x18,0x06,0x01,0x00,0x00, // /
|
||||
0x3e,0x41,0x41,0x3e,0x00,0x00, // 0
|
||||
0x42,0x7f,0x40,0x00,0x00,0x00, // 1
|
||||
0x62,0x51,0x49,0x46,0x00,0x00, // 2
|
||||
0x21,0x49,0x4d,0x33,0x00,0x00, // 3
|
||||
0x18,0x16,0x11,0x7f,0x00,0x00, // 4
|
||||
0x4f,0x49,0x49,0x31,0x00,0x00, // 5
|
||||
0x3c,0x4a,0x49,0x30,0x00,0x00, // 6
|
||||
0x01,0x61,0x19,0x07,0x00,0x00, // 7
|
||||
0x36,0x49,0x49,0x36,0x00,0x00, // 8
|
||||
0x06,0x49,0x29,0x1e,0x00,0x00, // 9
|
||||
0x33,0x00,0x00,0x00,0x00,0x00, // :
|
||||
0x80,0x6c,0x00,0x00,0x00,0x00, // ;
|
||||
0x10,0x28,0x44,0x00,0x00,0x00, // <
|
||||
0x28,0x28,0x28,0x00,0x00,0x00, // =
|
||||
0x44,0x28,0x10,0x00,0x00,0x00, // >
|
||||
0x02,0x51,0x09,0x06,0x00,0x00, // ?
|
||||
0x3e,0x49,0x55,0x5e,0x00,0x00, // @
|
||||
0x7e,0x09,0x09,0x7e,0x00,0x00, // A
|
||||
0x7f,0x49,0x49,0x36,0x00,0x00, // B
|
||||
0x3e,0x41,0x41,0x22,0x00,0x00, // C
|
||||
0x7f,0x41,0x41,0x3e,0x00,0x00, // D
|
||||
0x7f,0x49,0x49,0x41,0x00,0x00, // E
|
||||
0x7f,0x09,0x09,0x01,0x00,0x00, // F
|
||||
0x3e,0x41,0x49,0x79,0x00,0x00, // G
|
||||
0x7f,0x08,0x08,0x7f,0x00,0x00, // H
|
||||
0x41,0x7f,0x41,0x00,0x00,0x00, // I
|
||||
0x30,0x40,0x40,0x3f,0x00,0x00, // J
|
||||
0x7f,0x08,0x14,0x63,0x00,0x00, // K
|
||||
0x7f,0x40,0x40,0x40,0x00,0x00, // L
|
||||
0x7f,0x02,0x04,0x02,0x7f,0x00, // M
|
||||
0x7f,0x02,0x04,0x7f,0x00,0x00, // N
|
||||
0x3e,0x41,0x41,0x3e,0x00,0x00, // O
|
||||
0x7f,0x09,0x09,0x06,0x00,0x00, // P
|
||||
0x3e,0x41,0x21,0x5e,0x00,0x00, // Q
|
||||
0x7f,0x09,0x19,0x66,0x00,0x00, // R
|
||||
0x46,0x49,0x49,0x31,0x00,0x00, // S
|
||||
0x01,0x01,0x7f,0x01,0x01,0x00, // T
|
||||
0x3f,0x40,0x40,0x3f,0x00,0x00, // U
|
||||
0x7f,0x40,0x20,0x1f,0x00,0x00, // V
|
||||
0x3f,0x40,0x20,0x40,0x3f,0x00, // W
|
||||
0x77,0x08,0x08,0x77,0x00,0x00, // X
|
||||
0x47,0x48,0x48,0x3f,0x00,0x00, // Y
|
||||
0x71,0x49,0x45,0x43,0x00,0x00, // Z
|
||||
0x7f,0x41,0x00,0x00,0x00,0x00, // [
|
||||
0x01,0x06,0x18,0x60,0x00,0x00, // "\"
|
||||
0x41,0x7f,0x00,0x00,0x00,0x00, // ]
|
||||
0x04,0x02,0x04,0x00,0x00,0x00, // ^
|
||||
0x40,0x40,0x40,0x00,0x00,0x00, // _
|
||||
0x01,0x01,0x00,0x00,0x00,0x00, // `
|
||||
0x20,0x54,0x54,0x78,0x00,0x00, // a
|
||||
0x7f,0x44,0x44,0x38,0x00,0x00, // b
|
||||
0x38,0x44,0x44,0x28,0x00,0x00, // c
|
||||
0x38,0x44,0x44,0x7f,0x00,0x00, // d
|
||||
0x38,0x54,0x54,0x58,0x00,0x00, // e
|
||||
0x7e,0x09,0x09,0x02,0x00,0x00, // f
|
||||
0x18,0xa4,0xa4,0x7c,0x00,0x00, // g
|
||||
0x7f,0x04,0x04,0x78,0x00,0x00, // h
|
||||
0x04,0x7d,0x40,0x00,0x00,0x00, // i
|
||||
0x60,0x80,0x80,0x7d,0x00,0x00, // j
|
||||
0x7f,0x10,0x28,0x44,0x00,0x00, // k
|
||||
0x01,0x7f,0x40,0x00,0x00,0x00, // l
|
||||
0x7c,0x04,0x78,0x04,0x78,0x00, // m
|
||||
0x7c,0x04,0x04,0x78,0x00,0x00, // n
|
||||
0x38,0x44,0x44,0x38,0x00,0x00, // o
|
||||
0xfc,0x24,0x24,0x18,0x00,0x00, // p
|
||||
0x18,0x24,0x24,0xfc,0x00,0x00, // q
|
||||
0x7c,0x08,0x04,0x04,0x00,0x00, // r
|
||||
0x48,0x54,0x54,0x24,0x00,0x00, // s
|
||||
0x3e,0x44,0x44,0x20,0x00,0x00, // t
|
||||
0x3c,0x40,0x40,0x7c,0x00,0x00, // u
|
||||
0x7c,0x40,0x20,0x1c,0x00,0x00, // v
|
||||
0x3c,0x40,0x20,0x40,0x3c,0x00, // w
|
||||
0x6c,0x10,0x10,0x6c,0x00,0x00, // x
|
||||
0x1c,0xa0,0xa0,0x7c,0x00,0x00, // y
|
||||
0x64,0x54,0x4c,0x00,0x00,0x00, // z
|
||||
0x08,0x3e,0x41,0x00,0x00,0x00, // {
|
||||
0x7f,0x00,0x00,0x00,0x00,0x00, // |
|
||||
0x41,0x3e,0x08,0x00,0x00,0x00, // }
|
||||
0x08,0x04,0x08,0x04,0x00,0x00, // ~
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00, //
|
||||
0x5f,0x00,0x00,0x00,0x00, // !
|
||||
0x03,0x00,0x03,0x00,0x00, // "
|
||||
0x28,0x7c,0x28,0x7c,0x28, // #
|
||||
0x24,0x7a,0x2f,0x12,0x00, // $
|
||||
0x66,0x10,0x08,0x66,0x00, // %
|
||||
0x36,0x49,0x49,0x7c,0x00, // &
|
||||
0x03,0x00,0x00,0x00,0x00, // '
|
||||
0x1c,0x22,0x41,0x00,0x00, // (
|
||||
0x41,0x22,0x1c,0x00,0x00, // )
|
||||
0x54,0x38,0x54,0x00,0x00, // *
|
||||
0x10,0x38,0x10,0x00,0x00, // +
|
||||
0x80,0x60,0x00,0x00,0x00, // ,
|
||||
0x10,0x10,0x10,0x00,0x00, // -
|
||||
0x60,0x60,0x00,0x00,0x00, // .
|
||||
0x60,0x18,0x06,0x01,0x00, // /
|
||||
0x3e,0x41,0x41,0x3e,0x00, // 0
|
||||
0x42,0x7f,0x40,0x00,0x00, // 1
|
||||
0x62,0x51,0x49,0x46,0x00, // 2
|
||||
0x21,0x49,0x4d,0x33,0x00, // 3
|
||||
0x18,0x16,0x11,0x7f,0x00, // 4
|
||||
0x4f,0x49,0x49,0x31,0x00, // 5
|
||||
0x3c,0x4a,0x49,0x30,0x00, // 6
|
||||
0x01,0x61,0x19,0x07,0x00, // 7
|
||||
0x36,0x49,0x49,0x36,0x00, // 8
|
||||
0x06,0x49,0x29,0x1e,0x00, // 9
|
||||
0x33,0x00,0x00,0x00,0x00, // :
|
||||
0x80,0x6c,0x00,0x00,0x00, // ;
|
||||
0x10,0x28,0x44,0x00,0x00, // <
|
||||
0x28,0x28,0x28,0x00,0x00, // =
|
||||
0x44,0x28,0x10,0x00,0x00, // >
|
||||
0x02,0x51,0x09,0x06,0x00, // ?
|
||||
0x3e,0x49,0x55,0x5e,0x00, // @
|
||||
0x7e,0x09,0x09,0x7e,0x00, // A
|
||||
0x7f,0x49,0x49,0x36,0x00, // B
|
||||
0x3e,0x41,0x41,0x22,0x00, // C
|
||||
0x7f,0x41,0x41,0x3e,0x00, // D
|
||||
0x7f,0x49,0x49,0x41,0x00, // E
|
||||
0x7f,0x09,0x09,0x01,0x00, // F
|
||||
0x3e,0x41,0x49,0x79,0x00, // G
|
||||
0x7f,0x08,0x08,0x7f,0x00, // H
|
||||
0x41,0x7f,0x41,0x00,0x00, // I
|
||||
0x30,0x40,0x40,0x3f,0x00, // J
|
||||
0x7f,0x08,0x14,0x63,0x00, // K
|
||||
0x7f,0x40,0x40,0x40,0x00, // L
|
||||
0x7f,0x02,0x04,0x02,0x7f, // M
|
||||
0x7f,0x02,0x04,0x7f,0x00, // N
|
||||
0x3e,0x41,0x41,0x3e,0x00, // O
|
||||
0x7f,0x09,0x09,0x06,0x00, // P
|
||||
0x3e,0x41,0x21,0x5e,0x00, // Q
|
||||
0x7f,0x09,0x19,0x66,0x00, // R
|
||||
0x46,0x49,0x49,0x31,0x00, // S
|
||||
0x01,0x01,0x7f,0x01,0x01, // T
|
||||
0x3f,0x40,0x40,0x3f,0x00, // U
|
||||
0x7f,0x40,0x20,0x1f,0x00, // V
|
||||
0x3f,0x40,0x20,0x40,0x3f, // W
|
||||
0x77,0x08,0x08,0x77,0x00, // X
|
||||
0x47,0x48,0x48,0x3f,0x00, // Y
|
||||
0x71,0x49,0x45,0x43,0x00, // Z
|
||||
0x7f,0x41,0x00,0x00,0x00, // [
|
||||
0x01,0x06,0x18,0x60,0x00, // "\"
|
||||
0x41,0x7f,0x00,0x00,0x00, // ]
|
||||
0x04,0x02,0x04,0x00,0x00, // ^
|
||||
0x40,0x40,0x40,0x00,0x00, // _
|
||||
0x01,0x01,0x00,0x00,0x00, // `
|
||||
0x20,0x54,0x54,0x78,0x00, // a
|
||||
0x7f,0x44,0x44,0x38,0x00, // b
|
||||
0x38,0x44,0x44,0x28,0x00, // c
|
||||
0x38,0x44,0x44,0x7f,0x00, // d
|
||||
0x38,0x54,0x54,0x58,0x00, // e
|
||||
0x7e,0x09,0x09,0x02,0x00, // f
|
||||
0x18,0xa4,0xa4,0x7c,0x00, // g
|
||||
0x7f,0x04,0x04,0x78,0x00, // h
|
||||
0x04,0x7d,0x40,0x00,0x00, // i
|
||||
0x60,0x80,0x80,0x7d,0x00, // j
|
||||
0x7f,0x10,0x28,0x44,0x00, // k
|
||||
0x01,0x7f,0x40,0x00,0x00, // l
|
||||
0x7c,0x04,0x78,0x04,0x78, // m
|
||||
0x7c,0x04,0x04,0x78,0x00, // n
|
||||
0x38,0x44,0x44,0x38,0x00, // o
|
||||
0xfc,0x24,0x24,0x18,0x00, // p
|
||||
0x18,0x24,0x24,0xfc,0x00, // q
|
||||
0x7c,0x08,0x04,0x04,0x00, // r
|
||||
0x48,0x54,0x54,0x24,0x00, // s
|
||||
0x3e,0x44,0x44,0x20,0x00, // t
|
||||
0x3c,0x40,0x40,0x7c,0x00, // u
|
||||
0x7c,0x40,0x20,0x1c,0x00, // v
|
||||
0x3c,0x40,0x20,0x40,0x3c, // w
|
||||
0x6c,0x10,0x10,0x6c,0x00, // x
|
||||
0x1c,0xa0,0xa0,0x7c,0x00, // y
|
||||
0x64,0x54,0x4c,0x00,0x00, // z
|
||||
0x08,0x3e,0x41,0x00,0x00, // {
|
||||
0x7f,0x00,0x00,0x00,0x00, // |
|
||||
0x41,0x3e,0x08,0x00,0x00, // }
|
||||
0x08,0x04,0x08,0x04,0x00, // ~
|
||||
0x00,0x00,0x00,0x00,0x00,
|
||||
// Extra
|
||||
0x7e,0x09,0x7f,0x49,0x49,0x00, // Æ
|
||||
0x7e,0x24,0x24,0x18,0x00,0x00, // Þ
|
||||
0x7e,0x09,0x49,0x36,0x00,0x00, // ß
|
||||
0x20,0x54,0x78,0x54,0x58,0x00, // æ
|
||||
0x7f,0x24,0x24,0x18,0x00,0x00, // þ
|
||||
0x08,0x7e,0x49,0x41,0x00,0x00, // £
|
||||
0x47,0x48,0x48,0x3f,0x00,0x00, // ¥
|
||||
0x38,0x44,0x44,0x28,0x00,0x00, // ©
|
||||
0x02,0x05,0x02,0x00,0x00,0x00, // °
|
||||
0x7e,0x09,0x7f,0x49,0x49, // Æ
|
||||
0x7e,0x24,0x24,0x18,0x00, // Þ
|
||||
0x7e,0x09,0x49,0x36,0x00, // ß
|
||||
0x20,0x54,0x78,0x54,0x58, // æ
|
||||
0x7f,0x24,0x24,0x18,0x00, // þ
|
||||
0x08,0x7e,0x49,0x41,0x00, // £
|
||||
0x47,0x48,0x48,0x3f,0x00, // ¥
|
||||
0x38,0x44,0x44,0x28,0x00, // ©
|
||||
0x02,0x05,0x02,0x00,0x00, // °
|
||||
// Accents + Offsets
|
||||
// All chars are shifted 8px down into a 32 pixel canvas for combining with accents.
|
||||
// Accent shift values (the first two numbers in each line below) move the accent down to meet them.
|
||||
// These are the shift values for lower and UPPER case letters respectively.
|
||||
6,4, 0x00,0x00,0x01,0x02,0x00,0x00, // Grave
|
||||
6,4, 0x00,0x00,0x02,0x01,0x00,0x00, // Acute
|
||||
6,4, 0x00,0x02,0x01,0x02,0x00,0x00, // Circumflex
|
||||
6,4, 0x00,0x01,0x02,0x01,0x02,0x00, // Tilde
|
||||
6,4, 0x00,0x01,0x00,0x01,0x00,0x00, // Diaresis
|
||||
6,4, 0x00,0x02,0x05,0x02,0x00,0x00, // Ring Above
|
||||
6,4, 0x00,0x80,0x40,0x00,0x00,0x00, // Stroke
|
||||
9,9, 0x00,0x00,0xa0,0x40,0x00,0x00 // Cedilla
|
||||
6,4, 0x00,0x00,0x01,0x02,0x00, // Grave
|
||||
6,4, 0x00,0x00,0x02,0x01,0x00, // Acute
|
||||
6,4, 0x00,0x02,0x01,0x02,0x00, // Circumflex
|
||||
6,4, 0x00,0x01,0x02,0x01,0x02, // Tilde
|
||||
6,4, 0x00,0x01,0x00,0x01,0x00, // Diaresis
|
||||
6,4, 0x00,0x02,0x05,0x02,0x00, // Ring Above
|
||||
6,4, 0x00,0x80,0x40,0x00,0x00, // Stroke
|
||||
9,9, 0x00,0x00,0xa0,0x40,0x00 // Cedilla
|
||||
}
|
||||
};
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET as7262)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/as7262/as7262.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_as7262)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET bh1745)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/bh1745/bh1745.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_bh1745)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET ltp305)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ltp305/ltp305.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_dotmatrix)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET ioexpander)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ioexpander/ioexpander.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_encoder)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
include(breakout_encoder_wheel.cmake)
|
|
@ -0,0 +1,334 @@
|
|||
# RGB Encoder Wheel Breakout (C++) <!-- omit in toc -->
|
||||
|
||||
This is the C++ library reference for the [Pimoroni RGB Encoder Wheel Breakout](https://shop.pimoroni.com/products/rgb-encoder-wheel-breakout).
|
||||
|
||||
|
||||
## Table of Content <!-- omit in toc -->
|
||||
- [Getting Started](#getting-started)
|
||||
- [Reading the Buttons](#reading-the-buttons)
|
||||
- [Reading the Encoder](#reading-the-encoder)
|
||||
- [Count and Angle](#count-and-angle)
|
||||
- [Count Delta](#count-delta)
|
||||
- [Step and Turn](#step-and-turn)
|
||||
- [Changing the Direction](#changing-the-direction)
|
||||
- [Resetting to Zero](#resetting-to-zero)
|
||||
- [LEDs](#leds)
|
||||
- [Setting an LED](#setting-an-led)
|
||||
- [RGB](#rgb)
|
||||
- [HSV](#hsv)
|
||||
- [Clear all LEDs](#clear-all-leds)
|
||||
- [Showing](#showing)
|
||||
- [GPIOs](#gpios)
|
||||
- [Setup](#setup)
|
||||
- [Mode](#mode)
|
||||
- [As Input or ADC](#as-input-or-adc)
|
||||
- [As Output](#as-output)
|
||||
- [As PWM](#as-pwm)
|
||||
- [Delayed Loading](#delayed-loading)
|
||||
- [Limitations](#limitations)
|
||||
- [Function Reference](#function-reference)
|
||||
- [Constants Reference](#constants-reference)
|
||||
- [Address Constants](#address-constants)
|
||||
- [Value Constants](#value-constants)
|
||||
- [Button Constants](#button-constants)
|
||||
- [GPIO Constants](#gpio-constants)
|
||||
- [Count Constants](#count-constants)
|
||||
|
||||
|
||||
## Getting Started
|
||||
|
||||
To start coding for your Encoder Wheel breakout, you will first need to create an object for accessing the I2C bus that the breakout is connected to. The easiest way to do this is via the `PimoroniI2C` class, with one of the handy pin constants from `pimoroni`, like so:
|
||||
|
||||
```c++
|
||||
#include "pimoroni_i2c.hpp"
|
||||
using namespace pimoroni;
|
||||
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
```
|
||||
|
||||
This creates a `i2c` object that can be passed into the Encoder Wheel's class as part of its creation:
|
||||
```c++
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
using namespace encoderwheel;
|
||||
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
```
|
||||
|
||||
The above lines of code import the `BreakoutEncoderWheel` class and create an instance of it, called `wheel`. This will be used in the rest of the examples going forward.
|
||||
|
||||
|
||||
## Reading the Buttons
|
||||
|
||||
EncoderWheel has five buttons, covering up, down, left, right, and centre. These can be read using the `.pressed(button)` function, which accepts a button number between `0` and `4`. For convenience, each button can be referred to using these constants:
|
||||
|
||||
* `UP` = `0`
|
||||
* `DOWN` = `1`
|
||||
* `LEFT` = `2`
|
||||
* `RIGHT` = `3`
|
||||
* `CENTRE` = `4`
|
||||
|
||||
For example, to read the centre button you would write:
|
||||
|
||||
```c++
|
||||
bool centre_state = wheel.pressed(CENTRE);
|
||||
```
|
||||
|
||||
You can also get the number of buttons using the `NUM_BUTTONS` constant.
|
||||
|
||||
|
||||
## Reading the Encoder
|
||||
|
||||
Within the directional buttons of the Encoder Wheel breakout is a rotary encoder with 24 counts per revolution.
|
||||
|
||||
### Count and Angle
|
||||
|
||||
The current count can be read by calling `.count()`. It can also be read back as either the number of `.revolutions()` of the encoder, or the angle in `.degrees()` or `.radians()`.
|
||||
|
||||
Be aware that the count is stored as an integer, if it is continually increased or decreased it will eventually wrap at `+32767` and `-32768`. This will cause a jump in the returned by `.revolutions()`, `degrees()` and `.radians()`, that will need handling by your code.
|
||||
|
||||
|
||||
### Count Delta
|
||||
|
||||
Often you are not interested in the exact count that the encoder is at, but rather if the count has changed since the last time you checked. This change can be read by calling `.delta()` at regular intervals. The returned value can then be used with a check in code, for the value being non-zero.
|
||||
|
||||
|
||||
### Step and Turn
|
||||
|
||||
Sometimes it can be useful to know the encoder's position in the form of which step it is at and how many turns have occurred. The current step can be read by calling `.step()`, which returns a value from `0` to `23`, and the number of turns can be read by calling `.turn()`.
|
||||
|
||||
These functions differ from reading the `.count()` or `.revolutions()` by using separate counters, and so avoid the wrapping issue that these functions experience.
|
||||
|
||||
|
||||
### Changing the Direction
|
||||
|
||||
The counting direction of an encoder can be changed by calling `.direction(REVERSED_DIR)` at any time in code. The `REVERSED_DIR` constant comes from `pimoroni_common.hpp`. There is also a `NORMAL_DIR` constant, though this is the default.
|
||||
|
||||
|
||||
### Resetting to Zero
|
||||
|
||||
There are times where an encoder's count (and related values) need to be reset back to zero. This can be done by calling `.zero()`.
|
||||
|
||||
|
||||
## LEDs
|
||||
|
||||
The Encoder Wheel breakout features 24 RGB LEDs arranged in a ring around the wheel. This is the same number as there are steps on the wheel, letting you use the LEDs to show the current step of the wheel.
|
||||
|
||||
|
||||
### Setting an LED
|
||||
|
||||
You can set the colour of a LED on the ring in either the RGB colourspace, or HSV (Hue, Saturation, Value). HSV is useful for creating rainbow patterns.
|
||||
|
||||
#### RGB
|
||||
|
||||
Set the first LED - `0` - to Purple `255, 0, 255`:
|
||||
|
||||
```c++
|
||||
wheel.set_rgb(0, 255, 0, 255);
|
||||
```
|
||||
|
||||
#### HSV
|
||||
|
||||
Set the first LED - `0` - to Red `0.0`:
|
||||
|
||||
```c++
|
||||
wheel.set_hsv(0, 0.0f, 1.0f, 1.0f);
|
||||
```
|
||||
|
||||
|
||||
### Clear all LEDs
|
||||
|
||||
To turn off all the LEDs, the function `.clear()` can be called. This simply goes through each LED and sets its RGB colour to black, making them emit no light.
|
||||
|
||||
This function is useful to have at the end of your code to turn the lights off, otherwise they will continue to show the last colours they were given.
|
||||
|
||||
|
||||
### Showing
|
||||
|
||||
Changes to the LEDs do not get applied immediately, due to the amount of I2C communication involved. As such, to have the LEDs show what they have been set to after calling the `.set_rgb()`, `.set_hsv()`, and `.clear()` functions, a specific call to `.show()` needs to be made.
|
||||
|
||||
|
||||
## GPIOs
|
||||
|
||||
There are three spare GPIO pins on the edge of Encoder Wheel. These can be used as digital outputs, pwm outputs, digital inputs, and analog inputs.
|
||||
|
||||
|
||||
### Setup
|
||||
|
||||
To start using a GPIO pin, one of the handy constants from the `encoderwheel` namespace can be used to reference them (see [GPIO Constants](#gpio-constants)).
|
||||
|
||||
Then you need to import the constants for the pin mode to use. These are on the `IOExpander` class that Encoder Wheel is based on.
|
||||
|
||||
```c++
|
||||
#import "breakout_ioexpander.hpp"
|
||||
using namespace pimoroni;
|
||||
|
||||
// For input
|
||||
IOExpander::PIN_IN; // or PIN_IN_PU of a pull-up is wanted
|
||||
|
||||
// For output
|
||||
IOExpander::PIN_OUT;
|
||||
|
||||
// For PWM
|
||||
IOExpander::PIN_PWM;
|
||||
|
||||
// For ADC
|
||||
IOExpander::PIN_ADC;
|
||||
```
|
||||
|
||||
|
||||
### Mode
|
||||
|
||||
With the intended constants imported, the mode of a GPIO pin can be set by calling `.gpio_pin_mode(gpio, mode)`:
|
||||
|
||||
```c++
|
||||
wheel.gpio_pin_mode(GP7, IOExpander::PIN_<IN or IN_PU or OUT or PWM or ADC>);
|
||||
```
|
||||
|
||||
It is also possible to read the current mode of a GPIO pin by calling `.gpio_pin_mode(gpio)`:
|
||||
|
||||
```c++
|
||||
mode = wheel.gpio_pin_mode(GP7);
|
||||
```
|
||||
|
||||
|
||||
### As Input or ADC
|
||||
|
||||
The current value of an GPIO pin in input or ADC mode can be read by calling `.gpio_pin_value(gpio)`:
|
||||
|
||||
```c++
|
||||
value = wheel.gpio_pin_value(GP7);
|
||||
```
|
||||
|
||||
If the mode is digital, the value will either be `0` or `1`.
|
||||
If the mode is analog, the value will be a voltage from `0.0` to `3.3`.
|
||||
|
||||
|
||||
### As Output
|
||||
|
||||
The current value of a GPIO pin in output mode can be set by calling `.gpio_pin_value(gpio, value)`:
|
||||
|
||||
```c++
|
||||
wheel.gpio_pin_value(GP7, value);
|
||||
```
|
||||
|
||||
The expected value is either `0` or `1`, or `True` or `False`.
|
||||
|
||||
|
||||
### As PWM
|
||||
|
||||
The GPIO pins can also be set as PWM outputs. The `PIN_PWM` constant can be accessed from the `IOExpander` class, and passed into the `.gpio_pin_mode()` function.
|
||||
|
||||
The frequency of the PWM signal can then be configured by calling `.gpio_pwm_frequency()`, which accepts a frequency (in Hz). It returns the cycle period, which should be used to set duty cycles.
|
||||
|
||||
Finally, the duty cycle of the PWM signal can be set by calling `.gpio_pin_value()` and providing it with a value between `0` and the cycle period.
|
||||
|
||||
Below is an example of setting a gpio pin to output a 25KHz signal with a 50% duty cycle:
|
||||
|
||||
```c++
|
||||
#include "pimoroni_i2c.hpp"
|
||||
#include "breakout_encoder_wheel.hpp"
|
||||
|
||||
using namespace pimoroni;
|
||||
using namespace encoderwheel;
|
||||
|
||||
// Initialise EncoderWheel
|
||||
I2C i2c(BOARD::BREAKOUT_GARDEN);
|
||||
BreakoutEncoderWheel wheel(&i2c);
|
||||
|
||||
// Setup the gpio pin as a PWM output
|
||||
wheel.gpio_pin_mode(GP7, IOExpander::PIN_PWM);
|
||||
|
||||
// Set the gpio pin's frequency to 25KHz, and record the cycle period
|
||||
uint16_t period = wheel.gpio_pwm_frequency(25000.0f);
|
||||
|
||||
// Output a 50% duty cycle square wave
|
||||
wheel.gpio_pin_value(GP7, (int)(period * 0.5f));
|
||||
```
|
||||
|
||||
|
||||
#### Delayed Loading
|
||||
|
||||
By default, changes to a gpio pin's frequency or value are applied immediately. However, sometimes this may not be wanted, and instead you want all pins to receive updated parameters at the same time, regardless of how long the code ran that calculated the update.
|
||||
|
||||
For this purpose, `.gpio_pwm_frequency()` and `.gpio_pin_value()` include an optional parameter `load`, which by default is `true`. To avoid this "loading" set the parameter to `false`. Then either the last call can include a `true`, or a specific call to `.gpio_pwm_load()` can be made.
|
||||
|
||||
In addition, any function that performs a load, including the `.gpio_pwm_load()` function, can be made to wait until the new PWM value has been sent out of the pins. By default this is disabled, but can be enabled by including setting the `wait_for_load` parameter to `true` in the relevant function calls.
|
||||
|
||||
|
||||
#### Limitations
|
||||
|
||||
All of Encoder Wheel's PWM outputs share the same timing parameters. This means that GP7, GP8, and GP9 share the same frequency. Keep this in mind if changing the frequency of one, as the others will not automatically know about the change, resulting in unexpected duty cycle outputs.
|
||||
|
||||
|
||||
## Function Reference
|
||||
|
||||
Here is the complete list of functions available on the `BreakoutEncoderWheel` class:
|
||||
```c++
|
||||
BreakoutEncoderWheel(uint8_t ioe_address = DEFAULT_IOE_I2C_ADDRESS, uint8_t led_address = DEFAULT_LED_I2C_ADDRESS);
|
||||
BreakoutEncoderWheel(I2C *i2c, uint8_t ioe_address = 0x13, uint8_t led_address = 0x77, uint interrupt = PIN_UNUSED, uint32_t timeout = 1, bool debug = false);
|
||||
bool init(bool skip_chip_id_check = false);
|
||||
void set_ioe_address(uint8_t address);
|
||||
bool get_interrupt_flag();
|
||||
void clear_interrupt_flag();
|
||||
bool pressed(uint button);
|
||||
int16_t count();
|
||||
int16_t delta();
|
||||
void zero();
|
||||
int16_t step();
|
||||
int16_t turn();
|
||||
float revolutions();
|
||||
float degrees();
|
||||
float radians();
|
||||
Direction direction();
|
||||
void direction(Direction direction);
|
||||
void set_rgb(int index, int r, int g, int b);
|
||||
void set_hsv(int index, float h, float s = 1.0f, float v = 1.0f);
|
||||
void clear();
|
||||
void show();
|
||||
uint8_t gpio_pin_mode(uint8_t gpio);
|
||||
void gpio_pin_mode(uint8_t gpio, uint8_t mode);
|
||||
int16_t gpio_pin_value(uint8_t gpio);
|
||||
float gpio_pin_value_as_voltage(uint8_t gpio);
|
||||
void gpio_pin_value(uint8_t gpio, uint16_t value, bool load = true, bool wait_for_load = false);
|
||||
void gpio_pwm_load(bool wait_for_load = true);
|
||||
uint16_t gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false);
|
||||
```
|
||||
|
||||
## Constants Reference
|
||||
|
||||
Here is the complete list of public constants on the `BreakoutEncoderWheel` class:
|
||||
|
||||
### Address Constants
|
||||
|
||||
* `DEFAULT_IOE_I2C_ADDR` = `0x13`
|
||||
* `DEFAULT_LED_I2C_ADDR` = `0x77`
|
||||
* `ALTERNATE_LED_I2C_ADDR` = `0x74`
|
||||
|
||||
### Value Constants
|
||||
|
||||
* `DEFAULT_DIRECTION` = `NORMAL_DIR`
|
||||
* `DEFAULT_TIMEOUT` = `1`
|
||||
|
||||
|
||||
Here is the complete list of public constants in the `encoderwheel` namespace:
|
||||
|
||||
### Button Constants
|
||||
|
||||
* `UP` = `0`
|
||||
* `DOWN` = `1`
|
||||
* `LEFT` = `2`
|
||||
* `RIGHT` = `3`
|
||||
* `CENTRE` = `4`
|
||||
|
||||
### GPIO Constants
|
||||
|
||||
* `GP7` = `7`
|
||||
* `GP8` = `8`
|
||||
* `GP9` = `9`
|
||||
* `GPIOS` = (`7`, `8`, `9`)
|
||||
|
||||
### Count Constants
|
||||
|
||||
* `NUM_LEDS` = `24`
|
||||
* `NUM_BUTTONS` = `5`
|
||||
* `NUM_GPIOS` = `5`
|
|
@ -0,0 +1,19 @@
|
|||
if(NOT TARGET ioexpander)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ioexpander/ioexpander.cmake)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET is31fl3731)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/is31fl3731/is31fl3731.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_encoder_wheel)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
target_sources(${LIB_NAME} INTERFACE
|
||||
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
|
||||
)
|
||||
|
||||
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
# Pull in pico libraries that we need
|
||||
target_link_libraries(${LIB_NAME} INTERFACE pico_stdlib ioexpander is31fl3731)
|
|
@ -0,0 +1,260 @@
|
|||
#include "breakout_encoder_wheel.hpp"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace pimoroni {
|
||||
namespace encoderwheel {
|
||||
|
||||
bool BreakoutEncoderWheel::init(bool skip_chip_id_check) {
|
||||
bool success = false;
|
||||
if(ioe.init(skip_chip_id_check, true) && led_ring.init()) {
|
||||
|
||||
ioe.setup_rotary_encoder(ENC_CHANNEL, ENC_TERM_A, ENC_TERM_B, 0, true); // count microsteps
|
||||
|
||||
ioe.set_mode(SW_UP, IOExpander::PIN_IN_PU);
|
||||
ioe.set_mode(SW_DOWN, IOExpander::PIN_IN_PU);
|
||||
ioe.set_mode(SW_LEFT, IOExpander::PIN_IN_PU);
|
||||
ioe.set_mode(SW_RIGHT, IOExpander::PIN_IN_PU);
|
||||
ioe.set_mode(SW_CENTRE, IOExpander::PIN_IN_PU);
|
||||
|
||||
ioe.set_pin_interrupt(SW_UP, true);
|
||||
ioe.set_pin_interrupt(SW_DOWN, true);
|
||||
ioe.set_pin_interrupt(SW_LEFT, true);
|
||||
ioe.set_pin_interrupt(SW_RIGHT, true);
|
||||
ioe.set_pin_interrupt(SW_CENTRE, true);
|
||||
|
||||
led_ring.enable({
|
||||
0b00000000, 0b10111111,
|
||||
0b00111110, 0b00111110,
|
||||
0b00111111, 0b10111110,
|
||||
0b00000111, 0b10000110,
|
||||
0b00110000, 0b00110000,
|
||||
0b00111111, 0b10111110,
|
||||
0b00111111, 0b10111110,
|
||||
0b01111111, 0b11111110,
|
||||
0b01111111, 0b00000000
|
||||
}, 0);
|
||||
|
||||
success = true;
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
i2c_inst_t* BreakoutEncoderWheel::get_i2c() const {
|
||||
return ioe.get_i2c();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::get_ioe_address() const {
|
||||
return ioe.get_address();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::get_led_address() const {
|
||||
return led_ring.get_address();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::get_sda() const {
|
||||
return ioe.get_sda();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::get_scl() const {
|
||||
return ioe.get_scl();
|
||||
}
|
||||
|
||||
int BreakoutEncoderWheel::get_int() const {
|
||||
return ioe.get_int();
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_ioe_address(uint8_t address) {
|
||||
ioe.set_address(address);
|
||||
}
|
||||
|
||||
bool BreakoutEncoderWheel::get_interrupt_flag() {
|
||||
return ioe.get_interrupt_flag();
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::clear_interrupt_flag() {
|
||||
ioe.clear_interrupt_flag();
|
||||
}
|
||||
|
||||
bool BreakoutEncoderWheel::pressed(uint button) {
|
||||
switch(button) {
|
||||
case 0:
|
||||
return ioe.input(SW_UP) == 0;
|
||||
case 1:
|
||||
return ioe.input(SW_DOWN) == 0;
|
||||
case 2:
|
||||
return ioe.input(SW_LEFT) == 0;
|
||||
case 3:
|
||||
return ioe.input(SW_RIGHT) == 0;
|
||||
case 4:
|
||||
return ioe.input(SW_CENTRE) == 0;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoderWheel::count() {
|
||||
take_encoder_reading();
|
||||
return enc_count;
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoderWheel::delta() {
|
||||
take_encoder_reading();
|
||||
|
||||
// Determine the change in counts since the last time this function was performed
|
||||
int16_t change = enc_count - last_delta_count;
|
||||
last_delta_count = enc_count;
|
||||
|
||||
return change;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::zero() {
|
||||
ioe.clear_rotary_encoder(ENC_CHANNEL);
|
||||
enc_count = 0;
|
||||
enc_step = 0;
|
||||
enc_turn = 0;
|
||||
last_raw_count = 0;
|
||||
last_delta_count = 0;
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoderWheel::step() {
|
||||
take_encoder_reading();
|
||||
return enc_step;
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoderWheel::turn() {
|
||||
take_encoder_reading();
|
||||
return enc_turn;
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::revolutions() {
|
||||
return (float)count() / (float)ENC_COUNTS_PER_REV;
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::degrees() {
|
||||
return revolutions() * 360.0f;
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::radians() {
|
||||
return revolutions() * M_PI * 2.0f;
|
||||
}
|
||||
|
||||
Direction BreakoutEncoderWheel::direction() {
|
||||
return enc_direction;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::direction(Direction direction) {
|
||||
enc_direction = direction;
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_rgb(int index, int r, int g, int b) {
|
||||
RGBLookup rgb = lookup_table[index];
|
||||
led_ring.set(rgb.r, r);
|
||||
led_ring.set(rgb.g, g);
|
||||
led_ring.set(rgb.b, b);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::set_hsv(int index, float h, float s, float v) {
|
||||
int r, g, b;
|
||||
if(h < 0.0f) {
|
||||
h = 1.0f + fmodf(h, 1.0f);
|
||||
}
|
||||
|
||||
int i = int(h * 6);
|
||||
float f = h * 6 - i;
|
||||
|
||||
v = v * 255.0f;
|
||||
|
||||
float sv = s * v;
|
||||
float fsv = f * sv;
|
||||
|
||||
auto p = uint8_t(-sv + v);
|
||||
auto q = uint8_t(-fsv + v);
|
||||
auto t = uint8_t(fsv - sv + v);
|
||||
|
||||
uint8_t bv = uint8_t(v);
|
||||
|
||||
switch (i % 6) {
|
||||
default:
|
||||
case 0: r = bv; g = t; b = p; break;
|
||||
case 1: r = q; g = bv; b = p; break;
|
||||
case 2: r = p; g = bv; b = t; break;
|
||||
case 3: r = p; g = q; b = bv; break;
|
||||
case 4: r = t; g = p; b = bv; break;
|
||||
case 5: r = bv; g = p; b = q; break;
|
||||
}
|
||||
|
||||
set_rgb(index, r, g, b);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::clear() {
|
||||
led_ring.clear();
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::show() {
|
||||
led_ring.update();
|
||||
}
|
||||
|
||||
uint8_t BreakoutEncoderWheel::gpio_pin_mode(uint8_t gpio) {
|
||||
assert(gpio < GP7 || gpio > GP9);
|
||||
return ioe.get_mode(gpio);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pin_mode(uint8_t gpio, uint8_t mode) {
|
||||
assert(gpio < GP7 || gpio > GP9);
|
||||
ioe.set_mode(gpio, mode);
|
||||
}
|
||||
|
||||
int16_t BreakoutEncoderWheel::gpio_pin_value(uint8_t gpio) {
|
||||
assert(gpio < GP7 || gpio > GP9);
|
||||
return ioe.input(gpio);
|
||||
}
|
||||
|
||||
float BreakoutEncoderWheel::gpio_pin_value_as_voltage(uint8_t gpio) {
|
||||
assert(gpio < GP7 || gpio > GP9);
|
||||
return ioe.input_as_voltage(gpio);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pin_value(uint8_t gpio, uint16_t value, bool load, bool wait_for_load) {
|
||||
assert(gpio < GP7 || gpio > GP9);
|
||||
ioe.output(gpio, value, load, wait_for_load);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::gpio_pwm_load(bool wait_for_load) {
|
||||
ioe.pwm_load(wait_for_load);
|
||||
}
|
||||
|
||||
uint16_t BreakoutEncoderWheel::gpio_pwm_frequency(float frequency, bool load, bool wait_for_load) {
|
||||
return ioe.set_pwm_frequency(frequency, load, wait_for_load);
|
||||
}
|
||||
|
||||
void BreakoutEncoderWheel::take_encoder_reading() {
|
||||
// Read the current count
|
||||
int16_t raw_count = ioe.read_rotary_encoder(ENC_CHANNEL) / ENC_COUNT_DIVIDER;
|
||||
int16_t raw_change = raw_count - last_raw_count;
|
||||
last_raw_count = raw_count;
|
||||
|
||||
// Invert the change
|
||||
if(enc_direction == REVERSED_DIR) {
|
||||
raw_change = 0 - raw_change;
|
||||
}
|
||||
|
||||
enc_count += raw_change;
|
||||
|
||||
enc_step += raw_change;
|
||||
if(raw_change > 0) {
|
||||
while(enc_step >= ENC_COUNTS_PER_REV) {
|
||||
enc_step -= ENC_COUNTS_PER_REV;
|
||||
enc_turn += 1;
|
||||
}
|
||||
}
|
||||
else if(raw_change < 0) {
|
||||
while(enc_step < 0) {
|
||||
enc_step += ENC_COUNTS_PER_REV;
|
||||
enc_turn -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
|
||||
#include "drivers/ioexpander/ioexpander.hpp"
|
||||
#include "drivers/is31fl3731/is31fl3731.hpp"
|
||||
#include "common/pimoroni_common.hpp"
|
||||
|
||||
namespace pimoroni {
|
||||
namespace encoderwheel {
|
||||
static const uint8_t NUM_LEDS = 24;
|
||||
static const uint8_t NUM_BUTTONS = 5;
|
||||
static const uint8_t NUM_GPIOS = 3;
|
||||
|
||||
static const uint8_t UP = 0;
|
||||
static const uint8_t DOWN = 1;
|
||||
static const uint8_t LEFT = 2;
|
||||
static const uint8_t RIGHT = 3;
|
||||
static const uint8_t CENTRE = 4;
|
||||
|
||||
static const uint8_t GP7 = 7;
|
||||
static const uint8_t GP8 = 8;
|
||||
static const uint8_t GP9 = 9;
|
||||
static const uint8_t GPIOS[] = {GP7, GP8, GP9};
|
||||
|
||||
class BreakoutEncoderWheel {
|
||||
struct RGBLookup {
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constants
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
static const uint8_t DEFAULT_IOE_I2C_ADDRESS = 0x13;
|
||||
static const uint8_t DEFAULT_LED_I2C_ADDRESS = 0x77;
|
||||
static const uint8_t ALTERNATE_LED_I2C_ADDRESS = 0x74;
|
||||
|
||||
static const Direction DEFAULT_DIRECTION = NORMAL_DIR;
|
||||
static const uint32_t DEFAULT_TIMEOUT = 1;
|
||||
|
||||
private:
|
||||
static const uint8_t ENC_CHANNEL = 1;
|
||||
static const uint8_t ENC_TERM_A = 3;
|
||||
static const uint8_t ENC_TERM_B = 12;
|
||||
static const uint8_t ENC_COUNTS_PER_REV = 24;
|
||||
static const uint8_t ENC_COUNT_DIVIDER = 2;
|
||||
|
||||
static const uint8_t SW_UP = 13;
|
||||
static const uint8_t SW_DOWN = 4;
|
||||
static const uint8_t SW_LEFT = 11;
|
||||
static const uint8_t SW_RIGHT = 2;
|
||||
static const uint8_t SW_CENTRE = 1;
|
||||
|
||||
// This wonderful lookup table maps the LEDs on the encoder wheel
|
||||
// from their 3x24 (remember, they're RGB) configuration to
|
||||
// their specific location in the 144 pixel buffer.
|
||||
static constexpr RGBLookup lookup_table[24] = {
|
||||
{128, 32, 48},
|
||||
{129, 33, 49},
|
||||
{130, 17, 50},
|
||||
{131, 18, 34},
|
||||
{132, 19, 35},
|
||||
{133, 20, 36},
|
||||
{134, 21, 37},
|
||||
{112, 80, 96},
|
||||
{113, 81, 97},
|
||||
{114, 82, 98},
|
||||
{115, 83, 99},
|
||||
{116, 84, 100},
|
||||
{117, 68, 101},
|
||||
{118, 69, 85},
|
||||
{127, 47, 63},
|
||||
{121, 41, 57},
|
||||
{122, 25, 58},
|
||||
{123, 26, 42},
|
||||
{124, 27, 43},
|
||||
{125, 28, 44},
|
||||
{126, 29, 45},
|
||||
{15, 95, 111},
|
||||
{8, 89, 105},
|
||||
{9, 90, 106},
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Variables
|
||||
//--------------------------------------------------
|
||||
private:
|
||||
IOExpander ioe;
|
||||
IS31FL3731 led_ring;
|
||||
|
||||
Direction enc_direction = DEFAULT_DIRECTION;
|
||||
int16_t enc_count = 0;
|
||||
int16_t enc_step = 0;
|
||||
int16_t enc_turn = 0;
|
||||
int16_t last_raw_count = 0;
|
||||
int16_t last_delta_count = 0;
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Constructors/Destructor
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
BreakoutEncoderWheel(uint8_t ioe_address = DEFAULT_IOE_I2C_ADDRESS, uint8_t led_address = DEFAULT_LED_I2C_ADDRESS)
|
||||
: BreakoutEncoderWheel(new I2C(), ioe_address, led_address) {}
|
||||
|
||||
BreakoutEncoderWheel(I2C *i2c, uint8_t ioe_address = DEFAULT_IOE_I2C_ADDRESS, uint8_t led_address = DEFAULT_LED_I2C_ADDRESS, uint interrupt = PIN_UNUSED, uint32_t timeout = DEFAULT_TIMEOUT, bool debug = false)
|
||||
: ioe(i2c, ioe_address, interrupt, timeout, debug), led_ring(i2c, led_address) {}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// Methods
|
||||
//--------------------------------------------------
|
||||
public:
|
||||
bool init(bool skip_chip_id_check = false);
|
||||
|
||||
// For print access in micropython
|
||||
i2c_inst_t* get_i2c() const;
|
||||
int get_ioe_address() const;
|
||||
int get_led_address() const;
|
||||
int get_sda() const;
|
||||
int get_scl() const;
|
||||
int get_int() const;
|
||||
|
||||
// Calls through to IOExpander class
|
||||
void set_ioe_address(uint8_t address);
|
||||
bool get_interrupt_flag();
|
||||
void clear_interrupt_flag();
|
||||
|
||||
// Encoder breakout specific
|
||||
bool pressed(uint button);
|
||||
int16_t count();
|
||||
int16_t delta();
|
||||
void zero();
|
||||
int16_t step();
|
||||
int16_t turn();
|
||||
float revolutions();
|
||||
float degrees();
|
||||
float radians();
|
||||
Direction direction();
|
||||
void direction(Direction direction);
|
||||
void set_rgb(int index, int r, int g, int b);
|
||||
void set_hsv(int index, float h, float s = 1.0f, float v = 1.0f);
|
||||
void clear();
|
||||
void show();
|
||||
|
||||
uint8_t gpio_pin_mode(uint8_t gpio);
|
||||
void gpio_pin_mode(uint8_t gpio, uint8_t mode);
|
||||
int16_t gpio_pin_value(uint8_t gpio);
|
||||
float gpio_pin_value_as_voltage(uint8_t gpio);
|
||||
void gpio_pin_value(uint8_t gpio, uint16_t value, bool load = true, bool wait_for_load = false);
|
||||
void gpio_pwm_load(bool wait_for_load = true);
|
||||
uint16_t gpio_pwm_frequency(float frequency, bool load = true, bool wait_for_load = false);
|
||||
|
||||
private:
|
||||
void take_encoder_reading();
|
||||
};
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET ioexpander)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ioexpander/ioexpander.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_ioexpander)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET ltr559)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ltr559/ltr559.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_ltr559)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET is31fl3731)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/is31fl3731/is31fl3731.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_matrix11x7)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET ioexpander)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/ioexpander/ioexpander.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_mics6814)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ namespace pimoroni {
|
|||
static const uint8_t LED_B = 2;
|
||||
|
||||
static const uint8_t MICS_VREF = 14;
|
||||
static const uint8_t MICS_RED = 12;
|
||||
static const uint8_t MICS_RED = 13;
|
||||
static const uint8_t MICS_NH3 = 11;
|
||||
static const uint8_t MICS_OX = 13;
|
||||
static const uint8_t MICS_OX = 12;
|
||||
static const uint8_t MICS_HEATER_EN = 1;
|
||||
|
||||
static const bool INVERT_OUTPUT = true; //true for common cathode, false for common anode
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET msa301)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/msa301/msa301.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_msa301)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
if(NOT TARGET pmw3901)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../../drivers/pmw3901/pmw3901.cmake)
|
||||
endif()
|
||||
|
||||
set(LIB_NAME breakout_paa5100)
|
||||
add_library(${LIB_NAME} INTERFACE)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Ładowanie…
Reference in New Issue