Add example to poll encoder and display value on I2C display (#963)

Co-authored-by: Milton Eduardo Sosa <milton@Miltons-MacBook-Pro.local>
This commit is contained in:
Milton Eduardo Sosa 2024-10-02 20:46:42 +02:00 committed by GitHub
parent 805ea267a8
commit 87a8b74908
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 1010 additions and 0 deletions

View file

@ -0,0 +1,14 @@
[target.thumbv7em-none-eabihf]
runner = "probe-rs run --chip STM32F411CEUx"
rustflags = [
"-C", "link-arg=-Tlink.x",
"-C", "link-arg=-Tdefmt.x",
]
[build]
target = "thumbv7em-none-eabihf"
[env]
DEFMT_LOG = "debug"

View file

@ -0,0 +1,637 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "bare-metal"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3"
dependencies = [
"rustc_version",
]
[[package]]
name = "bare-metal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603"
[[package]]
name = "bitfield"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cortex-m"
version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9"
dependencies = [
"bare-metal 0.2.5",
"bitfield",
"critical-section",
"embedded-hal 0.2.7",
"volatile-register",
]
[[package]]
name = "cortex-m-rt"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee84e813d593101b1723e13ec38b6ab6abbdbaaa4546553f5395ed274079ddb1"
dependencies = [
"cortex-m-rt-macros",
]
[[package]]
name = "cortex-m-rt-macros"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0f6f3e36f203cfedbc78b357fb28730aa2c6dc1ab060ee5c2405e843988d3c7"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
]
[[package]]
name = "critical-section"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
[[package]]
name = "defmt"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a99dd22262668b887121d4672af5a64b238f026099f1a2a1b322066c9ecfe9e0"
dependencies = [
"bitflags",
"defmt-macros",
]
[[package]]
name = "defmt-macros"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3a9f309eff1f79b3ebdf252954d90ae440599c26c2c553fe87a2d17195f2dcb"
dependencies = [
"defmt-parser",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "defmt-parser"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff4a5fefe330e8d7f31b16a318f9ce81000d8e35e69b93eae154d16d2278f70f"
dependencies = [
"thiserror",
]
[[package]]
name = "defmt-rtt"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51"
dependencies = [
"critical-section",
"defmt",
]
[[package]]
name = "deranged"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
dependencies = [
"powerfmt",
]
[[package]]
name = "document-features"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef5282ad69563b5fc40319526ba27e0e7363d552a896f0297d54f767717f9b95"
dependencies = [
"litrs",
]
[[package]]
name = "embedded-dma"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "994f7e5b5cb23521c22304927195f236813053eb9c065dd2226a32ba64695446"
dependencies = [
"stable_deref_trait",
]
[[package]]
name = "embedded-hal"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff"
dependencies = [
"nb 0.1.3",
"void",
]
[[package]]
name = "embedded-hal"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89"
[[package]]
name = "embedded-hal-nb"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605"
dependencies = [
"embedded-hal 1.0.0",
"nb 1.1.0",
]
[[package]]
name = "embedded-storage"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032"
[[package]]
name = "enumflags2"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d232db7f5956f3f14313dc2f87985c58bd2c695ce124c8cdd984e08e15ac133d"
dependencies = [
"enumflags2_derive",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de0d48a183585823424a4ce1aa132d174a6a81bd540895822eb4c8373a8e49e8"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]]
name = "fugit"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7"
dependencies = [
"gcd",
]
[[package]]
name = "fugit-timer"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9607bfc4c388f9d629704f56ede4a007546cad417b3bcd6fc7c87dc7edce04a"
dependencies = [
"fugit",
"nb 1.1.0",
]
[[package]]
name = "futures-core"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
[[package]]
name = "futures-task"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
[[package]]
name = "futures-util"
version = "0.3.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
dependencies = [
"futures-core",
"futures-task",
"pin-project-lite",
"pin-utils",
]
[[package]]
name = "gcd"
version = "2.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a"
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
[[package]]
name = "hd44780-driver"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aab2b13fdeaed7dde9133a57c28b2cbde4a8fc8c3196b5631428aad114857d3a"
dependencies = [
"embedded-hal 0.2.7",
]
[[package]]
name = "indexmap"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
]
[[package]]
name = "litrs"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
[[package]]
name = "nb"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f"
dependencies = [
"nb 1.1.0",
]
[[package]]
name = "nb"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d"
[[package]]
name = "num-conv"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
[[package]]
name = "panic-halt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812"
[[package]]
name = "pin-project-lite"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
[[package]]
name = "pin-utils"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "powerfmt"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn 1.0.109",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]]
name = "proc-macro2"
version = "1.0.86"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
dependencies = [
"unicode-ident",
]
[[package]]
name = "quote"
version = "1.0.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
dependencies = [
"proc-macro2",
]
[[package]]
name = "rand_core"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]]
name = "rotary-encoder-embedded"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da300c653a5d74bd58ccad9cf160b1a22bd35f5996b824d1bb1f6abbcc7638af"
dependencies = [
"embedded-hal 0.2.7",
]
[[package]]
name = "rtic"
version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c443db16326376bdd64377da268f6616d5f804aba8ce799bac7d1f7f244e9d51"
dependencies = [
"atomic-polyfill",
"bare-metal 1.0.0",
"cortex-m",
"critical-section",
"rtic-core",
"rtic-macros",
"rtic-monotonics",
]
[[package]]
name = "rtic-common"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0786b50b81ef9d2a944a000f60405bb28bf30cd45da2d182f3fe636b2321f35c"
dependencies = [
"critical-section",
]
[[package]]
name = "rtic-core"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9369355b04d06a3780ec0f51ea2d225624db777acbc60abd8ca4832da5c1a42"
[[package]]
name = "rtic-macros"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "54053598ea24b1b74937724e366558412a1777eb2680b91ef646db540982789a"
dependencies = [
"indexmap",
"proc-macro-error",
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "rtic-monotonics"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "058c2397dbd5bb4c5650a0e368c3920953e458805ff5097a0511b8147b3619d7"
dependencies = [
"atomic-polyfill",
"cfg-if",
"embedded-hal 1.0.0",
"fugit",
"rtic-time",
]
[[package]]
name = "rtic-time"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75b232e7aebc045cfea81cdd164bc2727a10aca9a4568d406d0a5661cdfd0f19"
dependencies = [
"critical-section",
"futures-util",
"rtic-common",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [
"semver",
]
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "stm32f4"
version = "0.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb94729242cd1aebe6dab42a2ca0131985ae93bc3ab2751b680df724bb35528d"
dependencies = [
"bare-metal 1.0.0",
"cortex-m",
"cortex-m-rt",
"vcell",
]
[[package]]
name = "stm32f411_encoder_polling"
version = "0.1.0"
dependencies = [
"cortex-m",
"cortex-m-rt",
"defmt",
"defmt-rtt",
"embedded-hal 1.0.0",
"hd44780-driver",
"panic-halt",
"rotary-encoder-embedded",
"rtic",
"stm32f4xx-hal",
]
[[package]]
name = "stm32f4xx-hal"
version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ceed60591531f4da636d828701c74861a3d100e5c4e36677cadbd2eb6f46eb67"
dependencies = [
"bare-metal 1.0.0",
"cortex-m",
"cortex-m-rt",
"document-features",
"embedded-dma",
"embedded-hal 0.2.7",
"embedded-hal 1.0.0",
"embedded-hal-nb",
"embedded-storage",
"enumflags2",
"fugit",
"fugit-timer",
"nb 1.1.0",
"rand_core",
"stm32f4",
"time",
"vcell",
"void",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "syn"
version = "2.0.68"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
name = "thiserror"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.68",
]
[[package]]
name = "time"
version = "0.3.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885"
dependencies = [
"deranged",
"num-conv",
"powerfmt",
"time-core",
]
[[package]]
name = "time-core"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
[[package]]
name = "vcell"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002"
[[package]]
name = "version_check"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "void"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
[[package]]
name = "volatile-register"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc"
dependencies = [
"vcell",
]

View file

@ -0,0 +1,30 @@
[workspace]
[package]
authors = ["<Milton Sosa <milton.eduardo.sosa@gmail.com>"]
edition = "2018"
readme = "README.md"
name = "stm32f411_encoder_polling"
version = "0.1.0"
[dependencies]
cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7.1"
rtic = {version = "2.1.1", features=["thumbv7-backend", "rtic-monotonics"]}
panic-halt = "0.2.0"
embedded-hal = "1.0.0"
defmt = "0.3.5"
defmt-rtt = { version = "0.4.0"}
rotary-encoder-embedded = "0.3.0"
hd44780-driver = "0.4.0"
[dependencies.stm32f4xx-hal]
version = "0.21.0"
features = ["stm32f411"] # replace the model of your microcontroller here
# this lets you use `cargo fix`!
[[bin]]
name = "stm32f411_encoder_polling"
test = false
bench = false

View file

@ -0,0 +1,64 @@
# STM32F411CEU6 encoder polling and LCD display
This example uses an STM32F411CEU6 microcontroller on the Blackpill board to interface with an I2C LCD display and a rotary encoder.
## Features
- **Rotary Encoder Integration**: Reads input from a rotary encoder to adjust a value.
- **I2C LCD Display**: Displays the current encoder value on an I2C-connected HD44780 LCD.
## Working principle
The hardware task `tim2_timeout_interrupt_handler` polls the encoder state on each interrupt generated by TIM2, and updates the displayed value accordingly.
## Code Overview
### Key Components
- **Knob Struct**: Placeholder for the rotary encoder and its current value.
- **LCD I2C Communication**: Uses I2C protocol to communicate with the HD44780 LCD.
- **Timers**: Utilizes TIM1 for delays and TIM2 for polling the rotary encoder.
### Important Constants
- `LCD_I2C_ADDRESS`: The I2C address of the LCD display.
### Initialization
- **System Clock**: Configured to use an external 25 MHz clock.
- **GPIO Setup**: Configures GPIO pins for the LED, rotary encoder, and I2C communication.
- **I2C Initialization**: Sets up the I2C bus for LCD communication.
- **LCD Initialization**: Initializes the LCD and displays initial messages.
- **Timer Setup**: Configures TIM2 at 2 kHz and generate interrupts.
### Tasks and Handlers
- **idle**: Background task that runs when no other tasks are active.
- **tim2_timeout_interrupt_handler**: Handles interrupts generated by TIM2, updates the rotary encoder value, and displays the value on the LCD.
### Utility Functions
- `u8_to_str(n: u8) -> [u8; 3]`: Converts an 8-bit integer to a 3-character string representation.
## Dependencies
- **hd44780-driver**: Driver for HD44780 LCD over I2C.
- **rotary_encoder_embedded**: Library for handling rotary encoders.
- **defmt**: Logging framework for embedded systems.
## How-to
### Build
Run `cargo build --release` to compile the code. If you run it for the first time, it will take some time to download and compile dependencies.
### Run
Install `probe-rs` and configure it using the [debugging extension for VScode](https://probe.rs/docs/tools/debugger/).
The output should look like this:
[![IMAGE ALT TEXT HERE](https://img.youtube.com/vi/nn75gWDhHn0/0.jpg)](https://www.youtube.com/watch?v=nn75gWDhHn0)

View file

@ -0,0 +1,31 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;
fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());
// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");
}

View file

@ -0,0 +1,6 @@
MEMORY
{
/* NOTE 1 K = 1 KiBi = 1024 bytes */
FLASH : ORIGIN = 0x08000000, LENGTH = 512K
RAM : ORIGIN = 0x20000000, LENGTH = 96K
}

View file

@ -0,0 +1,228 @@
#![deny(unsafe_code)]
#![deny(warnings)]
#![no_main]
#![no_std]
use panic_halt as _;
#[rtic::app(device = stm32f4xx_hal::pac, peripherals = true)]
mod app {
use stm32f4xx_hal::i2c::I2c;
use stm32f4xx_hal::i2c::Mode;
use stm32f4xx_hal::{
gpio::{self, Input, Output, PushPull},
pac::{Peripherals, I2C1, TIM1, TIM2},
prelude::*,
timer,
timer::{CounterHz, Event, Timer2},
};
use rotary_encoder_embedded::standard::StandardMode;
use rotary_encoder_embedded::{Direction, RotaryEncoder};
use hd44780_driver::bus::I2CBus;
use hd44780_driver::{Cursor, CursorBlink, Display, DisplayMode, HD44780};
use defmt_rtt as _;
pub struct Knob {
rotary_encoder: RotaryEncoder<StandardMode, gpio::PB12<Input>, gpio::PB13<Input>>,
value: u8,
}
impl Knob {
pub fn new(
rotary_encoder: RotaryEncoder<StandardMode, gpio::PB12<Input>, gpio::PB13<Input>>,
) -> Knob {
Knob {
rotary_encoder: rotary_encoder,
value: 0_u8,
}
}
}
// Set the I2C address of the PCF8574 located on the back of the HD44780.
// Check the the jumpers A0, A1 and A2 and datasheet
const LCD_I2C_ADDRESS: u8 = 0x27;
// Resources shared between tasks
#[shared]
struct Shared {
delay: timer::DelayMs<TIM1>,
lcd: HD44780<I2CBus<I2c<I2C1>>>,
}
// Local resources to specific tasks (cannot be shared)
#[local]
struct Local {
led: gpio::PC13<Output<PushPull>>,
tim2_timer: CounterHz<TIM2>,
knob_1: Knob,
}
#[init]
fn init(ctx: init::Context) -> (Shared, Local) {
let dp: Peripherals = ctx.device;
// Configure and obtain handle for delay abstraction using TIM1
// Promote RCC structure to HAL to be able to configure clocks
let rcc = dp.RCC.constrain();
// Configure the system clocks 25 MHz must be used for HSE
// on the Blackpill-STM32F411CE board according to manual
let clocks = rcc.cfgr.use_hse(25.MHz()).freeze();
let mut delay = dp.TIM1.delay_ms(&clocks);
// Configure the LED pin as a push pull output and obtain handle
// On the Blackpill STM32F411CEU6 there is an on-board LED connected to pin PC13
// Promote the GPIOC PAC struct
let gpioc = dp.GPIOC.split();
let led = gpioc.pc13.into_push_pull_output();
// Configure the button pin as input and obtain handle
// On the Blackpill STM32F411CEU6 there is a button connected to pin PA0
// Promote the GPIOB PAC struct
let gpiob = dp.GPIOB.split();
// Configure Pins connected to encoder as floating input (only if your encoder
// board already has pull-up resistors, use 'into_pull_up_input' otherwise)
// and Obtain Handle.
let enc_1_a = gpiob.pb12.into_floating_input();
let enc_1_b = gpiob.pb13.into_floating_input();
// Instantiate RotaryEncoder struct
let encoder_1 = RotaryEncoder::new(enc_1_a, enc_1_b).into_standard_mode();
// Instantiate Knob struct to hold 'encoder_1' and its current value
let knob_1 = Knob::new(encoder_1);
// Instantiate TIM2 that will be used to poll the encoders
let tim2_timer = Timer2::new(dp.TIM2, &clocks);
let mut tim2_timer = tim2_timer.counter_hz();
// Get SDA and SCL pins for I2C1
let sda = gpiob.pb7;
let scl = gpiob.pb6;
// Instantiate I2C1 bus that will be used to communicate with the
// LCD display.
let i2c = I2c::new(
dp.I2C1,
(scl, sda),
Mode::Standard {
frequency: 400.kHz(),
},
&clocks,
);
let mut lcd = HD44780::new_i2c(i2c, LCD_I2C_ADDRESS, &mut delay).expect("Init LCD failed");
let _ = lcd.reset(&mut delay);
let _ = lcd.clear(&mut delay);
let _ = lcd.set_display_mode(
DisplayMode {
display: Display::On,
cursor_visibility: Cursor::Invisible,
cursor_blink: CursorBlink::Off,
},
&mut delay,
);
let _ = lcd.set_cursor_pos(57, &mut delay);
let _ = lcd.write_str("RTIC + I2C + Encoder", &mut delay);
delay.delay_ms(1500);
let _ = lcd.clear(&mut delay);
let _ = lcd.set_cursor_pos(68, &mut delay);
let _ = lcd.write_str("Encoder 1", &mut delay);
// Start the timer at 2 kHz
tim2_timer.start(2000.Hz()).unwrap();
// Generate an interrupt when the timer expires
tim2_timer.listen(Event::Update);
(
// Initialization of shared resources.
Shared { delay, lcd },
// Initialization of task local resources
Local {
led,
tim2_timer,
knob_1,
},
)
}
// Background task, runs whenever no other tasks are running
#[idle(shared = [])]
fn idle(mut _ctx: idle::Context) -> ! {
loop {}
}
// Handle the IRQ generated when the TIM2 times out
#[task(binds = TIM2, local=[led, tim2_timer, knob_1], shared=[lcd, delay])]
fn tim2_timeout_interrupt_handler(mut ctx: tim2_timeout_interrupt_handler::Context) {
ctx.local.tim2_timer.clear_all_flags();
let led = &mut ctx.local.led;
led.toggle();
//Obtain 2 shared resources: lcd and delay.
let delay = &mut ctx.shared.delay;
let lcd = &mut ctx.shared.lcd;
// Update the encoder, which will compute and return its direction
match ctx.local.knob_1.rotary_encoder.update() {
Direction::Clockwise => {
if ctx.local.knob_1.value < 255 {
ctx.local.knob_1.value += 1;
defmt::info!("Going UP! {:?}", ctx.local.knob_1.value);
let current_value = ctx.local.knob_1.value;
(delay, lcd).lock(|delay, lcd| {
//Move cursor to the middle of the third line and update value
let _ = lcd.set_cursor_pos(27, delay);
let _ = lcd.write_bytes(&u8_to_str(current_value), delay);
})
}
}
Direction::Anticlockwise => {
if ctx.local.knob_1.value > 0 {
ctx.local.knob_1.value -= 1;
defmt::info!("Going DN! {:?}", ctx.local.knob_1.value);
let current_value = ctx.local.knob_1.value;
(delay, lcd).lock(|delay, lcd| {
//Move cursor to the middle of the third line and update value
let _ = lcd.set_cursor_pos(27, delay);
let _ = lcd.write_bytes(&u8_to_str(current_value), delay);
})
}
}
Direction::None => {
// Do nothing
}
}
}
// This auxiliary function is in charge of converting a u8 number into
// a 3-char string representation without doing memory allocation.
// 0 is represented as "000"
// 84 is represented as "084"
fn u8_to_str(n: u8) -> [u8; 3] {
let mut buffer = [b'0'; 3]; // Initialize the buffer with '0'
let mut num = n;
let mut i = 2;
// Fill the buffer with digits from the end to the start
loop {
buffer[i] = (num % 10) + b'0';
num /= 10;
if num == 0 {
break;
}
i -= 1;
}
buffer
}
}