├── .cargo └── config ├── .gitignore ├── .vscode └── settings.json ├── Cargo.lock ├── Cargo.toml ├── Embed.toml ├── LICENSE ├── README.EN.md ├── README.md ├── examples ├── blink.rs ├── button-exti.rs ├── button.rs ├── hello.rs ├── iwdg.rs ├── pwm.rs ├── rng.rs ├── rtic-blink.rs ├── rust.raw ├── serial-console │ ├── command.rs │ ├── console.rs │ └── main.rs ├── spi-ssd1306.rs ├── timer.rs └── usart-irq.rs ├── imgs ├── crates.png └── usart-irq.png ├── memory.x ├── openocd.cfg ├── openocd.gdb └── src ├── buffer.rs ├── clock.rs └── lib.rs /.cargo/config: -------------------------------------------------------------------------------- 1 | [target.thumbv7em-none-eabihf] 2 | rustflags = [ 3 | "-C", "link-arg=-Tlink.x" 4 | ] 5 | 6 | [build] 7 | target = "thumbv7em-none-eabihf" 8 | 9 | [tasks.flash] 10 | command = "openocd" 11 | args = [ 12 | "-f", "openocd.cfg", 13 | 14 | ] -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | /.idea -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "rust-analyzer.checkOnSave.allTargets": false, 3 | "rust-analyzer.checkOnSave.extraArgs": [ 4 | "--target", 5 | "thumbv7em-none-eabihf" 6 | ], 7 | "rust.target": "thumbv7em-none-eabihf", 8 | "rust.all_targets": false 9 | } -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | [[package]] 4 | name = "aligned" 5 | version = "0.3.4" 6 | source = "registry+https://github.com/rust-lang/crates.io-index" 7 | checksum = "c19796bd8d477f1a9d4ac2465b464a8b1359474f06a96bb3cda650b4fca309bf" 8 | dependencies = [ 9 | "as-slice", 10 | ] 11 | 12 | [[package]] 13 | name = "as-slice" 14 | version = "0.1.4" 15 | source = "registry+https://github.com/rust-lang/crates.io-index" 16 | checksum = "bb4d1c23475b74e3672afa8c2be22040b8b7783ad9b461021144ed10a46bb0e6" 17 | dependencies = [ 18 | "generic-array 0.12.3", 19 | "generic-array 0.13.2", 20 | "generic-array 0.14.4", 21 | "stable_deref_trait", 22 | ] 23 | 24 | [[package]] 25 | name = "autocfg" 26 | version = "1.0.1" 27 | source = "registry+https://github.com/rust-lang/crates.io-index" 28 | checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" 29 | 30 | [[package]] 31 | name = "bare-metal" 32 | version = "0.2.5" 33 | source = "registry+https://github.com/rust-lang/crates.io-index" 34 | checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" 35 | dependencies = [ 36 | "rustc_version", 37 | ] 38 | 39 | [[package]] 40 | name = "bitfield" 41 | version = "0.13.2" 42 | source = "registry+https://github.com/rust-lang/crates.io-index" 43 | checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" 44 | 45 | [[package]] 46 | name = "byte-slice-cast" 47 | version = "0.3.5" 48 | source = "registry+https://github.com/rust-lang/crates.io-index" 49 | checksum = "b0a5e3906bcbf133e33c1d4d95afc664ad37fbdb9f6568d8043e7ea8c27d93d3" 50 | 51 | [[package]] 52 | name = "byteorder" 53 | version = "1.3.4" 54 | source = "registry+https://github.com/rust-lang/crates.io-index" 55 | checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" 56 | 57 | [[package]] 58 | name = "cast" 59 | version = "0.2.3" 60 | source = "registry+https://github.com/rust-lang/crates.io-index" 61 | checksum = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" 62 | dependencies = [ 63 | "rustc_version", 64 | ] 65 | 66 | [[package]] 67 | name = "cortex-m" 68 | version = "0.6.4" 69 | source = "registry+https://github.com/rust-lang/crates.io-index" 70 | checksum = "88cdafeafba636c00c467ded7f1587210725a1adfab0c24028a7844b87738263" 71 | dependencies = [ 72 | "aligned", 73 | "bare-metal", 74 | "bitfield", 75 | "volatile-register", 76 | ] 77 | 78 | [[package]] 79 | name = "cortex-m-rt" 80 | version = "0.6.13" 81 | source = "registry+https://github.com/rust-lang/crates.io-index" 82 | checksum = "980c9d0233a909f355ed297ef122f257942de5e0a2cb1c39f60684b65bcb90fb" 83 | dependencies = [ 84 | "cortex-m-rt-macros", 85 | "r0", 86 | ] 87 | 88 | [[package]] 89 | name = "cortex-m-rt-macros" 90 | version = "0.1.8" 91 | source = "registry+https://github.com/rust-lang/crates.io-index" 92 | checksum = "4717562afbba06e760d34451919f5c3bf3ac15c7bb897e8b04862a7428378647" 93 | dependencies = [ 94 | "proc-macro2", 95 | "quote", 96 | "syn", 97 | ] 98 | 99 | [[package]] 100 | name = "cortex-m-rtic" 101 | version = "0.5.5" 102 | source = "registry+https://github.com/rust-lang/crates.io-index" 103 | checksum = "b30efcb6b7920d9016182c485687f0012487032a14c415d2fce6e9862ef8260e" 104 | dependencies = [ 105 | "cortex-m", 106 | "cortex-m-rt", 107 | "cortex-m-rtic-macros", 108 | "heapless", 109 | "rtic-core", 110 | "version_check", 111 | ] 112 | 113 | [[package]] 114 | name = "cortex-m-rtic-macros" 115 | version = "0.5.2" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "9a1a6a4c9550373038c0e21a78d44d529bd697c25bbf6b8004bddc6e63b119c7" 118 | dependencies = [ 119 | "proc-macro2", 120 | "quote", 121 | "rtic-syntax", 122 | "syn", 123 | ] 124 | 125 | [[package]] 126 | name = "cortex-m-semihosting" 127 | version = "0.3.7" 128 | source = "registry+https://github.com/rust-lang/crates.io-index" 129 | checksum = "6bffa6c1454368a6aa4811ae60964c38e6996d397ff8095a8b9211b1c1f749bc" 130 | dependencies = [ 131 | "cortex-m", 132 | ] 133 | 134 | [[package]] 135 | name = "display-interface" 136 | version = "0.4.0" 137 | source = "registry+https://github.com/rust-lang/crates.io-index" 138 | checksum = "da12a892db5cce95ae247e8803dc653b1a73da3b0450f7983eb518dd54f583cf" 139 | 140 | [[package]] 141 | name = "display-interface-i2c" 142 | version = "0.4.0" 143 | source = "registry+https://github.com/rust-lang/crates.io-index" 144 | checksum = "4895cd4e54e5536ef370d7f1eec787aad8275dd8ad15815aebfa71dd847b4ebf" 145 | dependencies = [ 146 | "display-interface", 147 | "embedded-hal", 148 | ] 149 | 150 | [[package]] 151 | name = "display-interface-spi" 152 | version = "0.4.0" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "94d08c3a1682b166cbcbb4fe009a31a1834ba46c16599bf7a9b3cc7bc31b38b0" 155 | dependencies = [ 156 | "byte-slice-cast", 157 | "display-interface", 158 | "embedded-hal", 159 | ] 160 | 161 | [[package]] 162 | name = "embedded-graphics" 163 | version = "0.6.2" 164 | source = "registry+https://github.com/rust-lang/crates.io-index" 165 | checksum = "40a69991ceb896bd4810a0cf2bcc46fc94b7860573c71f965d8e5b3d66942fed" 166 | dependencies = [ 167 | "byteorder", 168 | ] 169 | 170 | [[package]] 171 | name = "embedded-hal" 172 | version = "0.2.4" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "fa998ce59ec9765d15216393af37a58961ddcefb14c753b4816ba2191d865fcb" 175 | dependencies = [ 176 | "nb 0.1.3", 177 | "void", 178 | ] 179 | 180 | [[package]] 181 | name = "generic-array" 182 | version = "0.12.3" 183 | source = "registry+https://github.com/rust-lang/crates.io-index" 184 | checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" 185 | dependencies = [ 186 | "typenum", 187 | ] 188 | 189 | [[package]] 190 | name = "generic-array" 191 | version = "0.13.2" 192 | source = "registry+https://github.com/rust-lang/crates.io-index" 193 | checksum = "0ed1e761351b56f54eb9dcd0cfaca9fd0daecf93918e1cfc01c8a3d26ee7adcd" 194 | dependencies = [ 195 | "typenum", 196 | ] 197 | 198 | [[package]] 199 | name = "generic-array" 200 | version = "0.14.4" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" 203 | dependencies = [ 204 | "typenum", 205 | "version_check", 206 | ] 207 | 208 | [[package]] 209 | name = "hash32" 210 | version = "0.1.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "d4041af86e63ac4298ce40e5cca669066e75b6f1aa3390fe2561ffa5e1d9f4cc" 213 | dependencies = [ 214 | "byteorder", 215 | ] 216 | 217 | [[package]] 218 | name = "hashbrown" 219 | version = "0.9.1" 220 | source = "registry+https://github.com/rust-lang/crates.io-index" 221 | checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" 222 | 223 | [[package]] 224 | name = "heapless" 225 | version = "0.5.6" 226 | source = "registry+https://github.com/rust-lang/crates.io-index" 227 | checksum = "74911a68a1658cfcfb61bc0ccfbd536e3b6e906f8c2f7883ee50157e3e2184f1" 228 | dependencies = [ 229 | "as-slice", 230 | "generic-array 0.13.2", 231 | "hash32", 232 | "stable_deref_trait", 233 | ] 234 | 235 | [[package]] 236 | name = "indexmap" 237 | version = "1.6.0" 238 | source = "registry+https://github.com/rust-lang/crates.io-index" 239 | checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" 240 | dependencies = [ 241 | "autocfg", 242 | "hashbrown", 243 | ] 244 | 245 | [[package]] 246 | name = "nb" 247 | version = "0.1.3" 248 | source = "registry+https://github.com/rust-lang/crates.io-index" 249 | checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" 250 | dependencies = [ 251 | "nb 1.0.0", 252 | ] 253 | 254 | [[package]] 255 | name = "nb" 256 | version = "1.0.0" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "546c37ac5d9e56f55e73b677106873d9d9f5190605e41a856503623648488cae" 259 | 260 | [[package]] 261 | name = "panic-halt" 262 | version = "0.2.0" 263 | source = "registry+https://github.com/rust-lang/crates.io-index" 264 | checksum = "de96540e0ebde571dc55c73d60ef407c653844e6f9a1e2fdbd40c07b9252d812" 265 | 266 | [[package]] 267 | name = "panic-rtt-target" 268 | version = "0.1.1" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "cfcd4deccf5edead7dcd0531448f0bab1b935e6d88e47225b4b7c6bd3a443180" 271 | dependencies = [ 272 | "cortex-m", 273 | "rtt-target 0.2.2", 274 | ] 275 | 276 | [[package]] 277 | name = "panic-semihosting" 278 | version = "0.5.6" 279 | source = "registry+https://github.com/rust-lang/crates.io-index" 280 | checksum = "c3d55dedd501dfd02514646e0af4d7016ce36bc12ae177ef52056989966a1eec" 281 | dependencies = [ 282 | "cortex-m", 283 | "cortex-m-semihosting", 284 | ] 285 | 286 | [[package]] 287 | name = "proc-macro2" 288 | version = "1.0.24" 289 | source = "registry+https://github.com/rust-lang/crates.io-index" 290 | checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" 291 | dependencies = [ 292 | "unicode-xid", 293 | ] 294 | 295 | [[package]] 296 | name = "quote" 297 | version = "1.0.7" 298 | source = "registry+https://github.com/rust-lang/crates.io-index" 299 | checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" 300 | dependencies = [ 301 | "proc-macro2", 302 | ] 303 | 304 | [[package]] 305 | name = "r0" 306 | version = "0.2.2" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "e2a38df5b15c8d5c7e8654189744d8e396bddc18ad48041a500ce52d6948941f" 309 | 310 | [[package]] 311 | name = "rand_core" 312 | version = "0.5.1" 313 | source = "registry+https://github.com/rust-lang/crates.io-index" 314 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 315 | 316 | [[package]] 317 | name = "rtic-core" 318 | version = "0.3.1" 319 | source = "registry+https://github.com/rust-lang/crates.io-index" 320 | checksum = "8bd58a6949de8ff797a346a28d9f13f7b8f54fa61bb5e3cb0985a4efb497a5ef" 321 | 322 | [[package]] 323 | name = "rtic-syntax" 324 | version = "0.4.0" 325 | source = "registry+https://github.com/rust-lang/crates.io-index" 326 | checksum = "8152fcaa845720d61e6cc570548b89144c2c307f18a480bbd97e55e9f6eeff04" 327 | dependencies = [ 328 | "indexmap", 329 | "proc-macro2", 330 | "syn", 331 | ] 332 | 333 | [[package]] 334 | name = "rtt-target" 335 | version = "0.2.2" 336 | source = "registry+https://github.com/rust-lang/crates.io-index" 337 | checksum = "0869b4c5b6a6d8c5583fc473f9eb3423a170f77626b8c8a7fb18eddcda5770e2" 338 | dependencies = [ 339 | "ufmt-write", 340 | ] 341 | 342 | [[package]] 343 | name = "rtt-target" 344 | version = "0.3.0" 345 | source = "registry+https://github.com/rust-lang/crates.io-index" 346 | checksum = "01a267556daa12832ffc20129af69a6db0a28af91bcf12b4468af21f48818f66" 347 | dependencies = [ 348 | "cortex-m", 349 | "ufmt-write", 350 | ] 351 | 352 | [[package]] 353 | name = "rustc_version" 354 | version = "0.2.3" 355 | source = "registry+https://github.com/rust-lang/crates.io-index" 356 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 357 | dependencies = [ 358 | "semver", 359 | ] 360 | 361 | [[package]] 362 | name = "semver" 363 | version = "0.9.0" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 366 | dependencies = [ 367 | "semver-parser", 368 | ] 369 | 370 | [[package]] 371 | name = "semver-parser" 372 | version = "0.7.0" 373 | source = "registry+https://github.com/rust-lang/crates.io-index" 374 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 375 | 376 | [[package]] 377 | name = "ssd1306" 378 | version = "0.5.0" 379 | source = "registry+https://github.com/rust-lang/crates.io-index" 380 | checksum = "28345cacf757b10972042dc60f4a06b0bdb13cd80b9a296669aaf07f20e5aa30" 381 | dependencies = [ 382 | "display-interface", 383 | "display-interface-i2c", 384 | "display-interface-spi", 385 | "embedded-graphics", 386 | "embedded-hal", 387 | "generic-array 0.14.4", 388 | ] 389 | 390 | [[package]] 391 | name = "stable_deref_trait" 392 | version = "1.2.0" 393 | source = "registry+https://github.com/rust-lang/crates.io-index" 394 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 395 | 396 | [[package]] 397 | name = "stm32-rustup" 398 | version = "0.1.0" 399 | dependencies = [ 400 | "cortex-m", 401 | "cortex-m-rt", 402 | "cortex-m-rtic", 403 | "cortex-m-semihosting", 404 | "embedded-graphics", 405 | "embedded-hal", 406 | "nb 1.0.0", 407 | "panic-halt", 408 | "panic-rtt-target", 409 | "panic-semihosting", 410 | "rand_core", 411 | "rtt-target 0.3.0", 412 | "ssd1306", 413 | "stm32f4xx-hal", 414 | "switch-hal", 415 | ] 416 | 417 | [[package]] 418 | name = "stm32f4" 419 | version = "0.11.0" 420 | source = "registry+https://github.com/rust-lang/crates.io-index" 421 | checksum = "11460b4de3a84f072e2cf6e76306c64d27f405a0e83bace0a726f555ddf4bf33" 422 | dependencies = [ 423 | "bare-metal", 424 | "cortex-m", 425 | "cortex-m-rt", 426 | "vcell", 427 | ] 428 | 429 | [[package]] 430 | name = "stm32f4xx-hal" 431 | version = "0.8.3" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "b3a2f044469d1e3aff2cd02bee8b2724f3d5d91f3175e5d1ec99770320d16192" 434 | dependencies = [ 435 | "bare-metal", 436 | "cast", 437 | "cortex-m", 438 | "cortex-m-rt", 439 | "embedded-hal", 440 | "nb 0.1.3", 441 | "rand_core", 442 | "stm32f4", 443 | "void", 444 | ] 445 | 446 | [[package]] 447 | name = "switch-hal" 448 | version = "0.3.2" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "92c10340167223b7e1b97a44339798d7ed28e8b6cba029fdbc0aaa395642acb7" 451 | dependencies = [ 452 | "embedded-hal", 453 | ] 454 | 455 | [[package]] 456 | name = "syn" 457 | version = "1.0.54" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" 460 | dependencies = [ 461 | "proc-macro2", 462 | "quote", 463 | "unicode-xid", 464 | ] 465 | 466 | [[package]] 467 | name = "typenum" 468 | version = "1.12.0" 469 | source = "registry+https://github.com/rust-lang/crates.io-index" 470 | checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 471 | 472 | [[package]] 473 | name = "ufmt-write" 474 | version = "0.1.0" 475 | source = "registry+https://github.com/rust-lang/crates.io-index" 476 | checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69" 477 | 478 | [[package]] 479 | name = "unicode-xid" 480 | version = "0.2.1" 481 | source = "registry+https://github.com/rust-lang/crates.io-index" 482 | checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" 483 | 484 | [[package]] 485 | name = "vcell" 486 | version = "0.1.2" 487 | source = "registry+https://github.com/rust-lang/crates.io-index" 488 | checksum = "876e32dcadfe563a4289e994f7cb391197f362b6315dc45e8ba4aa6f564a4b3c" 489 | 490 | [[package]] 491 | name = "version_check" 492 | version = "0.9.2" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" 495 | 496 | [[package]] 497 | name = "void" 498 | version = "1.0.2" 499 | source = "registry+https://github.com/rust-lang/crates.io-index" 500 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 501 | 502 | [[package]] 503 | name = "volatile-register" 504 | version = "0.2.0" 505 | source = "registry+https://github.com/rust-lang/crates.io-index" 506 | checksum = "0d67cb4616d99b940db1d6bd28844ff97108b498a6ca850e5b6191a532063286" 507 | dependencies = [ 508 | "vcell", 509 | ] 510 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "stm32-rustup" 3 | version = "0.1.0" 4 | authors = ["Logiase "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | 11 | embedded-hal = "0.2" # A Hardware Abstraction Layer (HAL) for embedded systems 12 | nb = "1" # Minimal non-blocking I/O layer 13 | cortex-m = "0.6.4" # Low level access to Cortex-M processors 14 | cortex-m-rt = "0.6.13" # Minimal runtime / startup for Cortex-M microcontrollers 15 | panic-halt = "0.2" 16 | switch-hal = "0.3.2" 17 | cortex-m-rtic = "0.5.5" 18 | rand_core = "0.5.1" 19 | cortex-m-semihosting = "0.3.7" 20 | panic-semihosting = "0.5.6" 21 | ssd1306 = "0.5" 22 | embedded-graphics = "0.6.2" 23 | 24 | # Peripheral access API for STM32F4 series microcontrollers 25 | [dependencies.stm32f4xx-hal] 26 | version = "0.8" 27 | features = ["rt", "stm32f429"] 28 | 29 | # Target side implementation of the RTT (Real-Time Transfer) I/O protocol 30 | [dependencies.rtt-target] 31 | version = "0.3.0" 32 | features = ["cortex-m"] 33 | 34 | [dependencies.panic-rtt-target] 35 | version = "0.1.1" 36 | features = ["cortex-m"] -------------------------------------------------------------------------------- /Embed.toml: -------------------------------------------------------------------------------- 1 | [default.general] 2 | chip = "STM32F429IGTX" 3 | 4 | [default.rtt] 5 | enabled = true -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Logiase 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.EN.md: -------------------------------------------------------------------------------- 1 | # stm32-rustup 2 | 3 | A guide about rustup your stm32 mcu. 4 | 5 | WIP 6 | 7 | ## Why use Rust 8 | 9 | Rust as a new-generation programming language has a lot of 10 | modern features than C and C++. 11 | Means that using Rust has a better experience. 12 | 13 | And Rust has a great variety crates in `no_std`. 14 | 15 | As Rust has a lot of modern features, it's possible to transplant your code 16 | to other type of chips, even other target such as RISC-V and AVR. 17 | 18 | See [Transplant](#Transplant) 19 | 20 | ![crates](/imgs/crates.png) 21 | 22 | > well done ! 23 | 24 | ## Try out 25 | 26 | ### IDE 27 | 28 | I'm using VSCode, and install these extensions: 29 | 30 | - crates 31 | - rust-analyzer 32 | 33 | > NOTE: bug fixed. Use latest version, at least `0.2.441`. 34 | > there is a bug in the newest version of `rust-analyzer`, 35 | > which can NOT parse macro properly, before the bug fixed, 36 | > please use version `0.2.400` instead. 37 | > 38 | > newest version now: `0.2.408` 39 | 40 | ## device 41 | 42 | my device is a STM32F429IGT6 chip and other peripherals 43 | which I'll introduce in Section [resource](#resource) 44 | 45 | As using Rust, you do not have to use a same board even a same target (ARM), 46 | you can try the examples use your own device. 47 | 48 | Oh, and a ST-Link debugger and TTL-Serial transformer and two usb cable 49 | 50 | ## Resource 51 | 52 | The resource used in examples 53 | 54 | High-Speed-External : 25MHz 55 | 56 | - PB0 - A green LED 57 | - PB1 - A red LED 58 | - PA0 - WK_UP 59 | - PC13 - key 60 | - PH2 - key 61 | - PH3 - key 62 | 63 | ## Transplant 64 | 65 | If you want to try out the examples in your device 66 | 67 | 1. according to your device's manufacture, edit the memory layout `memory.x` 68 | 2. fix the dependencies in `cargo.toml` 69 | 3. redeclare pins in examples 70 | 71 | And if you want try in another architecture chip 72 | 73 | 1. edit anything about target in `.cargo/config` 74 | 2. edit `cargo.toml` to add crates about HAL, PAC 75 | 3. Optionally, edit `.vscode/settings.json` to make vscode check your code correctly 76 | 77 | ## Read More 78 | 79 | - [Lib.rs](https://lib.rs) you can find a lot `no_std' crates here 80 | - [crates.io](https://crates.io) 81 | - [awesome-embedded-rust](https://github.com/rust-embedded/awesome-embedded-rust) 82 | you can find a lot crates about embedded, such as hardware driver, HAL, PAC. 83 | 84 | ## Q&A 85 | 86 | I'm also a noob. 87 | 88 | So just open an issue, and I'll try my best to answer. 89 | 90 | Give me a star to let me know this repo helps you and encourage me to do more. 91 | 92 | ## Author 93 | 94 | @Logiase 95 | 96 | ## LICENSE 97 | 98 | [MIT LICENSE](./LICENSE) 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # stm32-rustup 2 | 3 | English: [README.EN.md](README.EN.md) 4 | 5 | Rust嵌入式开发指北。 6 | 7 | ## Why 8 | 9 | 我C、C++写的好好的,为什么要换Rust? 10 | 11 | 首先Rust作为一门新兴的语言,相比C有着更良好的使用体验,其次使用Rust可以享受到Rust丰富的`no_std`环境。 12 | 13 | Rust具有的高级现代语言的特性使得其在不同型号芯片,甚至不同架构芯片上,仅仅通过简单的修改即可移植,See [移植](#移植)。 14 | 15 | 同时相比于`arm-gcc-none-eabi`,即标准的ARM嵌入式编译器,Rust有着更高的性能。 16 | 17 | ![crates](/imgs/crates.png) 18 | 19 | > 什么叫舒服啊.jpg 20 | 21 | ## 尝试 22 | 23 | 目前有如下例子: 24 | 25 | - hello 通过rtt输出 "Hello Embedded World" 26 | - blink 闪烁LED 27 | - button 读取GPIO控制LED 28 | - usart-irq 通过串口中断读取USART, 实现复读机 29 | - button-exti GPIO外部中断控制LED 30 | - iwdg 独立看门狗 31 | - timer 定时器控制LED 32 | - pwm PWM控制LED 33 | - rng 随机数发生器 34 | 35 | ### IDE 36 | 37 | VSCode是一个很好的选择,你需要安装如下扩展: 38 | 39 | - crates 40 | - rust-analyzer 41 | 42 | > 请注意:此bug已经修复, 请使用最新版本 `0.2.441`. 43 | > 在最新版本的`rust-analyzer`中存在着无法解析宏的Bug, 在修复之前请使用 0.2.400 版本 44 | > 当前最新版本:0.2.416 45 | 46 | ### 编译 47 | 48 | 使用如下命令进行编译 `blink` 49 | 50 | ```shell 51 | cargo build --example blink 52 | ``` 53 | 54 | 编译后的ELF产物在`target/thumbv7em-none-eabihf/debug/`目录下,执行`binutils`即可查看相关信息。 55 | 56 | 第一次编译的过程会很长,如果你修改了内存布局`memory.x`,再次执行`cargo build`并不会重新应用你的内存布局, 57 | 你需要清除掉之前的缓存重新进行编译才可以应用新的内存布局 58 | 59 | ```shell 60 | cargo clean 61 | cargo build --example some_bin 62 | ``` 63 | 64 | ## 设备 65 | 66 | stm32F429IGT6,若干导线,ST-Link调试器,TTL转串口。 67 | 68 | ### 资源 69 | 70 | 例子中用到的外设资源: 71 | 72 | 高速外部时钟源 25MHz 73 | 74 | - PB0 - 绿色LED 75 | - PB1 - 红色LED 76 | - PA0 - WK_UP 77 | - PC13 - 按键 78 | - PH2 - 按键 79 | - PH3 - 按键 80 | 81 | 在我的博客上有更多有关嵌入式Rust的相关内容,也在持续更新中。 82 | 83 | -> [Blog](https://blog.logiase.site) <- 84 | 85 | ## 移植 86 | 87 | 如果想要在你的设备上进行实验,请注意一些内容: 88 | 89 | 1. 首先根据自己的设备修改内存布局`memory.x` 90 | 2. 从`cargo.toml`中替换HAL,如果你的设备不是ARM内核,请同时修改`cortex-m`至你的目标架构 91 | 3. 根据你的设备重新定义源码中的引脚 92 | 93 | 如果你要在不同目标平台上进行修改尝试,请执行以下操作: 94 | 95 | 1. 修改`.cargo/config`文件,将其中有关target的内容修改为你的目标架构 96 | 2. 修改`cargo.toml`,引入你设备的布局,HAL等 97 | 3. 可选,修改`.vscode/settings.json`中的内容来让VSCode正确检查你的代码 98 | 99 | ## 更多资源 100 | 101 | - [Lib.rs](https://lib.rs) 102 | 在这你可以找到更多`no_std`库 103 | - [crates.io](https://crates.io) 104 | 同上 105 | - [awesome-embedded-rust](https://github.com/rust-embedded/awesome-embedded-rust) 106 | 在这你可以找到更多有关Rust嵌入式开发的资料,如硬件API,HAL,PAC 107 | 108 | ## Q&A 109 | 110 | Open an Issues And I‘ll try my best to answer. 111 | 112 | ## Author 113 | 114 | @Logiase 115 | 116 | ## LICENSE 117 | 118 | [MIT LICENSE](./LICENSE) 119 | -------------------------------------------------------------------------------- /examples/blink.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | // alias 7 | use stm32f4xx_hal as hal; 8 | 9 | // attribute 10 | use cortex_m_rt::entry; 11 | 12 | // prelude 13 | use hal::prelude::*; 14 | use stm32_rustup::*; 15 | 16 | // import 17 | use hal::{delay, stm32}; 18 | use rtt_target::{rprintln, rtt_init_print}; 19 | 20 | // program entry point 21 | #[entry] 22 | fn main() -> ! { 23 | rtt_init_print!(); 24 | 25 | // 获取外设 26 | // get Peripherals 27 | let dp = stm32::Peripherals::take().unwrap(); 28 | let cp = stm32::CorePeripherals::take().unwrap(); 29 | 30 | // 设置时钟 31 | // set up clocks 32 | let clocks = setup_clocks(dp.RCC.constrain()); 33 | 34 | // 初始化延时 (时钟实现) 35 | // get a delay 36 | let mut delays = delay::Delay::new(cp.SYST, clocks); 37 | 38 | // GPIOB 39 | let gb = dp.GPIOB.split(); 40 | 41 | // led 推挽输出 42 | let mut led_green = gb.pb0.into_push_pull_output(); 43 | let mut led_red = gb.pb1.into_push_pull_output(); 44 | 45 | rprintln!("ready"); 46 | 47 | loop { 48 | rprintln!("new loop"); 49 | // 反转 500ms 50 | led_green.toggle().unwrap(); 51 | delays.delay_ms(500_u32); 52 | led_red.toggle().unwrap(); 53 | delays.delay_ms(500_u32); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /examples/button-exti.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | extern crate stm32f4xx_hal as hal; 6 | 7 | use core::cell::RefCell; 8 | use core::ops::DerefMut; 9 | use cortex_m::interrupt::{free, Mutex}; 10 | use cortex_m_rt::entry; 11 | use hal::{ 12 | gpio::{gpiob, gpioc, gpioh, Edge, ExtiPin, Input, Output, PullUp, PushPull}, 13 | prelude::*, 14 | stm32::{self, interrupt, Interrupt}, 15 | }; 16 | use rtt_target::{rprintln, rtt_init_print}; 17 | 18 | static LED_GREEN: Mutex>>>> = 19 | Mutex::new(RefCell::new(None)); 20 | static LED_RED: Mutex>>>> = 21 | Mutex::new(RefCell::new(None)); 22 | static KEY0: Mutex>>>> = Mutex::new(RefCell::new(None)); 23 | static KEY1: Mutex>>>> = Mutex::new(RefCell::new(None)); 24 | static KEY2: Mutex>>>> = Mutex::new(RefCell::new(None)); 25 | 26 | #[entry] 27 | fn start() -> ! { 28 | rtt_init_print!(); 29 | let mut device = stm32::Peripherals::take().unwrap(); 30 | let _core = stm32::CorePeripherals::take().unwrap(); 31 | 32 | device.RCC.apb2enr.write(|w| w.syscfgen().enabled()); 33 | 34 | let rcc = device.RCC.constrain(); 35 | let _clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(72.mhz()).freeze(); 36 | 37 | let gb = device.GPIOB.split(); 38 | let gc = device.GPIOC.split(); 39 | let gh = device.GPIOH.split(); 40 | 41 | let led_green = gb.pb0.into_push_pull_output(); 42 | let led_red = gb.pb1.into_push_pull_output(); 43 | 44 | let mut key0 = gh.ph3.into_pull_up_input(); 45 | let mut key1 = gh.ph2.into_pull_up_input(); 46 | let mut key2 = gc.pc13.into_pull_up_input(); 47 | 48 | key0.make_interrupt_source(&mut device.SYSCFG); 49 | key0.enable_interrupt(&mut device.EXTI); 50 | key0.trigger_on_edge(&mut device.EXTI, Edge::FALLING); 51 | 52 | key1.make_interrupt_source(&mut device.SYSCFG); 53 | key1.enable_interrupt(&mut device.EXTI); 54 | key1.trigger_on_edge(&mut device.EXTI, Edge::FALLING); 55 | 56 | key2.make_interrupt_source(&mut device.SYSCFG); 57 | key2.enable_interrupt(&mut device.EXTI); 58 | key2.trigger_on_edge(&mut device.EXTI, Edge::FALLING); 59 | 60 | unsafe { 61 | stm32::NVIC::unmask(Interrupt::EXTI15_10); 62 | stm32::NVIC::unmask(Interrupt::EXTI2); 63 | stm32::NVIC::unmask(Interrupt::EXTI3); 64 | } 65 | 66 | free(|cs| { 67 | LED_GREEN.borrow(cs).replace(Some(led_green)); 68 | LED_RED.borrow(cs).replace(Some(led_red)); 69 | 70 | KEY0.borrow(cs).replace(key0.into()); 71 | KEY1.borrow(cs).replace(key1.into()); 72 | KEY2.borrow(cs).replace(key2.into()); 73 | }); 74 | 75 | rprintln!( 76 | "{}, {}, {}", 77 | stm32::NVIC::is_enabled(Interrupt::EXTI2), 78 | stm32::NVIC::is_enabled(Interrupt::EXTI3), 79 | stm32::NVIC::is_enabled(Interrupt::EXTI15_10) 80 | ); 81 | 82 | loop {} 83 | } 84 | 85 | enum BtnPressed { 86 | Key0Pressed, 87 | Key1Pressed, 88 | Key2Pressed, 89 | } 90 | 91 | fn key_pressed(btn: BtnPressed) { 92 | free(|cs| { 93 | if let (Some(ref mut led_red), Some(ref mut led_green)) = ( 94 | LED_RED.borrow(cs).borrow_mut().deref_mut(), 95 | LED_GREEN.borrow(cs).borrow_mut().deref_mut(), 96 | ) { 97 | match btn { 98 | BtnPressed::Key0Pressed => { 99 | led_green.toggle().unwrap(); 100 | } 101 | BtnPressed::Key1Pressed => { 102 | led_green.set_high().unwrap(); 103 | led_red.set_high().unwrap(); 104 | } 105 | BtnPressed::Key2Pressed => { 106 | led_red.toggle().unwrap(); 107 | } 108 | } 109 | } 110 | }); 111 | } 112 | 113 | #[interrupt] 114 | fn EXTI2() { 115 | rprintln!("EXTI2"); 116 | free(|cs| { 117 | let mut btn_ref = KEY1.borrow(cs).borrow_mut(); 118 | if let Some(ref mut btn) = btn_ref.deref_mut() { 119 | key_pressed(BtnPressed::Key1Pressed); 120 | btn.clear_interrupt_pending_bit(); 121 | } 122 | }); 123 | } 124 | 125 | #[interrupt] 126 | fn EXTI3() { 127 | rprintln!("EXTI3"); 128 | free(|cs| { 129 | let mut btn_ref = KEY0.borrow(cs).borrow_mut(); 130 | if let Some(ref mut btn) = btn_ref.deref_mut() { 131 | key_pressed(BtnPressed::Key0Pressed); 132 | btn.clear_interrupt_pending_bit(); 133 | } 134 | }); 135 | } 136 | 137 | #[interrupt] 138 | fn EXTI15_10() { 139 | rprintln!("EXTI15-10"); 140 | free(|cs| { 141 | let mut btn_ref = KEY2.borrow(cs).borrow_mut(); 142 | if let Some(ref mut btn) = btn_ref.deref_mut() { 143 | key_pressed(BtnPressed::Key2Pressed); 144 | btn.clear_interrupt_pending_bit(); 145 | } 146 | }); 147 | } 148 | -------------------------------------------------------------------------------- /examples/button.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use stm32f4xx_hal as hal; 7 | 8 | use cortex_m_rt::entry; 9 | 10 | use crate::ButtonDown::{Key0Pressed, Key1Pressed, Key2Pressed, NoPressed, WkUpPressed}; 11 | use core::cell::RefCell; 12 | use core::ops::DerefMut; 13 | use cortex_m::interrupt::{free, Mutex}; 14 | use hal::prelude::*; 15 | use hal::{ 16 | delay, 17 | gpio::{gpioa, gpioc, gpioh, Input, PullDown, PullUp}, 18 | stm32, 19 | }; 20 | use rtt_target::{rprintln, rtt_init_print}; 21 | use stm32_rustup::*; 22 | use switch_hal::{ 23 | ActiveHigh, ActiveLow, InputSwitch, IntoSwitch, OutputSwitch, Switch, ToggleableOutputSwitch, 24 | }; 25 | 26 | // global instance 27 | static DELAY: Mutex>> = Mutex::new(RefCell::new(None)); 28 | static KEY0: Mutex>, ActiveLow>>>> = 29 | Mutex::new(RefCell::new(None)); 30 | static KEY1: Mutex>, ActiveLow>>>> = 31 | Mutex::new(RefCell::new(None)); 32 | static KEY2: Mutex>, ActiveLow>>>> = 33 | Mutex::new(RefCell::new(None)); 34 | static WK_UP: Mutex>, ActiveHigh>>>> = 35 | Mutex::new(RefCell::new(None)); 36 | 37 | #[entry] 38 | fn main() -> ! { 39 | rtt_init_print!(); 40 | 41 | let dp = stm32::Peripherals::take().unwrap(); 42 | let cp = stm32::CorePeripherals::take().unwrap(); 43 | 44 | let clocks = setup_clocks(dp.RCC.constrain()); 45 | 46 | free(|cs| { 47 | DELAY 48 | .borrow(cs) 49 | .replace(Some(delay::Delay::new(cp.SYST, clocks))) 50 | }); 51 | 52 | let ga = dp.GPIOA.split(); 53 | let gb = dp.GPIOB.split(); 54 | let gc = dp.GPIOC.split(); 55 | let gh = dp.GPIOH.split(); 56 | 57 | let mut led_green = gb.pb0.into_push_pull_output().into_active_low_switch(); 58 | let mut led_red = gb.pb1.into_push_pull_output().into_active_low_switch(); 59 | 60 | free(|cs| { 61 | KEY0.borrow(cs) 62 | .replace(Some(gh.ph3.into_pull_up_input().into_active_low_switch())); 63 | KEY1.borrow(cs) 64 | .replace(Some(gh.ph2.into_pull_up_input().into_active_low_switch())); 65 | KEY2.borrow(cs) 66 | .replace(Some(gc.pc13.into_pull_up_input().into_active_low_switch())); 67 | WK_UP.borrow(cs).replace(Some( 68 | ga.pa0.into_pull_down_input().into_active_high_switch(), 69 | )) 70 | }); 71 | 72 | rprintln!("ready"); 73 | 74 | loop { 75 | match read_button() { 76 | Key0Pressed => { 77 | led_green.toggle().unwrap(); 78 | } 79 | Key1Pressed => { 80 | led_green.off().unwrap(); 81 | led_red.off().unwrap(); 82 | } 83 | Key2Pressed => { 84 | led_red.toggle().unwrap(); 85 | } 86 | WkUpPressed => { 87 | led_red.on().unwrap(); 88 | led_green.on().unwrap(); 89 | } 90 | NoPressed => {} 91 | } 92 | } 93 | } 94 | 95 | enum ButtonDown { 96 | Key0Pressed, 97 | Key1Pressed, 98 | Key2Pressed, 99 | WkUpPressed, 100 | NoPressed, 101 | } 102 | 103 | /// check button down 104 | /// KEY0 > KEY1 > KEY2 > WK_UP 105 | fn read_button() -> ButtonDown { 106 | static mut KEY_UP: bool = true; 107 | 108 | // get current button status 109 | fn read_status() -> (bool, bool, bool, bool) { 110 | free(|cs| { 111 | let key0 = KEY0 112 | .borrow(cs) 113 | .borrow() 114 | .as_ref() 115 | .unwrap() 116 | .is_active() 117 | .unwrap(); 118 | let key1 = KEY1 119 | .borrow(cs) 120 | .borrow() 121 | .as_ref() 122 | .unwrap() 123 | .is_active() 124 | .unwrap(); 125 | let key2 = KEY2 126 | .borrow(cs) 127 | .borrow() 128 | .as_ref() 129 | .unwrap() 130 | .is_active() 131 | .unwrap(); 132 | let wk_up = WK_UP 133 | .borrow(cs) 134 | .borrow() 135 | .as_ref() 136 | .unwrap() 137 | .is_active() 138 | .unwrap(); 139 | return (key0, key1, key2, wk_up); 140 | }) 141 | } 142 | 143 | free(|cs| { 144 | let status = read_status(); 145 | unsafe { 146 | if KEY_UP && (status.0 || status.1 || status.2 || status.3) { 147 | rprintln!("{}, {}, {}, {}", status.0, status.1, status.2, status.3); 148 | if let Some(ref mut delay) = DELAY.borrow(cs).borrow_mut().deref_mut() { 149 | delay.delay_ms(10_u8); 150 | } 151 | KEY_UP = false; 152 | let status = read_status(); 153 | if status.0 { 154 | return Key0Pressed; 155 | } else if status.1 { 156 | return Key1Pressed; 157 | } else if status.2 { 158 | return Key2Pressed; 159 | } else if status.3 { 160 | return WkUpPressed; 161 | } 162 | } else if read_status().eq(&(false, false, false, false)) { 163 | KEY_UP = true; 164 | } 165 | return NoPressed; 166 | } 167 | }) 168 | } 169 | -------------------------------------------------------------------------------- /examples/hello.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use cortex_m_rt::entry; 5 | use rtt_target::{rtt_init_print, rprintln}; 6 | 7 | // 引入未使用依赖以允许编译 8 | // panic handler 9 | extern crate panic_rtt_target; 10 | // 内存布局 11 | extern crate stm32f4xx_hal; 12 | 13 | #[entry] 14 | fn main() -> ! { 15 | rtt_init_print!(); 16 | 17 | rprintln!("hello, embedded world!!!!!!!!!"); 18 | 19 | loop {} 20 | } -------------------------------------------------------------------------------- /examples/iwdg.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use cortex_m_rt::entry; 7 | use hal::prelude::*; 8 | use hal::{ 9 | delay, 10 | stm32::{self}, 11 | time::MilliSeconds, 12 | watchdog::IndependentWatchdog, 13 | }; 14 | use rtt_target::{rprintln, rtt_init_print}; 15 | use stm32f4xx_hal as hal; 16 | 17 | #[entry] 18 | fn start() -> ! { 19 | rtt_init_print!(); 20 | 21 | let device = stm32::Peripherals::take().unwrap(); 22 | let core = stm32::CorePeripherals::take().unwrap(); 23 | 24 | let rcc = device.RCC.constrain(); 25 | let clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(180.mhz()).freeze(); 26 | 27 | let gb = device.GPIOB.split(); 28 | let gh = device.GPIOH.split(); 29 | 30 | let mut led_green = gb.pb0.into_push_pull_output(); 31 | let mut key = gh.ph3.into_pull_up_input(); 32 | let mut delays = delay::Delay::new(core.SYST, clocks); 33 | 34 | let mut watchdog = IndependentWatchdog::new(device.IWDG); 35 | 36 | delays.delay_ms(3000_u32); 37 | 38 | rprintln!("start"); 39 | led_green.set_low().unwrap(); 40 | 41 | watchdog.start(MilliSeconds(3000)); 42 | 43 | loop { 44 | if key.is_low().unwrap() { 45 | watchdog.feed(); 46 | rprintln!("feed"); 47 | } 48 | delays.delay_ms(50_u32); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /examples/pwm.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use cortex_m_rt::entry; 7 | use hal::prelude::*; 8 | use hal::{ 9 | delay, pwm, 10 | stm32::{self}, 11 | }; 12 | use rtt_target::{rprintln, rtt_init_print}; 13 | use stm32f4xx_hal as hal; 14 | 15 | #[entry] 16 | fn start() -> ! { 17 | rtt_init_print!(); 18 | 19 | let device = stm32::Peripherals::take().unwrap(); 20 | let core = stm32::CorePeripherals::take().unwrap(); 21 | 22 | let rcc = device.RCC.constrain(); 23 | let clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(180.mhz()).freeze(); 24 | 25 | let mut delay = delay::Delay::new(core.SYST, clocks); 26 | 27 | let gpiob = device.GPIOB.split(); 28 | let timer3_pwm_pins = ( 29 | gpiob.pb4.into_alternate_af2(), 30 | gpiob.pb5.into_alternate_af2(), 31 | gpiob.pb0.into_alternate_af2(), 32 | gpiob.pb1.into_alternate_af2(), 33 | ); 34 | 35 | let pwm_channels = pwm::tim3(device.TIM3, timer3_pwm_pins, clocks, 20.mhz()); 36 | let mut pb1 = pwm_channels.3; 37 | let max_duty = pb1.get_max_duty(); 38 | 39 | rprintln!("loop start"); 40 | loop { 41 | for i in 1..16 { 42 | rprintln!("{}", i); 43 | pb1.disable(); 44 | pb1.set_duty(max_duty / i); 45 | pb1.enable(); 46 | delay.delay_ms(3000_u32); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /examples/rng.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use cortex_m_rt::entry; 7 | use hal::prelude::*; 8 | use hal::{delay, stm32}; 9 | use rand_core::RngCore; 10 | use rtt_target::{rprintln, rtt_init_print}; 11 | use stm32f4xx_hal as hal; 12 | 13 | #[entry] 14 | fn start() -> ! { 15 | rtt_init_print!(); 16 | 17 | let device = stm32::Peripherals::take().unwrap(); 18 | let core = stm32::CorePeripherals::take().unwrap(); 19 | 20 | let rcc = device.RCC.constrain(); 21 | let clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(72.mhz()).freeze(); 22 | 23 | let mut delays = delay::Delay::new(core.SYST, clocks); 24 | 25 | let mut rand_source = device.RNG.constrain(clocks); 26 | 27 | rprintln!("start loop"); 28 | loop { 29 | let rn = rand_source.next_u32(); 30 | rprintln!("{}", rn); 31 | delays.delay_ms(3000_u32); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /examples/rtic-blink.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | #![deny(warnings)] 4 | 5 | use panic_rtt_target as _; 6 | use rtt_target::{rprintln, rtt_init_print}; 7 | use stm32f4xx_hal::{delay::Delay, prelude::*}; 8 | use stm32f4xx_hal::{ 9 | gpio::{ 10 | gpiob::{PB0, PB1}, 11 | Output, PushPull, 12 | }, 13 | interrupt, stm32, 14 | }; 15 | 16 | type LedGreen = PB0>; 17 | type LedRed = PB1>; 18 | 19 | #[rtic::app(device = stm32f4xx_hal::stm32, peripherals = true)] 20 | const APP: () = { 21 | struct Resources { 22 | led_green: LedGreen, 23 | led_red: LedRed, 24 | delays: Delay, 25 | } 26 | 27 | #[init(spawn = [t1])] 28 | fn init(cx: init::Context) -> init::LateResources { 29 | rtt_init_print!(); 30 | 31 | let core: cortex_m::Peripherals = cx.core; 32 | let device: stm32::Peripherals = cx.device; 33 | 34 | let clocks = device.RCC.constrain().cfgr.use_hse(25.mhz()).freeze(); 35 | let delays = Delay::new(core.SYST, clocks); 36 | 37 | let gb = device.GPIOB.split(); 38 | 39 | let led_green = gb.pb0.into_push_pull_output(); 40 | let led_red = gb.pb1.into_push_pull_output(); 41 | 42 | cx.spawn.t1().unwrap(); 43 | 44 | rprintln!("init return"); 45 | 46 | init::LateResources { 47 | led_green, 48 | led_red, 49 | delays, 50 | } 51 | } 52 | 53 | #[idle] 54 | fn idle(_: idle::Context) -> ! { 55 | rprintln!("idle"); 56 | rtic::pend(interrupt::USART1); 57 | loop {} 58 | } 59 | 60 | #[task(resources = [led_green, delays], spawn = [t2])] 61 | fn t1(cx: t1::Context) { 62 | rprintln!("t1"); 63 | cx.resources.led_green.toggle().unwrap(); 64 | cx.resources.delays.delay_ms(500_u32); 65 | cx.spawn.t2().unwrap(); 66 | rprintln!("t1 stop"); 67 | } 68 | 69 | #[task(resources = [led_red, delays], spawn = [t1])] 70 | fn t2(cx: t2::Context) { 71 | rprintln!("t2"); 72 | cx.resources.led_red.toggle().unwrap(); 73 | cx.resources.delays.delay_ms(500_u32); 74 | cx.spawn.t1().unwrap(); 75 | rprintln!("t2 stop"); 76 | } 77 | 78 | extern "C" { 79 | fn USART1(); 80 | fn USART2(); 81 | } 82 | }; 83 | -------------------------------------------------------------------------------- /examples/rust.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logiase/stm32-rustup/f461d96ee62d170735ac25b2457a3bd2855575a8/examples/rust.raw -------------------------------------------------------------------------------- /examples/serial-console/command.rs: -------------------------------------------------------------------------------- 1 | pub enum Commands { 2 | NotFound, 3 | Command1, 4 | Command2, 5 | } 6 | -------------------------------------------------------------------------------- /examples/serial-console/console.rs: -------------------------------------------------------------------------------- 1 | use crate::command::Commands; 2 | 3 | pub const BUFFER_SIZE: usize = 256; 4 | 5 | const CR: u8 = '\r' as u8; 6 | const LF: u8 = '\n' as u8; 7 | 8 | pub struct Console { 9 | buf: [u8; BUFFER_SIZE], 10 | pos: usize, 11 | } 12 | 13 | impl Console { 14 | pub fn new() -> Console { 15 | Console { 16 | buf: [0; BUFFER_SIZE], 17 | pos: 0, 18 | } 19 | } 20 | 21 | pub fn push(&mut self, b: u8) -> Option { 22 | if self.pos == BUFFER_SIZE { 23 | return None; 24 | } 25 | if b == CR || b == LF { 26 | if self.pos == 0 { 27 | return None; 28 | } 29 | let result = &self.buf[0..self.pos]; 30 | match result { 31 | b"command1" => { 32 | return Commands::Command1.into(); 33 | } 34 | b"command2" => { 35 | return Commands::Command2.into(); 36 | } 37 | _ => { 38 | return Commands::NotFound.into(); 39 | } 40 | } 41 | } 42 | self.buf[self.pos] = b; 43 | self.pos += 1; 44 | None 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /examples/serial-console/main.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | #![no_main] 3 | 4 | use panic_rtt_target as _; 5 | 6 | const APP: () = { 7 | 8 | }; 9 | -------------------------------------------------------------------------------- /examples/spi-ssd1306.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | use core::fmt::Write; 5 | use cortex_m_rt::entry; 6 | use embedded_graphics::{ 7 | image::{Image, ImageRaw}, 8 | pixelcolor::BinaryColor, 9 | prelude::*, 10 | }; 11 | use embedded_hal::spi::{Mode, Phase, Polarity}; 12 | use panic_rtt_target as _; 13 | use rtt_target::rtt_init_print; 14 | use ssd1306::{prelude::*, Builder}; 15 | use stm32f4xx_hal::{delay::Delay, prelude::*, spi::Spi, stm32}; 16 | 17 | #[entry] 18 | fn start() -> ! { 19 | rtt_init_print!(); 20 | let core = stm32::CorePeripherals::take().unwrap(); 21 | let device = stm32::Peripherals::take().unwrap(); 22 | 23 | let rcc = device.RCC.constrain(); 24 | let clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(48.mhz()).freeze(); 25 | 26 | let gpioa = device.GPIOA.split(); 27 | let gpioc = device.GPIOC.split(); 28 | let gpioh = device.GPIOH.split(); 29 | 30 | let sck = gpioa.pa5.into_alternate_af5(); 31 | let miso = gpioa.pa6.into_alternate_af5(); 32 | let mosi = gpioa.pa7.into_alternate_af5(); 33 | let dc = gpioc.pc5.into_push_pull_output(); 34 | let cs = gpioh.ph13.into_push_pull_output(); 35 | let mut rst = gpioc.pc4.into_push_pull_output(); 36 | 37 | let mut delay = Delay::new(core.SYST, clocks); 38 | 39 | let spi1 = Spi::spi1( 40 | device.SPI1, 41 | (sck, miso, mosi), 42 | Mode { 43 | polarity: Polarity::IdleLow, 44 | phase: Phase::CaptureOnFirstTransition, 45 | }, 46 | 8_u32.mhz().into(), 47 | clocks, 48 | ); 49 | 50 | let interface = SPIInterface::new(spi1, dc, cs); 51 | 52 | let mut disp: GraphicsMode<_,_> = Builder::new().connect(interface).into(); 53 | disp.reset(&mut rst, &mut delay); 54 | disp.init().unwrap(); 55 | disp.flush().unwrap(); 56 | 57 | let raw: ImageRaw = ImageRaw::new(include_bytes!("./rust.raw"), 64, 64); 58 | let im = Image::new(&raw, Point::new(32, 0)); 59 | 60 | im.draw(&mut disp).unwrap(); 61 | disp.flush().unwrap(); 62 | 63 | loop {} 64 | } 65 | -------------------------------------------------------------------------------- /examples/timer.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use core::cell::{Cell, RefCell}; 7 | use core::ops::DerefMut; 8 | use cortex_m::interrupt::{free, Mutex}; 9 | use cortex_m_rt::entry; 10 | use hal::{ 11 | prelude::*, 12 | stm32::{self, interrupt, Interrupt}, 13 | timer::{Event, Timer}, 14 | }; 15 | use rtt_target::{rprintln, rtt_init_print}; 16 | use stm32f4xx_hal as hal; 17 | 18 | static TIMER3: Mutex>>> = Mutex::new(RefCell::new(None)); 19 | static LED_STATE: Mutex> = Mutex::new(Cell::new(false)); 20 | 21 | #[entry] 22 | fn start() -> ! { 23 | rtt_init_print!(); 24 | 25 | let device = stm32::Peripherals::take().unwrap(); 26 | 27 | let mut _rcc = device.RCC.constrain(); 28 | let clocks = _rcc.cfgr.use_hse(25.mhz()).sysclk(72.mhz()).freeze(); 29 | 30 | let gb = device.GPIOB.split(); 31 | 32 | let mut led_green = gb.pb0.into_push_pull_output(); 33 | 34 | let mut timer = Timer::tim3(device.TIM3, 5.hz(), clocks); 35 | timer.listen(Event::TimeOut); 36 | free(|cs| { 37 | TIMER3.borrow(cs).replace(timer.into()); 38 | }); 39 | 40 | unsafe { 41 | stm32::NVIC::unmask(Interrupt::TIM3); 42 | } 43 | 44 | rprintln!("start loop"); 45 | loop { 46 | if free(|cs| LED_STATE.borrow(cs).get()) { 47 | led_green.set_low().unwrap(); 48 | } else { 49 | led_green.set_high().unwrap(); 50 | } 51 | } 52 | } 53 | 54 | #[interrupt] 55 | fn TIM3() { 56 | free(|cs| { 57 | let mut timer_ref = TIMER3.borrow(cs).borrow_mut(); 58 | if let Some(ref mut timer) = timer_ref.deref_mut() { 59 | timer.clear_interrupt(Event::TimeOut); 60 | } 61 | let stats = LED_STATE.borrow(cs); 62 | stats.set(!stats.get()); 63 | }); 64 | } 65 | -------------------------------------------------------------------------------- /examples/usart-irq.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | #![no_std] 3 | 4 | extern crate panic_rtt_target; 5 | 6 | use core::cell::RefCell; 7 | use core::ops::DerefMut; 8 | use cortex_m::interrupt::{free, Mutex}; 9 | use cortex_m_rt::entry; 10 | use cortex_m_rt::exception; 11 | use hal::prelude::*; 12 | use hal::{ 13 | gpio::{gpioa, Alternate, AF7}, 14 | serial, 15 | stm32::{self, interrupt, Interrupt}, 16 | }; 17 | use nb::block; 18 | use rtt_target::{rprintln, rtt_init_print}; 19 | use stm32_rustup::buffer::BytesBuffer; 20 | use stm32f4xx_hal as hal; 21 | 22 | static SERIAL1: Mutex< 23 | RefCell< 24 | Option< 25 | serial::Serial< 26 | stm32::USART1, 27 | (gpioa::PA9>, gpioa::PA10>), 28 | >, 29 | >, 30 | >, 31 | > = Mutex::new(RefCell::new(None)); 32 | static SERIAL1_BUF: Mutex>> = Mutex::new(RefCell::new(None)); 33 | 34 | #[entry] 35 | fn start() -> ! { 36 | rtt_init_print!(); 37 | 38 | rprintln!("reset"); 39 | 40 | let device = stm32::Peripherals::take().unwrap(); 41 | let _core = stm32::CorePeripherals::take().unwrap(); 42 | let rcc = device.RCC.constrain(); 43 | 44 | let clocks = rcc.cfgr.use_hse(25.mhz()).sysclk(64.mhz()).freeze(); 45 | 46 | let ga = device.GPIOA.split(); 47 | 48 | let mut serial1 = serial::Serial::usart1( 49 | device.USART1, 50 | (ga.pa9.into_alternate_af7(), ga.pa10.into_alternate_af7()), 51 | serial::config::Config::default().baudrate(115_200.bps()), 52 | clocks, 53 | ) 54 | .unwrap(); 55 | serial1.listen(serial::Event::Rxne); 56 | 57 | stm32::NVIC::unpend(Interrupt::USART1); 58 | unsafe { 59 | stm32::NVIC::unmask(Interrupt::USART1); 60 | } 61 | 62 | rprintln!("{}", stm32::NVIC::is_enabled(Interrupt::USART1)); 63 | 64 | free(|cs| { 65 | SERIAL1.borrow(cs).replace(Some(serial1)); 66 | SERIAL1_BUF.borrow(cs).replace(Some(BytesBuffer::new())); 67 | }); 68 | rprintln!("serial1 ok"); 69 | 70 | loop {} 71 | } 72 | 73 | #[interrupt] 74 | fn USART1() { 75 | free(|cs| { 76 | if let (Some(ref mut serial1), Some(ref mut serial1_buf)) = ( 77 | SERIAL1.borrow(cs).borrow_mut().deref_mut(), 78 | SERIAL1_BUF.borrow(cs).borrow_mut().deref_mut(), 79 | ) { 80 | if serial1.is_rxne() { 81 | let b = serial1.read().unwrap(); 82 | serial1_buf.push(b).unwrap(); 83 | } 84 | match serial1_buf.check_end() { 85 | Some((content, length)) => { 86 | for i in 0..length { 87 | block!(serial1.write(content[i])).unwrap(); 88 | } 89 | serial1_buf.clear(); 90 | } 91 | None => {} 92 | } 93 | } 94 | }); 95 | } 96 | -------------------------------------------------------------------------------- /imgs/crates.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logiase/stm32-rustup/f461d96ee62d170735ac25b2457a3bd2855575a8/imgs/crates.png -------------------------------------------------------------------------------- /imgs/usart-irq.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Logiase/stm32-rustup/f461d96ee62d170735ac25b2457a3bd2855575a8/imgs/usart-irq.png -------------------------------------------------------------------------------- /memory.x: -------------------------------------------------------------------------------- 1 | MEMORY 2 | { 3 | RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 192K 4 | CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K 5 | FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 1024K 6 | } 7 | 8 | 9 | _stack_start = ORIGIN(RAM) + LENGTH(RAM); -------------------------------------------------------------------------------- /openocd.cfg: -------------------------------------------------------------------------------- 1 | source [find interface/stlink.cfg] 2 | 3 | source [find target/stm32f4x.cfg] -------------------------------------------------------------------------------- /openocd.gdb: -------------------------------------------------------------------------------- 1 | target extended-remote :3333 2 | 3 | # print demangled symbols 4 | set print asm-demangle on 5 | 6 | # set backtrace limit to not have infinite backtrace loops 7 | set backtrace limit 32 8 | 9 | # detect unhandled exceptions, hard faults and panics 10 | break DefaultHandler 11 | break HardFault 12 | break rust_begin_unwind 13 | # # run the next few lines so the panic message is printed immediately 14 | # # the number needs to be adjusted for your panic handler 15 | # commands $bpnum 16 | # next 4 17 | # end 18 | 19 | # *try* to stop at the user entry point (it might be gone due to inlining) 20 | break main 21 | 22 | monitor arm semihosting enable 23 | 24 | # # send captured ITM to the file itm.fifo 25 | # # (the microcontroller SWO pin must be connected to the programmer SWO pin) 26 | # # 8000000 must match the core clock frequency 27 | # monitor tpiu config internal itm.txt uart off 8000000 28 | 29 | # # OR: make the microcontroller SWO pin output compatible with UART (8N1) 30 | # # 8000000 must match the core clock frequency 31 | # # 2000000 is the frequency of the SWO pin 32 | # monitor tpiu config external uart off 8000000 2000000 33 | 34 | # # enable ITM port 0 35 | # monitor itm port 0 on 36 | 37 | load 38 | 39 | # start the process but immediately halt the processor 40 | stepi -------------------------------------------------------------------------------- /src/buffer.rs: -------------------------------------------------------------------------------- 1 | const BUFFER_SIZE: usize = 512; 2 | 3 | pub struct BytesBuffer { 4 | index: usize, 5 | buffer: [u8; BUFFER_SIZE], 6 | } 7 | 8 | impl BytesBuffer { 9 | /// new return a new BytesBuffer 10 | pub fn new() -> Self { 11 | Self { 12 | index: 0, 13 | buffer: [0; BUFFER_SIZE], 14 | } 15 | } 16 | 17 | pub fn push(&mut self, data: u8) -> Result<(), ()> { 18 | if self.index < BUFFER_SIZE { 19 | self.buffer[self.index] = data; 20 | self.index += 1; 21 | return Ok(()); 22 | } 23 | Err(()) 24 | } 25 | 26 | pub fn read(&mut self) -> Option { 27 | if self.index > 0 { 28 | let tmp = self.index; 29 | self.index = 0; 30 | Some(Self { 31 | index: tmp, 32 | buffer: self.buffer, 33 | }) 34 | } else { 35 | None 36 | } 37 | } 38 | 39 | pub fn clear(&mut self) { 40 | self.index = 0; 41 | } 42 | 43 | pub fn check_end(&mut self) -> Option<([u8; BUFFER_SIZE], usize)> { 44 | if self.buffer[self.index - 1] == 0x0A { 45 | if self.buffer[self.index - 2] == 0x0D { 46 | return Some((self.buffer, self.index)); 47 | } 48 | } 49 | None 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/clock.rs: -------------------------------------------------------------------------------- 1 | use stm32f4xx_hal::prelude::*; 2 | use stm32f4xx_hal::rcc; 3 | 4 | /// 设置时钟 5 | /// `use_hse` 使用外部高速晶振 6 | /// `sysclk` 系统频率 7 | /// and ... 8 | pub fn setup_clocks(r: rcc::Rcc) -> rcc::Clocks { 9 | return r 10 | .cfgr 11 | .use_hse(25.mhz()) 12 | .sysclk(180.mhz()) 13 | .freeze(); 14 | } -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | pub mod buffer; 4 | pub mod clock; 5 | 6 | pub use clock::setup_clocks; 7 | --------------------------------------------------------------------------------