├── .envrc ├── .gitignore ├── .vscode └── settings.json ├── CITATION.cff ├── Cargo.lock ├── Cargo.toml ├── Contributing.md ├── LICENSE-MIT ├── Makefile.toml ├── README.md ├── core ├── Cargo.toml └── src │ ├── bldc_driver.rs │ ├── bldc_driver6pwm.rs │ ├── bldc_motor.rs │ ├── commands.rs │ ├── common.rs │ ├── common │ ├── defaults.rs │ ├── helpers.rs │ ├── lp_filter.rs │ ├── pid.rs │ └── types.rs │ ├── current_sensor.rs │ ├── foc_control.rs │ ├── foc_control │ └── control_utils.rs │ ├── hw_drivers.rs │ ├── lib.rs │ └── pos_sensor.rs ├── examples └── spinny.rs ├── flake.lock ├── flake.nix ├── peripherals └── AS5047P │ ├── Cargo.toml │ └── src │ └── lib.rs ├── platforms └── esp32_sfoc │ ├── .cargo │ └── config.toml │ ├── .gitignore │ ├── .vscode │ └── settings.json │ ├── Cargo.toml │ ├── rust-toolchain.toml │ └── src │ ├── device.rs │ ├── lib.rs │ ├── posn_encoder.rs │ └── time_source.rs ├── prototype ├── Cargo.lock ├── Cargo.toml └── src │ └── lib.rs ├── spinnies ├── esp32 │ ├── original │ │ ├── .cargo │ │ │ └── config.toml │ │ ├── .gitignore │ │ ├── Cargo.lock │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── rust-toolchain.toml │ │ └── src │ │ │ ├── bin │ │ │ └── main.rs │ │ │ └── lib.rs │ └── s3 │ │ ├── .cargo │ │ └── config.toml │ │ ├── .gitignore │ │ ├── Cargo.toml │ │ ├── build.rs │ │ ├── rust-toolchain.toml │ │ └── src │ │ ├── bin │ │ └── main.rs │ │ └── lib.rs └── generic_spinny │ ├── Cargo.toml │ ├── README.md │ └── src │ └── lib.rs ├── src └── lib.rs └── thoughts.md /.envrc: -------------------------------------------------------------------------------- 1 | use flake -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | # direnv files 13 | .envrc 14 | .direnv 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.check.allTargets": false, 3 | } 4 | -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.0.0 2 | message: "This is a re-write of Simple FOC. Below is the citation instructions of original work at time of writing this message" 3 | authors: 4 | - family-names: "Skuric" 5 | given-names: "Antun" 6 | orcid: "https://orcid.org/0000-0002-3323-4482" 7 | - family-names: "Bank" 8 | given-names: "Hasan Sinan" 9 | orcid: "https://orcid.org/0000-0002-0626-2664" 10 | - family-names: "Unger" 11 | given-names: "Richard" 12 | - family-names: "Williams" 13 | given-names: "Owen" 14 | - family-names: "González-Reyes" 15 | given-names: "David" 16 | orcid: "https://orcid.org/0000-0002-1535-3007" 17 | title: "SimpleFOC: A Field Oriented Control (FOC) Library for Controlling Brushless Direct Current (BLDC) and Stepper Motors" 18 | version: 2.2.2 19 | doi: 10.21105/joss.04232 20 | date-released: 2022-06-26 21 | url: "https://github.com/simplefoc/Arduino-FOC" 22 | 23 | preferred-citation: 24 | type: article 25 | authors: 26 | - family-names: "Skuric" 27 | given-names: "Antun" 28 | orcid: "https://orcid.org/0000-0002-3323-4482" 29 | - family-names: "Bank" 30 | given-names: "Hasan Sinan" 31 | orcid: "https://orcid.org/0000-0002-0626-2664" 32 | - family-names: "Unger" 33 | given-names: "Richard" 34 | - family-names: "Williams" 35 | given-names: "Owen" 36 | - family-names: "González-Reyes" 37 | given-names: "David" 38 | orcid: "https://orcid.org/0000-0002-1535-3007" 39 | doi: "10.21105/joss.04232" 40 | journal: "Journal of Open Source Software" 41 | url: "https://doi.org/10.21105/joss.04232" 42 | month: 6 43 | start: 4232 # First page number 44 | end: 4232 # Last page number 45 | title: "SimpleFOC: A Field Oriented Control (FOC) Library for Controlling Brushless Direct Current (BLDC) and Stepper Motors" 46 | volume: 7 47 | issue: 74 48 | year: 2022 49 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.93" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 10 | 11 | [[package]] 12 | name = "as5047p" 13 | version = "0.0.1" 14 | dependencies = [ 15 | "sfoc_rs_core", 16 | ] 17 | 18 | [[package]] 19 | name = "autocfg" 20 | version = "1.4.0" 21 | source = "registry+https://github.com/rust-lang/crates.io-index" 22 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 23 | 24 | [[package]] 25 | name = "az" 26 | version = "1.2.1" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 29 | 30 | [[package]] 31 | name = "bare-metal" 32 | version = "1.0.0" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 35 | 36 | [[package]] 37 | name = "basic-toml" 38 | version = "0.1.9" 39 | source = "registry+https://github.com/rust-lang/crates.io-index" 40 | checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" 41 | dependencies = [ 42 | "serde", 43 | ] 44 | 45 | [[package]] 46 | name = "bitfield" 47 | version = "0.17.0" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" 50 | 51 | [[package]] 52 | name = "bitflags" 53 | version = "1.3.2" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 56 | 57 | [[package]] 58 | name = "bitflags" 59 | version = "2.6.0" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 62 | 63 | [[package]] 64 | name = "bytemuck" 65 | version = "1.20.0" 66 | source = "registry+https://github.com/rust-lang/crates.io-index" 67 | checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" 68 | 69 | [[package]] 70 | name = "byteorder" 71 | version = "1.5.0" 72 | source = "registry+https://github.com/rust-lang/crates.io-index" 73 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 74 | 75 | [[package]] 76 | name = "cfg-if" 77 | version = "1.0.0" 78 | source = "registry+https://github.com/rust-lang/crates.io-index" 79 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 80 | 81 | [[package]] 82 | name = "chrono" 83 | version = "0.4.38" 84 | source = "registry+https://github.com/rust-lang/crates.io-index" 85 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 86 | dependencies = [ 87 | "num-traits", 88 | ] 89 | 90 | [[package]] 91 | name = "cordic" 92 | version = "0.1.5" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "0ed0a176c0b8c5c95fa0523177530364c5b68a8895d9745730dbfa692a7412d0" 95 | dependencies = [ 96 | "fixed", 97 | ] 98 | 99 | [[package]] 100 | name = "critical-section" 101 | version = "1.2.0" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 104 | 105 | [[package]] 106 | name = "crunchy" 107 | version = "0.2.2" 108 | source = "registry+https://github.com/rust-lang/crates.io-index" 109 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 110 | 111 | [[package]] 112 | name = "darling" 113 | version = "0.20.10" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 116 | dependencies = [ 117 | "darling_core", 118 | "darling_macro", 119 | ] 120 | 121 | [[package]] 122 | name = "darling_core" 123 | version = "0.20.10" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 126 | dependencies = [ 127 | "fnv", 128 | "ident_case", 129 | "proc-macro2", 130 | "quote", 131 | "strsim", 132 | "syn", 133 | ] 134 | 135 | [[package]] 136 | name = "darling_macro" 137 | version = "0.20.10" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 140 | dependencies = [ 141 | "darling_core", 142 | "quote", 143 | "syn", 144 | ] 145 | 146 | [[package]] 147 | name = "defmt" 148 | version = "0.3.10" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" 151 | dependencies = [ 152 | "bitflags 1.3.2", 153 | "defmt-macros", 154 | ] 155 | 156 | [[package]] 157 | name = "defmt-macros" 158 | version = "0.4.0" 159 | source = "registry+https://github.com/rust-lang/crates.io-index" 160 | checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" 161 | dependencies = [ 162 | "defmt-parser", 163 | "proc-macro-error2", 164 | "proc-macro2", 165 | "quote", 166 | "syn", 167 | ] 168 | 169 | [[package]] 170 | name = "defmt-parser" 171 | version = "0.4.1" 172 | source = "registry+https://github.com/rust-lang/crates.io-index" 173 | checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" 174 | dependencies = [ 175 | "thiserror", 176 | ] 177 | 178 | [[package]] 179 | name = "defmt-rtt" 180 | version = "0.4.1" 181 | source = "registry+https://github.com/rust-lang/crates.io-index" 182 | checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" 183 | dependencies = [ 184 | "critical-section", 185 | "defmt", 186 | ] 187 | 188 | [[package]] 189 | name = "delegate" 190 | version = "0.13.1" 191 | source = "registry+https://github.com/rust-lang/crates.io-index" 192 | checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" 193 | dependencies = [ 194 | "proc-macro2", 195 | "quote", 196 | "syn", 197 | ] 198 | 199 | [[package]] 200 | name = "discrete_count" 201 | version = "0.0.2" 202 | source = "git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951#de1ce8d5987319aeea4dba678d86659787aaf951" 203 | dependencies = [ 204 | "discrete_count_core", 205 | "fixed", 206 | "typenum", 207 | ] 208 | 209 | [[package]] 210 | name = "discrete_count_core" 211 | version = "0.0.2" 212 | source = "git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951#de1ce8d5987319aeea4dba678d86659787aaf951" 213 | 214 | [[package]] 215 | name = "document-features" 216 | version = "0.2.10" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" 219 | dependencies = [ 220 | "litrs", 221 | ] 222 | 223 | [[package]] 224 | name = "embassy-embedded-hal" 225 | version = "0.2.0" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" 228 | dependencies = [ 229 | "embassy-futures", 230 | "embassy-sync", 231 | "embassy-time", 232 | "embedded-hal 0.2.7", 233 | "embedded-hal 1.0.0", 234 | "embedded-hal-async", 235 | "embedded-storage", 236 | "embedded-storage-async", 237 | "nb 1.1.0", 238 | ] 239 | 240 | [[package]] 241 | name = "embassy-futures" 242 | version = "0.1.1" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" 245 | dependencies = [ 246 | "defmt", 247 | ] 248 | 249 | [[package]] 250 | name = "embassy-sync" 251 | version = "0.6.1" 252 | source = "registry+https://github.com/rust-lang/crates.io-index" 253 | checksum = "3899a6e39fa3f54bf8aaf00979f9f9c0145a522f7244810533abbb748be6ce82" 254 | dependencies = [ 255 | "cfg-if", 256 | "critical-section", 257 | "defmt", 258 | "embedded-io-async", 259 | "futures-sink", 260 | "futures-util", 261 | "heapless", 262 | ] 263 | 264 | [[package]] 265 | name = "embassy-time" 266 | version = "0.3.2" 267 | source = "registry+https://github.com/rust-lang/crates.io-index" 268 | checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" 269 | dependencies = [ 270 | "cfg-if", 271 | "critical-section", 272 | "document-features", 273 | "embassy-time-driver", 274 | "embassy-time-queue-driver", 275 | "embedded-hal 0.2.7", 276 | "embedded-hal 1.0.0", 277 | "embedded-hal-async", 278 | "futures-util", 279 | "heapless", 280 | ] 281 | 282 | [[package]] 283 | name = "embassy-time-driver" 284 | version = "0.1.0" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" 287 | dependencies = [ 288 | "document-features", 289 | ] 290 | 291 | [[package]] 292 | name = "embassy-time-queue-driver" 293 | version = "0.1.0" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" 296 | 297 | [[package]] 298 | name = "embedded-can" 299 | version = "0.4.1" 300 | source = "registry+https://github.com/rust-lang/crates.io-index" 301 | checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" 302 | dependencies = [ 303 | "nb 1.1.0", 304 | ] 305 | 306 | [[package]] 307 | name = "embedded-hal" 308 | version = "0.2.7" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 311 | dependencies = [ 312 | "nb 0.1.3", 313 | "void", 314 | ] 315 | 316 | [[package]] 317 | name = "embedded-hal" 318 | version = "1.0.0" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 321 | dependencies = [ 322 | "defmt", 323 | ] 324 | 325 | [[package]] 326 | name = "embedded-hal-async" 327 | version = "1.0.0" 328 | source = "registry+https://github.com/rust-lang/crates.io-index" 329 | checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" 330 | dependencies = [ 331 | "embedded-hal 1.0.0", 332 | ] 333 | 334 | [[package]] 335 | name = "embedded-hal-nb" 336 | version = "1.0.0" 337 | source = "registry+https://github.com/rust-lang/crates.io-index" 338 | checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" 339 | dependencies = [ 340 | "embedded-hal 1.0.0", 341 | "nb 1.1.0", 342 | ] 343 | 344 | [[package]] 345 | name = "embedded-io" 346 | version = "0.6.1" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 349 | dependencies = [ 350 | "defmt", 351 | ] 352 | 353 | [[package]] 354 | name = "embedded-io-async" 355 | version = "0.6.1" 356 | source = "registry+https://github.com/rust-lang/crates.io-index" 357 | checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" 358 | dependencies = [ 359 | "defmt", 360 | "embedded-io", 361 | ] 362 | 363 | [[package]] 364 | name = "embedded-storage" 365 | version = "0.3.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" 368 | 369 | [[package]] 370 | name = "embedded-storage-async" 371 | version = "0.4.1" 372 | source = "registry+https://github.com/rust-lang/crates.io-index" 373 | checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" 374 | dependencies = [ 375 | "embedded-storage", 376 | ] 377 | 378 | [[package]] 379 | name = "embedded-time" 380 | version = "0.12.1" 381 | source = "registry+https://github.com/rust-lang/crates.io-index" 382 | checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" 383 | dependencies = [ 384 | "num", 385 | ] 386 | 387 | [[package]] 388 | name = "enum-as-inner" 389 | version = "0.6.1" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" 392 | dependencies = [ 393 | "heck", 394 | "proc-macro2", 395 | "quote", 396 | "syn", 397 | ] 398 | 399 | [[package]] 400 | name = "enumset" 401 | version = "1.1.5" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" 404 | dependencies = [ 405 | "enumset_derive", 406 | ] 407 | 408 | [[package]] 409 | name = "enumset_derive" 410 | version = "0.10.0" 411 | source = "registry+https://github.com/rust-lang/crates.io-index" 412 | checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" 413 | dependencies = [ 414 | "darling", 415 | "proc-macro2", 416 | "quote", 417 | "syn", 418 | ] 419 | 420 | [[package]] 421 | name = "equivalent" 422 | version = "1.0.1" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 425 | 426 | [[package]] 427 | name = "esp-backtrace" 428 | version = "0.14.2" 429 | source = "registry+https://github.com/rust-lang/crates.io-index" 430 | checksum = "cb7660d85e3e7b0e113aaeeffb1a155e64a09a5035d4104031875acdba4cb68e" 431 | dependencies = [ 432 | "defmt", 433 | "esp-build", 434 | "esp-println", 435 | "semihosting", 436 | ] 437 | 438 | [[package]] 439 | name = "esp-build" 440 | version = "0.1.0" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "b94a4b8d74e7cc7baabcca5b2277b41877e039ad9cd49959d48ef94dac7eab4b" 443 | dependencies = [ 444 | "quote", 445 | "syn", 446 | "termcolor", 447 | ] 448 | 449 | [[package]] 450 | name = "esp-config" 451 | version = "0.2.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "f7584e4cd1dac06201fd92fff1c84b396be5458ac4d93e9457e7a89b1b42c60e" 454 | dependencies = [ 455 | "document-features", 456 | ] 457 | 458 | [[package]] 459 | name = "esp-hal" 460 | version = "0.22.0" 461 | source = "registry+https://github.com/rust-lang/crates.io-index" 462 | checksum = "1a5605e1518d63f7bf9fbd9885e61d2896060d2e4f28954736bdd74da911b676" 463 | dependencies = [ 464 | "basic-toml", 465 | "bitfield", 466 | "bitflags 2.6.0", 467 | "bytemuck", 468 | "cfg-if", 469 | "chrono", 470 | "critical-section", 471 | "defmt", 472 | "delegate", 473 | "document-features", 474 | "embassy-embedded-hal", 475 | "embassy-futures", 476 | "embassy-sync", 477 | "embedded-can", 478 | "embedded-hal 0.2.7", 479 | "embedded-hal 1.0.0", 480 | "embedded-hal-async", 481 | "embedded-hal-nb", 482 | "embedded-io", 483 | "embedded-io-async", 484 | "enumset", 485 | "esp-build", 486 | "esp-config", 487 | "esp-hal-procmacros", 488 | "esp-metadata", 489 | "esp-riscv-rt", 490 | "esp32", 491 | "esp32c2", 492 | "esp32c3", 493 | "esp32c6", 494 | "esp32h2", 495 | "esp32s2", 496 | "esp32s3", 497 | "fugit 0.3.7", 498 | "nb 1.1.0", 499 | "paste", 500 | "portable-atomic", 501 | "rand_core", 502 | "serde", 503 | "strum", 504 | "ufmt-write", 505 | "void", 506 | "xtensa-lx", 507 | "xtensa-lx-rt", 508 | ] 509 | 510 | [[package]] 511 | name = "esp-hal-procmacros" 512 | version = "0.15.0" 513 | source = "registry+https://github.com/rust-lang/crates.io-index" 514 | checksum = "69a9a8706b7d1182b56335d196e70eeb04e2b70f4b8db96432898bd3c2bdb91e" 515 | dependencies = [ 516 | "darling", 517 | "document-features", 518 | "litrs", 519 | "proc-macro-crate", 520 | "proc-macro-error2", 521 | "proc-macro2", 522 | "quote", 523 | "syn", 524 | ] 525 | 526 | [[package]] 527 | name = "esp-metadata" 528 | version = "0.4.0" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "f9972bbb21dcafe430b87f92efc7a788978a2d17cf8f572d104beeb48602482a" 531 | dependencies = [ 532 | "anyhow", 533 | "basic-toml", 534 | "serde", 535 | "strum", 536 | ] 537 | 538 | [[package]] 539 | name = "esp-println" 540 | version = "0.12.0" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "ee38e87bc7e303c299047c0e9bcd0f8ccca7c7e70d1fd78bbb565db14f33beb6" 543 | dependencies = [ 544 | "esp-build", 545 | "log", 546 | ] 547 | 548 | [[package]] 549 | name = "esp-riscv-rt" 550 | version = "0.9.1" 551 | source = "registry+https://github.com/rust-lang/crates.io-index" 552 | checksum = "94aca65db6157aa5f42d9df6595b21462f28207ca4230b799aa3620352ef6a72" 553 | dependencies = [ 554 | "document-features", 555 | "riscv", 556 | "riscv-rt-macros", 557 | ] 558 | 559 | [[package]] 560 | name = "esp32" 561 | version = "0.34.0" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "af7d3208ef4ffd96c3105b3fb6fd19e8512bc128b24cb866dc26a734b09f454c" 564 | dependencies = [ 565 | "critical-section", 566 | "defmt", 567 | "vcell", 568 | ] 569 | 570 | [[package]] 571 | name = "esp32_sfoc" 572 | version = "0.1.0" 573 | dependencies = [ 574 | "critical-section", 575 | "defmt", 576 | "defmt-rtt", 577 | "discrete_count", 578 | "embedded-hal 1.0.0", 579 | "embedded-time", 580 | "esp-backtrace", 581 | "esp-hal", 582 | "fixed", 583 | "foc", 584 | "fugit 0.4.0", 585 | "log", 586 | "sfoc_rs_core", 587 | "typenum", 588 | ] 589 | 590 | [[package]] 591 | name = "esp32c2" 592 | version = "0.23.0" 593 | source = "registry+https://github.com/rust-lang/crates.io-index" 594 | checksum = "e74f8ceff5249a39f6ffeaea7a9c048b36fd1ba67d365330e0970927c57759ab" 595 | dependencies = [ 596 | "critical-section", 597 | "defmt", 598 | "vcell", 599 | ] 600 | 601 | [[package]] 602 | name = "esp32c3" 603 | version = "0.26.0" 604 | source = "registry+https://github.com/rust-lang/crates.io-index" 605 | checksum = "5d1750382dc49fa333ee6b1ba96f8c540038b9666f5a233dc1221c98e3236118" 606 | dependencies = [ 607 | "critical-section", 608 | "defmt", 609 | "vcell", 610 | ] 611 | 612 | [[package]] 613 | name = "esp32c6" 614 | version = "0.17.0" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "8b98fcf7ae90ee4d55f06170dfeaaebbf2a1619bb38b4e14b9009b4d636b87e7" 617 | dependencies = [ 618 | "critical-section", 619 | "defmt", 620 | "vcell", 621 | ] 622 | 623 | [[package]] 624 | name = "esp32h2" 625 | version = "0.13.0" 626 | source = "registry+https://github.com/rust-lang/crates.io-index" 627 | checksum = "b1530274ade78283655a6810dd5d1840404945f4a5bf3d74729c35946beb8304" 628 | dependencies = [ 629 | "critical-section", 630 | "defmt", 631 | "vcell", 632 | ] 633 | 634 | [[package]] 635 | name = "esp32s2" 636 | version = "0.25.0" 637 | source = "registry+https://github.com/rust-lang/crates.io-index" 638 | checksum = "2f77ec7a694eb60741f53236e625456abf672ba5b0b73c4a2d708a343c6f3495" 639 | dependencies = [ 640 | "critical-section", 641 | "defmt", 642 | "vcell", 643 | ] 644 | 645 | [[package]] 646 | name = "esp32s3" 647 | version = "0.29.0" 648 | source = "registry+https://github.com/rust-lang/crates.io-index" 649 | checksum = "fe69dca8db0ed37d222555f12dfaf99232592e84f54e56dd81e450a4769718bf" 650 | dependencies = [ 651 | "critical-section", 652 | "defmt", 653 | "vcell", 654 | ] 655 | 656 | [[package]] 657 | name = "fixed" 658 | version = "1.28.0" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" 661 | dependencies = [ 662 | "az", 663 | "bytemuck", 664 | "half", 665 | "typenum", 666 | ] 667 | 668 | [[package]] 669 | name = "fnv" 670 | version = "1.0.7" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 673 | 674 | [[package]] 675 | name = "foc" 676 | version = "0.3.0" 677 | source = "registry+https://github.com/rust-lang/crates.io-index" 678 | checksum = "e162e4bf45e12dfb5de9c561acd8fffd5f9ecb7439440bfb7a7dababd972594f" 679 | dependencies = [ 680 | "cordic", 681 | "fixed", 682 | ] 683 | 684 | [[package]] 685 | name = "fugit" 686 | version = "0.3.7" 687 | source = "registry+https://github.com/rust-lang/crates.io-index" 688 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 689 | dependencies = [ 690 | "defmt", 691 | "gcd", 692 | ] 693 | 694 | [[package]] 695 | name = "fugit" 696 | version = "0.4.0" 697 | source = "git+https://github.com/Ben-PH/fugit.git?rev=aad2d2d97f45b9b12076648b78857f47ff6f1c1b#aad2d2d97f45b9b12076648b78857f47ff6f1c1b" 698 | dependencies = [ 699 | "gcd", 700 | "typenum", 701 | ] 702 | 703 | [[package]] 704 | name = "futures-core" 705 | version = "0.3.31" 706 | source = "registry+https://github.com/rust-lang/crates.io-index" 707 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 708 | 709 | [[package]] 710 | name = "futures-sink" 711 | version = "0.3.31" 712 | source = "registry+https://github.com/rust-lang/crates.io-index" 713 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 714 | 715 | [[package]] 716 | name = "futures-task" 717 | version = "0.3.31" 718 | source = "registry+https://github.com/rust-lang/crates.io-index" 719 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 720 | 721 | [[package]] 722 | name = "futures-util" 723 | version = "0.3.31" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 726 | dependencies = [ 727 | "futures-core", 728 | "futures-task", 729 | "pin-project-lite", 730 | "pin-utils", 731 | ] 732 | 733 | [[package]] 734 | name = "gcd" 735 | version = "2.3.0" 736 | source = "registry+https://github.com/rust-lang/crates.io-index" 737 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 738 | 739 | [[package]] 740 | name = "generic_spinny" 741 | version = "0.1.0" 742 | dependencies = [ 743 | "fugit 0.4.0", 744 | "sfoc_rs", 745 | ] 746 | 747 | [[package]] 748 | name = "half" 749 | version = "2.4.1" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 752 | dependencies = [ 753 | "cfg-if", 754 | "crunchy", 755 | ] 756 | 757 | [[package]] 758 | name = "hash32" 759 | version = "0.3.1" 760 | source = "registry+https://github.com/rust-lang/crates.io-index" 761 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 762 | dependencies = [ 763 | "byteorder", 764 | ] 765 | 766 | [[package]] 767 | name = "hashbrown" 768 | version = "0.15.2" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 771 | 772 | [[package]] 773 | name = "heapless" 774 | version = "0.8.0" 775 | source = "registry+https://github.com/rust-lang/crates.io-index" 776 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" 777 | dependencies = [ 778 | "hash32", 779 | "stable_deref_trait", 780 | ] 781 | 782 | [[package]] 783 | name = "heck" 784 | version = "0.5.0" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 787 | 788 | [[package]] 789 | name = "ident_case" 790 | version = "1.0.1" 791 | source = "registry+https://github.com/rust-lang/crates.io-index" 792 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 793 | 794 | [[package]] 795 | name = "indexmap" 796 | version = "2.7.0" 797 | source = "registry+https://github.com/rust-lang/crates.io-index" 798 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 799 | dependencies = [ 800 | "equivalent", 801 | "hashbrown", 802 | ] 803 | 804 | [[package]] 805 | name = "litrs" 806 | version = "0.4.1" 807 | source = "registry+https://github.com/rust-lang/crates.io-index" 808 | checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" 809 | dependencies = [ 810 | "proc-macro2", 811 | ] 812 | 813 | [[package]] 814 | name = "lock_api" 815 | version = "0.4.12" 816 | source = "registry+https://github.com/rust-lang/crates.io-index" 817 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 818 | dependencies = [ 819 | "autocfg", 820 | "scopeguard", 821 | ] 822 | 823 | [[package]] 824 | name = "log" 825 | version = "0.4.22" 826 | source = "registry+https://github.com/rust-lang/crates.io-index" 827 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 828 | 829 | [[package]] 830 | name = "memchr" 831 | version = "2.7.4" 832 | source = "registry+https://github.com/rust-lang/crates.io-index" 833 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 834 | 835 | [[package]] 836 | name = "micromath" 837 | version = "2.1.0" 838 | source = "registry+https://github.com/rust-lang/crates.io-index" 839 | checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" 840 | 841 | [[package]] 842 | name = "minijinja" 843 | version = "2.5.0" 844 | source = "registry+https://github.com/rust-lang/crates.io-index" 845 | checksum = "2c37e1b517d1dcd0e51dc36c4567b9d5a29262b3ec8da6cb5d35e27a8fb529b5" 846 | dependencies = [ 847 | "serde", 848 | ] 849 | 850 | [[package]] 851 | name = "mutex-trait" 852 | version = "0.2.0" 853 | source = "registry+https://github.com/rust-lang/crates.io-index" 854 | checksum = "b4bb1638d419e12f8b1c43d9e639abd0d1424285bdea2f76aa231e233c63cd3a" 855 | 856 | [[package]] 857 | name = "nb" 858 | version = "0.1.3" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 861 | dependencies = [ 862 | "nb 1.1.0", 863 | ] 864 | 865 | [[package]] 866 | name = "nb" 867 | version = "1.1.0" 868 | source = "registry+https://github.com/rust-lang/crates.io-index" 869 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 870 | 871 | [[package]] 872 | name = "num" 873 | version = "0.3.1" 874 | source = "registry+https://github.com/rust-lang/crates.io-index" 875 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 876 | dependencies = [ 877 | "num-complex", 878 | "num-integer", 879 | "num-iter", 880 | "num-rational", 881 | "num-traits", 882 | ] 883 | 884 | [[package]] 885 | name = "num-complex" 886 | version = "0.3.1" 887 | source = "registry+https://github.com/rust-lang/crates.io-index" 888 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 889 | dependencies = [ 890 | "num-traits", 891 | ] 892 | 893 | [[package]] 894 | name = "num-integer" 895 | version = "0.1.46" 896 | source = "registry+https://github.com/rust-lang/crates.io-index" 897 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 898 | dependencies = [ 899 | "num-traits", 900 | ] 901 | 902 | [[package]] 903 | name = "num-iter" 904 | version = "0.1.45" 905 | source = "registry+https://github.com/rust-lang/crates.io-index" 906 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 907 | dependencies = [ 908 | "autocfg", 909 | "num-integer", 910 | "num-traits", 911 | ] 912 | 913 | [[package]] 914 | name = "num-rational" 915 | version = "0.3.2" 916 | source = "registry+https://github.com/rust-lang/crates.io-index" 917 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 918 | dependencies = [ 919 | "autocfg", 920 | "num-integer", 921 | "num-traits", 922 | ] 923 | 924 | [[package]] 925 | name = "num-traits" 926 | version = "0.2.19" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 929 | dependencies = [ 930 | "autocfg", 931 | ] 932 | 933 | [[package]] 934 | name = "original" 935 | version = "0.1.0" 936 | dependencies = [ 937 | "critical-section", 938 | "defmt", 939 | "defmt-rtt", 940 | "esp-backtrace", 941 | "esp-hal", 942 | "generic_spinny", 943 | "sfoc_rs", 944 | ] 945 | 946 | [[package]] 947 | name = "paste" 948 | version = "1.0.15" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 951 | 952 | [[package]] 953 | name = "pid" 954 | version = "4.0.0" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "d7c931ef9756cd5e3fa3d395bfe09df4dfa6f0612c6ca8f6b12927d17ca34e36" 957 | dependencies = [ 958 | "num-traits", 959 | ] 960 | 961 | [[package]] 962 | name = "pin-project-lite" 963 | version = "0.2.15" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 966 | 967 | [[package]] 968 | name = "pin-utils" 969 | version = "0.1.0" 970 | source = "registry+https://github.com/rust-lang/crates.io-index" 971 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 972 | 973 | [[package]] 974 | name = "portable-atomic" 975 | version = "1.10.0" 976 | source = "registry+https://github.com/rust-lang/crates.io-index" 977 | checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" 978 | 979 | [[package]] 980 | name = "proc-macro-crate" 981 | version = "3.2.0" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" 984 | dependencies = [ 985 | "toml_edit", 986 | ] 987 | 988 | [[package]] 989 | name = "proc-macro-error-attr2" 990 | version = "2.0.0" 991 | source = "registry+https://github.com/rust-lang/crates.io-index" 992 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 993 | dependencies = [ 994 | "proc-macro2", 995 | "quote", 996 | ] 997 | 998 | [[package]] 999 | name = "proc-macro-error2" 1000 | version = "2.0.1" 1001 | source = "registry+https://github.com/rust-lang/crates.io-index" 1002 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 1003 | dependencies = [ 1004 | "proc-macro-error-attr2", 1005 | "proc-macro2", 1006 | "quote", 1007 | "syn", 1008 | ] 1009 | 1010 | [[package]] 1011 | name = "proc-macro2" 1012 | version = "1.0.92" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 1015 | dependencies = [ 1016 | "unicode-ident", 1017 | ] 1018 | 1019 | [[package]] 1020 | name = "quote" 1021 | version = "1.0.37" 1022 | source = "registry+https://github.com/rust-lang/crates.io-index" 1023 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1024 | dependencies = [ 1025 | "proc-macro2", 1026 | ] 1027 | 1028 | [[package]] 1029 | name = "r0" 1030 | version = "1.0.0" 1031 | source = "registry+https://github.com/rust-lang/crates.io-index" 1032 | checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" 1033 | 1034 | [[package]] 1035 | name = "rand_core" 1036 | version = "0.6.4" 1037 | source = "registry+https://github.com/rust-lang/crates.io-index" 1038 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1039 | 1040 | [[package]] 1041 | name = "riscv" 1042 | version = "0.12.1" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" 1045 | dependencies = [ 1046 | "critical-section", 1047 | "embedded-hal 1.0.0", 1048 | "paste", 1049 | "riscv-macros", 1050 | "riscv-pac", 1051 | ] 1052 | 1053 | [[package]] 1054 | name = "riscv-macros" 1055 | version = "0.1.0" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" 1058 | dependencies = [ 1059 | "proc-macro2", 1060 | "quote", 1061 | "syn", 1062 | ] 1063 | 1064 | [[package]] 1065 | name = "riscv-pac" 1066 | version = "0.2.0" 1067 | source = "registry+https://github.com/rust-lang/crates.io-index" 1068 | checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" 1069 | 1070 | [[package]] 1071 | name = "riscv-rt-macros" 1072 | version = "0.2.2" 1073 | source = "registry+https://github.com/rust-lang/crates.io-index" 1074 | checksum = "30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0" 1075 | dependencies = [ 1076 | "proc-macro2", 1077 | "quote", 1078 | "syn", 1079 | ] 1080 | 1081 | [[package]] 1082 | name = "rustversion" 1083 | version = "1.0.18" 1084 | source = "registry+https://github.com/rust-lang/crates.io-index" 1085 | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" 1086 | 1087 | [[package]] 1088 | name = "scopeguard" 1089 | version = "1.2.0" 1090 | source = "registry+https://github.com/rust-lang/crates.io-index" 1091 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1092 | 1093 | [[package]] 1094 | name = "semihosting" 1095 | version = "0.1.16" 1096 | source = "registry+https://github.com/rust-lang/crates.io-index" 1097 | checksum = "a5c5996e5d1dec34b0dff3285e27124e70964504e3fd361bce330dc476cebafd" 1098 | 1099 | [[package]] 1100 | name = "serde" 1101 | version = "1.0.215" 1102 | source = "registry+https://github.com/rust-lang/crates.io-index" 1103 | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 1104 | dependencies = [ 1105 | "serde_derive", 1106 | ] 1107 | 1108 | [[package]] 1109 | name = "serde_derive" 1110 | version = "1.0.215" 1111 | source = "registry+https://github.com/rust-lang/crates.io-index" 1112 | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 1113 | dependencies = [ 1114 | "proc-macro2", 1115 | "quote", 1116 | "syn", 1117 | ] 1118 | 1119 | [[package]] 1120 | name = "serde_spanned" 1121 | version = "0.6.8" 1122 | source = "registry+https://github.com/rust-lang/crates.io-index" 1123 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1124 | dependencies = [ 1125 | "serde", 1126 | ] 1127 | 1128 | [[package]] 1129 | name = "sfoc_rs" 1130 | version = "0.3.0" 1131 | dependencies = [ 1132 | "embedded-hal 1.0.0", 1133 | "esp32_sfoc", 1134 | "sfoc_rs_core", 1135 | ] 1136 | 1137 | [[package]] 1138 | name = "sfoc_rs_core" 1139 | version = "0.0.1" 1140 | dependencies = [ 1141 | "cordic", 1142 | "discrete_count", 1143 | "embedded-hal 1.0.0", 1144 | "embedded-time", 1145 | "foc", 1146 | "micromath", 1147 | "pid", 1148 | ] 1149 | 1150 | [[package]] 1151 | name = "spin" 1152 | version = "0.9.8" 1153 | source = "registry+https://github.com/rust-lang/crates.io-index" 1154 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1155 | dependencies = [ 1156 | "lock_api", 1157 | ] 1158 | 1159 | [[package]] 1160 | name = "stable_deref_trait" 1161 | version = "1.2.0" 1162 | source = "registry+https://github.com/rust-lang/crates.io-index" 1163 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1164 | 1165 | [[package]] 1166 | name = "strsim" 1167 | version = "0.11.1" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1170 | 1171 | [[package]] 1172 | name = "strum" 1173 | version = "0.26.3" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1176 | dependencies = [ 1177 | "strum_macros", 1178 | ] 1179 | 1180 | [[package]] 1181 | name = "strum_macros" 1182 | version = "0.26.4" 1183 | source = "registry+https://github.com/rust-lang/crates.io-index" 1184 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1185 | dependencies = [ 1186 | "heck", 1187 | "proc-macro2", 1188 | "quote", 1189 | "rustversion", 1190 | "syn", 1191 | ] 1192 | 1193 | [[package]] 1194 | name = "syn" 1195 | version = "2.0.90" 1196 | source = "registry+https://github.com/rust-lang/crates.io-index" 1197 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 1198 | dependencies = [ 1199 | "proc-macro2", 1200 | "quote", 1201 | "unicode-ident", 1202 | ] 1203 | 1204 | [[package]] 1205 | name = "termcolor" 1206 | version = "1.4.1" 1207 | source = "registry+https://github.com/rust-lang/crates.io-index" 1208 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1209 | dependencies = [ 1210 | "winapi-util", 1211 | ] 1212 | 1213 | [[package]] 1214 | name = "thiserror" 1215 | version = "2.0.3" 1216 | source = "registry+https://github.com/rust-lang/crates.io-index" 1217 | checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" 1218 | dependencies = [ 1219 | "thiserror-impl", 1220 | ] 1221 | 1222 | [[package]] 1223 | name = "thiserror-impl" 1224 | version = "2.0.3" 1225 | source = "registry+https://github.com/rust-lang/crates.io-index" 1226 | checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" 1227 | dependencies = [ 1228 | "proc-macro2", 1229 | "quote", 1230 | "syn", 1231 | ] 1232 | 1233 | [[package]] 1234 | name = "toml" 1235 | version = "0.8.19" 1236 | source = "registry+https://github.com/rust-lang/crates.io-index" 1237 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 1238 | dependencies = [ 1239 | "serde", 1240 | "serde_spanned", 1241 | "toml_datetime", 1242 | "toml_edit", 1243 | ] 1244 | 1245 | [[package]] 1246 | name = "toml_datetime" 1247 | version = "0.6.8" 1248 | source = "registry+https://github.com/rust-lang/crates.io-index" 1249 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1250 | dependencies = [ 1251 | "serde", 1252 | ] 1253 | 1254 | [[package]] 1255 | name = "toml_edit" 1256 | version = "0.22.22" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 1259 | dependencies = [ 1260 | "indexmap", 1261 | "serde", 1262 | "serde_spanned", 1263 | "toml_datetime", 1264 | "winnow", 1265 | ] 1266 | 1267 | [[package]] 1268 | name = "typenum" 1269 | version = "1.17.0" 1270 | source = "registry+https://github.com/rust-lang/crates.io-index" 1271 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1272 | 1273 | [[package]] 1274 | name = "ufmt-write" 1275 | version = "0.1.0" 1276 | source = "registry+https://github.com/rust-lang/crates.io-index" 1277 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 1278 | 1279 | [[package]] 1280 | name = "unicode-ident" 1281 | version = "1.0.14" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1284 | 1285 | [[package]] 1286 | name = "vcell" 1287 | version = "0.1.3" 1288 | source = "registry+https://github.com/rust-lang/crates.io-index" 1289 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 1290 | 1291 | [[package]] 1292 | name = "void" 1293 | version = "1.0.2" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1296 | 1297 | [[package]] 1298 | name = "winapi-util" 1299 | version = "0.1.9" 1300 | source = "registry+https://github.com/rust-lang/crates.io-index" 1301 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1302 | dependencies = [ 1303 | "windows-sys", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "windows-sys" 1308 | version = "0.59.0" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1311 | dependencies = [ 1312 | "windows-targets", 1313 | ] 1314 | 1315 | [[package]] 1316 | name = "windows-targets" 1317 | version = "0.52.6" 1318 | source = "registry+https://github.com/rust-lang/crates.io-index" 1319 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1320 | dependencies = [ 1321 | "windows_aarch64_gnullvm", 1322 | "windows_aarch64_msvc", 1323 | "windows_i686_gnu", 1324 | "windows_i686_gnullvm", 1325 | "windows_i686_msvc", 1326 | "windows_x86_64_gnu", 1327 | "windows_x86_64_gnullvm", 1328 | "windows_x86_64_msvc", 1329 | ] 1330 | 1331 | [[package]] 1332 | name = "windows_aarch64_gnullvm" 1333 | version = "0.52.6" 1334 | source = "registry+https://github.com/rust-lang/crates.io-index" 1335 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1336 | 1337 | [[package]] 1338 | name = "windows_aarch64_msvc" 1339 | version = "0.52.6" 1340 | source = "registry+https://github.com/rust-lang/crates.io-index" 1341 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1342 | 1343 | [[package]] 1344 | name = "windows_i686_gnu" 1345 | version = "0.52.6" 1346 | source = "registry+https://github.com/rust-lang/crates.io-index" 1347 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1348 | 1349 | [[package]] 1350 | name = "windows_i686_gnullvm" 1351 | version = "0.52.6" 1352 | source = "registry+https://github.com/rust-lang/crates.io-index" 1353 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1354 | 1355 | [[package]] 1356 | name = "windows_i686_msvc" 1357 | version = "0.52.6" 1358 | source = "registry+https://github.com/rust-lang/crates.io-index" 1359 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1360 | 1361 | [[package]] 1362 | name = "windows_x86_64_gnu" 1363 | version = "0.52.6" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1366 | 1367 | [[package]] 1368 | name = "windows_x86_64_gnullvm" 1369 | version = "0.52.6" 1370 | source = "registry+https://github.com/rust-lang/crates.io-index" 1371 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1372 | 1373 | [[package]] 1374 | name = "windows_x86_64_msvc" 1375 | version = "0.52.6" 1376 | source = "registry+https://github.com/rust-lang/crates.io-index" 1377 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1378 | 1379 | [[package]] 1380 | name = "winnow" 1381 | version = "0.6.20" 1382 | source = "registry+https://github.com/rust-lang/crates.io-index" 1383 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 1384 | dependencies = [ 1385 | "memchr", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "xtensa-lx" 1390 | version = "0.9.0" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "e758f94e1a1f71758f94052a2766dcb12604998eb372b8b2e30576e3ab1ba1e6" 1393 | dependencies = [ 1394 | "bare-metal", 1395 | "mutex-trait", 1396 | "spin", 1397 | ] 1398 | 1399 | [[package]] 1400 | name = "xtensa-lx-rt" 1401 | version = "0.17.2" 1402 | source = "registry+https://github.com/rust-lang/crates.io-index" 1403 | checksum = "5c0307d03dadbf95633942e13901984f2059df4c963367348168cbd21c962669" 1404 | dependencies = [ 1405 | "anyhow", 1406 | "bare-metal", 1407 | "document-features", 1408 | "enum-as-inner", 1409 | "minijinja", 1410 | "r0", 1411 | "serde", 1412 | "strum", 1413 | "toml", 1414 | "xtensa-lx", 1415 | "xtensa-lx-rt-proc-macros", 1416 | ] 1417 | 1418 | [[package]] 1419 | name = "xtensa-lx-rt-proc-macros" 1420 | version = "0.2.2" 1421 | source = "registry+https://github.com/rust-lang/crates.io-index" 1422 | checksum = "11277b1e4cbb7ffe44678c668518b249c843c81df249b8f096701757bc50d7ee" 1423 | dependencies = [ 1424 | "darling", 1425 | "proc-macro2", 1426 | "quote", 1427 | "syn", 1428 | ] 1429 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sfoc_rs" 3 | version = "0.3.0" 4 | authors = ["Ben PHL "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [workspace] 9 | members = [ 10 | "core", 11 | "platforms/esp32_sfoc", 12 | "peripherals/AS5047P", 13 | "spinnies/esp32/original", "spinnies/generic_spinny", 14 | ] 15 | exclude = [ 16 | "prototype", 17 | ] 18 | 19 | 20 | [dependencies] 21 | embedded-hal = "1.0.0" 22 | esp32_sfoc = { version = "0.1.0", path = "platforms/esp32_sfoc", optional = true } 23 | sfoc_rs_core = { version = "0.0.1", path = "./core" } 24 | 25 | [features] 26 | esp32 = ["dep:esp32_sfoc"] 27 | 28 | -------------------------------------------------------------------------------- /Contributing.md: -------------------------------------------------------------------------------- 1 | > If any of these describe you, you'll probably have something enjoyable to work with. 2 | 3 | 4 | ## Interested in learning Rust, know CPP 5 | 6 | This is essentially a re-write of a CPP code base. I'd be happy to help you navigate the rust learning-curve as part of getting a PR through 7 | 8 | > Sounds cool to get involved? How about... 9 | 10 | DM me in the community forum(@Ben-PH)/discord(#Hawkey5212) and we can have a chat about getting started. 11 | 12 | ## Not interested in Rust, but familiar with Simple FOC code base 13 | 14 | There are gaps in my knowledge that I'm working on filling. There are also a lot of improvements that Rust is particularly well suited for if you deeply understand the operating principals the code is responsible for. I have a big overlap between these two domains. For example, `float` is quite common in Simple FOC, but Rust has some very nice ways to do away with floats so long as you understand everything going on. 15 | 16 | > Sounds cool to get involved? How about... 17 | 18 | Search through the github issues, where I raise some thoughts/questions. The code-base also follows the SFOC structure somewhat closely, and if you see some `todo!()`s, or missing implementations, raise an issue. 19 | 20 | DM me is also a great option 21 | 22 | ## Want to improve the Simple FOC code base 23 | 24 | This is very much a "fresh-eyes" project. 25 | 26 | - I've already seen that the phase-state enum should instead express the on/off state of each pin inside a struct. 27 | - I will be, in a way, "auditing" the use of floats and seeing where integers can be used 28 | - I will be writing things so that a rotary/linear(/other?) motors are concrete implementations of the generic `Motor` 29 | - ... 30 | 31 | To me, the work done here feeding benefits back through to Simple FOC would bring be a great thing to see. If contributing to discussions, documentation, code, etc takes your fancy, you will also be contributing to Simple FOC improvements, though perhaps less directly. 32 | 33 | > Sounds cool to get involved? How about... 34 | 35 | Point me in the direction of any discussions aleady being had about things that need to be improved/added/etc in SFOC that deserves to get attention during a re-write. 36 | 37 | And as always, DMs welcome. 38 | 39 | ## Know Rust, but everything else about this is new and strange? 40 | 41 | Are you me? Please don't make me disapear and replace me. I like my life :) 42 | 43 | 44 | ## Just want to give support? 45 | 46 | Starring the repo is not nothing. Supporting Ukraine in some meaningful way and letting me know it's because you read also helps (DM, github issue, etc). 47 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Copyright 2024 Benjamin Pieter-Hawke 2 | 3 | Permission is hereby granted, free of charge, to any 4 | person obtaining a copy of this software and associated 5 | documentation files (the "Software"), to deal in the 6 | Software without restriction, including without 7 | limitation the rights to use, copy, modify, merge, 8 | publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software 10 | is furnished to do so, subject to the following 11 | conditions: 12 | 13 | The above copyright notice and this permission notice 14 | shall be included in all copies or substantial portions 15 | of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 18 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 19 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 20 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 21 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 22 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 24 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 | DEALINGS IN THE SOFTWARE. 26 | -------------------------------------------------------------------------------- /Makefile.toml: -------------------------------------------------------------------------------- 1 | [env] 2 | CARGO_MAKE_EXTEND_WORKSPACE_MAKEFILE = true 3 | [tasks.check] 4 | command = "cargo" 5 | args = ["check"] 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Simple FOC, but with Rust. 2 | 3 | Still a heavy WIP. Getting close to a very basic const-voltage implementation for esp32. 4 | 5 | One motivation is the prospect of, sometime down the line, there being a Rust option in which to explore the Simple FOC playground. To that end, some design principals that I try to think about: 6 | 7 | - No suprises when moving between Arduino and Rust: Moving between the two should bring a sense of familiarity. It should feel like applying the same concepts, in familiar patterns, just using idioms that change with the language being used. 8 | - Simplicity, Accesibility, and Educational Enjoyment: Simple FOC delliberately makes design and implementation decisions that prioritises ease of use and enjoyment, and I aim to follow their lead. This will often imply that in order to make _using_ this library simple, the underlying code must bear the burden of managing complexity. 9 | - Advanced usage: Though not a primary aim, a bonus acheivement would include suitability for more advanced and nuanced use, such as 3d printer firmware. For emphasis: this goal is secondary to the first two. 10 | 11 | 12 | 13 | ### With respect to licence and assigning credit for work: 14 | 15 | This project started as a direct rewrite of the Simple FOC library. This has changed a touch, as Rust idioms and C++ Arduino idoms are at times in conflict. With that said, the project has gotten to its current state with a lot of direct input from the SFOC people, and this project continues to draw heavily from the original works of the SFOC Arduino library. 16 | 17 | At time of writing, this is a re-write of Simple FOC library. "We stand on the shoulders of giants" couldn't apply more here. Please refer to the Citations file, and the OG library [here](https://github.com/simplefoc/Arduino-FOC) 18 | 19 | #### Simple demo 20 | 21 | `cargo run --expample spinny` each second, prints out the duty cycles to make a slowly rotating magnetic field 22 | 23 | #### Supported platforms 24 | 25 | None yet, but esp32 and esp32s3 are in the works 26 | 27 | #### How to use this library. 28 | 29 | Still working out that story, but here is where we are right now: 30 | 31 | - `cargo make check` to check the code base 32 | - `cargo build` in any of the projects in `platforms` to build for a platform 33 | 34 | 35 | This is, essentially, the goal: 36 | 37 | 1. fork and clone this repo 38 | 2. `cd platforms ` 39 | 3. trivially-easy task to assign gpio pins for motor control and motor feedback pins 40 | 4. `cargo run` to run a default, slow-spinning motor 41 | 5. plug in functions/modules/features/etc. to make your program less trivial 42 | 6. ??? 43 | 7. profit 44 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sfoc_rs_core" 3 | version = "0.0.1" 4 | authors = ["Ben PHL "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | cordic = "0.1.5" 10 | embedded-hal = "1.0.0" 11 | embedded-time = "0.12.1" 12 | foc = "0.3.0" 13 | micromath = "2.1.0" 14 | pid = "4.0.0" 15 | discrete_count = {git = "https://github.com/Ben-PH/discrete_count", rev = "de1ce8d5987319aeea4dba678d86659787aaf951", features = ["typenum", "fixed"]} 16 | -------------------------------------------------------------------------------- /core/src/bldc_driver.rs: -------------------------------------------------------------------------------- 1 | use discrete_count::re_exports::{ 2 | fixed::types::I16F16, 3 | typenum::{IsGreater, True, Unsigned, U0}, 4 | }; 5 | use embedded_hal::pwm::SetDutyCycle; 6 | 7 | use crate::common::helpers::{DutyCycle, Triplet}; 8 | 9 | /// Describes what a given phase/coil/inductor is doing 10 | #[derive(Default, Copy, Clone)] 11 | pub struct PhaseState { 12 | pub hi_side: bool, 13 | pub lo_side: bool, 14 | } 15 | 16 | pub trait MotorPins { 17 | fn set_pwms(&mut self, dc_a: DutyCycle, dc_b: DutyCycle, dc_c: DutyCycle); 18 | fn set_zero(&mut self) { 19 | self.set_pwms( 20 | DutyCycle(I16F16::ZERO), 21 | DutyCycle(I16F16::ZERO), 22 | DutyCycle(I16F16::ZERO), 23 | ); 24 | } 25 | } 26 | pub trait VLimitedHiPins: MotorPins { 27 | /// TODO: go nightly, or wait for assosciated type defaults to stabalise, and set this to 120 28 | /// This is Deci-volts. easier than setting up a fixed point setup. 29 | /// If the scale here changes, account for the notion of users over-volting. 30 | type DeciVLimit: Unsigned + IsGreater; 31 | #[allow(unused_variables)] 32 | #[allow(unreachable_code)] 33 | fn set_limited_pwms(&mut self, dc_a: DutyCycle, dc_b: DutyCycle, dc_c: DutyCycle) { 34 | todo!("do the voltage clamp thing here"); 35 | ::set_pwms(self, dc_a, dc_b, dc_c) 36 | } 37 | } 38 | 39 | impl MotorPins for Triplet 40 | where 41 | A: SetDutyCycle, 42 | B: SetDutyCycle, 43 | C: SetDutyCycle, 44 | { 45 | fn set_pwms(&mut self, dc_a: DutyCycle, dc_b: DutyCycle, dc_c: DutyCycle) { 46 | let hundred = I16F16::from_num(100); 47 | let _ = 48 | SetDutyCycle::set_duty_cycle_percent(&mut self.member_a, (dc_a.0 * hundred).to_num()); 49 | let _ = 50 | SetDutyCycle::set_duty_cycle_percent(&mut self.member_b, (dc_b.0 * hundred).to_num()); 51 | let _ = 52 | SetDutyCycle::set_duty_cycle_percent(&mut self.member_c, (dc_c.0 * hundred).to_num()); 53 | } 54 | 55 | fn set_zero(&mut self) { 56 | let _ = SetDutyCycle::set_duty_cycle_fully_off(&mut self.member_a); 57 | let _ = SetDutyCycle::set_duty_cycle_fully_off(&mut self.member_a); 58 | let _ = SetDutyCycle::set_duty_cycle_fully_off(&mut self.member_a); 59 | } 60 | } 61 | 62 | pub struct VoltageConfig { 63 | pub psu_millivolts: u16, 64 | pub limit_millivolts: u16, 65 | // todo: think about where the pwm ferquency needs to go. 66 | } 67 | -------------------------------------------------------------------------------- /core/src/bldc_driver6pwm.rs: -------------------------------------------------------------------------------- 1 | use embedded_hal::{digital::OutputPin, pwm::SetDutyCycle}; 2 | 3 | use crate::{ 4 | base_traits::bldc_driver::{BLDCDriver, PhaseState}, 5 | common::helpers::{HBridgePins, PhaseVoltages}, 6 | }; 7 | 8 | pub struct BldcDriver6PWM< 9 | Ah: SetDutyCycle, 10 | Al: SetDutyCycle, 11 | Bh: SetDutyCycle, 12 | Bl: SetDutyCycle, 13 | Ch: SetDutyCycle, 14 | Cl: SetDutyCycle, 15 | En: OutputPin, 16 | > { 17 | a_phase: HBridgePins, 18 | b_phase: HBridgePins, 19 | c_phase: HBridgePins, 20 | enable: Option, 21 | 22 | phase_states: [PhaseState; 3], 23 | phase_voltages: PhaseVoltages, 24 | duty_cycles: (f32, f32, f32), 25 | } 26 | 27 | impl< 28 | Ah: SetDutyCycle, 29 | Al: SetDutyCycle, 30 | Bh: SetDutyCycle, 31 | Bl: SetDutyCycle, 32 | Ch: SetDutyCycle, 33 | Cl: SetDutyCycle, 34 | En: OutputPin, 35 | > BLDCDriver for BldcDriver6PWM 36 | { 37 | fn enable(&mut self) { 38 | if let Some(mut enable_pin) = self.enable { 39 | enable_pin.set_high(); 40 | } 41 | self.set_phasestate( 42 | [PhaseState { 43 | hi_side: true, 44 | lo_side: true, 45 | }; 3], 46 | ); 47 | self.set_pwm(Default::default()); 48 | } 49 | 50 | fn disable(&mut self) { 51 | self.set_phasestate([PhaseState::default(); 3]); 52 | self.set_pwm(Default::default()); 53 | if let Some(mut enable_pin) = self.enable { 54 | enable_pin.set_low(); 55 | } 56 | } 57 | 58 | fn set_pwm(&mut self, voltages: PhaseVoltages) { 59 | // TODO: clamp between 0 and voltage limit 60 | 61 | self.phase_voltages = PhaseVoltages { 62 | a: todo!(), 63 | b: todo!(), 64 | c: todo!(), 65 | }; 66 | // TODO: write in `_writeDutyCycle6PWM` 67 | todo!() 68 | } 69 | 70 | fn set_phasestate(&mut self, state: [PhaseState; 3]) { 71 | self.phase_states = state; 72 | } 73 | } 74 | 75 | impl< 76 | Ah: SetDutyCycle, 77 | Al: SetDutyCycle, 78 | Bh: SetDutyCycle, 79 | Bl: SetDutyCycle, 80 | Ch: SetDutyCycle, 81 | Cl: SetDutyCycle, 82 | En: OutputPin, 83 | > BldcDriver6PWM 84 | { 85 | pub fn init( 86 | a_phase: HBridgePins, 87 | b_phase: HBridgePins, 88 | c_phase: HBridgePins, 89 | enable: Option, 90 | ) -> Result { 91 | // TODO: account for voltage-limit config-vals 92 | // TODO: hardware-specific configuration 93 | Ok(Self { 94 | a_phase, 95 | b_phase, 96 | c_phase, 97 | enable, 98 | 99 | duty_cycles: (0.0, 0.0, 0.0), 100 | phase_states: Default::default(), 101 | phase_voltages: Default::default(), 102 | }) 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /core/src/bldc_motor.rs: -------------------------------------------------------------------------------- 1 | #[allow(dead_code)] 2 | // D: implements the bldc driver 3 | pub struct BLDCMotor { 4 | pole_pairs: u8, 5 | phase_resistance: f32, 6 | /// phases/second/volt 7 | /// 8 | /// A more generalised form of the kV metric. A 1kV motor with 12 permenant magnets means 6 9 | /// pairs, which means 6 pitches per revolution. 1kV implies that 6000 pitches traversed in 1 10 | /// minuite induces a 1V back-emf. 11 | /// 12 | /// This metric allows one to denote rotary kV (take the pair-count of a rotary motor, and infer the 13 | /// rpm needed to traverse `psv` pitches in a minute), as well as linear motor characteristics 14 | psv: f32, 15 | phase_inductance: f32, 16 | driver: D, 17 | } 18 | 19 | impl BLDCMotor { 20 | pub fn align_position_sensor() { 21 | todo!() 22 | } 23 | pub fn align_current_sense() { 24 | todo!() 25 | } 26 | pub fn find_zero_reference() { 27 | todo!() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /core/src/commands.rs: -------------------------------------------------------------------------------- 1 | pub enum Command { 2 | CurrentDPID, 3 | CurrentQPID, 4 | VelocityPID, 5 | PositionPID, 6 | Status, 7 | Limits, 8 | MotionType, 9 | ForceType, 10 | SensorOffsets, 11 | Monitor, 12 | Resist, 13 | Inductants, 14 | PVS, 15 | PWMModulation, 16 | } 17 | 18 | pub enum PIDSubComm { 19 | P, 20 | I, 21 | D, 22 | Ramp, 23 | Limit, 24 | TimeConst, 25 | } 26 | 27 | pub enum LimitsSubComm { 28 | Current, 29 | Voltage, 30 | Velocity, 31 | } 32 | 33 | // TODO 34 | // enum SensorSubComm {} 35 | 36 | pub enum MonitoringSubComm { 37 | DownSample, 38 | Clear, 39 | Get, 40 | Set, 41 | } 42 | 43 | pub enum PWMModulationSubComm { 44 | Type, 45 | CenterFlag, 46 | } 47 | -------------------------------------------------------------------------------- /core/src/common.rs: -------------------------------------------------------------------------------- 1 | pub mod defaults; 2 | pub mod helpers; 3 | pub mod lp_filter; 4 | // pub mod pid; 5 | pub mod types; 6 | -------------------------------------------------------------------------------- /core/src/common/defaults.rs: -------------------------------------------------------------------------------- 1 | /// Default configuration values 2 | /// Change this file to optimal values for your application 3 | 4 | pub const DEF_POWER_SUPPLY: f32 = 12.0; 5 | 6 | // Velocity PI controller params 7 | 8 | /// Default PID controller Position value 9 | pub const DEF_PID_VEL_P: f32 = 0.5; 10 | /// Default PID controller Integral value 11 | pub const DEF_PID_VEL_I: f32 = 10.0; 12 | /// Default PID controller Derivitive value 13 | pub const DEF_PID_VEL_D: f32 = 0.0; 14 | /// Default PID controller voltage ramp value 15 | pub const DEF_PID_VEL_RAMP: f32 = 1_000.0; 16 | /// Default PID controller voltage limit 17 | pub const DEF_PID_VEL_LIMIT: f32 = DEF_POWER_SUPPLY; 18 | 19 | // Current sensing PID values 20 | // For 16MHz controllers like Arduino Uno and Mega 21 | // TODO: AVR_ATmega[328P || 168 || 328PB || 2560] only 22 | pub const DEF_PID_CURR_P_16MHZ: i32 = 2; 23 | pub const DEF_PID_CURR_I_16MHZ: i32 = 100; 24 | pub const DEF_PID_CURR_D_16MHZ: f32 = 0.0; 25 | pub const DEF_PID_CURR_RAMP_16MHZ: f32 = 10_00.0; 26 | pub const DEF_PID_CURR_LIMIT_16MHZ: f32 = DEF_POWER_SUPPLY; 27 | pub const DEF_CURR_FILTER_TF_16MHZ: f32 = 0.01; 28 | 29 | //TODO: For STM32, Due, Teensy, ESP32, and similar 30 | pub const DEF_PID_CURR_P_32BIT: i32 = 3; 31 | pub const DEF_PID_CURR_I_32BIT: f32 = 300.0; 32 | pub const DEF_PID_CURR_D_32BIT: f32 = 0.0; 33 | pub const DEF_PID_CURR_RAMP_32BIT: i32 = 0; 34 | pub const DEF_PID_CURR_LIMIT_32BIT: f32 = DEF_POWER_SUPPLY; 35 | pub const DEF_CURR_FILTER_TF_32BIT: f32 = 0.005; 36 | 37 | /// Default current limit values 38 | pub const DEF_CURRENT_LIM: f32 = 2.0; 39 | 40 | /// Default monitor downsample 41 | pub const DEF_MON_DOWNSAMPLE: i32 = 100; 42 | pub const DEF_MOTION_DOWNSAMPLE: i32 = 0; 43 | 44 | /// Angle P params 45 | pub const DEF_P_ANGLE_P: f32 = 20.0; 46 | pub const DEF_VEL_LIM: f32 = 20.0; 47 | 48 | /// Index search 49 | pub const DEF_INDEX_SEARCH_TARGET_VELOCITY: f32 = 1.0; 50 | 51 | /// Align voltage 52 | pub const DEF_VOLTAGE_SENSOR_ALIGN: f32 = 3.0; 53 | 54 | /// Low pass filter velocity 55 | pub const DEF_VEL_FILTER_TF: f32 = 0.005; 56 | 57 | /// Current sense default parameters 58 | pub const DEF_LPF_PER_PHASE_CURRENT_SENSE_TF: f32 = 0.0; 59 | -------------------------------------------------------------------------------- /core/src/common/helpers.rs: -------------------------------------------------------------------------------- 1 | #![allow(clippy::excessive_precision)] 2 | 3 | use discrete_count::re_exports::fixed::types::I16F16; 4 | pub const SQRT3: f32 = 1.732_050_807_57; 5 | pub const _3PI_2: f32 = 4.712_388_980_38; 6 | pub const RPM_TO_RADS: f32 = 0.104_719_755_12; 7 | pub const _2_SQRT3: f32 = 1.154_700_538_38; 8 | pub const _1_SQRT3: f32 = 0.577_350_269_19; 9 | pub const SQRT3_2: f32 = 0.866_025_403_78; 10 | pub const _120_D2R: f32 = 2.094_395_102_39; 11 | 12 | #[derive(Default)] 13 | pub struct Current(pub f32); 14 | #[derive(Default)] 15 | pub struct Voltage(pub f32); 16 | pub struct DutyCycle(pub I16F16); 17 | 18 | /// Encapsulates the common pattern of three-way-coupling in 3-phase motors. 19 | /// E.g. 3 pairs of pins to control an h-bridge. ADC reader pins. etc. 20 | pub struct Triplet { 21 | pub member_a: A, 22 | pub member_b: B, 23 | pub member_c: C, 24 | } 25 | 26 | /// Encapsulates the common pattern of two-way-coupling. 27 | /// E.g. A pin-pair to control each side of an h-bridge, AB encoder pins, etc. 28 | pub struct Couplet { 29 | pub member_a: A, 30 | pub member_b: B, 31 | } 32 | 33 | pub struct DQCurrent { 34 | pub d: Current, 35 | pub q: Current, 36 | } 37 | // alpha beta current structure 38 | pub struct ABCurrent { 39 | pub alpha: Current, 40 | pub beta: Current, 41 | } 42 | // dq voltage structs 43 | pub struct DQVoltage { 44 | pub d: Voltage, 45 | pub q: Voltage, 46 | } 47 | #[derive(Default)] 48 | pub struct PhaseVoltages { 49 | pub a: Voltage, 50 | pub b: Voltage, 51 | pub c: Voltage, 52 | } 53 | pub struct PhaseCurrent { 54 | pub a: Current, 55 | pub b: Current, 56 | pub c: Current, 57 | } 58 | -------------------------------------------------------------------------------- /core/src/common/lp_filter.rs: -------------------------------------------------------------------------------- 1 | use embedded_time::{duration::Microseconds, Clock, Instant}; 2 | 3 | #[allow(dead_code)] 4 | pub struct LPFilter { 5 | pub time_constant: Microseconds, 6 | timestamp_prev: Instant, 7 | y_prev: f32, 8 | } 9 | 10 | impl LPFilter { 11 | pub fn new(time_constant: Microseconds, clock: &C) -> Self { 12 | Self { 13 | time_constant, 14 | timestamp_prev: clock.try_now().unwrap(), 15 | y_prev: 0.0, 16 | } 17 | } 18 | #[allow(unreachable_code)] 19 | pub fn run(&mut self, clock: &C, _x: f32) -> f32 { 20 | let now = clock.try_now().unwrap(); 21 | let _dt = now.checked_duration_since(&self.timestamp_prev).unwrap(); 22 | todo!("work out what the limit should be"); 23 | if _dt.integer() > todo!() { 24 | self.y_prev = _x; 25 | self.timestamp_prev = now; 26 | return _x; 27 | } 28 | 29 | let alpha = 1.0; // self.time_constant.0 as f32 / (self.time_constant.0 as f32 + u32::from(dt.integer().into()) as f32); 30 | let y = alpha * self.y_prev + (1.0 - alpha) * _x; 31 | self.y_prev = y; 32 | self.timestamp_prev = now; 33 | 34 | _x 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /core/src/common/pid.rs: -------------------------------------------------------------------------------- 1 | use core::ops::Deref; 2 | 3 | use embedded_time::{clock::Error as ClockError, Clock, Instant}; 4 | 5 | pub enum PIDError { 6 | Clock(ClockError), 7 | NegativeTimeDelta, 8 | } 9 | 10 | impl From for PIDError { 11 | fn from(value: ClockError) -> Self { 12 | Self::Clock(value) 13 | } 14 | } 15 | 16 | /// the p, i and d in pid 17 | pub struct PIDParam(f32); 18 | impl Deref for PIDParam { 19 | type Target = f32; 20 | 21 | fn deref(&self) -> &Self::Target { 22 | &self.0 23 | } 24 | } 25 | 26 | pub struct PID { 27 | pub p: PIDParam, 28 | pub i: PIDParam, 29 | pub d: PIDParam, 30 | pub output_ramp: Option, 31 | pub upper_limit: f32, 32 | lookback: PIDLookBack, 33 | } 34 | 35 | struct PIDLookBack { 36 | prev_error: f32, 37 | prev_output: f32, 38 | prev_integral: PIDParam, 39 | prev_timestamp: Instant, 40 | } 41 | 42 | impl PIDLookBack { 43 | fn new(clock: &C) -> Self { 44 | Self { 45 | prev_error: 0.0, 46 | prev_output: 0.0, 47 | prev_integral: PIDParam(0.0), 48 | prev_timestamp: clock.try_now().unwrap(), 49 | } 50 | } 51 | 52 | fn reset(&mut self) { 53 | self.prev_error = 0.0; 54 | self.prev_output = 0.0; 55 | self.prev_integral = PIDParam(0.0); 56 | } 57 | } 58 | 59 | impl PID { 60 | pub fn init( 61 | p: PIDParam, 62 | i: PIDParam, 63 | d: PIDParam, 64 | output_ramp: Option, 65 | upper_limit: f32, 66 | clock: &C, 67 | ) -> Self { 68 | Self { 69 | p, 70 | i, 71 | d, 72 | output_ramp, 73 | upper_limit, 74 | lookback: PIDLookBack::new(clock), 75 | } 76 | } 77 | pub fn run(&mut self, clock: &C, _error: f32) -> Result { 78 | let now = clock.try_now()?; 79 | let _delta = now 80 | .checked_duration_since(&self.lookback.prev_timestamp) 81 | .ok_or(PIDError::NegativeTimeDelta)?; 82 | let _proportional = self.p.deref() * self.lookback.prev_error; 83 | 84 | // let integral = { 85 | // let unclamped = self.lookback.prev_integral.deref() 86 | // + self.i.deref() * (delta as f32) * 0.5 * (error + self.lookback.prev_error); 87 | // unclamped.clamp(self.upper_limit, -self.upper_limit) 88 | // }; 89 | 90 | // let derivitive = self.d.deref() * (error - self.lookback.prev_error) / (delta as f32); 91 | 92 | // let mut output = { 93 | // let unclamped = proportional + integral + derivitive; 94 | // unclamped.clamp(self.upper_limit, -self.upper_limit) 95 | // }; 96 | // if let Some(ramp) = self.output_ramp { 97 | // let output_rate = (output - self.lookback.prev_output) / (delta as f32); 98 | // if output_rate > ramp { 99 | // output = self.lookback.prev_output + ramp * (delta as f32); 100 | // } else if output_rate < -ramp { 101 | // output = self.lookback.prev_output - ramp * (delta as f32); 102 | // } 103 | // } 104 | 105 | // self.lookback.prev_integral = PIDParam(integral); 106 | // self.lookback.prev_output = output; 107 | // self.lookback.prev_error = error; 108 | // self.lookback.prev_timestamp = now; 109 | // Ok(output) 110 | todo!("embeded clocks are hard. work out how to make cross-platform, hal'd timekeeping compatable with these functions"); 111 | } 112 | pub fn reset(&mut self) { 113 | self.lookback.reset(); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /core/src/common/types.rs: -------------------------------------------------------------------------------- 1 | #![allow(dead_code)] 2 | use core::marker::PhantomData; 3 | 4 | pub trait MovementOrientation { 5 | fn dirstr(dir: &Option) -> &'static str; 6 | } 7 | 8 | struct LinearMovement; 9 | impl MovementOrientation for LinearMovement { 10 | fn dirstr(dir: &Option) -> &'static str { 11 | match dir { 12 | Some(true) => "Forwards", 13 | Some(false) => "Backwards", 14 | None => "Unknown", 15 | } 16 | } 17 | } 18 | struct RotaryMovement; 19 | impl MovementOrientation for RotaryMovement { 20 | fn dirstr(dir: &Option) -> &'static str { 21 | match dir { 22 | Some(true) => "Clockwise", 23 | Some(false) => "CounterClockwise", 24 | None => "Unknown", 25 | } 26 | } 27 | } 28 | 29 | struct Direction { 30 | dir: Option, 31 | orientation: PhantomData, 32 | } 33 | 34 | impl core::fmt::Debug for Direction { 35 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { 36 | f.debug_tuple("Direction") 37 | .field(&T::dirstr(&self.dir)) 38 | .finish() 39 | } 40 | } 41 | 42 | // So velocity must have a non-zero denominator. Because this is a run-time thing, the use of 43 | // typnum for the denominator would explode the binary size 44 | // 45 | // The default is looking like this Because 46 | // a) at time of writing, this was a "get it done" solution 47 | // b) can't think of a nicer way to ensure that the denominotor is constrained to have a suitable 48 | // deafult impl 49 | // impl Default for Velocity 50 | // where 51 | // D: Default, 52 | // E: core::fmt::Debug, 53 | // T: TryFrom, 54 | // { 55 | // fn default() -> Self { 56 | // Self { 57 | // displacement: Default::default(), 58 | // // this should be trivial for the compiler to optimise into a single op 59 | // time: T::try_from(NonZeroU64::new(1).unwrap()).unwrap(), 60 | // } 61 | // } 62 | // } 63 | -------------------------------------------------------------------------------- /core/src/current_sensor.rs: -------------------------------------------------------------------------------- 1 | // TODO: move to cordic, which leans into Fixed. 2 | use micromath::F32; 3 | 4 | use crate::common::helpers::{ABCurrent, Current, DQCurrent, PhaseCurrent}; 5 | 6 | pub trait CurrentSensor: Sized { 7 | // TODO: core error stabalised in rust 1.81 8 | type InitError; // : core::error::Error; 9 | fn init_current_sensor() -> Result; 10 | // fn link_driver?(&mut self, driver: BLDCDriver); 11 | // fn linked_driver?(&self) -> Option<&BLDCDriver>; 12 | fn driver_allign(&self, allign_voltage: f32); 13 | fn get_phase_currents(&self) -> PhaseCurrent; 14 | fn get_dc_current(&self, phase_theta: Option) -> f32 { 15 | let phase_current = self.get_phase_currents(); 16 | let ab_current = Self::get_ab_currents(phase_current); 17 | let sign: f32 = if let Some(theta) = phase_theta { 18 | let theta = F32(theta); 19 | let (F32(st), F32(ct)) = theta.sin_cos(); 20 | let sign = ab_current.beta.0 * ct - ab_current.alpha.0 * st; 21 | if sign > 0.0 { 22 | 1.0 23 | } else { 24 | -1.0 25 | } 26 | } else { 27 | 1.0 28 | }; 29 | sign * F32(ab_current.alpha.0 * ab_current.alpha.0 + ab_current.beta.0 * ab_current.beta.0) 30 | .sqrt() 31 | .0 32 | } 33 | fn get_foc_currents(&self, angle_el: f32) -> DQCurrent { 34 | let current = self.get_phase_currents(); 35 | let ab_current = Self::get_ab_currents(current); 36 | Self::get_dq_currents(ab_current, angle_el) 37 | } 38 | fn get_ab_currents(current: PhaseCurrent) -> ABCurrent; 39 | fn get_dq_currents(current: ABCurrent, phase_theta: f32) -> DQCurrent { 40 | let angle_el = F32(phase_theta); 41 | let (F32(st), F32(ct)) = angle_el.sin_cos(); 42 | let d = current.alpha.0 * ct + current.beta.0 * st; 43 | let q = current.beta.0 * ct + current.alpha.0 * st; 44 | DQCurrent { 45 | d: Current(d), 46 | q: Current(q), 47 | } 48 | } 49 | /// usually this is just implemented as a no-op 50 | fn enable(&mut self); 51 | /// usually this is just implemented as a no-op 52 | fn disable(&mut self); 53 | } 54 | -------------------------------------------------------------------------------- /core/src/foc_control.rs: -------------------------------------------------------------------------------- 1 | pub mod control_utils; 2 | use core::mem::MaybeUninit; 3 | use discrete_count::{re_exports::fixed::types::I16F16, CountRaw, CountReader, Counter}; 4 | use foc::{park_clarke::RotatingReferenceFrame, pwm::Modulation}; 5 | use pid::Pid; 6 | 7 | use crate::common::helpers::DutyCycle; 8 | 9 | use super::bldc_driver::MotorPins; 10 | 11 | pub struct ForceVoltage(pub f32); 12 | pub struct DCCurrent(pub f32); 13 | pub struct FOCCurrent(pub f32); 14 | 15 | pub struct PhaseAngle(pub I16F16); 16 | /// Distance from 0-reference to denote position. 17 | /// T could be encoder pulses, Millimeters, etc 18 | pub struct Displacement(pub T); 19 | /// Used in the derivitives of Displacement 20 | pub struct TimeDelta(pub T); 21 | pub struct Velocity { 22 | _d_disp: Displacement
, 23 | _d_time: TimeDelta
, 24 | } 25 | 26 | pub struct QCurrentPID(pub Pid); 27 | pub struct DCurrentPID(pub Pid); 28 | pub struct VelocityPID(pub Pid); 29 | pub struct VoltagePID(pub Pid); 30 | pub struct PositionPID(pub Pid); 31 | 32 | pub struct Amps(pub I16F16); 33 | 34 | /// Note: P::Output and Instant relies on popping the stack to release memory. 35 | // TODO: setup BufSize so that its length is typed. Len 1: position, 2: vel, and so on 36 | // ...with arbitrary buffer-len, we can use math-magic like taylor siries and 37 | // other cool things to get nice analysis 38 | pub struct MotionTracker { 39 | pub clock_source: T, 40 | pos_source: P, 41 | mvmnt_buffer: [MaybeUninit<(CountRaw

, CountRaw)>; BUF_SIZE], 42 | 43 | head: u8, 44 | entry_count: u8, 45 | } 46 | // + NonZero + typenum::IsLess 47 | impl MotionTracker 48 | where 49 | T: Counter + CountReader, 50 | P: Counter + CountReader, 51 | { 52 | pub fn init( 53 | clock_source: T, 54 | instant: <::Reader as CountReader>::RawData, 55 | pos_source: P, 56 | pos: <

::Reader as CountReader>::RawData, 57 | ) -> Self { 58 | let mut mvmnt_buffer: [_; BUF_SIZE] = unsafe { MaybeUninit::uninit().assume_init() }; 59 | mvmnt_buffer[0] = MaybeUninit::new((pos, instant)); 60 | Self { 61 | clock_source, 62 | pos_source, 63 | mvmnt_buffer, 64 | head: 1, 65 | entry_count: 1, 66 | } 67 | } 68 | fn push_update(&mut self) { 69 | let pos = self.pos_source.read(); 70 | let instant = self.clock_source.read(); 71 | let (Ok(pos), Ok(instant)) = (pos, instant) else { 72 | panic!("todo. just read the code and weep..."); 73 | }; 74 | self.head += 1; 75 | self.head %= BUF_SIZE as u8; 76 | self.mvmnt_buffer[self.head as usize] = MaybeUninit::new((pos, instant)); 77 | if self.entry_count != (BUF_SIZE as u8) { 78 | self.entry_count += 1; 79 | } 80 | } 81 | // pub fn latest_pos(&self) -> P::RawData { 82 | // let head = self.mvmnt_buffer[self.head as usize]; 83 | // unsafe { head.assume_init() }.0 84 | // } 85 | // pub fn latest_vel(&self) -> (P::CountMeasure, T::TickMeasure) 86 | // where 87 | // T::RawData: num::CheckedSub, 88 | // P::RawData: Sub, 89 | // { 90 | // assert!(self.entry_count > 1, "todo: getting latest velocity should by type-constrained to when it's tracked two position/instant pairs"); 91 | // let _pta = self.mvmnt_buffer[self.head as usize]; 92 | // let prev = if self.head == 0 { 93 | // BUF_SIZE - 1 94 | // } else { 95 | // self.head as usize - 1 96 | // }; 97 | // let pt_before = self.mvmnt_buffer[self.head as usize]; 98 | // let pt_latest = self.mvmnt_buffer[prev]; 99 | // let (pt_before, pt_latest) = unsafe { (pt_before.assume_init(), pt_latest.assume_init()) }; 100 | // let raw_diff: T::RawData = num::CheckedSub::checked_sub(&pt_latest.1, &pt_before.1) 101 | // .unwrap(); 102 | // let time_diff = T::raw_to_measure(raw_diff); 103 | // (P::raw_to_measure(pt_latest.0 - pt_before.0), time_diff) 104 | // } 105 | } 106 | 107 | pub trait MotionControlMode: MotionControl { 108 | type MotionParams; 109 | fn do_motion_impl(&mut self, motion: Self::MotionParams); 110 | } 111 | 112 | // TODO: these varients determine behavior, and deserve to be encapsulated using type-state 113 | // patterns 114 | pub enum FOCMotorStatus { 115 | Uninit, 116 | Initting, 117 | Uncalibrated, 118 | Callibrating, 119 | Ready, 120 | RecoverableError, 121 | CalbrationFail, 122 | InitFail, 123 | } 124 | #[derive(Default)] 125 | pub enum FOCModulationType { 126 | #[default] 127 | SinePWM, 128 | SpaceVectorPWM, 129 | Trapezoid120, 130 | Trapezoid150, 131 | } 132 | 133 | pub enum PidSetpoints { 134 | Displacement(Displacement), 135 | Velocity(Velocity), 136 | Current(Amps), 137 | } 138 | 139 | pub trait MotionControl: Sized { 140 | type PosSource: Counter; 141 | fn set_displacement(&mut self, disp: Displacement); 142 | // fn do_motion_impl(&mut self, motion: M); 143 | } 144 | 145 | pub struct DefaultMotionCtrl { 146 | motion_down_sample: Option<(u32, u32)>, 147 | pub motion_tracker: MotionTracker, 148 | } 149 | 150 | // impl DefaultMotionCtrl { 151 | // pub fn new( 152 | // motion_down_sample: Option<(u32, u32)>, 153 | // motion_tracker: MotionTracker, 154 | // ) -> Self { 155 | // Self { 156 | // motion_down_sample, 157 | // motion_tracker, 158 | // } 159 | // } 160 | // } 161 | 162 | impl MotionControl for DefaultMotionCtrl 163 | where 164 | T: Counter + CountReader, 165 | P: Counter + CountReader, 166 | ::ReadErr: core::fmt::Display + core::fmt::Debug, 167 | T: Counter, 168 | P: Counter, 169 | { 170 | type PosSource = P; 171 | 172 | // fn do_motion_impl(&mut self, motion: Displacement) { 173 | // todo!() 174 | // } 175 | fn set_displacement(&mut self, _motion: Displacement) { 176 | // optional downsample early-return/update 177 | if let Some(&mut (ref mut count, sample)) = self.motion_down_sample.as_mut() { 178 | *count += 1; 179 | if *count < sample { 180 | return; 181 | } else { 182 | *count = 0; 183 | } 184 | } 185 | 186 | self.motion_tracker.push_update(); 187 | 188 | // self.do_motion_impl(motion); 189 | } 190 | } 191 | 192 | // temporarily hacked to be for a 3pwm bldc motor, const voltage, svpm 193 | pub trait FOController: MotorPins { 194 | // fn enable(&mut self); 195 | // fn disable(&mut self); 196 | // fn link_sensor/current_sensor(.... 197 | // todo: fn init_foc_algo(&mut self) -> u32; // why the u32? 198 | // todo: fn foc_loop(&mut self) -> !; 199 | // todo: fn move_command(motion: MotionCtrl); 200 | fn set_phase_voltage(&mut self, voltages_q_d: RotatingReferenceFrame, phase_angle: PhaseAngle) { 201 | let (sin_angle, cos_angle) = cordic::sin_cos(phase_angle.0); 202 | let orth_v = foc::park_clarke::inverse_park(cos_angle, sin_angle, voltages_q_d); 203 | let [phase_a, phase_b, phase_c] = foc::pwm::SpaceVector::modulate(orth_v); 204 | self.set_pwms(DutyCycle(phase_a), DutyCycle(phase_b), DutyCycle(phase_c)) 205 | } 206 | fn set_psu_millivolt(&self, mv: u16); 207 | } 208 | -------------------------------------------------------------------------------- /core/src/foc_control/control_utils.rs: -------------------------------------------------------------------------------- 1 | use pid::Pid; 2 | 3 | use crate::common::helpers::{DQCurrent, DQVoltage}; 4 | 5 | pub struct RawRewriteStateVars { 6 | pub set_pont: f32, 7 | pub feed_forward_velocity: f32, 8 | pub shaft_angle: f32, 9 | pub electrical_angle: f32, 10 | pub shaft_velocity: f32, 11 | pub target_shaft_angle: f32, 12 | pub latest_dq_voltage: DQVoltage, 13 | pub latest_dq_current: DQCurrent, 14 | pub estimated_back_emf: f32, 15 | pub park_clarke_dq: (f32, f32), 16 | } 17 | 18 | pub struct RawRewriteConfigParams { 19 | pub voltage_sensor_align: f32, 20 | pub velocity_index_search: f32, 21 | } 22 | 23 | pub struct RawRewritePhysParams { 24 | pub phase_resistance: f32, 25 | pub pole_pars: u8, 26 | pub kv_rating: f32, 27 | pub phase_inductance: f32, 28 | } 29 | pub struct RawRewriteLimits { 30 | pub millivolt_limit: u16, 31 | pub milliamp_limit: u16, 32 | pub velocity_limit: u16, 33 | } 34 | 35 | pub struct LowPassFilter { 36 | pub constant: f32, 37 | pub previous: (), 38 | } 39 | pub struct Controlers { 40 | pub q_current: Pid, 41 | pub lpf_q_current: LowPassFilter, 42 | pub d_current: Pid, 43 | pub lpf_d_current: LowPassFilter, 44 | 45 | pub velocity: Pid, 46 | pub lpf_q_velocity: LowPassFilter, 47 | pub angle: Pid, 48 | pub lpf_q_angle: LowPassFilter, 49 | 50 | pub motion_downsample: u32, 51 | pub motion_count: u32, 52 | } 53 | 54 | pub struct RawRewriteSensorVars { 55 | pub zero_offset: f32, 56 | pub abs_zero_angle: Option, 57 | pub is_forward: Option, 58 | pub pp_check_res: bool, 59 | } 60 | -------------------------------------------------------------------------------- /core/src/hw_drivers.rs: -------------------------------------------------------------------------------- 1 | // pub trait HWApi 2 | // { 3 | // 4 | // // TODO: make `pins` a heterogenous list of pins, all implementing PwmControl, of length N. 5 | // // should be doable with `frunk::HList` 6 | // fn config_pwm(freq: embedded_time::rate::Hertz) -> Self; 7 | // fn write_duty_cycle Self; 8 | // } 9 | 10 | // impl HWApi for Esp32MCPWM 11 | // { 12 | // 13 | // 14 | // fn config_pwm(freq: embedded_time::rate::Hertz, pins: ()) -> Self { 15 | // todo!(); 16 | // // cpp impl finds an ampty pwm-motor slot, and puts pin a in it, then puts that into the 17 | // // local m_slot variable 18 | // 19 | // // depending on which slot number used, it marks certain stepper/bldc slots as taken 20 | // 21 | // // run `mcpwm_gpio_init`, passing in that slots mcpwm unit, its mcpwm_a/b, and pinA/B 22 | // 23 | // // then runs configuration of the timer frequency 24 | // 25 | // // returns the esp32MCPWMDriverParams struct 26 | // } 27 | // 28 | // fn write_duty_cycle(&mut self, duties: ()) { 29 | // todo!(); 30 | // // Okay, so the esp32 has a nice way of organising the different structs. We have: 31 | // // 32 | // // mcpwm::MCPWM struct with the three timers, and the three operators 33 | // // - this has the PwmPeripheral trait attached to it. 34 | // // - its construction requireres a PeripheralClockConfig struct as well 35 | // // 36 | // // if we pull out the operator0 field, we get the methods 37 | // // - `set_timer`, to select the timer to serve as timing reference 38 | // // - getters for the two pins 39 | // // - `with_linked_pins` that takes the two pins, an `a` and `b` cgonfig, and a `dt` 40 | // // config and gives back `LinkedPins` 41 | // // - "useful for complementary/mirrored signals with/without configured deadtime" 42 | // // 43 | // // `PwmPin` to get period( 44 | // // let mut pin_a = slf.operator0.with_pin_a(...); 45 | // // pin_a.set_duty(duties.0); 46 | // // let mut pin_b = slf.operator0.with_pin_a(...); 47 | // // pin_b.set_duty(duties.1); 48 | // } 49 | // } 50 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod bldc_driver; 4 | pub mod bldc_motor; 5 | pub mod commands; 6 | pub mod common; 7 | pub mod current_sensor; 8 | pub mod foc_control; 9 | pub mod hw_drivers; 10 | pub mod pos_sensor; 11 | 12 | pub mod rexports { 13 | pub use cordic; 14 | pub use discrete_count; 15 | pub use foc; 16 | pub use pid; 17 | } 18 | -------------------------------------------------------------------------------- /core/src/pos_sensor.rs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /examples/spinny.rs: -------------------------------------------------------------------------------- 1 | /// The sfoc equivilent of a micro-controller "blinky" 2 | /// 3 | /// Running something modeled on this example, except with actual hardware, a motor that is at a 4 | /// fixed rpm, and outputting the pwm duty telemetry, you "should" see the same behavior. 5 | /// 6 | /// Coming Soon™ will be actual code that you can run on $HARDWARE. It will use constant voltage, 7 | /// chosen such that a matching back-EMF is generated at around 30RPM. 8 | use std::time::SystemTime; 9 | 10 | use sfoc_rs::{ 11 | self, 12 | bldc_driver::MotorPins, 13 | common::helpers::DutyCycle, 14 | foc_control::FOController, 15 | pos_sensor::PosSensor, 16 | rexports::{ 17 | cordic, 18 | discrete_count::re_exports::fixed::types::I16F16, 19 | foc::{self, park_clarke, pwm::Modulation}, 20 | }, 21 | }; 22 | 23 | fn main() { 24 | let driver = SomePlatformSpecificImpl; 25 | foc_main(driver) 26 | } 27 | 28 | // This can be made portable. We'll be using the `FOController` and `PosSensor` traits. In the near 29 | // future, there will also be examples on how to write a portable implementation. 30 | fn foc_main(mut driver: SomePlatformSpecificImpl) -> ! { 31 | loop { 32 | // The "FO" part of the FOC. Here, we derive the position of the motor. We will use this to 33 | // determine which electro-magnetic-field angle we wish to set. 34 | // 35 | // In this example, we've hacked the sensor such that this method is hard-coded to rotate at 30rpm 36 | let angle = driver.get_position_um(); 37 | // TODO: make an interface so you just... set the angle. 38 | // this will allow `cordic` to not need re-exporting 39 | let (sin, cos) = cordic::sin_cos(angle); 40 | 41 | // we are setting 10% in the quadrature (torque) and 0% direct-axis 42 | let qd = park_clarke::RotatingReferenceFrame { 43 | d: I16F16::ZERO, 44 | q: I16F16::from_num(0.1), 45 | }; 46 | 47 | // Orient our q/d values to the phase-angle we desire 48 | let inv_parke = foc::park_clarke::inverse_park(cos, sin, qd); 49 | // and use the ideal, though computationally heavy, scale-vector calculation for desired 50 | // pwm duty-cycles, i.e. the percentage-of-maximum that each motor-phase will be set to 51 | let [dc_a, dc_b, dc_c] = foc::pwm::SpaceVector::modulate(inv_parke); 52 | 53 | //... and set them. 54 | driver.set_pwms(DutyCycle(dc_a), DutyCycle(dc_b), DutyCycle(dc_c)); 55 | 56 | // Let's artificially slow things down for the purpose of this example 57 | std::thread::sleep(std::time::Duration::from_millis(117)); 58 | } 59 | } 60 | 61 | /// This would be replaced by a platform specific struct in the code that provides MCU-specific 62 | /// support 63 | struct SomePlatformSpecificImpl; 64 | 65 | impl FOController for SomePlatformSpecificImpl { 66 | fn set_psu_millivolt(&self, _mv: u16) { 67 | unimplemented!() 68 | } 69 | } 70 | 71 | impl MotorPins for SomePlatformSpecificImpl { 72 | fn set_pwms( 73 | &mut self, 74 | dc_a: sfoc_rs::common::helpers::DutyCycle, 75 | dc_b: sfoc_rs::common::helpers::DutyCycle, 76 | dc_c: sfoc_rs::common::helpers::DutyCycle, 77 | ) { 78 | println!( 79 | "DCs set: {:>+6.4}|{:>+6.4}|{:>+6.4}", 80 | dc_a.0, dc_b.0, dc_c.0 81 | ); 82 | } 83 | } 84 | 85 | impl PosSensor for SomePlatformSpecificImpl { 86 | type Output = I16F16; 87 | 88 | /// For an actual motor, this would read a position encoder, and give you a position. This 89 | /// might be milliradians, for example. 90 | /// In this case, we use std-time to get millis that rolls back to zero every 2 seconds 91 | fn get_position_um(&self) -> Self::Output { 92 | let now = std::time::SystemTime::now() 93 | .duration_since(SystemTime::UNIX_EPOCH) 94 | .unwrap() 95 | .as_millis(); 96 | let millis = now % 2000; 97 | let frac = I16F16::from_num(millis) / 2000; 98 | I16F16::TAU * frac 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "esp-rs-nix": { 4 | "inputs": { 5 | "flake-parts": "flake-parts", 6 | "nixpkgs": "nixpkgs" 7 | }, 8 | "locked": { 9 | "lastModified": 1733015274, 10 | "narHash": "sha256-2XvnGZkbwh9i9diIgFNV4GNfRiKkImv1PYDx6GfgDP8=", 11 | "owner": "crabdancing", 12 | "repo": "esp-rs-nix", 13 | "rev": "8ab71204c7408bb44563d391b890ce1abb8bde6c", 14 | "type": "github" 15 | }, 16 | "original": { 17 | "owner": "crabdancing", 18 | "repo": "esp-rs-nix", 19 | "type": "github" 20 | } 21 | }, 22 | "flake-parts": { 23 | "inputs": { 24 | "nixpkgs-lib": "nixpkgs-lib" 25 | }, 26 | "locked": { 27 | "lastModified": 1730504689, 28 | "narHash": "sha256-hgmguH29K2fvs9szpq2r3pz2/8cJd2LPS+b4tfNFCwE=", 29 | "owner": "hercules-ci", 30 | "repo": "flake-parts", 31 | "rev": "506278e768c2a08bec68eb62932193e341f55c90", 32 | "type": "github" 33 | }, 34 | "original": { 35 | "owner": "hercules-ci", 36 | "repo": "flake-parts", 37 | "type": "github" 38 | } 39 | }, 40 | "flake-utils": { 41 | "inputs": { 42 | "systems": "systems" 43 | }, 44 | "locked": { 45 | "lastModified": 1726560853, 46 | "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", 47 | "owner": "numtide", 48 | "repo": "flake-utils", 49 | "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "numtide", 54 | "repo": "flake-utils", 55 | "type": "github" 56 | } 57 | }, 58 | "flake-utils_2": { 59 | "inputs": { 60 | "systems": "systems_2" 61 | }, 62 | "locked": { 63 | "lastModified": 1726560853, 64 | "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", 65 | "owner": "numtide", 66 | "repo": "flake-utils", 67 | "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", 68 | "type": "github" 69 | }, 70 | "original": { 71 | "owner": "numtide", 72 | "repo": "flake-utils", 73 | "type": "github" 74 | } 75 | }, 76 | "nixpkgs": { 77 | "locked": { 78 | "lastModified": 1732837521, 79 | "narHash": "sha256-jNRNr49UiuIwaarqijgdTR2qLPifxsVhlJrKzQ8XUIE=", 80 | "owner": "NixOS", 81 | "repo": "nixpkgs", 82 | "rev": "970e93b9f82e2a0f3675757eb0bfc73297cc6370", 83 | "type": "github" 84 | }, 85 | "original": { 86 | "owner": "NixOS", 87 | "ref": "nixos-unstable", 88 | "repo": "nixpkgs", 89 | "type": "github" 90 | } 91 | }, 92 | "nixpkgs-esp-dev": { 93 | "inputs": { 94 | "flake-utils": "flake-utils_2", 95 | "nixpkgs": "nixpkgs_3" 96 | }, 97 | "locked": { 98 | "lastModified": 1729678934, 99 | "narHash": "sha256-fSyXeWJ+9IVJJvZztu1suJm/zp/FgfAzh8RVoveVssQ=", 100 | "owner": "mirrexagon", 101 | "repo": "nixpkgs-esp-dev", 102 | "rev": "3f748af71ac7890e1f860801fdca2beef65e8353", 103 | "type": "github" 104 | }, 105 | "original": { 106 | "owner": "mirrexagon", 107 | "repo": "nixpkgs-esp-dev", 108 | "type": "github" 109 | } 110 | }, 111 | "nixpkgs-lib": { 112 | "locked": { 113 | "lastModified": 1730504152, 114 | "narHash": "sha256-lXvH/vOfb4aGYyvFmZK/HlsNsr/0CVWlwYvo2rxJk3s=", 115 | "type": "tarball", 116 | "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz" 117 | }, 118 | "original": { 119 | "type": "tarball", 120 | "url": "https://github.com/NixOS/nixpkgs/archive/cc2f28000298e1269cea6612cd06ec9979dd5d7f.tar.gz" 121 | } 122 | }, 123 | "nixpkgs_2": { 124 | "locked": { 125 | "lastModified": 1728018373, 126 | "narHash": "sha256-NOiTvBbRLIOe5F6RbHaAh6++BNjsb149fGZd1T4+KBg=", 127 | "owner": "NixOS", 128 | "repo": "nixpkgs", 129 | "rev": "bc947f541ae55e999ffdb4013441347d83b00feb", 130 | "type": "github" 131 | }, 132 | "original": { 133 | "owner": "NixOS", 134 | "ref": "nixos-unstable", 135 | "repo": "nixpkgs", 136 | "type": "github" 137 | } 138 | }, 139 | "nixpkgs_3": { 140 | "locked": { 141 | "lastModified": 1729501122, 142 | "narHash": "sha256-tScdcYQ37kMqlyqb5yizNDTKXZASLB4zHitlHwOg+/o=", 143 | "owner": "NixOS", 144 | "repo": "nixpkgs", 145 | "rev": "56c7c4a3f5fdbef5bf81c7d9c28fbb45dc626611", 146 | "type": "github" 147 | }, 148 | "original": { 149 | "id": "nixpkgs", 150 | "ref": "nixpkgs-unstable", 151 | "type": "indirect" 152 | } 153 | }, 154 | "root": { 155 | "inputs": { 156 | "esp-rs-nix": "esp-rs-nix", 157 | "flake-utils": "flake-utils", 158 | "nixpkgs": "nixpkgs_2", 159 | "nixpkgs-esp-dev": "nixpkgs-esp-dev", 160 | "rust-overlay": "rust-overlay" 161 | } 162 | }, 163 | "rust-overlay": { 164 | "inputs": { 165 | "nixpkgs": [ 166 | "nixpkgs" 167 | ] 168 | }, 169 | "locked": { 170 | "lastModified": 1728181869, 171 | "narHash": "sha256-sQXHXsjIcGEoIHkB+RO6BZdrPfB+43V1TEpyoWRI3ww=", 172 | "owner": "oxalica", 173 | "repo": "rust-overlay", 174 | "rev": "cd46aa3906c14790ef5cbe278d9e54f2c38f95c0", 175 | "type": "github" 176 | }, 177 | "original": { 178 | "owner": "oxalica", 179 | "repo": "rust-overlay", 180 | "type": "github" 181 | } 182 | }, 183 | "systems": { 184 | "locked": { 185 | "lastModified": 1681028828, 186 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 187 | "owner": "nix-systems", 188 | "repo": "default", 189 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 190 | "type": "github" 191 | }, 192 | "original": { 193 | "owner": "nix-systems", 194 | "repo": "default", 195 | "type": "github" 196 | } 197 | }, 198 | "systems_2": { 199 | "locked": { 200 | "lastModified": 1681028828, 201 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 202 | "owner": "nix-systems", 203 | "repo": "default", 204 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 205 | "type": "github" 206 | }, 207 | "original": { 208 | "owner": "nix-systems", 209 | "repo": "default", 210 | "type": "github" 211 | } 212 | } 213 | }, 214 | "root": "root", 215 | "version": 7 216 | } 217 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "SimpleFOC-rs flake"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | rust-overlay = { 7 | url = "github:oxalica/rust-overlay"; 8 | inputs.nixpkgs.follows = "nixpkgs"; 9 | }; 10 | esp-rs-nix = { 11 | url = "github:crabdancing/esp-rs-nix"; 12 | }; 13 | nixpkgs-esp-dev = { 14 | url = "github:mirrexagon/nixpkgs-esp-dev"; 15 | }; 16 | 17 | flake-utils.url = "github:numtide/flake-utils"; 18 | }; 19 | 20 | outputs = {...} @ inputs: 21 | inputs.flake-utils.lib.eachDefaultSystem ( 22 | system: let 23 | esp-rust = inputs.esp-rs-nix.packages.${pkgs.system}.default; 24 | overlays = [(import inputs.rust-overlay)]; 25 | pkgs = import inputs.nixpkgs { 26 | inherit system overlays; 27 | }; 28 | in { 29 | devShells.default = pkgs.mkShell { 30 | buildInputs = 31 | (with pkgs; [ 32 | openssl 33 | pkg-config 34 | eza 35 | fd 36 | cargo-make 37 | gnumake 38 | ]) 39 | ++ [ 40 | esp-rust 41 | ]; 42 | 43 | shellHook = '' 44 | export RUST_SRC_PATH="$(rustc --print sysroot)/lib/rustlib/src/rust/src" 45 | ''; 46 | }; 47 | } 48 | ); 49 | } 50 | -------------------------------------------------------------------------------- /peripherals/AS5047P/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "as5047p" 3 | version = "0.0.1" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | sfoc_rs_core = { version = "0.0.1", path = "../../core" } 8 | -------------------------------------------------------------------------------- /peripherals/AS5047P/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | use sfoc_rs_core::rexports::discrete_count::{ 3 | re_exports::{fixed::types::I20F12, typenum::*}, 4 | CountReader, Counter, 5 | }; 6 | 7 | struct AS5047Periph; 8 | 9 | struct MilliTau(I20F12); 10 | struct Nothing; 11 | 12 | impl CountReader for Nothing { 13 | type ReadErr = (); 14 | 15 | type RawData = u16; 16 | 17 | fn read(&self) -> Result { 18 | todo!() 19 | } 20 | } 21 | impl Counter for AS5047Periph { 22 | type Reader = Nothing; 23 | 24 | type Resolution = (U1, U4096); 25 | 26 | type Measure = MilliTau; 27 | 28 | fn update_count_state( 29 | &mut self, 30 | _count: sfoc_rs_core::rexports::discrete_count::CountRaw, 31 | ) -> Result<(), ::ReadErr> 32 | { 33 | todo!() 34 | } 35 | 36 | fn read_count_state(&self) -> &sfoc_rs_core::rexports::discrete_count::CountRaw { 37 | todo!() 38 | } 39 | 40 | fn try_update_count( 41 | &mut self, 42 | ) -> Result<(), ::ReadErr> 43 | { 44 | todo!() 45 | } 46 | 47 | fn try_read_measure( 48 | &self, 49 | ) -> Result< 50 | Self::Measure, 51 | ::ReadErr, 52 | > { 53 | todo!() 54 | } 55 | 56 | fn measure_count_state(&self) -> Self::Measure { 57 | todo!() 58 | } 59 | 60 | fn try_update_and_measure( 61 | &mut self, 62 | _count: &sfoc_rs_core::rexports::discrete_count::CountRaw, 63 | ) -> Result< 64 | Self::Measure, 65 | ::ReadErr, 66 | > { 67 | todo!() 68 | } 69 | 70 | fn measure_count( 71 | _count: &sfoc_rs_core::rexports::discrete_count::CountRaw, 72 | ) -> Self::Measure { 73 | todo!() 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.xtensa-esp32-none-elf] 2 | runner = "probe-rs run --chip=esp32" 3 | 4 | [env] 5 | DEFMT_LOG="info" 6 | 7 | [build] 8 | rustflags = [ 9 | "-C", "link-arg=-nostartfiles", 10 | ] 11 | 12 | target = "xtensa-esp32-none-elf" 13 | 14 | [unstable] 15 | build-std = ["core"] 16 | 17 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.check.allTargets": false, 3 | } 4 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "esp32_sfoc" 3 | version = "0.1.0" 4 | authors = ["Ben PHL "] 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | 8 | [dependencies] 9 | defmt = "0.3.10" 10 | defmt-rtt = "0.4.1" 11 | discrete_count = {git = "https://github.com/Ben-PH/discrete_count", rev = "de1ce8d5987319aeea4dba678d86659787aaf951", features = ["typenum", "fixed"]} 12 | embedded-hal = "1.0.0" 13 | embedded-time = "0.12.1" 14 | esp-backtrace = { version = "0.14.2", features = [ 15 | "esp32", 16 | "exception-handler", 17 | "panic-handler", 18 | "defmt", 19 | # "println", 20 | # "uart" 21 | ] } 22 | 23 | critical-section = "1.2.0" 24 | 25 | 26 | esp-hal = { version = "0.22.0", features = [ "esp32", "defmt" ] } 27 | fixed = "1.27.0" 28 | foc = "0.3.0" 29 | fugit = { git = "https://github.com/Ben-PH/fugit.git", rev = "aad2d2d97f45b9b12076648b78857f47ff6f1c1b", version = "0.4.0" } 30 | log = { version = "0.4.20" } 31 | sfoc_rs_core = {path = "../../core"} 32 | typenum = "1.17.0" 33 | 34 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "esp" 3 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/src/device.rs: -------------------------------------------------------------------------------- 1 | use core::marker::PhantomData; 2 | 3 | use embedded_hal::pwm::SetDutyCycle; 4 | use esp_backtrace as _; 5 | use esp_hal::{ 6 | gpio::interconnect::PeripheralOutput, 7 | mcpwm::{ 8 | operator::{PwmActions, PwmPin, PwmPinConfig, PwmUpdateMethod}, 9 | timer::PwmWorkingMode, 10 | McPwm, PeripheralClockConfig, PwmPeripheral, 11 | }, 12 | pcnt::unit::Unit, 13 | peripheral::Peripheral, 14 | peripherals, 15 | prelude::*, 16 | }; 17 | 18 | use sfoc_rs_core::{ 19 | bldc_driver::MotorPins, 20 | common::helpers::{Couplet, DutyCycle, Triplet}, 21 | foc_control::FOController, 22 | }; 23 | 24 | // use crate::posn_encoder::EncoderPosn; 25 | 26 | pub struct Esp3PWM<'d, PwmOp> { 27 | motor_triplet: 28 | Triplet, PwmPin<'d, PwmOp, 1, true>, PwmPin<'d, PwmOp, 2, true>>, 29 | } 30 | 31 | impl<'d, PwmOp: PwmPeripheral> Esp3PWM<'d, PwmOp> { 32 | /// Takes in the peripherals needed in order run a motor: 33 | /// - pin_a/b/c: These pins will be attached to the mcpwm peripheral 34 | /// - enc_a/b: these pins will be attached to the Pcnt peripheral. 35 | /// - esp32 has two timer groups and two mcpwm peripherals. you can pass in one of either 36 | /// - the timer group will use one of its timers for the mcpwm operators. 37 | /// 38 | pub fn init( 39 | // timg_choice: impl Peripheral

+ 'd, 40 | mcpwm_choice: impl Peripheral

+ 'd, 41 | pcnt_periph: impl Peripheral

+ 'd, 42 | motor_pins: ( 43 | impl Peripheral

+ 'd, 44 | impl Peripheral

+ 'd, 45 | impl Peripheral

+ 'd, 46 | ), 47 | // encoder_pins: ( 48 | // impl Peripheral

+ 'd, 49 | // impl Peripheral

+ 'd, 50 | // ), 51 | ) -> Self { 52 | // set up the peripherals for our specific usecase 53 | // let timg0 = TimerGroup::new(timg_choice, clocks, None); 54 | // let time_src = Timer0::init(timg0.timer0); 55 | let clock_cfg = PeripheralClockConfig::with_frequency(40.MHz()).unwrap(); 56 | 57 | // Boiler-plate configuration... 58 | let pin_config = 59 | || PwmPinConfig::::new(PwmActions::empty(), PwmUpdateMethod::empty()); 60 | let mut mcpwm_periph = McPwm::new(mcpwm_choice, clock_cfg); 61 | mcpwm_periph.operator0.set_timer(&mcpwm_periph.timer0); 62 | mcpwm_periph.operator1.set_timer(&mcpwm_periph.timer0); 63 | mcpwm_periph.operator2.set_timer(&mcpwm_periph.timer0); 64 | 65 | // Give each operator a pin. 66 | let pin_a: PwmPin<'d, _, 0, true> = mcpwm_periph 67 | .operator0 68 | .with_pin_a(motor_pins.0, pin_config()); 69 | let pin_b: PwmPin<'d, _, 1, true> = mcpwm_periph 70 | .operator1 71 | .with_pin_a(motor_pins.1, pin_config()); 72 | let pin_c: PwmPin<'d, _, 2, true> = mcpwm_periph 73 | .operator2 74 | .with_pin_a(motor_pins.2, pin_config()); 75 | // Put that into a Triplet. Because the pins meets the impl-constraints for 76 | // `MotorPins` trait, it is now the pin-control driver/object 77 | let mut motor_triplet = Triplet { 78 | member_a: pin_a, 79 | member_b: pin_b, 80 | member_c: pin_c, 81 | }; 82 | MotorPins::set_zero(&mut motor_triplet); 83 | 84 | // We want middle-out. I don't know about the pre-scaler or freq settings, but this is my 85 | // best initial guess 86 | let pw_timer_cfg = clock_cfg 87 | .timer_clock_with_frequency(99, PwmWorkingMode::UpDown, 20.kHz()) 88 | .unwrap(); 89 | 90 | // Let's get the party started. 91 | mcpwm_periph.timer0.start(pw_timer_cfg); 92 | 93 | // let pcnt = Pcnt::new(pcnt_periph); 94 | // let pcnt_unit0 = pcnt.unit0; 95 | // let _ = pcnt_unit0.set_low_limit(Some(-100)); 96 | // let _ = pcnt_unit0.set_high_limit(Some(100)); 97 | // 98 | // let pcnt_chann0 = &pcnt_unit0.channel0; 99 | // pcnt_chann0.set_ctrl_signal(encoder_pins.0); 100 | // pcnt_chann0.set_edge_signal(encoder_pins.1); 101 | // pcnt_chann0.set_input_mode(channel::EdgeMode::Decrement, channel::EdgeMode::Increment); 102 | 103 | Self { motor_triplet } 104 | } 105 | } 106 | 107 | impl<'d, PwmOp> MotorPins for Esp3PWM<'d, PwmOp> 108 | where 109 | PwmPin<'d, PwmOp, 0, true>: SetDutyCycle, 110 | PwmPin<'d, PwmOp, 1, true>: SetDutyCycle, 111 | PwmPin<'d, PwmOp, 2, true>: SetDutyCycle, 112 | { 113 | fn set_pwms(&mut self, dc_a: DutyCycle, dc_b: DutyCycle, dc_c: DutyCycle) { 114 | self.motor_triplet.set_pwms(dc_a, dc_b, dc_c) 115 | } 116 | 117 | fn set_zero(&mut self) { 118 | self.motor_triplet.set_zero() 119 | } 120 | } 121 | 122 | impl<'d, PwmOp> FOController for Esp3PWM<'d, PwmOp> 123 | where 124 | PwmPin<'d, PwmOp, 0, true>: SetDutyCycle, 125 | PwmPin<'d, PwmOp, 1, true>: SetDutyCycle, 126 | PwmPin<'d, PwmOp, 2, true>: SetDutyCycle, 127 | { 128 | fn set_psu_millivolt(&self, _mv: u16) { 129 | todo!() 130 | } 131 | } 132 | 133 | pub struct EspPcnt<'a, A, B, const UNIT_NUM: usize, Resolution, Measure> { 134 | ab_pins: Couplet, 135 | unit: Unit<'a, UNIT_NUM>, 136 | _resolution: PhantomData, 137 | _measure: PhantomData, 138 | } 139 | 140 | pub struct UnitReader<'a, const UNIT_NUM: usize>(pub Unit<'a, UNIT_NUM>); 141 | impl<'a, const UNIT_NUM: usize> discrete_count::CountReader for UnitReader<'a, UNIT_NUM> { 142 | type ReadErr = (); 143 | 144 | type RawData = i16; 145 | 146 | fn read(&self) -> Result { 147 | Ok(self.0.counter.get()) 148 | } 149 | } 150 | 151 | impl<'a, A, B, const UNIT_NUM: usize, Resolution, Measure> discrete_count::Counter 152 | for EspPcnt<'a, A, B, UNIT_NUM, Resolution, Measure> 153 | { 154 | type Reader = UnitReader<'a, UNIT_NUM>; 155 | 156 | type Resolution = Resolution; 157 | 158 | type Measure = Measure; 159 | 160 | fn update_count_state( 161 | &mut self, 162 | count: discrete_count::CountRaw, 163 | ) -> Result<(), ::ReadErr> { 164 | todo!() 165 | } 166 | 167 | fn read_count_state(&self) -> &discrete_count::CountRaw { 168 | todo!() 169 | } 170 | 171 | fn try_update_count( 172 | &mut self, 173 | ) -> Result<(), ::ReadErr> { 174 | todo!() 175 | } 176 | 177 | fn try_read_measure( 178 | &self, 179 | ) -> Result::ReadErr> { 180 | todo!() 181 | } 182 | 183 | fn measure_count_state(&self) -> Self::Measure { 184 | todo!() 185 | } 186 | 187 | fn try_update_and_measure( 188 | &mut self, 189 | count: &discrete_count::CountRaw, 190 | ) -> Result::ReadErr> { 191 | todo!() 192 | } 193 | 194 | fn measure_count(count: &discrete_count::CountRaw) -> Self::Measure { 195 | todo!() 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | pub mod device; 3 | pub mod posn_encoder; 4 | pub mod time_source; 5 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/src/posn_encoder.rs: -------------------------------------------------------------------------------- 1 | use discrete_count::CountReader; 2 | use esp_hal::pcnt::unit; 3 | 4 | /// micrometers for each pulse 5 | pub struct EncoderPosn<'a, const NUM: usize> { 6 | // the underlying esp32 pulse count reader 7 | _unit: unit::Unit<'a, NUM>, 8 | } 9 | 10 | impl<'a, const UNIT_NUM: usize> EncoderPosn<'a, UNIT_NUM> { 11 | pub fn new(unit: unit::Unit<'a, UNIT_NUM>) -> Self { 12 | Self { _unit: unit } 13 | } 14 | } 15 | 16 | // TODO 17 | pub struct ABReader; 18 | 19 | impl CountReader for ABReader { 20 | type ReadErr = (); 21 | 22 | type RawData = (); 23 | 24 | fn read(&self) -> Result { 25 | todo!() 26 | } 27 | } 28 | 29 | impl discrete_count::Counter for EncoderPosn<'_, UNIT_NUM> { 30 | type Reader = ABReader; 31 | 32 | type Resolution = u64; 33 | 34 | type Measure = u64; 35 | 36 | fn update_count_state( 37 | &mut self, 38 | _count: discrete_count::CountRaw, 39 | ) -> Result<(), ::ReadErr> { 40 | todo!() 41 | } 42 | 43 | fn read_count_state(&self) -> &discrete_count::CountRaw { 44 | todo!() 45 | } 46 | 47 | fn try_update_count( 48 | &mut self, 49 | ) -> Result<(), ::ReadErr> { 50 | todo!() 51 | } 52 | 53 | fn try_read_measure( 54 | &self, 55 | ) -> Result::ReadErr> { 56 | todo!() 57 | } 58 | 59 | fn measure_count_state(&self) -> Self::Measure { 60 | todo!() 61 | } 62 | 63 | fn try_update_and_measure( 64 | &mut self, 65 | _count: &discrete_count::CountRaw, 66 | ) -> Result::ReadErr> { 67 | todo!() 68 | } 69 | 70 | fn measure_count(_count: &discrete_count::CountRaw) -> Self::Measure { 71 | todo!() 72 | } 73 | // type RawData = i16; 74 | // type CountMeasure = i16; 75 | // type Error = (); 76 | // fn try_read_raw(&self) -> Result { 77 | // Ok(self.unit.get_value()) 78 | // } 79 | // 80 | // fn raw_to_measure(_from: Self::RawData) -> Self::CountMeasure { 81 | // todo!("Each pulse should be scaled by a distance here") 82 | // } 83 | } 84 | -------------------------------------------------------------------------------- /platforms/esp32_sfoc/src/time_source.rs: -------------------------------------------------------------------------------- 1 | use discrete_count::CountReader; 2 | use esp_hal::{ 3 | timer::timg::{Timer, Timer0}, 4 | Blocking, 5 | }; 6 | use fixed::types::I16F16; 7 | use fugit::Duration; 8 | use typenum::{U1, U10000}; 9 | 10 | pub struct TimerHolder { 11 | timer: Timer, Blocking>, 12 | } 13 | 14 | impl TimerHolder { 15 | pub fn init(timer: Timer, Blocking>) -> Self { 16 | // timer. 17 | Self { timer } 18 | } 19 | } 20 | 21 | impl discrete_count::CountReader for TimerHolder { 22 | type RawData = u64; 23 | type ReadErr = (); 24 | fn read(&self) -> Result { 25 | todo!() 26 | // Ok(self.timer.now()) 27 | } 28 | } 29 | impl discrete_count::Counter for TimerHolder { 30 | type Reader = Self; 31 | 32 | type Resolution = I16F16; 33 | 34 | type Measure = Duration<::RawData, U1, U10000>; 35 | 36 | fn update_count_state( 37 | &mut self, 38 | count: discrete_count::CountRaw, 39 | ) -> Result<(), ::ReadErr> { 40 | todo!() 41 | } 42 | 43 | fn read_count_state(&self) -> &discrete_count::CountRaw { 44 | todo!() 45 | } 46 | 47 | fn try_update_count( 48 | &mut self, 49 | ) -> Result<(), ::ReadErr> { 50 | todo!() 51 | } 52 | 53 | fn try_read_measure( 54 | &self, 55 | ) -> Result::ReadErr> { 56 | todo!() 57 | } 58 | 59 | fn measure_count_state(&self) -> Self::Measure { 60 | todo!() 61 | } 62 | 63 | fn try_update_and_measure( 64 | &mut self, 65 | count: &discrete_count::CountRaw, 66 | ) -> Result::ReadErr> { 67 | todo!() 68 | } 69 | 70 | fn measure_count(count: &discrete_count::CountRaw) -> Self::Measure { 71 | todo!() 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /prototype/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "autocfg" 7 | version = "1.4.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 10 | 11 | [[package]] 12 | name = "az" 13 | version = "1.2.1" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 16 | 17 | [[package]] 18 | name = "bytemuck" 19 | version = "1.20.0" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" 22 | 23 | [[package]] 24 | name = "cfg-if" 25 | version = "1.0.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 28 | 29 | [[package]] 30 | name = "cordic" 31 | version = "0.1.5" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "0ed0a176c0b8c5c95fa0523177530364c5b68a8895d9745730dbfa692a7412d0" 34 | dependencies = [ 35 | "fixed", 36 | ] 37 | 38 | [[package]] 39 | name = "crunchy" 40 | version = "0.2.2" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 43 | 44 | [[package]] 45 | name = "discrete_count" 46 | version = "0.0.2" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "72946f16007d8d92d6ef8f8d3b8d274059435ae5d39dc7dc824fd6d68b18b3ce" 49 | dependencies = [ 50 | "discrete_count_core 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 51 | "fixed", 52 | "typenum", 53 | ] 54 | 55 | [[package]] 56 | name = "discrete_count" 57 | version = "0.0.2" 58 | source = "git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951#de1ce8d5987319aeea4dba678d86659787aaf951" 59 | dependencies = [ 60 | "discrete_count_core 0.0.2 (git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951)", 61 | "fixed", 62 | "typenum", 63 | ] 64 | 65 | [[package]] 66 | name = "discrete_count_core" 67 | version = "0.0.2" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "3f112db7875891b885dd69e43af92618d79fef9a803b0a513b601818b7fc5cdb" 70 | 71 | [[package]] 72 | name = "discrete_count_core" 73 | version = "0.0.2" 74 | source = "git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951#de1ce8d5987319aeea4dba678d86659787aaf951" 75 | 76 | [[package]] 77 | name = "embedded-hal" 78 | version = "1.0.0" 79 | source = "registry+https://github.com/rust-lang/crates.io-index" 80 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 81 | 82 | [[package]] 83 | name = "embedded-time" 84 | version = "0.12.1" 85 | source = "registry+https://github.com/rust-lang/crates.io-index" 86 | checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" 87 | dependencies = [ 88 | "num 0.3.1", 89 | ] 90 | 91 | [[package]] 92 | name = "fixed" 93 | version = "1.28.0" 94 | source = "registry+https://github.com/rust-lang/crates.io-index" 95 | checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" 96 | dependencies = [ 97 | "az", 98 | "bytemuck", 99 | "half", 100 | "typenum", 101 | ] 102 | 103 | [[package]] 104 | name = "foc" 105 | version = "0.3.0" 106 | source = "registry+https://github.com/rust-lang/crates.io-index" 107 | checksum = "e162e4bf45e12dfb5de9c561acd8fffd5f9ecb7439440bfb7a7dababd972594f" 108 | dependencies = [ 109 | "cordic", 110 | "fixed", 111 | ] 112 | 113 | [[package]] 114 | name = "fugit" 115 | version = "0.3.7" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 118 | dependencies = [ 119 | "gcd", 120 | ] 121 | 122 | [[package]] 123 | name = "gcd" 124 | version = "2.3.0" 125 | source = "registry+https://github.com/rust-lang/crates.io-index" 126 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 127 | 128 | [[package]] 129 | name = "half" 130 | version = "2.4.1" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 133 | dependencies = [ 134 | "cfg-if", 135 | "crunchy", 136 | ] 137 | 138 | [[package]] 139 | name = "log" 140 | version = "0.4.22" 141 | source = "registry+https://github.com/rust-lang/crates.io-index" 142 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 143 | 144 | [[package]] 145 | name = "micromath" 146 | version = "2.1.0" 147 | source = "registry+https://github.com/rust-lang/crates.io-index" 148 | checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" 149 | 150 | [[package]] 151 | name = "num" 152 | version = "0.3.1" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 155 | dependencies = [ 156 | "num-complex 0.3.1", 157 | "num-integer", 158 | "num-iter", 159 | "num-rational 0.3.2", 160 | "num-traits", 161 | ] 162 | 163 | [[package]] 164 | name = "num" 165 | version = "0.4.3" 166 | source = "registry+https://github.com/rust-lang/crates.io-index" 167 | checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" 168 | dependencies = [ 169 | "num-complex 0.4.6", 170 | "num-integer", 171 | "num-iter", 172 | "num-rational 0.4.2", 173 | "num-traits", 174 | ] 175 | 176 | [[package]] 177 | name = "num-complex" 178 | version = "0.3.1" 179 | source = "registry+https://github.com/rust-lang/crates.io-index" 180 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 181 | dependencies = [ 182 | "num-traits", 183 | ] 184 | 185 | [[package]] 186 | name = "num-complex" 187 | version = "0.4.6" 188 | source = "registry+https://github.com/rust-lang/crates.io-index" 189 | checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" 190 | dependencies = [ 191 | "num-traits", 192 | ] 193 | 194 | [[package]] 195 | name = "num-integer" 196 | version = "0.1.46" 197 | source = "registry+https://github.com/rust-lang/crates.io-index" 198 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 199 | dependencies = [ 200 | "num-traits", 201 | ] 202 | 203 | [[package]] 204 | name = "num-iter" 205 | version = "0.1.45" 206 | source = "registry+https://github.com/rust-lang/crates.io-index" 207 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 208 | dependencies = [ 209 | "autocfg", 210 | "num-integer", 211 | "num-traits", 212 | ] 213 | 214 | [[package]] 215 | name = "num-rational" 216 | version = "0.3.2" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 219 | dependencies = [ 220 | "autocfg", 221 | "num-integer", 222 | "num-traits", 223 | ] 224 | 225 | [[package]] 226 | name = "num-rational" 227 | version = "0.4.2" 228 | source = "registry+https://github.com/rust-lang/crates.io-index" 229 | checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" 230 | dependencies = [ 231 | "num-integer", 232 | "num-traits", 233 | ] 234 | 235 | [[package]] 236 | name = "num-traits" 237 | version = "0.2.19" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 240 | dependencies = [ 241 | "autocfg", 242 | ] 243 | 244 | [[package]] 245 | name = "pid" 246 | version = "4.0.0" 247 | source = "registry+https://github.com/rust-lang/crates.io-index" 248 | checksum = "d7c931ef9756cd5e3fa3d395bfe09df4dfa6f0612c6ca8f6b12927d17ca34e36" 249 | dependencies = [ 250 | "num-traits", 251 | ] 252 | 253 | [[package]] 254 | name = "prototype" 255 | version = "0.1.0" 256 | dependencies = [ 257 | "discrete_count 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 258 | "embedded-hal", 259 | "sfoc_rs", 260 | ] 261 | 262 | [[package]] 263 | name = "sfoc_rs" 264 | version = "0.3.0" 265 | dependencies = [ 266 | "sfoc_rs_core", 267 | ] 268 | 269 | [[package]] 270 | name = "sfoc_rs_core" 271 | version = "0.0.1" 272 | dependencies = [ 273 | "cordic", 274 | "discrete_count 0.0.2 (git+https://github.com/Ben-PH/discrete_count?rev=de1ce8d5987319aeea4dba678d86659787aaf951)", 275 | "embedded-hal", 276 | "embedded-time", 277 | "foc", 278 | "fugit", 279 | "log", 280 | "micromath", 281 | "num 0.4.3", 282 | "pid", 283 | ] 284 | 285 | [[package]] 286 | name = "typenum" 287 | version = "1.17.0" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 290 | -------------------------------------------------------------------------------- /prototype/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "prototype" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | discrete_count = { version = "0.0.2", features = ["fixed", "typenum"] } 8 | embedded-hal = "1.0.0" 9 | sfoc_rs = { version = "0.3.0", path = ".." } 10 | -------------------------------------------------------------------------------- /prototype/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// If you're reading this, I've probably asked for your thoughts on this as a "design reference". 2 | /// The goal is that the examples can be 100% self documenting. The comments throughout this file 3 | /// are to communicate with you the thinking/philosophy/etc. 4 | /// 5 | /// This is intended as a simple-foc-rs version of the velocity_control example in the arduino 6 | /// library. 7 | 8 | mod pin_numbers { 9 | use discrete_count::re_exports::typenum::*; 10 | pub type PhaseA = U3; 11 | pub type PhaseB = U4; 12 | pub type PhaseC = U5; 13 | 14 | pub type EncA = U1; 15 | pub type EncB = U2; 16 | } 17 | 18 | mod initial_config { 19 | use discrete_count::re_exports::typenum::U12; 20 | use sfoc_rs::{foc_control::VelocityPID, rexports::pid::Pid}; 21 | 22 | pub fn initial_velocity_pid() -> VelocityPID { 23 | let mut v_pid = VelocityPID(Pid::new(0.0, 6.0)); 24 | v_pid.0.kp = 0.2; 25 | v_pid.0.ki = 2.0; 26 | v_pid.0.kd = 0.0; 27 | v_pid 28 | } 29 | // 12 volts 30 | pub type DriverVoltagePwrSup = U12; 31 | } 32 | 33 | use discrete_count::Counter; 34 | use embedded_hal::{digital::InputPin, pwm::SetDutyCycle}; 35 | use initial_config::*; 36 | use sfoc_rs::{common::helpers::Triplet, foc_control::FOController}; 37 | 38 | // as it currently stands, the user will need to use platform specific code to get the right pins. 39 | // This can very in complexity, but the goal is to make it 40 | // e.g. for esp32: 41 | // 42 | // ``` 43 | // // expose the resources 44 | // let peripherals = Peripherals::take(); 45 | // let system = peripherals.SYSTEM.split(); 46 | // 47 | // // marshal the pins for encoder and motor mins 48 | // let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); 49 | // let pins = io.pins; 50 | // 51 | // let encoder_pins = ( 52 | // pins.gpio1.into_pull_up_input(), 53 | // pins.gpio2.into_pull_up_input(), 54 | // ); 55 | // 56 | // let motor_pins = Triplet { 57 | // phase_a: pins.gpio3, 58 | // phase_a: pins.gpio4, 59 | // phase_a: pins.gpio5, 60 | // }; 61 | // 62 | // // create a time-source. This would feasibly be baked into the platform library, but easily 63 | // enough implemented as part of sfoc platform support. 64 | // let clock_ctrl = ClockControl::boot_defaults(system.clock_control); 65 | // let clocks: Clocks = clock_ctrl.freeze(); 66 | // let group = TimerGroup::new(peripherals.TIMG0, &clocks, None); 67 | // let time_src = Timer0::init(group.timer0); 68 | // 69 | // entry(motor_pins, encoder_pins, time_src) 70 | // ``` 71 | fn entry< 72 | PA: SetDutyCycle, 73 | PB: SetDutyCycle, 74 | PC: SetDutyCycle, 75 | MPinSource: Into>, 76 | EncA: InputPin, 77 | EncB: InputPin, 78 | >( 79 | motor_pins: MPinSource, 80 | encoder_pins: (EncA, EncB), 81 | time_getter: impl Counter, 82 | ) -> ! { 83 | // ...my thinking being is that the hardware support library defines how the pins are made 84 | // available/initialised. e.g.: 85 | // ``` 86 | // impl From<$PINS> for `Triplet<...> { 87 | // fn into(...) -> ... { 88 | // $hw-specific-conversions-here 89 | // } 90 | // } 91 | let motor_pins: Triplet = motor_pins.into(); 92 | 93 | // Ideally, this `Placeholder` type would encapsulate specific implementations, such as BLDC(4/6)/Stepper(2/4) and platform. That's a fair way away, at least for now, and not so sure what that will look like. Key points of this comment: 94 | // - Platform selection (i.e. which MCU to use) is aliased/abstracted/etc out of user-code almost entirely. 95 | // - Use-case specifics such as which motor is used, voltages, pins, etc is encapsulated at 96 | // the type level. 97 | // 98 | // The FOController trait, and the init function, must have its constraints setup so that 99 | // incompatable pins (i.e. not all pins can be encoder input pins. motor pins should belong to 100 | // the same timer) is a compiletime error. This places a burden on making sure the 101 | // platform-specific pin-getters are type-constrained properly. 102 | // 103 | let foced_up_motor: PlaceHolderFOCInstance = FOController::init_fo_control( 104 | encoder_pins, 105 | motor_pins, 106 | initial_velocity_pid(), 107 | time_getter, 108 | ); 109 | 110 | // I'm not exactly sure what is going on with the `command` global, and in the velocity control 111 | // example, what is going on exactly there. This is an approximation: you can optionally have a 112 | // tx, rx channel that acts as a command buffer that gets filled... somehow? 113 | let command_channel = CommandChannel::init(); 114 | foced_up_motor.attach_command_recv(command_channel.rx); 115 | 116 | foced_up_motor.begin_monitoring(Serial::new(115200)); 117 | 118 | command_channel.tx.push(('T', (), "target velocity")); 119 | println!("Motor ready"); 120 | println!("Using the serial terminal to set a target velocity:"); 121 | 122 | main_loop(foced_up_motor, command_channel.rx) 123 | } 124 | 125 | fn main_loop(controller: (), command_channel: ()) -> ! { 126 | loop { 127 | controller.loopFOC(); 128 | controller.move_motor(); 129 | 130 | todo!("workout the sfoc command.run() idiom and downstream it to here"); 131 | } 132 | } 133 | 134 | fn main() { 135 | todo!() 136 | } 137 | -------------------------------------------------------------------------------- /spinnies/esp32/original/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.xtensa-esp32-none-elf] 2 | runner = "probe-rs run --chip=esp32" 3 | 4 | [env] 5 | DEFMT_LOG="info" 6 | 7 | [build] 8 | rustflags = [ 9 | "-C", "link-arg=-nostartfiles", 10 | ] 11 | 12 | target = "xtensa-esp32-none-elf" 13 | 14 | [unstable] 15 | build-std = ["core"] 16 | -------------------------------------------------------------------------------- /spinnies/esp32/original/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | # RustRover 13 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 14 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 15 | # and can be added to the global gitignore or merged into this file. For a more nuclear 16 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 17 | #.idea/ 18 | -------------------------------------------------------------------------------- /spinnies/esp32/original/Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 3 4 | 5 | [[package]] 6 | name = "anyhow" 7 | version = "1.0.93" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775" 10 | 11 | [[package]] 12 | name = "autocfg" 13 | version = "1.4.0" 14 | source = "registry+https://github.com/rust-lang/crates.io-index" 15 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 16 | 17 | [[package]] 18 | name = "az" 19 | version = "1.2.1" 20 | source = "registry+https://github.com/rust-lang/crates.io-index" 21 | checksum = "7b7e4c2464d97fe331d41de9d5db0def0a96f4d823b8b32a2efd503578988973" 22 | 23 | [[package]] 24 | name = "bare-metal" 25 | version = "1.0.0" 26 | source = "registry+https://github.com/rust-lang/crates.io-index" 27 | checksum = "f8fe8f5a8a398345e52358e18ff07cc17a568fbca5c6f73873d3a62056309603" 28 | 29 | [[package]] 30 | name = "basic-toml" 31 | version = "0.1.9" 32 | source = "registry+https://github.com/rust-lang/crates.io-index" 33 | checksum = "823388e228f614e9558c6804262db37960ec8821856535f5c3f59913140558f8" 34 | dependencies = [ 35 | "serde", 36 | ] 37 | 38 | [[package]] 39 | name = "bitfield" 40 | version = "0.17.0" 41 | source = "registry+https://github.com/rust-lang/crates.io-index" 42 | checksum = "f798d2d157e547aa99aab0967df39edd0b70307312b6f8bd2848e6abe40896e0" 43 | 44 | [[package]] 45 | name = "bitflags" 46 | version = "1.3.2" 47 | source = "registry+https://github.com/rust-lang/crates.io-index" 48 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" 49 | 50 | [[package]] 51 | name = "bitflags" 52 | version = "2.6.0" 53 | source = "registry+https://github.com/rust-lang/crates.io-index" 54 | checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" 55 | 56 | [[package]] 57 | name = "bytemuck" 58 | version = "1.20.0" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" 61 | 62 | [[package]] 63 | name = "byteorder" 64 | version = "1.5.0" 65 | source = "registry+https://github.com/rust-lang/crates.io-index" 66 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 67 | 68 | [[package]] 69 | name = "cfg-if" 70 | version = "1.0.0" 71 | source = "registry+https://github.com/rust-lang/crates.io-index" 72 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 73 | 74 | [[package]] 75 | name = "chrono" 76 | version = "0.4.38" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" 79 | dependencies = [ 80 | "num-traits", 81 | ] 82 | 83 | [[package]] 84 | name = "cordic" 85 | version = "0.1.5" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "0ed0a176c0b8c5c95fa0523177530364c5b68a8895d9745730dbfa692a7412d0" 88 | dependencies = [ 89 | "fixed", 90 | ] 91 | 92 | [[package]] 93 | name = "critical-section" 94 | version = "1.2.0" 95 | source = "registry+https://github.com/rust-lang/crates.io-index" 96 | checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" 97 | 98 | [[package]] 99 | name = "crunchy" 100 | version = "0.2.2" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" 103 | 104 | [[package]] 105 | name = "darling" 106 | version = "0.20.10" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 109 | dependencies = [ 110 | "darling_core", 111 | "darling_macro", 112 | ] 113 | 114 | [[package]] 115 | name = "darling_core" 116 | version = "0.20.10" 117 | source = "registry+https://github.com/rust-lang/crates.io-index" 118 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 119 | dependencies = [ 120 | "fnv", 121 | "ident_case", 122 | "proc-macro2", 123 | "quote", 124 | "strsim", 125 | "syn", 126 | ] 127 | 128 | [[package]] 129 | name = "darling_macro" 130 | version = "0.20.10" 131 | source = "registry+https://github.com/rust-lang/crates.io-index" 132 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 133 | dependencies = [ 134 | "darling_core", 135 | "quote", 136 | "syn", 137 | ] 138 | 139 | [[package]] 140 | name = "defmt" 141 | version = "0.3.10" 142 | source = "registry+https://github.com/rust-lang/crates.io-index" 143 | checksum = "86f6162c53f659f65d00619fe31f14556a6e9f8752ccc4a41bd177ffcf3d6130" 144 | dependencies = [ 145 | "bitflags 1.3.2", 146 | "defmt-macros", 147 | ] 148 | 149 | [[package]] 150 | name = "defmt-macros" 151 | version = "0.4.0" 152 | source = "registry+https://github.com/rust-lang/crates.io-index" 153 | checksum = "9d135dd939bad62d7490b0002602d35b358dce5fd9233a709d3c1ef467d4bde6" 154 | dependencies = [ 155 | "defmt-parser", 156 | "proc-macro-error2", 157 | "proc-macro2", 158 | "quote", 159 | "syn", 160 | ] 161 | 162 | [[package]] 163 | name = "defmt-parser" 164 | version = "0.4.1" 165 | source = "registry+https://github.com/rust-lang/crates.io-index" 166 | checksum = "3983b127f13995e68c1e29071e5d115cd96f215ccb5e6812e3728cd6f92653b3" 167 | dependencies = [ 168 | "thiserror", 169 | ] 170 | 171 | [[package]] 172 | name = "defmt-rtt" 173 | version = "0.4.1" 174 | source = "registry+https://github.com/rust-lang/crates.io-index" 175 | checksum = "bab697b3dbbc1750b7c8b821aa6f6e7f2480b47a99bc057a2ed7b170ebef0c51" 176 | dependencies = [ 177 | "critical-section", 178 | "defmt", 179 | ] 180 | 181 | [[package]] 182 | name = "delegate" 183 | version = "0.13.1" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "bc2323e10c92e1cf4d86e11538512e6dc03ceb586842970b6332af3d4046a046" 186 | dependencies = [ 187 | "proc-macro2", 188 | "quote", 189 | "syn", 190 | ] 191 | 192 | [[package]] 193 | name = "discrete_count" 194 | version = "0.0.2" 195 | source = "git+https://github.com/Ben-PH/discrete_count?rev=2b04f9d6953ffeba56fb4ee36ad4ca3522457250#2b04f9d6953ffeba56fb4ee36ad4ca3522457250" 196 | dependencies = [ 197 | "discrete_count_core", 198 | "fixed", 199 | "typenum", 200 | ] 201 | 202 | [[package]] 203 | name = "discrete_count_core" 204 | version = "0.0.2" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "3f112db7875891b885dd69e43af92618d79fef9a803b0a513b601818b7fc5cdb" 207 | 208 | [[package]] 209 | name = "document-features" 210 | version = "0.2.10" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "cb6969eaabd2421f8a2775cfd2471a2b634372b4a25d41e3bd647b79912850a0" 213 | dependencies = [ 214 | "litrs", 215 | ] 216 | 217 | [[package]] 218 | name = "embassy-embedded-hal" 219 | version = "0.2.0" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "5794414bc20e0d750f145bc0e82366b19dd078e9e075e8331fb8dd069a1cb6a2" 222 | dependencies = [ 223 | "embassy-futures", 224 | "embassy-sync", 225 | "embassy-time", 226 | "embedded-hal 0.2.7", 227 | "embedded-hal 1.0.0", 228 | "embedded-hal-async", 229 | "embedded-storage", 230 | "embedded-storage-async", 231 | "nb 1.1.0", 232 | ] 233 | 234 | [[package]] 235 | name = "embassy-futures" 236 | version = "0.1.1" 237 | source = "registry+https://github.com/rust-lang/crates.io-index" 238 | checksum = "1f878075b9794c1e4ac788c95b728f26aa6366d32eeb10c7051389f898f7d067" 239 | dependencies = [ 240 | "defmt", 241 | ] 242 | 243 | [[package]] 244 | name = "embassy-sync" 245 | version = "0.6.1" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "3899a6e39fa3f54bf8aaf00979f9f9c0145a522f7244810533abbb748be6ce82" 248 | dependencies = [ 249 | "cfg-if", 250 | "critical-section", 251 | "defmt", 252 | "embedded-io-async", 253 | "futures-sink", 254 | "futures-util", 255 | "heapless", 256 | ] 257 | 258 | [[package]] 259 | name = "embassy-time" 260 | version = "0.3.2" 261 | source = "registry+https://github.com/rust-lang/crates.io-index" 262 | checksum = "158080d48f824fad101d7b2fae2d83ac39e3f7a6fa01811034f7ab8ffc6e7309" 263 | dependencies = [ 264 | "cfg-if", 265 | "critical-section", 266 | "document-features", 267 | "embassy-time-driver", 268 | "embassy-time-queue-driver", 269 | "embedded-hal 0.2.7", 270 | "embedded-hal 1.0.0", 271 | "embedded-hal-async", 272 | "futures-util", 273 | "heapless", 274 | ] 275 | 276 | [[package]] 277 | name = "embassy-time-driver" 278 | version = "0.1.0" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "6e0c214077aaa9206958b16411c157961fb7990d4ea628120a78d1a5a28aed24" 281 | dependencies = [ 282 | "document-features", 283 | ] 284 | 285 | [[package]] 286 | name = "embassy-time-queue-driver" 287 | version = "0.1.0" 288 | source = "registry+https://github.com/rust-lang/crates.io-index" 289 | checksum = "f1177859559ebf42cd24ae7ba8fe6ee707489b01d0bf471f8827b7b12dcb0bc0" 290 | 291 | [[package]] 292 | name = "embedded-can" 293 | version = "0.4.1" 294 | source = "registry+https://github.com/rust-lang/crates.io-index" 295 | checksum = "e9d2e857f87ac832df68fa498d18ddc679175cf3d2e4aa893988e5601baf9438" 296 | dependencies = [ 297 | "nb 1.1.0", 298 | ] 299 | 300 | [[package]] 301 | name = "embedded-hal" 302 | version = "0.2.7" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" 305 | dependencies = [ 306 | "nb 0.1.3", 307 | "void", 308 | ] 309 | 310 | [[package]] 311 | name = "embedded-hal" 312 | version = "1.0.0" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" 315 | dependencies = [ 316 | "defmt", 317 | ] 318 | 319 | [[package]] 320 | name = "embedded-hal-async" 321 | version = "1.0.0" 322 | source = "registry+https://github.com/rust-lang/crates.io-index" 323 | checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" 324 | dependencies = [ 325 | "embedded-hal 1.0.0", 326 | ] 327 | 328 | [[package]] 329 | name = "embedded-hal-nb" 330 | version = "1.0.0" 331 | source = "registry+https://github.com/rust-lang/crates.io-index" 332 | checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" 333 | dependencies = [ 334 | "embedded-hal 1.0.0", 335 | "nb 1.1.0", 336 | ] 337 | 338 | [[package]] 339 | name = "embedded-io" 340 | version = "0.6.1" 341 | source = "registry+https://github.com/rust-lang/crates.io-index" 342 | checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" 343 | dependencies = [ 344 | "defmt", 345 | ] 346 | 347 | [[package]] 348 | name = "embedded-io-async" 349 | version = "0.6.1" 350 | source = "registry+https://github.com/rust-lang/crates.io-index" 351 | checksum = "3ff09972d4073aa8c299395be75161d582e7629cd663171d62af73c8d50dba3f" 352 | dependencies = [ 353 | "defmt", 354 | "embedded-io", 355 | ] 356 | 357 | [[package]] 358 | name = "embedded-storage" 359 | version = "0.3.1" 360 | source = "registry+https://github.com/rust-lang/crates.io-index" 361 | checksum = "a21dea9854beb860f3062d10228ce9b976da520a73474aed3171ec276bc0c032" 362 | 363 | [[package]] 364 | name = "embedded-storage-async" 365 | version = "0.4.1" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "1763775e2323b7d5f0aa6090657f5e21cfa02ede71f5dc40eead06d64dcd15cc" 368 | dependencies = [ 369 | "embedded-storage", 370 | ] 371 | 372 | [[package]] 373 | name = "embedded-time" 374 | version = "0.12.1" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "d7a4b4d10ac48d08bfe3db7688c402baadb244721f30a77ce360bd24c3dffe58" 377 | dependencies = [ 378 | "num", 379 | ] 380 | 381 | [[package]] 382 | name = "enum-as-inner" 383 | version = "0.6.1" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" 386 | dependencies = [ 387 | "heck", 388 | "proc-macro2", 389 | "quote", 390 | "syn", 391 | ] 392 | 393 | [[package]] 394 | name = "enumset" 395 | version = "1.1.5" 396 | source = "registry+https://github.com/rust-lang/crates.io-index" 397 | checksum = "d07a4b049558765cef5f0c1a273c3fc57084d768b44d2f98127aef4cceb17293" 398 | dependencies = [ 399 | "enumset_derive", 400 | ] 401 | 402 | [[package]] 403 | name = "enumset_derive" 404 | version = "0.10.0" 405 | source = "registry+https://github.com/rust-lang/crates.io-index" 406 | checksum = "59c3b24c345d8c314966bdc1832f6c2635bfcce8e7cf363bd115987bba2ee242" 407 | dependencies = [ 408 | "darling", 409 | "proc-macro2", 410 | "quote", 411 | "syn", 412 | ] 413 | 414 | [[package]] 415 | name = "equivalent" 416 | version = "1.0.1" 417 | source = "registry+https://github.com/rust-lang/crates.io-index" 418 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 419 | 420 | [[package]] 421 | name = "esp-backtrace" 422 | version = "0.14.2" 423 | source = "registry+https://github.com/rust-lang/crates.io-index" 424 | checksum = "cb7660d85e3e7b0e113aaeeffb1a155e64a09a5035d4104031875acdba4cb68e" 425 | dependencies = [ 426 | "defmt", 427 | "esp-build", 428 | "esp-println", 429 | "semihosting", 430 | ] 431 | 432 | [[package]] 433 | name = "esp-build" 434 | version = "0.1.0" 435 | source = "registry+https://github.com/rust-lang/crates.io-index" 436 | checksum = "b94a4b8d74e7cc7baabcca5b2277b41877e039ad9cd49959d48ef94dac7eab4b" 437 | dependencies = [ 438 | "quote", 439 | "syn", 440 | "termcolor", 441 | ] 442 | 443 | [[package]] 444 | name = "esp-config" 445 | version = "0.2.0" 446 | source = "registry+https://github.com/rust-lang/crates.io-index" 447 | checksum = "f7584e4cd1dac06201fd92fff1c84b396be5458ac4d93e9457e7a89b1b42c60e" 448 | dependencies = [ 449 | "document-features", 450 | ] 451 | 452 | [[package]] 453 | name = "esp-hal" 454 | version = "0.22.0" 455 | source = "registry+https://github.com/rust-lang/crates.io-index" 456 | checksum = "1a5605e1518d63f7bf9fbd9885e61d2896060d2e4f28954736bdd74da911b676" 457 | dependencies = [ 458 | "basic-toml", 459 | "bitfield", 460 | "bitflags 2.6.0", 461 | "bytemuck", 462 | "cfg-if", 463 | "chrono", 464 | "critical-section", 465 | "defmt", 466 | "delegate", 467 | "document-features", 468 | "embassy-embedded-hal", 469 | "embassy-futures", 470 | "embassy-sync", 471 | "embedded-can", 472 | "embedded-hal 0.2.7", 473 | "embedded-hal 1.0.0", 474 | "embedded-hal-async", 475 | "embedded-hal-nb", 476 | "embedded-io", 477 | "embedded-io-async", 478 | "enumset", 479 | "esp-build", 480 | "esp-config", 481 | "esp-hal-procmacros", 482 | "esp-metadata", 483 | "esp-riscv-rt", 484 | "esp32", 485 | "esp32c2", 486 | "esp32c3", 487 | "esp32c6", 488 | "esp32h2", 489 | "esp32s2", 490 | "esp32s3", 491 | "fugit", 492 | "nb 1.1.0", 493 | "paste", 494 | "portable-atomic", 495 | "rand_core", 496 | "serde", 497 | "strum", 498 | "ufmt-write", 499 | "void", 500 | "xtensa-lx", 501 | "xtensa-lx-rt", 502 | ] 503 | 504 | [[package]] 505 | name = "esp-hal-procmacros" 506 | version = "0.15.0" 507 | source = "registry+https://github.com/rust-lang/crates.io-index" 508 | checksum = "69a9a8706b7d1182b56335d196e70eeb04e2b70f4b8db96432898bd3c2bdb91e" 509 | dependencies = [ 510 | "darling", 511 | "document-features", 512 | "litrs", 513 | "proc-macro-crate", 514 | "proc-macro-error2", 515 | "proc-macro2", 516 | "quote", 517 | "syn", 518 | ] 519 | 520 | [[package]] 521 | name = "esp-metadata" 522 | version = "0.4.0" 523 | source = "registry+https://github.com/rust-lang/crates.io-index" 524 | checksum = "f9972bbb21dcafe430b87f92efc7a788978a2d17cf8f572d104beeb48602482a" 525 | dependencies = [ 526 | "anyhow", 527 | "basic-toml", 528 | "serde", 529 | "strum", 530 | ] 531 | 532 | [[package]] 533 | name = "esp-println" 534 | version = "0.12.0" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "ee38e87bc7e303c299047c0e9bcd0f8ccca7c7e70d1fd78bbb565db14f33beb6" 537 | dependencies = [ 538 | "esp-build", 539 | "log", 540 | ] 541 | 542 | [[package]] 543 | name = "esp-riscv-rt" 544 | version = "0.9.1" 545 | source = "registry+https://github.com/rust-lang/crates.io-index" 546 | checksum = "94aca65db6157aa5f42d9df6595b21462f28207ca4230b799aa3620352ef6a72" 547 | dependencies = [ 548 | "document-features", 549 | "riscv", 550 | "riscv-rt-macros", 551 | ] 552 | 553 | [[package]] 554 | name = "esp32" 555 | version = "0.34.0" 556 | source = "registry+https://github.com/rust-lang/crates.io-index" 557 | checksum = "af7d3208ef4ffd96c3105b3fb6fd19e8512bc128b24cb866dc26a734b09f454c" 558 | dependencies = [ 559 | "critical-section", 560 | "defmt", 561 | "vcell", 562 | ] 563 | 564 | [[package]] 565 | name = "esp32_sfoc" 566 | version = "0.1.0" 567 | dependencies = [ 568 | "critical-section", 569 | "defmt", 570 | "defmt-rtt", 571 | "discrete_count", 572 | "embedded-hal 1.0.0", 573 | "embedded-time", 574 | "esp-backtrace", 575 | "esp-hal", 576 | "fixed", 577 | "foc", 578 | "fugit", 579 | "log", 580 | "sfoc_rs_core", 581 | "typenum", 582 | ] 583 | 584 | [[package]] 585 | name = "esp32c2" 586 | version = "0.23.0" 587 | source = "registry+https://github.com/rust-lang/crates.io-index" 588 | checksum = "e74f8ceff5249a39f6ffeaea7a9c048b36fd1ba67d365330e0970927c57759ab" 589 | dependencies = [ 590 | "critical-section", 591 | "defmt", 592 | "vcell", 593 | ] 594 | 595 | [[package]] 596 | name = "esp32c3" 597 | version = "0.26.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "5d1750382dc49fa333ee6b1ba96f8c540038b9666f5a233dc1221c98e3236118" 600 | dependencies = [ 601 | "critical-section", 602 | "defmt", 603 | "vcell", 604 | ] 605 | 606 | [[package]] 607 | name = "esp32c6" 608 | version = "0.17.0" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "8b98fcf7ae90ee4d55f06170dfeaaebbf2a1619bb38b4e14b9009b4d636b87e7" 611 | dependencies = [ 612 | "critical-section", 613 | "defmt", 614 | "vcell", 615 | ] 616 | 617 | [[package]] 618 | name = "esp32h2" 619 | version = "0.13.0" 620 | source = "registry+https://github.com/rust-lang/crates.io-index" 621 | checksum = "b1530274ade78283655a6810dd5d1840404945f4a5bf3d74729c35946beb8304" 622 | dependencies = [ 623 | "critical-section", 624 | "defmt", 625 | "vcell", 626 | ] 627 | 628 | [[package]] 629 | name = "esp32s2" 630 | version = "0.25.0" 631 | source = "registry+https://github.com/rust-lang/crates.io-index" 632 | checksum = "2f77ec7a694eb60741f53236e625456abf672ba5b0b73c4a2d708a343c6f3495" 633 | dependencies = [ 634 | "critical-section", 635 | "defmt", 636 | "vcell", 637 | ] 638 | 639 | [[package]] 640 | name = "esp32s3" 641 | version = "0.29.0" 642 | source = "registry+https://github.com/rust-lang/crates.io-index" 643 | checksum = "fe69dca8db0ed37d222555f12dfaf99232592e84f54e56dd81e450a4769718bf" 644 | dependencies = [ 645 | "critical-section", 646 | "defmt", 647 | "vcell", 648 | ] 649 | 650 | [[package]] 651 | name = "fixed" 652 | version = "1.28.0" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "85c6e0b89bf864acd20590dbdbad56f69aeb898abfc9443008fd7bd48b2cc85a" 655 | dependencies = [ 656 | "az", 657 | "bytemuck", 658 | "half", 659 | "typenum", 660 | ] 661 | 662 | [[package]] 663 | name = "fnv" 664 | version = "1.0.7" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 667 | 668 | [[package]] 669 | name = "foc" 670 | version = "0.3.0" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "e162e4bf45e12dfb5de9c561acd8fffd5f9ecb7439440bfb7a7dababd972594f" 673 | dependencies = [ 674 | "cordic", 675 | "fixed", 676 | ] 677 | 678 | [[package]] 679 | name = "fugit" 680 | version = "0.3.7" 681 | source = "registry+https://github.com/rust-lang/crates.io-index" 682 | checksum = "17186ad64927d5ac8f02c1e77ccefa08ccd9eaa314d5a4772278aa204a22f7e7" 683 | dependencies = [ 684 | "defmt", 685 | "gcd", 686 | ] 687 | 688 | [[package]] 689 | name = "futures-core" 690 | version = "0.3.31" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 693 | 694 | [[package]] 695 | name = "futures-sink" 696 | version = "0.3.31" 697 | source = "registry+https://github.com/rust-lang/crates.io-index" 698 | checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" 699 | 700 | [[package]] 701 | name = "futures-task" 702 | version = "0.3.31" 703 | source = "registry+https://github.com/rust-lang/crates.io-index" 704 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 705 | 706 | [[package]] 707 | name = "futures-util" 708 | version = "0.3.31" 709 | source = "registry+https://github.com/rust-lang/crates.io-index" 710 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 711 | dependencies = [ 712 | "futures-core", 713 | "futures-task", 714 | "pin-project-lite", 715 | "pin-utils", 716 | ] 717 | 718 | [[package]] 719 | name = "gcd" 720 | version = "2.3.0" 721 | source = "registry+https://github.com/rust-lang/crates.io-index" 722 | checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" 723 | 724 | [[package]] 725 | name = "half" 726 | version = "2.4.1" 727 | source = "registry+https://github.com/rust-lang/crates.io-index" 728 | checksum = "6dd08c532ae367adf81c312a4580bc67f1d0fe8bc9c460520283f4c0ff277888" 729 | dependencies = [ 730 | "cfg-if", 731 | "crunchy", 732 | ] 733 | 734 | [[package]] 735 | name = "hash32" 736 | version = "0.3.1" 737 | source = "registry+https://github.com/rust-lang/crates.io-index" 738 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 739 | dependencies = [ 740 | "byteorder", 741 | ] 742 | 743 | [[package]] 744 | name = "hashbrown" 745 | version = "0.15.2" 746 | source = "registry+https://github.com/rust-lang/crates.io-index" 747 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 748 | 749 | [[package]] 750 | name = "heapless" 751 | version = "0.8.0" 752 | source = "registry+https://github.com/rust-lang/crates.io-index" 753 | checksum = "0bfb9eb618601c89945a70e254898da93b13be0388091d42117462b265bb3fad" 754 | dependencies = [ 755 | "hash32", 756 | "stable_deref_trait", 757 | ] 758 | 759 | [[package]] 760 | name = "heck" 761 | version = "0.5.0" 762 | source = "registry+https://github.com/rust-lang/crates.io-index" 763 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 764 | 765 | [[package]] 766 | name = "ident_case" 767 | version = "1.0.1" 768 | source = "registry+https://github.com/rust-lang/crates.io-index" 769 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 770 | 771 | [[package]] 772 | name = "indexmap" 773 | version = "2.7.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" 776 | dependencies = [ 777 | "equivalent", 778 | "hashbrown", 779 | ] 780 | 781 | [[package]] 782 | name = "litrs" 783 | version = "0.4.1" 784 | source = "registry+https://github.com/rust-lang/crates.io-index" 785 | checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5" 786 | dependencies = [ 787 | "proc-macro2", 788 | ] 789 | 790 | [[package]] 791 | name = "lock_api" 792 | version = "0.4.12" 793 | source = "registry+https://github.com/rust-lang/crates.io-index" 794 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 795 | dependencies = [ 796 | "autocfg", 797 | "scopeguard", 798 | ] 799 | 800 | [[package]] 801 | name = "log" 802 | version = "0.4.22" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" 805 | 806 | [[package]] 807 | name = "memchr" 808 | version = "2.7.4" 809 | source = "registry+https://github.com/rust-lang/crates.io-index" 810 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 811 | 812 | [[package]] 813 | name = "micromath" 814 | version = "2.1.0" 815 | source = "registry+https://github.com/rust-lang/crates.io-index" 816 | checksum = "c3c8dda44ff03a2f238717214da50f65d5a53b45cd213a7370424ffdb6fae815" 817 | 818 | [[package]] 819 | name = "minijinja" 820 | version = "2.5.0" 821 | source = "registry+https://github.com/rust-lang/crates.io-index" 822 | checksum = "2c37e1b517d1dcd0e51dc36c4567b9d5a29262b3ec8da6cb5d35e27a8fb529b5" 823 | dependencies = [ 824 | "serde", 825 | ] 826 | 827 | [[package]] 828 | name = "mutex-trait" 829 | version = "0.2.0" 830 | source = "registry+https://github.com/rust-lang/crates.io-index" 831 | checksum = "b4bb1638d419e12f8b1c43d9e639abd0d1424285bdea2f76aa231e233c63cd3a" 832 | 833 | [[package]] 834 | name = "nb" 835 | version = "0.1.3" 836 | source = "registry+https://github.com/rust-lang/crates.io-index" 837 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 838 | dependencies = [ 839 | "nb 1.1.0", 840 | ] 841 | 842 | [[package]] 843 | name = "nb" 844 | version = "1.1.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" 847 | 848 | [[package]] 849 | name = "num" 850 | version = "0.3.1" 851 | source = "registry+https://github.com/rust-lang/crates.io-index" 852 | checksum = "8b7a8e9be5e039e2ff869df49155f1c06bd01ade2117ec783e56ab0932b67a8f" 853 | dependencies = [ 854 | "num-complex", 855 | "num-integer", 856 | "num-iter", 857 | "num-rational", 858 | "num-traits", 859 | ] 860 | 861 | [[package]] 862 | name = "num-complex" 863 | version = "0.3.1" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "747d632c0c558b87dbabbe6a82f3b4ae03720d0646ac5b7b4dae89394be5f2c5" 866 | dependencies = [ 867 | "num-traits", 868 | ] 869 | 870 | [[package]] 871 | name = "num-integer" 872 | version = "0.1.46" 873 | source = "registry+https://github.com/rust-lang/crates.io-index" 874 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 875 | dependencies = [ 876 | "num-traits", 877 | ] 878 | 879 | [[package]] 880 | name = "num-iter" 881 | version = "0.1.45" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 884 | dependencies = [ 885 | "autocfg", 886 | "num-integer", 887 | "num-traits", 888 | ] 889 | 890 | [[package]] 891 | name = "num-rational" 892 | version = "0.3.2" 893 | source = "registry+https://github.com/rust-lang/crates.io-index" 894 | checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" 895 | dependencies = [ 896 | "autocfg", 897 | "num-integer", 898 | "num-traits", 899 | ] 900 | 901 | [[package]] 902 | name = "num-traits" 903 | version = "0.2.19" 904 | source = "registry+https://github.com/rust-lang/crates.io-index" 905 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 906 | dependencies = [ 907 | "autocfg", 908 | ] 909 | 910 | [[package]] 911 | name = "original" 912 | version = "0.1.0" 913 | dependencies = [ 914 | "critical-section", 915 | "defmt", 916 | "defmt-rtt", 917 | "esp-backtrace", 918 | "esp-hal", 919 | "sfoc_rs", 920 | ] 921 | 922 | [[package]] 923 | name = "paste" 924 | version = "1.0.15" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 927 | 928 | [[package]] 929 | name = "pid" 930 | version = "4.0.0" 931 | source = "registry+https://github.com/rust-lang/crates.io-index" 932 | checksum = "d7c931ef9756cd5e3fa3d395bfe09df4dfa6f0612c6ca8f6b12927d17ca34e36" 933 | dependencies = [ 934 | "num-traits", 935 | ] 936 | 937 | [[package]] 938 | name = "pin-project-lite" 939 | version = "0.2.15" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" 942 | 943 | [[package]] 944 | name = "pin-utils" 945 | version = "0.1.0" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 948 | 949 | [[package]] 950 | name = "portable-atomic" 951 | version = "1.10.0" 952 | source = "registry+https://github.com/rust-lang/crates.io-index" 953 | checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" 954 | 955 | [[package]] 956 | name = "proc-macro-crate" 957 | version = "3.2.0" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" 960 | dependencies = [ 961 | "toml_edit", 962 | ] 963 | 964 | [[package]] 965 | name = "proc-macro-error-attr2" 966 | version = "2.0.0" 967 | source = "registry+https://github.com/rust-lang/crates.io-index" 968 | checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" 969 | dependencies = [ 970 | "proc-macro2", 971 | "quote", 972 | ] 973 | 974 | [[package]] 975 | name = "proc-macro-error2" 976 | version = "2.0.1" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" 979 | dependencies = [ 980 | "proc-macro-error-attr2", 981 | "proc-macro2", 982 | "quote", 983 | "syn", 984 | ] 985 | 986 | [[package]] 987 | name = "proc-macro2" 988 | version = "1.0.92" 989 | source = "registry+https://github.com/rust-lang/crates.io-index" 990 | checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" 991 | dependencies = [ 992 | "unicode-ident", 993 | ] 994 | 995 | [[package]] 996 | name = "quote" 997 | version = "1.0.37" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" 1000 | dependencies = [ 1001 | "proc-macro2", 1002 | ] 1003 | 1004 | [[package]] 1005 | name = "r0" 1006 | version = "1.0.0" 1007 | source = "registry+https://github.com/rust-lang/crates.io-index" 1008 | checksum = "bd7a31eed1591dcbc95d92ad7161908e72f4677f8fabf2a32ca49b4237cbf211" 1009 | 1010 | [[package]] 1011 | name = "rand_core" 1012 | version = "0.6.4" 1013 | source = "registry+https://github.com/rust-lang/crates.io-index" 1014 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1015 | 1016 | [[package]] 1017 | name = "riscv" 1018 | version = "0.12.1" 1019 | source = "registry+https://github.com/rust-lang/crates.io-index" 1020 | checksum = "5ea8ff73d3720bdd0a97925f0bf79ad2744b6da8ff36be3840c48ac81191d7a7" 1021 | dependencies = [ 1022 | "critical-section", 1023 | "embedded-hal 1.0.0", 1024 | "paste", 1025 | "riscv-macros", 1026 | "riscv-pac", 1027 | ] 1028 | 1029 | [[package]] 1030 | name = "riscv-macros" 1031 | version = "0.1.0" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "f265be5d634272320a7de94cea15c22a3bfdd4eb42eb43edc528415f066a1f25" 1034 | dependencies = [ 1035 | "proc-macro2", 1036 | "quote", 1037 | "syn", 1038 | ] 1039 | 1040 | [[package]] 1041 | name = "riscv-pac" 1042 | version = "0.2.0" 1043 | source = "registry+https://github.com/rust-lang/crates.io-index" 1044 | checksum = "8188909339ccc0c68cfb5a04648313f09621e8b87dc03095454f1a11f6c5d436" 1045 | 1046 | [[package]] 1047 | name = "riscv-rt-macros" 1048 | version = "0.2.2" 1049 | source = "registry+https://github.com/rust-lang/crates.io-index" 1050 | checksum = "30f19a85fe107b65031e0ba8ec60c34c2494069fe910d6c297f5e7cb5a6f76d0" 1051 | dependencies = [ 1052 | "proc-macro2", 1053 | "quote", 1054 | "syn", 1055 | ] 1056 | 1057 | [[package]] 1058 | name = "rustversion" 1059 | version = "1.0.18" 1060 | source = "registry+https://github.com/rust-lang/crates.io-index" 1061 | checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" 1062 | 1063 | [[package]] 1064 | name = "scopeguard" 1065 | version = "1.2.0" 1066 | source = "registry+https://github.com/rust-lang/crates.io-index" 1067 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1068 | 1069 | [[package]] 1070 | name = "semihosting" 1071 | version = "0.1.16" 1072 | source = "registry+https://github.com/rust-lang/crates.io-index" 1073 | checksum = "a5c5996e5d1dec34b0dff3285e27124e70964504e3fd361bce330dc476cebafd" 1074 | 1075 | [[package]] 1076 | name = "serde" 1077 | version = "1.0.215" 1078 | source = "registry+https://github.com/rust-lang/crates.io-index" 1079 | checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" 1080 | dependencies = [ 1081 | "serde_derive", 1082 | ] 1083 | 1084 | [[package]] 1085 | name = "serde_derive" 1086 | version = "1.0.215" 1087 | source = "registry+https://github.com/rust-lang/crates.io-index" 1088 | checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" 1089 | dependencies = [ 1090 | "proc-macro2", 1091 | "quote", 1092 | "syn", 1093 | ] 1094 | 1095 | [[package]] 1096 | name = "serde_spanned" 1097 | version = "0.6.8" 1098 | source = "registry+https://github.com/rust-lang/crates.io-index" 1099 | checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" 1100 | dependencies = [ 1101 | "serde", 1102 | ] 1103 | 1104 | [[package]] 1105 | name = "sfoc_rs" 1106 | version = "0.3.0" 1107 | dependencies = [ 1108 | "esp32_sfoc", 1109 | "sfoc_rs_core", 1110 | ] 1111 | 1112 | [[package]] 1113 | name = "sfoc_rs_core" 1114 | version = "0.0.1" 1115 | dependencies = [ 1116 | "cordic", 1117 | "discrete_count", 1118 | "embedded-hal 1.0.0", 1119 | "embedded-time", 1120 | "foc", 1121 | "micromath", 1122 | "pid", 1123 | ] 1124 | 1125 | [[package]] 1126 | name = "spin" 1127 | version = "0.9.8" 1128 | source = "registry+https://github.com/rust-lang/crates.io-index" 1129 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1130 | dependencies = [ 1131 | "lock_api", 1132 | ] 1133 | 1134 | [[package]] 1135 | name = "stable_deref_trait" 1136 | version = "1.2.0" 1137 | source = "registry+https://github.com/rust-lang/crates.io-index" 1138 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1139 | 1140 | [[package]] 1141 | name = "strsim" 1142 | version = "0.11.1" 1143 | source = "registry+https://github.com/rust-lang/crates.io-index" 1144 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1145 | 1146 | [[package]] 1147 | name = "strum" 1148 | version = "0.26.3" 1149 | source = "registry+https://github.com/rust-lang/crates.io-index" 1150 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 1151 | dependencies = [ 1152 | "strum_macros", 1153 | ] 1154 | 1155 | [[package]] 1156 | name = "strum_macros" 1157 | version = "0.26.4" 1158 | source = "registry+https://github.com/rust-lang/crates.io-index" 1159 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 1160 | dependencies = [ 1161 | "heck", 1162 | "proc-macro2", 1163 | "quote", 1164 | "rustversion", 1165 | "syn", 1166 | ] 1167 | 1168 | [[package]] 1169 | name = "syn" 1170 | version = "2.0.90" 1171 | source = "registry+https://github.com/rust-lang/crates.io-index" 1172 | checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" 1173 | dependencies = [ 1174 | "proc-macro2", 1175 | "quote", 1176 | "unicode-ident", 1177 | ] 1178 | 1179 | [[package]] 1180 | name = "termcolor" 1181 | version = "1.4.1" 1182 | source = "registry+https://github.com/rust-lang/crates.io-index" 1183 | checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" 1184 | dependencies = [ 1185 | "winapi-util", 1186 | ] 1187 | 1188 | [[package]] 1189 | name = "thiserror" 1190 | version = "2.0.3" 1191 | source = "registry+https://github.com/rust-lang/crates.io-index" 1192 | checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" 1193 | dependencies = [ 1194 | "thiserror-impl", 1195 | ] 1196 | 1197 | [[package]] 1198 | name = "thiserror-impl" 1199 | version = "2.0.3" 1200 | source = "registry+https://github.com/rust-lang/crates.io-index" 1201 | checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" 1202 | dependencies = [ 1203 | "proc-macro2", 1204 | "quote", 1205 | "syn", 1206 | ] 1207 | 1208 | [[package]] 1209 | name = "toml" 1210 | version = "0.8.19" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" 1213 | dependencies = [ 1214 | "serde", 1215 | "serde_spanned", 1216 | "toml_datetime", 1217 | "toml_edit", 1218 | ] 1219 | 1220 | [[package]] 1221 | name = "toml_datetime" 1222 | version = "0.6.8" 1223 | source = "registry+https://github.com/rust-lang/crates.io-index" 1224 | checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" 1225 | dependencies = [ 1226 | "serde", 1227 | ] 1228 | 1229 | [[package]] 1230 | name = "toml_edit" 1231 | version = "0.22.22" 1232 | source = "registry+https://github.com/rust-lang/crates.io-index" 1233 | checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" 1234 | dependencies = [ 1235 | "indexmap", 1236 | "serde", 1237 | "serde_spanned", 1238 | "toml_datetime", 1239 | "winnow", 1240 | ] 1241 | 1242 | [[package]] 1243 | name = "typenum" 1244 | version = "1.17.0" 1245 | source = "registry+https://github.com/rust-lang/crates.io-index" 1246 | checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" 1247 | 1248 | [[package]] 1249 | name = "ufmt-write" 1250 | version = "0.1.0" 1251 | source = "registry+https://github.com/rust-lang/crates.io-index" 1252 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 1253 | 1254 | [[package]] 1255 | name = "unicode-ident" 1256 | version = "1.0.14" 1257 | source = "registry+https://github.com/rust-lang/crates.io-index" 1258 | checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" 1259 | 1260 | [[package]] 1261 | name = "vcell" 1262 | version = "0.1.3" 1263 | source = "registry+https://github.com/rust-lang/crates.io-index" 1264 | checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" 1265 | 1266 | [[package]] 1267 | name = "void" 1268 | version = "1.0.2" 1269 | source = "registry+https://github.com/rust-lang/crates.io-index" 1270 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 1271 | 1272 | [[package]] 1273 | name = "winapi-util" 1274 | version = "0.1.9" 1275 | source = "registry+https://github.com/rust-lang/crates.io-index" 1276 | checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" 1277 | dependencies = [ 1278 | "windows-sys", 1279 | ] 1280 | 1281 | [[package]] 1282 | name = "windows-sys" 1283 | version = "0.59.0" 1284 | source = "registry+https://github.com/rust-lang/crates.io-index" 1285 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 1286 | dependencies = [ 1287 | "windows-targets", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "windows-targets" 1292 | version = "0.52.6" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 1295 | dependencies = [ 1296 | "windows_aarch64_gnullvm", 1297 | "windows_aarch64_msvc", 1298 | "windows_i686_gnu", 1299 | "windows_i686_gnullvm", 1300 | "windows_i686_msvc", 1301 | "windows_x86_64_gnu", 1302 | "windows_x86_64_gnullvm", 1303 | "windows_x86_64_msvc", 1304 | ] 1305 | 1306 | [[package]] 1307 | name = "windows_aarch64_gnullvm" 1308 | version = "0.52.6" 1309 | source = "registry+https://github.com/rust-lang/crates.io-index" 1310 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 1311 | 1312 | [[package]] 1313 | name = "windows_aarch64_msvc" 1314 | version = "0.52.6" 1315 | source = "registry+https://github.com/rust-lang/crates.io-index" 1316 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 1317 | 1318 | [[package]] 1319 | name = "windows_i686_gnu" 1320 | version = "0.52.6" 1321 | source = "registry+https://github.com/rust-lang/crates.io-index" 1322 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 1323 | 1324 | [[package]] 1325 | name = "windows_i686_gnullvm" 1326 | version = "0.52.6" 1327 | source = "registry+https://github.com/rust-lang/crates.io-index" 1328 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 1329 | 1330 | [[package]] 1331 | name = "windows_i686_msvc" 1332 | version = "0.52.6" 1333 | source = "registry+https://github.com/rust-lang/crates.io-index" 1334 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 1335 | 1336 | [[package]] 1337 | name = "windows_x86_64_gnu" 1338 | version = "0.52.6" 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" 1340 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 1341 | 1342 | [[package]] 1343 | name = "windows_x86_64_gnullvm" 1344 | version = "0.52.6" 1345 | source = "registry+https://github.com/rust-lang/crates.io-index" 1346 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 1347 | 1348 | [[package]] 1349 | name = "windows_x86_64_msvc" 1350 | version = "0.52.6" 1351 | source = "registry+https://github.com/rust-lang/crates.io-index" 1352 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 1353 | 1354 | [[package]] 1355 | name = "winnow" 1356 | version = "0.6.20" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" 1359 | dependencies = [ 1360 | "memchr", 1361 | ] 1362 | 1363 | [[package]] 1364 | name = "xtensa-lx" 1365 | version = "0.9.0" 1366 | source = "registry+https://github.com/rust-lang/crates.io-index" 1367 | checksum = "e758f94e1a1f71758f94052a2766dcb12604998eb372b8b2e30576e3ab1ba1e6" 1368 | dependencies = [ 1369 | "bare-metal", 1370 | "mutex-trait", 1371 | "spin", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "xtensa-lx-rt" 1376 | version = "0.17.2" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "5c0307d03dadbf95633942e13901984f2059df4c963367348168cbd21c962669" 1379 | dependencies = [ 1380 | "anyhow", 1381 | "bare-metal", 1382 | "document-features", 1383 | "enum-as-inner", 1384 | "minijinja", 1385 | "r0", 1386 | "serde", 1387 | "strum", 1388 | "toml", 1389 | "xtensa-lx", 1390 | "xtensa-lx-rt-proc-macros", 1391 | ] 1392 | 1393 | [[package]] 1394 | name = "xtensa-lx-rt-proc-macros" 1395 | version = "0.2.2" 1396 | source = "registry+https://github.com/rust-lang/crates.io-index" 1397 | checksum = "11277b1e4cbb7ffe44678c668518b249c843c81df249b8f096701757bc50d7ee" 1398 | dependencies = [ 1399 | "darling", 1400 | "proc-macro2", 1401 | "quote", 1402 | "syn", 1403 | ] 1404 | -------------------------------------------------------------------------------- /spinnies/esp32/original/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "original" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | esp-backtrace = { version = "0.14.2", features = [ 8 | "esp32", 9 | "exception-handler", 10 | "panic-handler", 11 | "defmt", 12 | ]} 13 | 14 | esp-hal = { version = "0.22.0", features = [ 15 | "esp32", 16 | "defmt", 17 | ] } 18 | defmt = "0.3.8" 19 | defmt-rtt = "0.4.1" 20 | critical-section = "1.2.0" 21 | sfoc_rs = { version = "0.3.0", path = "../../..", features = ["esp32"] } 22 | generic_spinny = { version = "0.1.0", path = "../../generic_spinny" } 23 | 24 | [profile.dev] 25 | # Rust debug is too slow. 26 | # For debug builds always builds with some optimization 27 | opt-level = "s" 28 | 29 | [profile.release] 30 | codegen-units = 1 # LLVM can perform better optimizations using a single thread 31 | debug = 2 32 | debug-assertions = false 33 | incremental = false 34 | lto = 'fat' 35 | opt-level = 's' 36 | overflow-checks = false 37 | -------------------------------------------------------------------------------- /spinnies/esp32/original/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-arg-bins=-Tlinkall.x"); 3 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 4 | } 5 | -------------------------------------------------------------------------------- /spinnies/esp32/original/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "esp" 3 | -------------------------------------------------------------------------------- /spinnies/esp32/original/src/bin/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use esp_backtrace as _; 5 | use esp_hal::peripheral::Peripheral; 6 | use esp_hal::peripherals::TIMG0; 7 | use esp_hal::prelude::*; 8 | 9 | use defmt_rtt as _; 10 | // use defmt::info; 11 | 12 | // use fixed::types::I16F16; 13 | use sfoc_rs::esp32_sfoc::device::Esp3PWM; 14 | use sfoc_rs::esp32_sfoc::time_source::TimerHolder; 15 | use sfoc_rs::{ 16 | bldc_driver::MotorPins, 17 | foc_control::{FOController, PhaseAngle}, 18 | rexports::{discrete_count::re_exports::fixed::types::I16F16, foc}, 19 | }; 20 | 21 | use esp_hal::{ 22 | timer::timg::{Timer, Timer0, TimerGroup}, 23 | Blocking, 24 | }; 25 | 26 | #[entry] 27 | fn main() -> ! { 28 | let peripherals = esp_hal::init(esp_hal::Config::default()); 29 | let timg0: TimerGroup<'_, ::P, Blocking> = 30 | TimerGroup::new(peripherals.TIMG0); 31 | let timer0: Timer::P>, Blocking> = timg0.timer0; 32 | let timer0: TimerHolder<::P> = TimerHolder::init(timer0); 33 | 34 | let pin1 = peripherals.GPIO1; 35 | let pin2 = peripherals.GPIO2; 36 | let pin3 = peripherals.GPIO3; 37 | // let pin4 = peripherals.GPIO4; 38 | // let pin5 = peripherals.GPIO5; 39 | 40 | let mut driver: Esp3PWM<'_, _> = Esp3PWM::init( 41 | peripherals.MCPWM0, 42 | peripherals.PCNT, 43 | (pin1, pin2, pin3), 44 | // (pin4, pin5), 45 | ); 46 | 47 | FOController::set_phase_voltage( 48 | &mut driver, 49 | foc::park_clarke::RotatingReferenceFrame { 50 | d: I16F16::ZERO, 51 | q: I16F16::ONE, 52 | }, 53 | PhaseAngle(I16F16::PI), 54 | ); 55 | MotorPins::set_zero(&mut driver); 56 | // driver.get_position_um(); 57 | #[allow(clippy::empty_loop)] 58 | generic_spinny::main_loop(driver, timer0); 59 | } 60 | -------------------------------------------------------------------------------- /spinnies/esp32/original/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.xtensa-esp32s3-none-elf] 2 | runner = "probe-rs run --chip=esp32s3" 3 | 4 | [env] 5 | DEFMT_LOG="info" 6 | 7 | [build] 8 | rustflags = [ 9 | "-C", "link-arg=-nostartfiles", 10 | ] 11 | 12 | target = "xtensa-esp32s3-none-elf" 13 | 14 | [unstable] 15 | build-std = ["core"] 16 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # These are backup files generated by rustfmt 7 | **/*.rs.bk 8 | 9 | # MSVC Windows builds of rustc generate these, which store debugging information 10 | *.pdb 11 | 12 | # RustRover 13 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 14 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 15 | # and can be added to the global gitignore or merged into this file. For a more nuclear 16 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 17 | #.idea/ 18 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "s3" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | esp-backtrace = { version = "0.14.2", features = [ 8 | "esp32s3", 9 | "exception-handler", 10 | "panic-handler", 11 | "defmt", 12 | ]} 13 | 14 | esp-hal = { version = "0.22.0", features = [ 15 | "esp32s3", 16 | "defmt", 17 | ] } 18 | defmt = "0.3.8" 19 | defmt-rtt = "0.4.1" 20 | critical-section = "1.2.0" 21 | 22 | [profile.dev] 23 | # Rust debug is too slow. 24 | # For debug builds always builds with some optimization 25 | opt-level = "s" 26 | 27 | [profile.release] 28 | codegen-units = 1 # LLVM can perform better optimizations using a single thread 29 | debug = 2 30 | debug-assertions = false 31 | incremental = false 32 | lto = 'fat' 33 | opt-level = 's' 34 | overflow-checks = false 35 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/build.rs: -------------------------------------------------------------------------------- 1 | fn main() { 2 | println!("cargo:rustc-link-arg-bins=-Tlinkall.x"); 3 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); 4 | } 5 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "esp" 3 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/src/bin/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use esp_backtrace as _; 5 | use esp_hal::{delay::Delay, prelude::*}; 6 | 7 | use defmt_rtt as _; 8 | use defmt::info; 9 | 10 | 11 | #[entry] 12 | fn main() -> ! { 13 | let _peripherals = esp_hal::init({ 14 | let mut config = esp_hal::Config::default(); 15 | config.cpu_clock = CpuClock::max(); 16 | config 17 | }); 18 | 19 | 20 | 21 | 22 | let delay = Delay::new(); 23 | loop { 24 | info!("Hello world!"); 25 | delay.delay(500.millis()); 26 | } 27 | 28 | // for inspiration have a look at the examples at https://github.com/esp-rs/esp-hal/tree/v0.22.0/examples/src/bin 29 | 30 | } 31 | -------------------------------------------------------------------------------- /spinnies/esp32/s3/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | -------------------------------------------------------------------------------- /spinnies/generic_spinny/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "generic_spinny" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | fugit = { git = "https://github.com/Ben-PH/fugit.git", rev = "aad2d2d97f45b9b12076648b78857f47ff6f1c1b", version = "0.4.0" } 8 | sfoc_rs = { version = "0.3.0", path = "../.." } 9 | -------------------------------------------------------------------------------- /spinnies/generic_spinny/README.md: -------------------------------------------------------------------------------- 1 | This is where platform specific setups go to in order to become generic. 2 | 3 | The idea being, is that you marshal pins, and set things up as far as the hardware is concerned in the other spinnies, and then you just call `generic_spinny::main_loop(...)` 4 | 5 | 6 | This will only rotate a magnetic field at 10rpm at a 10% power setting. 7 | 8 | The roadmap calls for the next to be a PID spinny, which uses position sensing to set a 10rpm rotation. 9 | 10 | Also plan on writing: 11 | 12 | - constant speed spinny 13 | - pot-controlled position hold 14 | - pot-controlled speed hold 15 | -------------------------------------------------------------------------------- /spinnies/generic_spinny/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | use fugit::Duration; 4 | use sfoc_rs::{ 5 | common::helpers::DutyCycle, 6 | foc_control::FOController, 7 | rexports::{ 8 | cordic, 9 | discrete_count::{ 10 | re_exports::{ 11 | fixed::types::I16F16, 12 | typenum::{NonZero, Unsigned}, 13 | }, 14 | CountReader, Counter, 15 | }, 16 | foc::{self, park_clarke, pwm::Modulation}, 17 | }, 18 | }; 19 | pub fn main_loop(mut motor_pins: FOC, timer: TIM) -> ! 20 | where 21 | PdNumer: Unsigned, 22 | PdDenom: NonZero + Unsigned, 23 | FOC: FOController, 24 | R: CountReader, 25 | TIM: Counter>, 26 | { 27 | loop { 28 | let elapsed: Duration = timer 29 | .try_read_measure() 30 | .unwrap_or_else(|_| panic!("should be never-fail for all implemented so far")); 31 | let millis = Duration::::to_millis(&elapsed) % 6000; 32 | 33 | let ms_fixed = I16F16::from_num(millis as u64); 34 | let ratio = ms_fixed / I16F16::from_num(6000); 35 | let angle = ratio * I16F16::TAU; 36 | let (sin, cos) = cordic::sin_cos(angle); 37 | 38 | // we are setting 10% in the quadrature (torque) and 0% direct-axis 39 | let qd = park_clarke::RotatingReferenceFrame { 40 | d: I16F16::ZERO, 41 | q: I16F16::from_num(0.1), 42 | }; 43 | 44 | // Orient our q/d values to the phase-angle we desire 45 | let inv_parke = foc::park_clarke::inverse_park(cos, sin, qd); 46 | // and use the ideal, though computationally heavy, scale-vector calculation for desired 47 | // pwm duty-cycles, i.e. the percentage-of-maximum that each motor-phase will be set to 48 | let [dc_a, dc_b, dc_c] = foc::pwm::SpaceVector::modulate(inv_parke); 49 | 50 | //... and set them. 51 | motor_pins.set_pwms(DutyCycle(dc_a), DutyCycle(dc_b), DutyCycle(dc_c)); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #[cfg(feature = "esp32")] 3 | pub use esp32_sfoc; 4 | #[cfg(feature = "esp32s3")] 5 | pub use esp32s3_sfoc; 6 | pub use sfoc_rs_core::*; 7 | #[cfg(feature = "AS5047P")] 8 | #[allow(non_snake_case)] 9 | pub use AS5047P; 10 | -------------------------------------------------------------------------------- /thoughts.md: -------------------------------------------------------------------------------- 1 | ```rust 2 | // Top level interface 3 | pub trait FOController: Sized { 4 | fn init_fo_control() -> Result; 5 | fn enable(&mut self); 6 | fn disable(&mut self); 7 | // fn link_sensor/current_sensor(.... 8 | fn init_foc_algo(&mut self) -> u32; // why the u32? 9 | fn foc_loop(&mut self) -> !; 10 | fn move_command(motion: MotionCtrl); 11 | fn set_phase_voltage(u_q: f32, u_d: f32, phase_angle: PhaseAngle); 12 | } 13 | ``` 14 | 15 | ...stuff here 16 | 17 | ```rust 18 | // bottom level, to-the-hardware interface 19 | pub trait BLDCDriver: Sized { 20 | fn init_bldc_driver() -> Result; 21 | fn enable(&mut self); 22 | fn disable(&mut self); 23 | fn set_pwms(&mut self, dc_a: DutyCycle, dc_b: DutyCycle, dc_c: DutyCycle); 24 | fn set_phase_state(&mut self, ps_a: PhaseState, ps_b: PhaseState, ps_c: PhaseState); 25 | } 26 | ``` 27 | 28 | ...the encoder needs to have its a and b channels defined, as well as interupts if applicable. 29 | 30 | the foc controller interface needs position, driver, and the option for monotoring over serial interface. 31 | 32 | if doing velocity control, at the global scope: 33 | 34 | - BLDCController is constructed with pole-pairs 11 35 | - 3pwm driver is constructed with the **3 pin numbers,** then an enable pin chosen 36 | - An encoder is constructed, with **pins**, ppr and index 0xA0 (pin 36, i think?) 37 | - interupt handlers for the a, b and index pulse are defined and setup 38 | - A commander is constructed with a serial 39 | - **target velocity** global is defined. it's used by `doTarget` and `motor.move` in the main-loop. the controler needs access to this 40 | - doTarget is defined. taking a command, and running it with reference to &target_velocity 41 | 42 | 43 | the setup() function: 44 | 45 | - **initialises the encoder** 46 | - enables interupts on the encoder 47 | - registers the software interupts as a fallback if harware ints aren't there 48 | - **links said encoder** into the FOCControllerBLDC global instance 49 | - sets a **driver voltage** power supply 50 | - initialises the driver 51 | - **links said BLDCdriver** to the global FOCControllerBLDC instance 52 | - **sets control type** to velocity 53 | - sets pid values of velocity 54 | - sets voltage limit to the FOCControllerBLDC 55 | - sets lp-filter time-constant for the FOCControllerBLDC velocity 56 | - begins the monitoring 57 | - initialises the FOCControllerBLDC 58 | - initialises the foc of the FOCControllerBLDC 59 | - adds a "target velocity" command 60 | - "motor ready" 61 | - "set the target velocity using serial" 62 | 63 | 64 | `loop()` function: 65 | 66 | - FOCControllerBLDC::loopFOC() 67 | - FOCControllerBLDC::move(target_velocity_global) 68 | - command.run() // user-communication 69 | 70 | 71 | so it comes down to having something that is an implementation of foc control, either stepper or bldc. 72 | 73 | ...but the foccontroller needs a driver with a motor behind it and a position encoder with an encoder behind it. 74 | 75 | ...the shopping list of resources includes the pins 76 | 77 | 78 | so brass-tax on setup: 79 | 80 | - pins (encoder, motor) 81 | - initial target velocity 82 | - power supply voltage (driver assisciated) 83 | - voltage limit (controller assosciated) 84 | - initial pid values 85 | - lp filter time constant 86 | 87 | ...but this doesn't account for the need for a time-source. arduino just uses some obfuscated global, but that just won't do... 88 | 89 | 90 | ### That was for non-hardware-specific examples. 91 | 92 | ...but I have a hunch that the rust way of doing this is slightly different to the cpp/arduino way. not better or worse. just different. 93 | 94 | Being _super_ minimilist at the platform specific level, it seems that "for any given platform, just pull out 3 pins that can impl `SetDutyCycle`, 2 pins that are input pins, and setup a `Clock` implementor to create a time-source. 95 | 96 | E.g. the library would just be a set of interfaces, with default implementations that defer to the methods of assosciated types. e.g. the FOCController would defer to the clock impl for time-getting. when it needs to set the duty cycles, it defers to the assosciated type that is constrained to implement the motor driver trait. 97 | 98 | so this to track the workflow: 99 | 100 | - encoder init. this is in two parts. the encoder itself, and the MCU implementation of configuring. esp32, for example, can just use the pcnt periph, and optionally, interupts for position-limits, index ticks, etc., then a raw register read when incremental position is needed. 101 | - encoder init in upstream caches a timestamp. It seems that speed tracking is handled in here? 102 | - 3 and 6PWM init are the same* "set the pins to output, normalise voltage, return the cpp-equivilent to `Result` 103 | 104 | easy, right? 105 | --------------------------------------------------------------------------------