Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cb68ff7248 | ||
|
|
55f44f21be | ||
|
|
f38979def1 | ||
|
|
ba27df0b57 | ||
|
|
f39fa8ebef | ||
|
|
5832d097c6 | ||
|
|
2a2879a3b0 | ||
|
|
daea420f17 | ||
|
|
b7884948b2 | ||
|
|
01e9a597c1 | ||
|
|
ae503ee8fb | ||
|
|
4a398df058 | ||
|
|
efb84ccf53 | ||
|
|
a462ab027d | ||
|
|
6da25bced8 | ||
|
|
7cb137968b | ||
|
|
7ae7245956 | ||
|
|
91a894e369 | ||
|
|
f7cf8de167 | ||
|
|
66c0c588b0 | ||
|
|
0f139c386b | ||
|
|
3a4a5be709 | ||
|
|
a35486b2f4 | ||
|
|
8e79d05cc4 | ||
|
|
0e2ec97ce6 | ||
|
|
f6988f1ced | ||
|
|
43acbc4e12 | ||
|
|
a18a2fe64b | ||
|
|
3b2e5699f3 | ||
|
|
72b23f0e85 | ||
|
|
2cd4ea31e5 | ||
|
|
6f62705eaf | ||
|
|
1d3d6e708c | ||
|
|
fb3f403be5 | ||
|
|
578dfc7f86 | ||
|
|
23ae289bf4 | ||
|
|
5206ef79d2 | ||
|
|
46c97c6cee | ||
|
|
ba8994a2ed | ||
|
|
7ebac078c0 | ||
|
|
d002e0f239 | ||
|
|
9f573d73b2 | ||
|
|
bf91f60d40 | ||
|
|
682fe4e77c | ||
|
|
d60563ff45 | ||
|
|
48ce24b303 | ||
|
|
3dc0cf09db | ||
|
|
59b8b866c7 | ||
|
|
1bb99c92f1 | ||
|
|
d41dd6a4c7 | ||
|
|
a8a02d9162 | ||
|
|
affd24f2bb | ||
|
|
67003f069c | ||
|
|
51f4b4e7ed | ||
|
|
8890c461d6 | ||
|
|
3f66a585a8 | ||
|
|
ba1263e7a1 | ||
|
|
4b1a2f3811 | ||
|
|
805b63afb1 | ||
|
|
6780d81e4d | ||
|
|
59a780d0c4 | ||
|
|
c03bded663 | ||
|
|
f88a44fd78 | ||
|
|
9c37db3d3b | ||
|
|
797e750a32 | ||
|
|
ea13292cc4 | ||
|
|
207591ef4c | ||
|
|
0b22a8aabb | ||
|
|
adda589c71 | ||
|
|
d4c6bde00f | ||
|
|
96e0b4e96b | ||
|
|
f5fca936c6 | ||
|
|
f1329524c8 | ||
|
|
2bb6e419af | ||
|
|
0154a9efc7 | ||
|
|
c6fafaedc2 | ||
|
|
82e36ffe13 | ||
|
|
d035016e65 | ||
|
|
362c715b19 | ||
|
|
8aa495ac66 | ||
|
|
62453e1e94 | ||
|
|
9e44d099bd | ||
|
|
22d921658e | ||
|
|
7260cd522c | ||
|
|
5390231c1e | ||
|
|
9669b788d1 |
@@ -1,27 +1,27 @@
|
|||||||
[target.thumbv6m-none-eabi]
|
[target.thumbv6m-none-eabi]
|
||||||
|
runner = 'arm-none-eabi-gdb'
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Wl,-Tlink.x",
|
||||||
"-C", "linker=arm-none-eabi-ld",
|
"-C", "link-arg=-nostartfiles",
|
||||||
"-Z", "linker-flavor=ld",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.thumbv7m-none-eabi]
|
[target.thumbv7m-none-eabi]
|
||||||
|
runner = 'arm-none-eabi-gdb'
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Wl,-Tlink.x",
|
||||||
"-C", "linker=arm-none-eabi-ld",
|
"-C", "link-arg=-nostartfiles",
|
||||||
"-Z", "linker-flavor=ld",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.thumbv7em-none-eabi]
|
[target.thumbv7em-none-eabi]
|
||||||
|
runner = 'arm-none-eabi-gdb'
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Wl,-Tlink.x",
|
||||||
"-C", "linker=arm-none-eabi-ld",
|
"-C", "link-arg=-nostartfiles",
|
||||||
"-Z", "linker-flavor=ld",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[target.thumbv7em-none-eabihf]
|
[target.thumbv7em-none-eabihf]
|
||||||
|
runner = 'arm-none-eabi-gdb'
|
||||||
rustflags = [
|
rustflags = [
|
||||||
"-C", "link-arg=-Tlink.x",
|
"-C", "link-arg=-Wl,-Tlink.x",
|
||||||
"-C", "linker=arm-none-eabi-ld",
|
"-C", "link-arg=-nostartfiles",
|
||||||
"-Z", "linker-flavor=ld",
|
|
||||||
]
|
]
|
||||||
|
|||||||
20
.gdbinit
20
.gdbinit
@@ -1,9 +1,21 @@
|
|||||||
target remote :3333
|
target remote :3333
|
||||||
|
|
||||||
|
# print demangled symbols by default
|
||||||
|
set print asm-demangle on
|
||||||
|
|
||||||
monitor arm semihosting enable
|
monitor arm semihosting enable
|
||||||
# if using ITM
|
|
||||||
|
# # send captured ITM to the file itm.fifo
|
||||||
|
# # (the microcontroller SWO pin must be connected to the programmer SWO pin)
|
||||||
|
# # 8000000 must match the core clock frequency
|
||||||
# monitor tpiu config internal itm.fifo uart off 8000000
|
# monitor tpiu config internal itm.fifo uart off 8000000
|
||||||
|
|
||||||
|
# # OR: make the microcontroller SWO pin output compatible with UART (8N1)
|
||||||
|
# # 2000000 is the frequency of the SWO pin
|
||||||
|
# monitor tpiu config external uart off 8000000 2000000
|
||||||
|
|
||||||
|
# # enable ITM port 0
|
||||||
# monitor itm port 0 on
|
# monitor itm port 0 on
|
||||||
|
|
||||||
load
|
load
|
||||||
tbreak cortex_m_rt::reset_handler
|
step
|
||||||
monitor reset halt
|
|
||||||
continue
|
|
||||||
|
|||||||
1
.github/CODEOWNERS
vendored
Normal file
1
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* @rust-embedded/cortex-m
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,4 +1,5 @@
|
|||||||
**/*.rs.bk
|
**/*.rs.bk
|
||||||
|
.#*
|
||||||
.gdb_history
|
.gdb_history
|
||||||
Cargo.lock
|
Cargo.lock
|
||||||
target/
|
target/
|
||||||
|
|||||||
61
.travis.yml
Normal file
61
.travis.yml
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
language: rust
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- env: TARGET=thumbv6m-none-eabi
|
||||||
|
rust: nightly
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
|
- env: TARGET=thumbv7m-none-eabi
|
||||||
|
rust: nightly
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
|
- env: TARGET=thumbv7em-none-eabi
|
||||||
|
rust: nightly
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
|
- env: TARGET=thumbv7em-none-eabihf
|
||||||
|
rust: nightly
|
||||||
|
addons:
|
||||||
|
apt:
|
||||||
|
packages:
|
||||||
|
- gcc-arm-none-eabi
|
||||||
|
if: (branch = staging OR branch = trying) OR (type = pull_request AND branch = master)
|
||||||
|
|
||||||
|
before_install: set -e
|
||||||
|
|
||||||
|
install:
|
||||||
|
- bash ci/install.sh
|
||||||
|
|
||||||
|
script:
|
||||||
|
- bash ci/script.sh
|
||||||
|
|
||||||
|
after_script: set +e
|
||||||
|
|
||||||
|
cache: cargo
|
||||||
|
|
||||||
|
before_cache:
|
||||||
|
# Travis can't cache files that are not readable by "others"
|
||||||
|
- chmod -R a+r $HOME/.cargo
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
- staging
|
||||||
|
- trying
|
||||||
|
|
||||||
|
notifications:
|
||||||
|
email:
|
||||||
|
on_success: never
|
||||||
190
CHANGELOG.md
190
CHANGELOG.md
@@ -5,13 +5,179 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
## v0.1.2 - 2017-05-07
|
## [v0.3.3] - 2018-08-07
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Stopped recommending LLD as it requires an unstable feature.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The allocator example. It now uses the `#[alloc_error_handler]` attribute
|
||||||
|
instead of the unstable `oom` lang item.
|
||||||
|
|
||||||
|
## [v0.3.2] - 2018-06-19
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Bumped the panic-semihosting dependency to fix some examples when compiling with latest nightly.
|
||||||
|
|
||||||
|
## [v0.3.1] - 2018-05-13
|
||||||
|
|
||||||
|
- Document the standard `main` interface issue in the troubleshooting guide.
|
||||||
|
|
||||||
|
## [v0.3.0] - 2018-05-12
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [breaking-change] `arm-none-eabi-gcc` is now a mandatory dependency as it's required by the
|
||||||
|
`cortex-m-rt` dependency and also the default linker.
|
||||||
|
|
||||||
|
- Bumped the `cortex-m` and `cortex-m-rt` dependencies to v0.5.0. Updated all the examples to match
|
||||||
|
the new `cortex-m-rt` API.
|
||||||
|
|
||||||
|
- Updated the `allocator` example to compile on a recent nightly.
|
||||||
|
|
||||||
|
- Set the number of codegen-units to 1 when compiling in release mode. This produces smaller and
|
||||||
|
faster binaries.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Removed `opt-level = "s"` from `profile.release`. This flag is still unstable.
|
||||||
|
|
||||||
|
## [v0.2.7] - 2018-04-24
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bumped the dependency of `cortex-m-rt` to v0.4.0.
|
||||||
|
|
||||||
|
## [v0.2.6] - 2018-04-09
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- The documentation to instruct the user to use Cargo instead of Xargo
|
||||||
|
|
||||||
|
## [v0.2.5] - 2018-02-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Comments to Cargo.toml and Xargo.toml to make it easier to try the examples.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- The `allocator` example to use the `#[global_allocator]` feature.
|
||||||
|
|
||||||
|
## [v0.2.4] - 2018-01-26
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Disable ThinLTO which causes extreme binary size bloat. See rust-lang/rust#47770 for details.
|
||||||
|
|
||||||
|
## [v0.2.3] - 2018-01-20
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Tweaked docs. Instruction steps are now numbered.
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- The `CARGO_INCREMENTAL=1` workaround has been removed since it's now controlled via Cargo.toml and
|
||||||
|
we have the setting disabled in the template.
|
||||||
|
|
||||||
|
## [v0.2.2] - 2018-01-17
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Troubleshooting documentation: how to workaround the "Ignoring packet error, continuing..." GDB
|
||||||
|
error.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Disabled incremental compilation and parallel codegen on the dev profile to reduce the changes of
|
||||||
|
running into rust-lang/rust#47074.
|
||||||
|
|
||||||
|
- Bumped the version of the `cortex-m-rt` dependency to v0.3.12.
|
||||||
|
|
||||||
|
## [v0.2.1] - 2017-07-14
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Troubleshooting documentation: how to fix the error of overwriting the
|
||||||
|
`.cargo/config` file when you meant to append text to it.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Xargo.toml: Changed the source of the `compiler-builtins` crate from git to
|
||||||
|
the `rust-src` component.
|
||||||
|
|
||||||
|
- Expanded the `device` example to do some I/O.
|
||||||
|
|
||||||
|
## [v0.2.0] - 2017-07-07
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- [breaking-change] Bumped the cortex-m and cortex-m-rt versions to v0.3.0.
|
||||||
|
|
||||||
|
## [v0.1.8] - 2017-05-30
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bumped the cortex-m-rt dependency to v0.2.3, and documented the `_stext`
|
||||||
|
symbol (see memory.x).
|
||||||
|
|
||||||
|
## [v0.1.7] - 2017-05-27
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Documentation and an example about how to use the heap and a dynamic memory
|
||||||
|
allocator.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bumped the `cortex-m-rt` dependency to v0.2.2
|
||||||
|
- Bumped the `cortex-m` dependency to v0.2.7
|
||||||
|
|
||||||
|
## [v0.1.6] - 2017-05-26
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Set the default runner in .cargo/config to `arm-none-eabi-gdb`. Now `xargo
|
||||||
|
run` will build the program and start a debug session.
|
||||||
|
|
||||||
|
## [v0.1.5] - 2017-05-16
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A warning about using CARGO_INCREMENTAL to the how to use and the
|
||||||
|
troubleshooting sections.
|
||||||
|
|
||||||
|
## [v0.1.4] - 2017-05-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A dependencies section to the documentation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Extend troubleshooting section
|
||||||
|
|
||||||
|
## [v0.1.3] - 2017-05-13
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- A troubleshooting section to the documentation
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Bumped the cortex-m crate version to v0.2.6
|
||||||
|
|
||||||
|
## [v0.1.2] - 2017-05-07
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- .gdbinit: jump to reset handler after loading the program.
|
- .gdbinit: jump to reset handler after loading the program.
|
||||||
|
|
||||||
## v0.1.1 - 2017-04-27
|
## [v0.1.1] - 2017-04-27
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
@@ -23,6 +189,24 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
||||||
[Unreleased]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.2...HEAD
|
[Unreleased]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.3...HEAD
|
||||||
|
[v0.3.3]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.2...v0.3.3
|
||||||
|
[v0.3.2]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.1...v0.3.2
|
||||||
|
[v0.3.1]: https://github.com/japaric/cortex-m-quickstart/compare/v0.3.0...v0.3.1
|
||||||
|
[v0.3.0]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.7...v0.3.0
|
||||||
|
[v0.2.7]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.6...v0.2.7
|
||||||
|
[v0.2.6]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.5...v0.2.6
|
||||||
|
[v0.2.5]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.4...v0.2.5
|
||||||
|
[v0.2.4]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.3...v0.2.4
|
||||||
|
[v0.2.3]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.2...v0.2.3
|
||||||
|
[v0.2.2]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.1...v0.2.2
|
||||||
|
[v0.2.1]: https://github.com/japaric/cortex-m-quickstart/compare/v0.2.0...v0.2.1
|
||||||
|
[v0.2.0]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.8...v0.2.0
|
||||||
|
[v0.1.8]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.7...v0.1.8
|
||||||
|
[v0.1.7]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.6...v0.1.7
|
||||||
|
[v0.1.6]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.5...v0.1.6
|
||||||
|
[v0.1.5]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.4...v0.1.5
|
||||||
|
[v0.1.4]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.3...v0.1.4
|
||||||
|
[v0.1.3]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.2...v0.1.3
|
||||||
[v0.1.2]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.1...v0.1.2
|
[v0.1.2]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.1...v0.1.2
|
||||||
[v0.1.1]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.0...v0.1.1
|
[v0.1.1]: https://github.com/japaric/cortex-m-quickstart/compare/v0.1.0...v0.1.1
|
||||||
|
|||||||
37
CODE_OF_CONDUCT.md
Normal file
37
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
# The Rust Code of Conduct
|
||||||
|
|
||||||
|
## Conduct
|
||||||
|
|
||||||
|
**Contact**: [Cortex-M team](https://github.com/rust-embedded/wg#the-cortex-m-team)
|
||||||
|
|
||||||
|
* We are committed to providing a friendly, safe and welcoming environment for all, regardless of level of experience, gender identity and expression, sexual orientation, disability, personal appearance, body size, race, ethnicity, age, religion, nationality, or other similar characteristic.
|
||||||
|
* On IRC, please avoid using overtly sexual nicknames or other nicknames that might detract from a friendly, safe and welcoming environment for all.
|
||||||
|
* Please be kind and courteous. There's no need to be mean or rude.
|
||||||
|
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
|
||||||
|
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
|
||||||
|
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the [Citizen Code of Conduct](http://citizencodeofconduct.org/); if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
|
||||||
|
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Cortex-M team][team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
|
||||||
|
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
|
||||||
|
|
||||||
|
## Moderation
|
||||||
|
|
||||||
|
These are the policies for upholding our community's standards of conduct.
|
||||||
|
|
||||||
|
1. Remarks that violate the Rust standards of conduct, including hateful, hurtful, oppressive, or exclusionary remarks, are not allowed. (Cursing is allowed, but never targeting another user, and never in a hateful manner.)
|
||||||
|
2. Remarks that moderators find inappropriate, whether listed in the code of conduct or not, are also not allowed.
|
||||||
|
3. Moderators will first respond to such remarks with a warning.
|
||||||
|
4. If the warning is unheeded, the user will be "kicked," i.e., kicked out of the communication channel to cool off.
|
||||||
|
5. If the user comes back and continues to make trouble, they will be banned, i.e., indefinitely excluded.
|
||||||
|
6. Moderators may choose at their discretion to un-ban the user if it was a first offense and they offer the offended party a genuine apology.
|
||||||
|
7. If a moderator bans someone and you think it was unjustified, please take it up with that moderator, or with a different moderator, **in private**. Complaints about bans in-channel are not allowed.
|
||||||
|
8. Moderators are held to a higher standard than other community members. If a moderator creates an inappropriate situation, they should expect less leeway than others.
|
||||||
|
|
||||||
|
In the Rust community we strive to go the extra step to look out for each other. Don't just aim to be technically unimpeachable, try to be your best self. In particular, avoid flirting with offensive or sensitive issues, particularly if they're off-topic; this all too often leads to unnecessary fights, hurt feelings, and damaged trust; worse, it can drive people away from the community entirely.
|
||||||
|
|
||||||
|
And if someone takes issue with something you said or did, resist the urge to be defensive. Just stop doing what it was they complained about and apologize. Even if you feel you were misinterpreted or unfairly accused, chances are good there was something you could've communicated better — remember that it's your responsibility to make your fellow Rustaceans comfortable. Everyone wants to get along and we are all here first and foremost because we want to talk about cool technology. You will find that people will be eager to assume good intent and forgive as long as you earn their trust.
|
||||||
|
|
||||||
|
The enforcement policies listed above apply to all official embedded WG venues; including official IRC channels (#rust-embedded); GitHub repositories under rust-embedded; and all forums under rust-embedded.org (forum.rust-embedded.org).
|
||||||
|
|
||||||
|
*Adapted from the [Node.js Policy on Trolling](http://blog.izs.me/post/30036893703/policy-on-trolling) as well as the [Contributor Covenant v1.3.0](https://www.contributor-covenant.org/version/1/3/0/).*
|
||||||
|
|
||||||
|
[team]: https://github.com/rust-embedded/wg#the-cortex-m-team
|
||||||
22
Cargo.toml
22
Cargo.toml
@@ -6,12 +6,26 @@ keywords = ["arm", "cortex-m", "template"]
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-quickstart"
|
name = "cortex-m-quickstart"
|
||||||
repository = "https://github.com/japaric/cortex-m-quickstart"
|
repository = "https://github.com/japaric/cortex-m-quickstart"
|
||||||
version = "0.1.2"
|
version = "0.3.3"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.2.4"
|
cortex-m = "0.5.0"
|
||||||
cortex-m-rt = "0.2.0"
|
cortex-m-rt = "0.5.0"
|
||||||
|
cortex-m-semihosting = "0.3.0"
|
||||||
|
panic-semihosting = "0.3.0"
|
||||||
|
|
||||||
|
# Uncomment for the panic example.
|
||||||
|
# panic-itm = "0.1.1"
|
||||||
|
|
||||||
|
# Uncomment for the allocator example.
|
||||||
|
# alloc-cortex-m = "0.3.4"
|
||||||
|
|
||||||
|
# Uncomment for the device example.
|
||||||
|
# [dependencies.stm32f103xx]
|
||||||
|
# features = ["rt"]
|
||||||
|
# version = "0.10.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
codegen-units = 1 # better optimizations
|
||||||
debug = true
|
debug = true
|
||||||
|
lto = true # better optimizations
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
Copyright (c) 2017 {{toml-escape author}}
|
Copyright (c) 2018
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any
|
Permission is hereby granted, free of charge, to any
|
||||||
person obtaining a copy of this software and associated
|
person obtaining a copy of this software and associated
|
||||||
|
|||||||
11
README.md
11
README.md
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
> A template for building applications for ARM Cortex-M microcontrollers
|
> A template for building applications for ARM Cortex-M microcontrollers
|
||||||
|
|
||||||
|
This project is developed and maintained by the [Cortex-M team][team].
|
||||||
|
|
||||||
# [Documentation](https://docs.rs/cortex-m-quickstart)
|
# [Documentation](https://docs.rs/cortex-m-quickstart)
|
||||||
|
|
||||||
# License
|
# License
|
||||||
@@ -20,3 +22,12 @@ at your option.
|
|||||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||||
dual licensed as above, without any additional terms or conditions.
|
dual licensed as above, without any additional terms or conditions.
|
||||||
|
|
||||||
|
## Code of Conduct
|
||||||
|
|
||||||
|
Contribution to this crate is organized under the terms of the [Rust Code of
|
||||||
|
Conduct][CoC], the maintainer of this crate, the [Cortex-M team][team], promises
|
||||||
|
to intervene to uphold that code of conduct.
|
||||||
|
|
||||||
|
[CoC]: CODE_OF_CONDUCT.md
|
||||||
|
[team]: https://github.com/rust-embedded/wg#the-cortex-m-team
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
[dependencies.core]
|
|
||||||
|
|
||||||
[dependencies.compiler_builtins]
|
|
||||||
features = ["mem"]
|
|
||||||
git = "https://github.com/rust-lang-nursery/compiler-builtins"
|
|
||||||
stage = 1
|
|
||||||
3
bors.toml
Normal file
3
bors.toml
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
delete_merged_branches = true
|
||||||
|
required_approvals = 1
|
||||||
|
status = ["continuous-integration/travis-ci/push"]
|
||||||
3
build.rs
3
build.rs
@@ -12,6 +12,7 @@ fn main() {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
println!("cargo:rustc-link-search={}", out.display());
|
println!("cargo:rustc-link-search={}", out.display());
|
||||||
|
|
||||||
println!("cargo:rerun-if-changed=build.rs");
|
// Only re-run the build script when memory.x is changed,
|
||||||
|
// instead of when any part of the source code changes.
|
||||||
println!("cargo:rerun-if-changed=memory.x");
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
}
|
}
|
||||||
|
|||||||
7
ci/install.sh
Normal file
7
ci/install.sh
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
main() {
|
||||||
|
rustup target add $TARGET
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
70
ci/script.sh
Normal file
70
ci/script.sh
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
set -euxo pipefail
|
||||||
|
|
||||||
|
main() {
|
||||||
|
local td=$(mktemp -d)
|
||||||
|
|
||||||
|
git clone . $td
|
||||||
|
pushd $td
|
||||||
|
|
||||||
|
cat >memory.x <<'EOF'
|
||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
|
RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local examples=(
|
||||||
|
crash
|
||||||
|
exception
|
||||||
|
hello
|
||||||
|
minimal
|
||||||
|
panic
|
||||||
|
)
|
||||||
|
for ex in "${examples[@]}"; do
|
||||||
|
cargo build --target $TARGET --example $ex
|
||||||
|
cargo build --target $TARGET --example $ex --release
|
||||||
|
done
|
||||||
|
|
||||||
|
# ITM is not available on Cortex-M0
|
||||||
|
if [ $TARGET != thumbv6m-none-eabi ]; then
|
||||||
|
local ex=itm
|
||||||
|
cargo build --target $TARGET --example $ex
|
||||||
|
cargo build --target $TARGET --example $ex --release
|
||||||
|
|
||||||
|
examples+=( $ex )
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Allocator example needs an extra dependency
|
||||||
|
cat >>Cargo.toml <<'EOF'
|
||||||
|
[dependencies.alloc-cortex-m]
|
||||||
|
version = "0.3.4"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local ex=allocator
|
||||||
|
cargo build --target $TARGET --example $ex --release
|
||||||
|
|
||||||
|
examples+=( $ex )
|
||||||
|
|
||||||
|
# Device example needs an extra dependency
|
||||||
|
if [ $TARGET = thumbv7m-none-eabi ]; then
|
||||||
|
cat >>Cargo.toml <<'EOF'
|
||||||
|
[dependencies.stm32f103xx]
|
||||||
|
features = ["rt"]
|
||||||
|
version = "0.10.0"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
local ex=device
|
||||||
|
cargo build --target $TARGET --example $ex
|
||||||
|
cargo build --target $TARGET --example $ex --release
|
||||||
|
|
||||||
|
examples+=( $ex )
|
||||||
|
fi
|
||||||
|
|
||||||
|
IFS=,;eval arm-none-eabi-size target/$TARGET/release/examples/"{${examples[*]}}"
|
||||||
|
|
||||||
|
popd
|
||||||
|
rm -rf $td
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
||||||
77
examples/allocator.rs
Normal file
77
examples/allocator.rs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
//! How to use the heap and a dynamic memory allocator
|
||||||
|
//!
|
||||||
|
//! This example depends on the alloc-cortex-m crate so you'll have to add it to your Cargo.toml:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! # or edit the Cargo.toml file manually
|
||||||
|
//! $ cargo add alloc-cortex-m
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
|
#![feature(alloc)]
|
||||||
|
#![feature(alloc_error_handler)]
|
||||||
|
#![feature(global_allocator)]
|
||||||
|
#![feature(lang_items)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
// This is the allocator crate; you can use a different one
|
||||||
|
extern crate alloc_cortex_m;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate alloc;
|
||||||
|
extern crate cortex_m;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
extern crate cortex_m_semihosting as sh;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use core::alloc::Layout;
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use alloc_cortex_m::CortexMHeap;
|
||||||
|
use cortex_m::asm;
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
use sh::hio;
|
||||||
|
|
||||||
|
// this is the allocator the application will use
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
||||||
|
|
||||||
|
const HEAP_SIZE: usize = 1024; // in bytes
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
// Initialize the allocator BEFORE you use it
|
||||||
|
unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) }
|
||||||
|
|
||||||
|
// Growable array allocated on the heap
|
||||||
|
let xs = vec![0, 1, 2];
|
||||||
|
|
||||||
|
let mut stdout = hio::hstdout().unwrap();
|
||||||
|
writeln!(stdout, "{:?}", xs).unwrap();
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// define what happens in an Out Of Memory (OOM) condition
|
||||||
|
#[alloc_error_handler]
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn alloc_error(layout: Layout) -> ! {
|
||||||
|
asm::bkpt();
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(HardFault, hard_fault);
|
||||||
|
|
||||||
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
}
|
||||||
@@ -1,58 +1,114 @@
|
|||||||
//! Debugging a crash (exception)
|
//! Debugging a crash (exception)
|
||||||
//!
|
//!
|
||||||
//! The `cortex-m-rt` crate provides functionality for this through a default
|
//! Most crash conditions trigger a hard fault exception, whose handler is defined via
|
||||||
//! exception handler. When an exception is hit, the default handler will
|
//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a
|
||||||
//! trigger a breakpoint and in this debugging context the stacked registers
|
//! snapshot of the CPU registers at the moment of the exception.
|
||||||
//! are accessible.
|
|
||||||
//!
|
//!
|
||||||
//! In you run the example below, you'll be able to inspect the state of your
|
//! This program crashes and the `HardFault` handler prints to the console the contents of the
|
||||||
//! program under the debugger using these commands:
|
//! `ExceptionFrame` and then triggers a breakpoint. From that breakpoint one can see the backtrace
|
||||||
|
//! that led to the exception.
|
||||||
//!
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! (gdb) continue
|
||||||
|
//! Program received signal SIGTRAP, Trace/breakpoint trap.
|
||||||
|
//! __bkpt () at asm/bkpt.s:3
|
||||||
|
//! 3 bkpt
|
||||||
|
//!
|
||||||
|
//! (gdb) backtrace
|
||||||
|
//! #0 __bkpt () at asm/bkpt.s:3
|
||||||
|
//! #1 0x080030b4 in cortex_m::asm::bkpt () at $$/cortex-m-0.5.0/src/asm.rs:19
|
||||||
|
//! #2 rust_begin_unwind (args=..., file=..., line=99, col=5) at $$/panic-semihosting-0.2.0/src/lib.rs:87
|
||||||
|
//! #3 0x08001d06 in core::panicking::panic_fmt () at libcore/panicking.rs:71
|
||||||
|
//! #4 0x080004a6 in crash::hard_fault (ef=0x20004fa0) at examples/crash.rs:99
|
||||||
|
//! #5 0x08000548 in UserHardFault (ef=0x20004fa0) at <exception macros>:10
|
||||||
|
//! #6 0x0800093a in HardFault () at asm.s:5
|
||||||
|
//! Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
||||||
//! ```
|
//! ```
|
||||||
//! (gdb) # Stacked registers = program state during the crash
|
|
||||||
//! (gdb) print/x *_sr
|
|
||||||
//! $1 = cortex_m::exception::StackedRegisters {
|
|
||||||
//! r0 = 0x2fffffff,
|
|
||||||
//! r1 = 0x2fffffff,
|
|
||||||
//! r2 = 0x0,
|
|
||||||
//! r3 = 0x0,
|
|
||||||
//! r12 = 0x0,
|
|
||||||
//! lr = 0x8000443,
|
|
||||||
//! pc = 0x8000190,
|
|
||||||
//! xpsr = 0x61000200,
|
|
||||||
//! }
|
|
||||||
//!
|
//!
|
||||||
//! (gdb) # What exception was triggered?
|
//! In the console output one will find the state of the Program Counter (PC) register at the time
|
||||||
//! (gdb) print _e
|
//! of the exception.
|
||||||
//! $2 = cortex_m::exception::Exception::HardFault
|
|
||||||
//!
|
//!
|
||||||
//! (gdb) # Where did we come from?
|
//! ``` text
|
||||||
//! (gdb) print _e
|
//! panicked at 'HardFault at ExceptionFrame {
|
||||||
|
//! r0: 0x2fffffff,
|
||||||
|
//! r1: 0x2fffffff,
|
||||||
|
//! r2: 0x080051d4,
|
||||||
|
//! r3: 0x080051d4,
|
||||||
|
//! r12: 0x20000000,
|
||||||
|
//! lr: 0x08000435,
|
||||||
|
//! pc: 0x08000ab6,
|
||||||
|
//! xpsr: 0x61000000
|
||||||
|
//! }', examples/crash.rs:106:5
|
||||||
//! ```
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This register contains the address of the instruction that caused the exception. In GDB one can
|
||||||
|
//! disassemble the program around this address to observe the instruction that caused the
|
||||||
|
//! exception.
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! (gdb) disassemble/m 0x08000ab6
|
||||||
|
//! Dump of assembler code for function core::ptr::read_volatile:
|
||||||
|
//! 451 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||||
|
//! 0x08000aae <+0>: sub sp, #16
|
||||||
|
//! 0x08000ab0 <+2>: mov r1, r0
|
||||||
|
//! 0x08000ab2 <+4>: str r0, [sp, #8]
|
||||||
|
//!
|
||||||
|
//! 452 intrinsics::volatile_load(src)
|
||||||
|
//! 0x08000ab4 <+6>: ldr r0, [sp, #8]
|
||||||
|
//! -> 0x08000ab6 <+8>: ldr r0, [r0, #0]
|
||||||
|
//! 0x08000ab8 <+10>: str r0, [sp, #12]
|
||||||
|
//! 0x08000aba <+12>: ldr r0, [sp, #12]
|
||||||
|
//! 0x08000abc <+14>: str r1, [sp, #4]
|
||||||
|
//! 0x08000abe <+16>: str r0, [sp, #0]
|
||||||
|
//! 0x08000ac0 <+18>: b.n 0x8000ac2 <core::ptr::read_volatile+20>
|
||||||
|
//!
|
||||||
|
//! 453 }
|
||||||
|
//! 0x08000ac2 <+20>: ldr r0, [sp, #0]
|
||||||
|
//! 0x08000ac4 <+22>: add sp, #16
|
||||||
|
//! 0x08000ac6 <+24>: bx lr
|
||||||
|
//!
|
||||||
|
//! End of assembler dump.
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word
|
||||||
|
//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame`
|
||||||
|
//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt;
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
use cortex_m::asm;
|
use rt::ExceptionFrame;
|
||||||
|
|
||||||
fn main() {
|
entry!(main);
|
||||||
// Read an invalid memory address
|
|
||||||
|
fn main() -> ! {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
// read an address outside of the RAM region; causes a HardFault exception
|
||||||
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
// define the hard fault handler
|
||||||
#[allow(dead_code)]
|
exception!(HardFault, hard_fault);
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
asm::bkpt();
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the default exception handler
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
}
|
}
|
||||||
|
|||||||
89
examples/device.rs
Normal file
89
examples/device.rs
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
//! Using a device crate
|
||||||
|
//!
|
||||||
|
//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an
|
||||||
|
//! API to access the peripherals of a device.
|
||||||
|
//!
|
||||||
|
//! [`svd2rust`]: https://crates.io/crates/svd2rust
|
||||||
|
//!
|
||||||
|
//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt
|
||||||
|
//! handlers.
|
||||||
|
//!
|
||||||
|
//! This example depends on the [`stm32f103xx`] crate so you'll have to add it to your Cargo.toml.
|
||||||
|
//!
|
||||||
|
//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! $ edit Cargo.toml && tail $_
|
||||||
|
//! [dependencies.stm32f103xx]
|
||||||
|
//! features = ["rt"]
|
||||||
|
//! version = "0.10.0"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate cortex_m;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
extern crate cortex_m_semihosting as sh;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate stm32f103xx;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
use sh::hio::{self, HStdout};
|
||||||
|
use stm32f103xx::Interrupt;
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
let p = cortex_m::Peripherals::take().unwrap();
|
||||||
|
|
||||||
|
let mut syst = p.SYST;
|
||||||
|
let mut nvic = p.NVIC;
|
||||||
|
|
||||||
|
nvic.enable(Interrupt::EXTI0);
|
||||||
|
|
||||||
|
// configure the system timer to wrap around every second
|
||||||
|
syst.set_clock_source(SystClkSource::Core);
|
||||||
|
syst.set_reload(8_000_000); // 1s
|
||||||
|
syst.enable_counter();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
// busy wait until the timer wraps around
|
||||||
|
while !syst.has_wrapped() {}
|
||||||
|
|
||||||
|
// trigger the `EXTI0` interrupt
|
||||||
|
nvic.set_pending(Interrupt::EXTI0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try commenting out this line: you'll end in `default_handler` instead of in `exti0`
|
||||||
|
interrupt!(EXTI0, exti0, state: Option<HStdout> = None);
|
||||||
|
|
||||||
|
fn exti0(state: &mut Option<HStdout>) {
|
||||||
|
if state.is_none() {
|
||||||
|
*state = Some(hio::hstdout().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(hstdout) = state.as_mut() {
|
||||||
|
hstdout.write_str(".").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(HardFault, hard_fault);
|
||||||
|
|
||||||
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
}
|
||||||
64
examples/exception.rs
Normal file
64
examples/exception.rs
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
//! Overriding an exception handler
|
||||||
|
//!
|
||||||
|
//! You can override an exception handler using the [`exception!`][1] macro.
|
||||||
|
//!
|
||||||
|
//! [1]: https://docs.rs/cortex-m-rt/0.5.0/cortex_m_rt/macro.exception.html
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
|
#![deny(unsafe_code)]
|
||||||
|
#![no_main]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate cortex_m;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
extern crate cortex_m_semihosting as sh;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
|
use cortex_m::Peripherals;
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
use sh::hio::{self, HStdout};
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
let p = Peripherals::take().unwrap();
|
||||||
|
let mut syst = p.SYST;
|
||||||
|
|
||||||
|
// configures the system timer to trigger a SysTick exception every second
|
||||||
|
syst.set_clock_source(SystClkSource::Core);
|
||||||
|
syst.set_reload(8_000_000); // period = 1s
|
||||||
|
syst.enable_counter();
|
||||||
|
syst.enable_interrupt();
|
||||||
|
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try commenting out this line: you'll end in `default_handler` instead of in `sys_tick`
|
||||||
|
exception!(SysTick, sys_tick, state: Option<HStdout> = None);
|
||||||
|
|
||||||
|
fn sys_tick(state: &mut Option<HStdout>) {
|
||||||
|
if state.is_none() {
|
||||||
|
*state = Some(hio::hstdout().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(hstdout) = state.as_mut() {
|
||||||
|
hstdout.write_str(".").unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(HardFault, hard_fault);
|
||||||
|
|
||||||
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
}
|
||||||
@@ -1,24 +1,37 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cortex_m;
|
extern crate cortex_m_rt as rt;
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_semihosting as sh;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m::asm;
|
use core::fmt::Write;
|
||||||
|
|
||||||
fn main() {
|
use rt::ExceptionFrame;
|
||||||
hprintln!("Hello, world!");
|
use sh::hio;
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
let mut stdout = hio::hstdout().unwrap();
|
||||||
|
writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
|
||||||
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
exception!(HardFault, hard_fault);
|
||||||
#[allow(dead_code)]
|
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
asm::bkpt();
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,41 +1,54 @@
|
|||||||
//! Sends "Hello, world!" through the ITM port 0
|
//! Sends "Hello, world!" through the ITM port 0
|
||||||
//!
|
//!
|
||||||
//! **IMPORTANT** Not all Cortex-M chips support ITM. You'll have to connect the
|
|
||||||
//! microcontroller's SWO pin to the SWD interface. Note that some development
|
|
||||||
//! boards don't provide this option.
|
|
||||||
//!
|
|
||||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
||||||
//!
|
//!
|
||||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need
|
//! **NOTE** Cortex-M0 chips don't support ITM.
|
||||||
//! to uncomment OpenOCD's ITM support in `.gdbinit`.
|
|
||||||
//!
|
//!
|
||||||
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
//! You'll have to connect the microcontroller's SWO pin to the SWD interface. Note that some
|
||||||
|
//! development boards don't provide this option.
|
||||||
|
//!
|
||||||
|
//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two
|
||||||
|
//! `monitor` commands in the `.gdbinit` file.
|
||||||
|
//!
|
||||||
|
//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
|
||||||
#![feature(used)]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt;
|
#[macro_use]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
use cortex_m::{asm, interrupt, peripheral};
|
use cortex_m::{asm, Peripherals};
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
|
||||||
fn main() {
|
entry!(main);
|
||||||
interrupt::free(
|
|
||||||
|cs| {
|
|
||||||
let itm = peripheral::ITM.borrow(&cs);
|
|
||||||
|
|
||||||
iprintln!(&itm.stim[0], "Hello, world!");
|
fn main() -> ! {
|
||||||
},
|
let mut p = Peripherals::take().unwrap();
|
||||||
);
|
let stim = &mut p.ITM.stim[0];
|
||||||
|
|
||||||
|
iprintln!(stim, "Hello, world!");
|
||||||
|
|
||||||
|
loop {
|
||||||
|
asm::bkpt();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
// define the hard fault handler
|
||||||
#[allow(dead_code)]
|
exception!(HardFault, hard_fault);
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
asm::bkpt();
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the default exception handler
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
}
|
}
|
||||||
|
|||||||
63
examples/minimal.rs
Normal file
63
examples/minimal.rs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
//! Minimal Cortex-M program
|
||||||
|
//!
|
||||||
|
//! When executed this program will hit the breakpoint set in `main`.
|
||||||
|
//!
|
||||||
|
//! All Cortex-M programs need to:
|
||||||
|
//!
|
||||||
|
//! - Contain the `#![no_main]` and `#![no_std]` attributes. Embedded programs don't use the
|
||||||
|
//! standard Rust `main` interface or the Rust standard (`std`) library.
|
||||||
|
//!
|
||||||
|
//! - Define their entry point using [`entry!`] macro.
|
||||||
|
//!
|
||||||
|
//! [`entry!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro.entry.html
|
||||||
|
//!
|
||||||
|
//! - Define their panicking behavior, i.e. what happens when `panic!` is called. The easiest way to
|
||||||
|
//! define a panicking behavior is to link to a [panic handler crate][0]
|
||||||
|
//!
|
||||||
|
//! [0]: https://crates.io/keywords/panic-impl
|
||||||
|
//!
|
||||||
|
//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is
|
||||||
|
//! called when a hard fault exception is raised by the hardware.
|
||||||
|
//!
|
||||||
|
//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html
|
||||||
|
//!
|
||||||
|
//! - Define a default handler using the [`exception!`] macro. This function will be used to handle
|
||||||
|
//! all interrupts and exceptions which have not been assigned a specific handler.
|
||||||
|
|
||||||
|
#![no_main] // <- IMPORTANT!
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate cortex_m;
|
||||||
|
|
||||||
|
#[macro_use(entry, exception)]
|
||||||
|
extern crate cortex_m_rt as rt;
|
||||||
|
|
||||||
|
// makes `panic!` print messages to the host stderr using semihosting
|
||||||
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
use cortex_m::asm;
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
|
||||||
|
// the program entry point is ...
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
// ... this never ending function
|
||||||
|
fn main() -> ! {
|
||||||
|
loop {
|
||||||
|
asm::bkpt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the hard fault handler
|
||||||
|
exception!(HardFault, hard_fault);
|
||||||
|
|
||||||
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the default exception handler
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
}
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
//! Overriding an exception
|
|
||||||
//!
|
|
||||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
|
||||||
//! to make this work.
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate cortex_m;
|
|
||||||
extern crate cortex_m_rt;
|
|
||||||
|
|
||||||
use core::ptr;
|
|
||||||
|
|
||||||
use cortex_m::{asm, exception};
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
unsafe {
|
|
||||||
// Invalid memory access
|
|
||||||
ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn hard_fault(_: exception::HardFault) {
|
|
||||||
// You'll hit this breakpoint rather than the one in cortex-m-rt
|
|
||||||
asm::bkpt()
|
|
||||||
}
|
|
||||||
|
|
||||||
// When the "exceptions" feature is disabled, you'll have to provide this symbol
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.exceptions"]
|
|
||||||
static EXCEPTIONS: exception::Handlers = exception::Handlers {
|
|
||||||
// This is the exception handler override
|
|
||||||
hard_fault: hard_fault,
|
|
||||||
..exception::DEFAULT_HANDLERS
|
|
||||||
};
|
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
|
||||||
asm::bkpt();
|
|
||||||
}
|
|
||||||
@@ -1,35 +1,44 @@
|
|||||||
//! Redirecting `panic!` messages
|
//! Changing the panic handler
|
||||||
//!
|
//!
|
||||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
//! The easiest way to change the panic handler is to use a different [panic handler crate][0].
|
||||||
//! through these two Cargo features:
|
|
||||||
//!
|
//!
|
||||||
//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD
|
//! [0]: https://crates.io/keywords/panic-impl
|
||||||
//! console using semihosting. This is slow.
|
|
||||||
//!
|
//!
|
||||||
//! - `panic-over-itm`. `panic!` messages will be send through the ITM port 0.
|
//! ---
|
||||||
//! This is much faster but requires ITM support on the device.
|
|
||||||
//!
|
|
||||||
//! If neither of these options is specified then the `panic!` message will be
|
|
||||||
//! lost. Note that all `panic!`s will trigger a debugger breakpoint.
|
|
||||||
|
|
||||||
#![feature(used)]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
extern crate cortex_m;
|
#[macro_use]
|
||||||
extern crate cortex_m_rt;
|
extern crate cortex_m_rt as rt;
|
||||||
|
|
||||||
use cortex_m::asm;
|
// Pick one of these two panic handlers:
|
||||||
|
|
||||||
fn main() {
|
// Reports panic messages to the host stderr using semihosting
|
||||||
panic!("Oops");
|
extern crate panic_semihosting;
|
||||||
|
|
||||||
|
// Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
||||||
|
// NOTE to use this you need to uncomment the `panic-itm` dependency in Cargo.toml
|
||||||
|
// extern crate panic_itm;
|
||||||
|
|
||||||
|
use rt::ExceptionFrame;
|
||||||
|
|
||||||
|
entry!(main);
|
||||||
|
|
||||||
|
fn main() -> ! {
|
||||||
|
panic!("Oops")
|
||||||
}
|
}
|
||||||
|
|
||||||
// As we are not using interrupts, we just register a dummy catch all handler
|
// define the hard fault handler
|
||||||
#[allow(dead_code)]
|
exception!(HardFault, hard_fault);
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
|
|
||||||
extern "C" fn default_handler() {
|
fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
asm::bkpt();
|
panic!("HardFault at {:#?}", ef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// define the default exception handler
|
||||||
|
exception!(*, default_handler);
|
||||||
|
|
||||||
|
fn default_handler(irqn: i16) {
|
||||||
|
panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
//! Register an interrupt handler
|
|
||||||
//!
|
|
||||||
//! NOTE Requires a device crate generated using `svd2rust`
|
|
||||||
|
|
||||||
#![feature(used)]
|
|
||||||
#![no_std]
|
|
||||||
|
|
||||||
extern crate cortex_m;
|
|
||||||
extern crate cortex_m_rt;
|
|
||||||
// NOTE this is the device crate
|
|
||||||
extern crate stm32f30x;
|
|
||||||
|
|
||||||
use cortex_m::asm;
|
|
||||||
use stm32f30x::interrupt;
|
|
||||||
|
|
||||||
fn main() {}
|
|
||||||
|
|
||||||
// NOTE each interrupt handler has a different signature
|
|
||||||
extern "C" fn my_interrupt_handler(_ctxt: interrupt::Tim7) {
|
|
||||||
asm::bkpt();
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" fn another_interrupt_handler(_ctxt: interrupt::Exti0) {
|
|
||||||
asm::bkpt();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Here we override only two interrupt handlers, the rest of interrupt are
|
|
||||||
// handled by the same interrupt handler
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[used]
|
|
||||||
#[link_section = ".rodata.interrupts"]
|
|
||||||
static INTERRUPTS: interrupt::Handlers = interrupt::Handlers {
|
|
||||||
Tim7: my_interrupt_handler,
|
|
||||||
Exti0: another_interrupt_handler,
|
|
||||||
..interrupt::DEFAULT_HANDLERS
|
|
||||||
};
|
|
||||||
@@ -5,12 +5,14 @@ set -ex
|
|||||||
|
|
||||||
main() {
|
main() {
|
||||||
local examples=(
|
local examples=(
|
||||||
|
minimal
|
||||||
hello
|
hello
|
||||||
itm
|
itm
|
||||||
panic
|
panic
|
||||||
crash
|
crash
|
||||||
register-interrupt-handler
|
exception
|
||||||
override-exception-handler
|
allocator
|
||||||
|
device
|
||||||
)
|
)
|
||||||
|
|
||||||
rm -rf src/examples
|
rm -rf src/examples
|
||||||
@@ -18,7 +20,7 @@ main() {
|
|||||||
mkdir src/examples
|
mkdir src/examples
|
||||||
|
|
||||||
cat >src/examples/mod.rs <<'EOF'
|
cat >src/examples/mod.rs <<'EOF'
|
||||||
//! Examples
|
//! Examples sorted in increasing degree of complexity
|
||||||
// Auto-generated. Do not modify.
|
// Auto-generated. Do not modify.
|
||||||
EOF
|
EOF
|
||||||
|
|
||||||
|
|||||||
19
memory.x
19
memory.x
@@ -2,11 +2,22 @@ MEMORY
|
|||||||
{
|
{
|
||||||
/* NOTE K = KiBi = 1024 bytes */
|
/* NOTE K = KiBi = 1024 bytes */
|
||||||
/* TODO Adjust these memory regions to match your device memory layout */
|
/* TODO Adjust these memory regions to match your device memory layout */
|
||||||
FLASH : ORIGIN = 0xBAAAAAAD, LENGTH = 0K
|
FLASH : ORIGIN = 0x000BAAD0, LENGTH = 0K
|
||||||
RAM : ORIGIN = 0xBAAAAAAD, LENGTH = 0K
|
RAM : ORIGIN = 0xBAAD0000, LENGTH = 0K
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This is where the call stack will be allocated. */
|
/* This is where the call stack will be allocated. */
|
||||||
/* The stack is of the full descending type. */
|
/* The stack is of the full descending type. */
|
||||||
/* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
|
/* You may want to use this variable to locate the call stack and static
|
||||||
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
variables in different memory regions. Below is shown the default value */
|
||||||
|
/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */
|
||||||
|
|
||||||
|
/* You can use this symbol to customize the location of the .text section */
|
||||||
|
/* If omitted the .text section will be placed right after the .vector_table
|
||||||
|
section */
|
||||||
|
/* This is required only on microcontrollers that store some configuration right
|
||||||
|
after the vector table */
|
||||||
|
/* _stext = ORIGIN(FLASH) + 0x400; */
|
||||||
|
|
||||||
|
/* Size of the heap (in bytes) */
|
||||||
|
/* _heap_size = 1024; */
|
||||||
|
|||||||
@@ -1,28 +0,0 @@
|
|||||||
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! hprintln!("Hello, world!");
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
//!
|
|
||||||
//! extern "C" fn default_handler() {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
67
src/examples/_0_minimal.rs
Normal file
67
src/examples/_0_minimal.rs
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
//! Minimal Cortex-M program
|
||||||
|
//!
|
||||||
|
//! When executed this program will hit the breakpoint set in `main`.
|
||||||
|
//!
|
||||||
|
//! All Cortex-M programs need to:
|
||||||
|
//!
|
||||||
|
//! - Contain the `#![no_main]` and `#![no_std]` attributes. Embedded programs don't use the
|
||||||
|
//! standard Rust `main` interface or the Rust standard (`std`) library.
|
||||||
|
//!
|
||||||
|
//! - Define their entry point using [`entry!`] macro.
|
||||||
|
//!
|
||||||
|
//! [`entry!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro.entry.html
|
||||||
|
//!
|
||||||
|
//! - Define their panicking behavior, i.e. what happens when `panic!` is called. The easiest way to
|
||||||
|
//! define a panicking behavior is to link to a [panic handler crate][0]
|
||||||
|
//!
|
||||||
|
//! [0]: https://crates.io/keywords/panic-impl
|
||||||
|
//!
|
||||||
|
//! - Define the `HardFault` handler using the [`exception!`] macro. This handler (function) is
|
||||||
|
//! called when a hard fault exception is raised by the hardware.
|
||||||
|
//!
|
||||||
|
//! [`exception!`]: https://docs.rs/cortex-m-rt/~0.5/cortex_m_rt/macro..html
|
||||||
|
//!
|
||||||
|
//! - Define a default handler using the [`exception!`] macro. This function will be used to handle
|
||||||
|
//! all interrupts and exceptions which have not been assigned a specific handler.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main] // <- IMPORTANT!
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//!
|
||||||
|
//! #[macro_use(entry, exception)]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//!
|
||||||
|
//! // makes `panic!` print messages to the host stderr using semihosting
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use cortex_m::asm;
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//!
|
||||||
|
//! // the program entry point is ...
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! // ... this never ending function
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! loop {
|
||||||
|
//! asm::bkpt();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the hard fault handler
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the default exception handler
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
41
src/examples/_1_hello.rs
Normal file
41
src/examples/_1_hello.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
//! Prints "Hello, world!" on the OpenOCD console using semihosting
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate cortex_m_semihosting as sh;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
|
//!
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//! use sh::hio;
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! let mut stdout = hio::hstdout().unwrap();
|
||||||
|
//! writeln!(stdout, "Hello, world!").unwrap();
|
||||||
|
//!
|
||||||
|
//! loop {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
//! Sends "Hello, world!" through the ITM port 0
|
|
||||||
//!
|
|
||||||
//! **IMPORTANT** Not all Cortex-M chips support ITM. You'll have to connect the
|
|
||||||
//! microcontroller's SWO pin to the SWD interface. Note that some development
|
|
||||||
//! boards don't provide this option.
|
|
||||||
//!
|
|
||||||
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
|
||||||
//!
|
|
||||||
//! You'll need [`itmdump`] to receive the message on the host plus you'll need
|
|
||||||
//! to uncomment OpenOCD's ITM support in `.gdbinit`.
|
|
||||||
//!
|
|
||||||
//! [`itmdump`]: https://docs.rs/itm/0.1.1/itm/
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! #[macro_use]
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::{asm, interrupt, peripheral};
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! interrupt::free(
|
|
||||||
//! |cs| {
|
|
||||||
//! let itm = peripheral::ITM.borrow(&cs);
|
|
||||||
//!
|
|
||||||
//! iprintln!(&itm.stim[0], "Hello, world!");
|
|
||||||
//! },
|
|
||||||
//! );
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
//!
|
|
||||||
//! extern "C" fn default_handler() {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
58
src/examples/_2_itm.rs
Normal file
58
src/examples/_2_itm.rs
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
//! Sends "Hello, world!" through the ITM port 0
|
||||||
|
//!
|
||||||
|
//! ITM is much faster than semihosting. Like 4 orders of magnitude or so.
|
||||||
|
//!
|
||||||
|
//! **NOTE** Cortex-M0 chips don't support ITM.
|
||||||
|
//!
|
||||||
|
//! You'll have to connect the microcontroller's SWO pin to the SWD interface. Note that some
|
||||||
|
//! development boards don't provide this option.
|
||||||
|
//!
|
||||||
|
//! You'll need [`itmdump`] to receive the message on the host plus you'll need to uncomment two
|
||||||
|
//! `monitor` commands in the `.gdbinit` file.
|
||||||
|
//!
|
||||||
|
//! [`itmdump`]: https://docs.rs/itm/0.2.1/itm/
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use cortex_m::{asm, Peripherals};
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! let mut p = Peripherals::take().unwrap();
|
||||||
|
//! let stim = &mut p.ITM.stim[0];
|
||||||
|
//!
|
||||||
|
//! iprintln!(stim, "Hello, world!");
|
||||||
|
//!
|
||||||
|
//! loop {
|
||||||
|
//! asm::bkpt();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the hard fault handler
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the default exception handler
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
//! Redirecting `panic!` messages
|
|
||||||
//!
|
|
||||||
//! The `cortex-m-rt` crate provides two options to redirect `panic!` messages
|
|
||||||
//! through these two Cargo features:
|
|
||||||
//!
|
|
||||||
//! - `panic-over-semihosting`. `panic!` messages will be printed to the OpenOCD
|
|
||||||
//! console using semihosting. This is slow.
|
|
||||||
//!
|
|
||||||
//! - `panic-over-itm`. `panic!` messages will be send through the ITM port 0.
|
|
||||||
//! This is much faster but requires ITM support on the device.
|
|
||||||
//!
|
|
||||||
//! If neither of these options is specified then the `panic!` message will be
|
|
||||||
//! lost. Note that all `panic!`s will trigger a debugger breakpoint.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! panic!("Oops");
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
//!
|
|
||||||
//! extern "C" fn default_handler() {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
@@ -1,62 +0,0 @@
|
|||||||
//! Debugging a crash (exception)
|
|
||||||
//!
|
|
||||||
//! The `cortex-m-rt` crate provides functionality for this through a default
|
|
||||||
//! exception handler. When an exception is hit, the default handler will
|
|
||||||
//! trigger a breakpoint and in this debugging context the stacked registers
|
|
||||||
//! are accessible.
|
|
||||||
//!
|
|
||||||
//! In you run the example below, you'll be able to inspect the state of your
|
|
||||||
//! program under the debugger using these commands:
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//! (gdb) # Stacked registers = program state during the crash
|
|
||||||
//! (gdb) print/x *_sr
|
|
||||||
//! $1 = cortex_m::exception::StackedRegisters {
|
|
||||||
//! r0 = 0x2fffffff,
|
|
||||||
//! r1 = 0x2fffffff,
|
|
||||||
//! r2 = 0x0,
|
|
||||||
//! r3 = 0x0,
|
|
||||||
//! r12 = 0x0,
|
|
||||||
//! lr = 0x8000443,
|
|
||||||
//! pc = 0x8000190,
|
|
||||||
//! xpsr = 0x61000200,
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! (gdb) # What exception was triggered?
|
|
||||||
//! (gdb) print _e
|
|
||||||
//! $2 = cortex_m::exception::Exception::HardFault
|
|
||||||
//!
|
|
||||||
//! (gdb) # Where did we come from?
|
|
||||||
//! (gdb) print _e
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//!
|
|
||||||
//! use core::ptr;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! // Read an invalid memory address
|
|
||||||
//! unsafe {
|
|
||||||
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
//!
|
|
||||||
//! extern "C" fn default_handler() {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
47
src/examples/_3_panic.rs
Normal file
47
src/examples/_3_panic.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
//! Changing the panic handler
|
||||||
|
//!
|
||||||
|
//! The easiest way to change the panic handler is to use a different [panic handler crate][0].
|
||||||
|
//!
|
||||||
|
//! [0]: https://crates.io/keywords/panic-impl
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//!
|
||||||
|
//! // Pick one of these two panic handlers:
|
||||||
|
//!
|
||||||
|
//! // Reports panic messages to the host stderr using semihosting
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! // Logs panic messages using the ITM (Instrumentation Trace Macrocell)
|
||||||
|
//! // extern crate panic_itm;
|
||||||
|
//!
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! panic!("Oops")
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the hard fault handler
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the default exception handler
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
118
src/examples/_4_crash.rs
Normal file
118
src/examples/_4_crash.rs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
//! Debugging a crash (exception)
|
||||||
|
//!
|
||||||
|
//! Most crash conditions trigger a hard fault exception, whose handler is defined via
|
||||||
|
//! `exception!(HardFault, ..)`. The `HardFault` handler has access to the exception frame, a
|
||||||
|
//! snapshot of the CPU registers at the moment of the exception.
|
||||||
|
//!
|
||||||
|
//! This program crashes and the `HardFault` handler prints to the console the contents of the
|
||||||
|
//! `ExceptionFrame` and then triggers a breakpoint. From that breakpoint one can see the backtrace
|
||||||
|
//! that led to the exception.
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! (gdb) continue
|
||||||
|
//! Program received signal SIGTRAP, Trace/breakpoint trap.
|
||||||
|
//! __bkpt () at asm/bkpt.s:3
|
||||||
|
//! 3 bkpt
|
||||||
|
//!
|
||||||
|
//! (gdb) backtrace
|
||||||
|
//! #0 __bkpt () at asm/bkpt.s:3
|
||||||
|
//! #1 0x080030b4 in cortex_m::asm::bkpt () at $$/cortex-m-0.5.0/src/asm.rs:19
|
||||||
|
//! #2 rust_begin_unwind (args=..., file=..., line=99, col=5) at $$/panic-semihosting-0.2.0/src/lib.rs:87
|
||||||
|
//! #3 0x08001d06 in core::panicking::panic_fmt () at libcore/panicking.rs:71
|
||||||
|
//! #4 0x080004a6 in crash::hard_fault (ef=0x20004fa0) at examples/crash.rs:99
|
||||||
|
//! #5 0x08000548 in UserHardFault (ef=0x20004fa0) at <exception macros>:10
|
||||||
|
//! #6 0x0800093a in HardFault () at asm.s:5
|
||||||
|
//! Backtrace stopped: previous frame identical to this frame (corrupt stack?)
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! In the console output one will find the state of the Program Counter (PC) register at the time
|
||||||
|
//! of the exception.
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! panicked at 'HardFault at ExceptionFrame {
|
||||||
|
//! r0: 0x2fffffff,
|
||||||
|
//! r1: 0x2fffffff,
|
||||||
|
//! r2: 0x080051d4,
|
||||||
|
//! r3: 0x080051d4,
|
||||||
|
//! r12: 0x20000000,
|
||||||
|
//! lr: 0x08000435,
|
||||||
|
//! pc: 0x08000ab6,
|
||||||
|
//! xpsr: 0x61000000
|
||||||
|
//! }', examples/crash.rs:106:5
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! This register contains the address of the instruction that caused the exception. In GDB one can
|
||||||
|
//! disassemble the program around this address to observe the instruction that caused the
|
||||||
|
//! exception.
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! (gdb) disassemble/m 0x08000ab6
|
||||||
|
//! Dump of assembler code for function core::ptr::read_volatile:
|
||||||
|
//! 451 pub unsafe fn read_volatile<T>(src: *const T) -> T {
|
||||||
|
//! 0x08000aae <+0>: sub sp, #16
|
||||||
|
//! 0x08000ab0 <+2>: mov r1, r0
|
||||||
|
//! 0x08000ab2 <+4>: str r0, [sp, #8]
|
||||||
|
//!
|
||||||
|
//! 452 intrinsics::volatile_load(src)
|
||||||
|
//! 0x08000ab4 <+6>: ldr r0, [sp, #8]
|
||||||
|
//! -> 0x08000ab6 <+8>: ldr r0, [r0, #0]
|
||||||
|
//! 0x08000ab8 <+10>: str r0, [sp, #12]
|
||||||
|
//! 0x08000aba <+12>: ldr r0, [sp, #12]
|
||||||
|
//! 0x08000abc <+14>: str r1, [sp, #4]
|
||||||
|
//! 0x08000abe <+16>: str r0, [sp, #0]
|
||||||
|
//! 0x08000ac0 <+18>: b.n 0x8000ac2 <core::ptr::read_volatile+20>
|
||||||
|
//!
|
||||||
|
//! 453 }
|
||||||
|
//! 0x08000ac2 <+20>: ldr r0, [sp, #0]
|
||||||
|
//! 0x08000ac4 <+22>: add sp, #16
|
||||||
|
//! 0x08000ac6 <+24>: bx lr
|
||||||
|
//!
|
||||||
|
//! End of assembler dump.
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! `ldr r0, [r0, #0]` caused the exception. This instruction tried to load (read) a 32-bit word
|
||||||
|
//! from the address stored in the register `r0`. Looking again at the contents of `ExceptionFrame`
|
||||||
|
//! we see that the `r0` contained the address `0x2FFF_FFFF` when this instruction was executed.
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::ptr;
|
||||||
|
//!
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! unsafe {
|
||||||
|
//! // read an address outside of the RAM region; causes a HardFault exception
|
||||||
|
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! loop {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the hard fault handler
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define the default exception handler
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
//! Register an interrupt handler
|
|
||||||
//!
|
|
||||||
//! NOTE Requires a device crate generated using `svd2rust`
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//! // NOTE this is the device crate
|
|
||||||
//! extern crate stm32f30x;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::asm;
|
|
||||||
//! use stm32f30x::interrupt;
|
|
||||||
//!
|
|
||||||
//! fn main() {}
|
|
||||||
//!
|
|
||||||
//! // NOTE each interrupt handler has a different signature
|
|
||||||
//! extern "C" fn my_interrupt_handler(_ctxt: interrupt::Tim7) {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! extern "C" fn another_interrupt_handler(_ctxt: interrupt::Exti0) {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // Here we override only two interrupt handlers, the rest of interrupt are
|
|
||||||
//! // handled by the same interrupt handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: interrupt::Handlers = interrupt::Handlers {
|
|
||||||
//! Tim7: my_interrupt_handler,
|
|
||||||
//! Exti0: another_interrupt_handler,
|
|
||||||
//! ..interrupt::DEFAULT_HANDLERS
|
|
||||||
//! };
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
68
src/examples/_5_exception.rs
Normal file
68
src/examples/_5_exception.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
//! Overriding an exception handler
|
||||||
|
//!
|
||||||
|
//! You can override an exception handler using the [`exception!`][1] macro.
|
||||||
|
//!
|
||||||
|
//! [1]: https://docs.rs/cortex-m-rt/0.5.0/cortex_m_rt/macro.exception.html
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![deny(unsafe_code)]
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate cortex_m_semihosting as sh;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
|
//!
|
||||||
|
//! use cortex_m::peripheral::syst::SystClkSource;
|
||||||
|
//! use cortex_m::Peripherals;
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//! use sh::hio::{self, HStdout};
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! let p = Peripherals::take().unwrap();
|
||||||
|
//! let mut syst = p.SYST;
|
||||||
|
//!
|
||||||
|
//! // configures the system timer to trigger a SysTick exception every second
|
||||||
|
//! syst.set_clock_source(SystClkSource::Core);
|
||||||
|
//! syst.set_reload(8_000_000); // period = 1s
|
||||||
|
//! syst.enable_counter();
|
||||||
|
//! syst.enable_interrupt();
|
||||||
|
//!
|
||||||
|
//! loop {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // try commenting out this line: you'll end in `default_handler` instead of in `sys_tick`
|
||||||
|
//! exception!(SysTick, sys_tick, state: Option<HStdout> = None);
|
||||||
|
//!
|
||||||
|
//! fn sys_tick(state: &mut Option<HStdout>) {
|
||||||
|
//! if state.is_none() {
|
||||||
|
//! *state = Some(hio::hstdout().unwrap());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! if let Some(hstdout) = state.as_mut() {
|
||||||
|
//! hstdout.write_str(".").unwrap();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
//! Overriding an exception
|
|
||||||
//!
|
|
||||||
//! **NOTE** You have to disable the `cortex-m-rt` crate's "exceptions" feature
|
|
||||||
//! to make this work.
|
|
||||||
//!
|
|
||||||
//! ```
|
|
||||||
//!
|
|
||||||
//! #![feature(used)]
|
|
||||||
//! #![no_std]
|
|
||||||
//!
|
|
||||||
//! extern crate cortex_m;
|
|
||||||
//! extern crate cortex_m_rt;
|
|
||||||
//!
|
|
||||||
//! use core::ptr;
|
|
||||||
//!
|
|
||||||
//! use cortex_m::{asm, exception};
|
|
||||||
//!
|
|
||||||
//! fn main() {
|
|
||||||
//! unsafe {
|
|
||||||
//! // Invalid memory access
|
|
||||||
//! ptr::read_volatile(0x2FFF_FFFF as *const u32);
|
|
||||||
//! }
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! extern "C" fn hard_fault(_: exception::HardFault) {
|
|
||||||
//! // You'll hit this breakpoint rather than the one in cortex-m-rt
|
|
||||||
//! asm::bkpt()
|
|
||||||
//! }
|
|
||||||
//!
|
|
||||||
//! // When the "exceptions" feature is disabled, you'll have to provide this symbol
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.exceptions"]
|
|
||||||
//! static EXCEPTIONS: exception::Handlers = exception::Handlers {
|
|
||||||
//! // This is the exception handler override
|
|
||||||
//! hard_fault: hard_fault,
|
|
||||||
//! ..exception::DEFAULT_HANDLERS
|
|
||||||
//! };
|
|
||||||
//!
|
|
||||||
//! // As we are not using interrupts, we just register a dummy catch all handler
|
|
||||||
//! #[allow(dead_code)]
|
|
||||||
//! #[used]
|
|
||||||
//! #[link_section = ".rodata.interrupts"]
|
|
||||||
//! static INTERRUPTS: [extern "C" fn(); 240] = [default_handler; 240];
|
|
||||||
//!
|
|
||||||
//! extern "C" fn default_handler() {
|
|
||||||
//! asm::bkpt();
|
|
||||||
//! }
|
|
||||||
//! ```
|
|
||||||
// Auto-generated. Do not modify.
|
|
||||||
79
src/examples/_6_allocator.rs
Normal file
79
src/examples/_6_allocator.rs
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//! How to use the heap and a dynamic memory allocator
|
||||||
|
//!
|
||||||
|
//! This example depends on the alloc-cortex-m crate so you'll have to add it to your Cargo.toml:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! # or edit the Cargo.toml file manually
|
||||||
|
//! $ cargo add alloc-cortex-m
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![feature(alloc)]
|
||||||
|
//! #![feature(global_allocator)]
|
||||||
|
//! #![feature(lang_items)]
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! // This is the allocator crate; you can use a different one
|
||||||
|
//! extern crate alloc_cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate alloc;
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate cortex_m_semihosting as sh;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
|
//!
|
||||||
|
//! use alloc_cortex_m::CortexMHeap;
|
||||||
|
//! use cortex_m::asm;
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//! use sh::hio;
|
||||||
|
//!
|
||||||
|
//! // this is the allocator the application will use
|
||||||
|
//! #[global_allocator]
|
||||||
|
//! static ALLOCATOR: CortexMHeap = CortexMHeap::empty();
|
||||||
|
//!
|
||||||
|
//! const HEAP_SIZE: usize = 1024; // in bytes
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! // Initialize the allocator BEFORE you use it
|
||||||
|
//! unsafe { ALLOCATOR.init(rt::heap_start() as usize, HEAP_SIZE) }
|
||||||
|
//!
|
||||||
|
//! // Growable array allocated on the heap
|
||||||
|
//! let xs = vec![0, 1, 2];
|
||||||
|
//!
|
||||||
|
//! let mut stdout = hio::hstdout().unwrap();
|
||||||
|
//! writeln!(stdout, "{:?}", xs).unwrap();
|
||||||
|
//!
|
||||||
|
//! loop {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // define what happens in an Out Of Memory (OOM) condition
|
||||||
|
//! #[lang = "oom"]
|
||||||
|
//! #[no_mangle]
|
||||||
|
//! pub fn rust_oom() -> ! {
|
||||||
|
//! asm::bkpt();
|
||||||
|
//!
|
||||||
|
//! loop {}
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
93
src/examples/_7_device.rs
Normal file
93
src/examples/_7_device.rs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
//! Using a device crate
|
||||||
|
//!
|
||||||
|
//! Crates generated using [`svd2rust`] are referred to as device crates. These crates provide an
|
||||||
|
//! API to access the peripherals of a device.
|
||||||
|
//!
|
||||||
|
//! [`svd2rust`]: https://crates.io/crates/svd2rust
|
||||||
|
//!
|
||||||
|
//! Device crates also provide an `interrupt!` macro (behind the "rt" feature) to register interrupt
|
||||||
|
//! handlers.
|
||||||
|
//!
|
||||||
|
//! This example depends on the [`stm32f103xx`] crate so you'll have to add it to your Cargo.toml.
|
||||||
|
//!
|
||||||
|
//! [`stm32f103xx`]: https://crates.io/crates/stm32f103xx
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! $ edit Cargo.toml && tail $_
|
||||||
|
//! [dependencies.stm32f103xx]
|
||||||
|
//! features = ["rt"]
|
||||||
|
//! version = "0.10.0"
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ---
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #![no_main]
|
||||||
|
//! #![no_std]
|
||||||
|
//!
|
||||||
|
//! extern crate cortex_m;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate cortex_m_rt as rt;
|
||||||
|
//! extern crate cortex_m_semihosting as sh;
|
||||||
|
//! #[macro_use]
|
||||||
|
//! extern crate stm32f103xx;
|
||||||
|
//! extern crate panic_semihosting;
|
||||||
|
//!
|
||||||
|
//! use core::fmt::Write;
|
||||||
|
//!
|
||||||
|
//! use cortex_m::peripheral::syst::SystClkSource;
|
||||||
|
//! use rt::ExceptionFrame;
|
||||||
|
//! use sh::hio::{self, HStdout};
|
||||||
|
//! use stm32f103xx::Interrupt;
|
||||||
|
//!
|
||||||
|
//! entry!(main);
|
||||||
|
//!
|
||||||
|
//! fn main() -> ! {
|
||||||
|
//! let p = cortex_m::Peripherals::take().unwrap();
|
||||||
|
//!
|
||||||
|
//! let mut syst = p.SYST;
|
||||||
|
//! let mut nvic = p.NVIC;
|
||||||
|
//!
|
||||||
|
//! nvic.enable(Interrupt::EXTI0);
|
||||||
|
//!
|
||||||
|
//! // configure the system timer to wrap around every second
|
||||||
|
//! syst.set_clock_source(SystClkSource::Core);
|
||||||
|
//! syst.set_reload(8_000_000); // 1s
|
||||||
|
//! syst.enable_counter();
|
||||||
|
//!
|
||||||
|
//! loop {
|
||||||
|
//! // busy wait until the timer wraps around
|
||||||
|
//! while !syst.has_wrapped() {}
|
||||||
|
//!
|
||||||
|
//! // trigger the `EXTI0` interrupt
|
||||||
|
//! nvic.set_pending(Interrupt::EXTI0);
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! // try commenting out this line: you'll end in `default_handler` instead of in `exti0`
|
||||||
|
//! interrupt!(EXTI0, exti0, state: Option<HStdout> = None);
|
||||||
|
//!
|
||||||
|
//! fn exti0(state: &mut Option<HStdout>) {
|
||||||
|
//! if state.is_none() {
|
||||||
|
//! *state = Some(hio::hstdout().unwrap());
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! if let Some(hstdout) = state.as_mut() {
|
||||||
|
//! hstdout.write_str(".").unwrap();
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(HardFault, hard_fault);
|
||||||
|
//!
|
||||||
|
//! fn hard_fault(ef: &ExceptionFrame) -> ! {
|
||||||
|
//! panic!("HardFault at {:#?}", ef);
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! exception!(*, default_handler);
|
||||||
|
//!
|
||||||
|
//! fn default_handler(irqn: i16) {
|
||||||
|
//! panic!("Unhandled exception (IRQn = {})", irqn);
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
// Auto-generated. Do not modify.
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
//! Examples
|
//! Examples sorted in increasing degree of complexity
|
||||||
// Auto-generated. Do not modify.
|
// Auto-generated. Do not modify.
|
||||||
pub mod _0_hello;
|
pub mod _0_minimal;
|
||||||
pub mod _1_itm;
|
pub mod _1_hello;
|
||||||
pub mod _2_panic;
|
pub mod _2_itm;
|
||||||
pub mod _3_crash;
|
pub mod _3_panic;
|
||||||
pub mod _4_register_interrupt_handler;
|
pub mod _4_crash;
|
||||||
pub mod _5_override_exception_handler;
|
pub mod _5_exception;
|
||||||
|
pub mod _6_allocator;
|
||||||
|
pub mod _7_device;
|
||||||
|
|||||||
298
src/lib.rs
298
src/lib.rs
@@ -1,14 +1,36 @@
|
|||||||
//! A template for building applications for ARM Cortex-M microcontrollers
|
//! A template for building applications for ARM Cortex-M microcontrollers
|
||||||
//!
|
//!
|
||||||
|
//! # Dependencies
|
||||||
|
//!
|
||||||
|
//! - Nightly Rust toolchain newer than `nightly-2018-04-08`: `rustup default nightly`
|
||||||
|
//! - Cargo `clone` subcommand: `cargo install cargo-clone`
|
||||||
|
//! - ARM toolchain: `sudo apt-get install gcc-arm-none-eabi` (on Ubuntu)
|
||||||
|
//! - GDB: `sudo apt-get install gdb-arm-none-eabi` (on Ubuntu)
|
||||||
|
//! - OpenOCD: `sudo apt-get install OpenOCD` (on Ubuntu)
|
||||||
|
//! - [Optional] Cargo `add` subcommand: `cargo install cargo-edit`
|
||||||
|
//!
|
||||||
//! # Usage
|
//! # Usage
|
||||||
//!
|
//!
|
||||||
//! - Clone this crate
|
//! 0) Figure out the cross compilation *target* to use.
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! - Use `thumbv6m-none-eabi` for ARM Cortex-M0 and Cortex-M0+
|
||||||
//! $ cargo clone cortex-m-quickstart && cd $_
|
//! - Use `thumbv7m-none-eabi` for ARM Cortex-M3
|
||||||
|
//! - Use `thumbv7em-none-eabi` for ARM Cortex-M4 and Cortex-M7 (*no* FPU support)
|
||||||
|
//! - Use `thumbv7em-none-eabihf` for ARM Cortex-M4**F** and Cortex-M7**F** (*with* FPU support)
|
||||||
|
//!
|
||||||
|
//! 1) Install the `rust-std` component for your target, if you haven't done so already
|
||||||
|
//!
|
||||||
|
//! ``` console
|
||||||
|
//! $ rustup target add thumbv7em-none-eabihf
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Change the crate name, author and version
|
//! 2) Clone this crate
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo clone cortex-m-quickstart --vers 0.3.0
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! 3) Change the crate name, author and version
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! $ edit Cargo.toml && head $_
|
//! $ edit Cargo.toml && head $_
|
||||||
@@ -18,28 +40,25 @@
|
|||||||
//! version = "0.1.0"
|
//! version = "0.1.0"
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Specify the memory layout of the target device
|
//! 4) Specify the memory layout of the target device
|
||||||
//!
|
//!
|
||||||
//! (Note that some board support crates may provide this file for you (check
|
//! **NOTE** board support crates sometimes provide this file for you (check the crate
|
||||||
//! the crate documentation). If you are using one that does that then remove
|
//! documentation). If you are using one that does then remove *both* `memory.x` and `build.rs` from
|
||||||
//! *both* the `memory.x` and `build.rs` files.)
|
//! the root of this crate.
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! $ edit memory.x && cat $_
|
//! $ cat >memory.x <<'EOF'
|
||||||
//! MEMORY
|
//! MEMORY
|
||||||
//! {
|
//! {
|
||||||
//! /* NOTE K = KiBi = 1024 bytes */
|
//! /* NOTE K = KiBi = 1024 bytes */
|
||||||
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
//! FLASH : ORIGIN = 0x08000000, LENGTH = 256K
|
||||||
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
//! RAM : ORIGIN = 0x20000000, LENGTH = 40K
|
||||||
//! }
|
//! }
|
||||||
//!
|
//! EOF
|
||||||
//! /* This is where the call stack will be allocated. */
|
|
||||||
//! /* The stack is of the full descending type. */
|
|
||||||
//! /* NOTE Do NOT modify `_stack_start` unless you know what you are doing */
|
|
||||||
//! _stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Optionally, set a default build target
|
//! 5) Optionally, set a default build target. This way you don't have to pass `--target` to each
|
||||||
|
//! Cargo invocation.
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! $ cat >>.cargo/config <<'EOF'
|
//! $ cat >>.cargo/config <<'EOF'
|
||||||
@@ -48,31 +67,31 @@
|
|||||||
//! EOF
|
//! EOF
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Very likely, depend on a device or a BSP (Board Support Package) crate.
|
//! 6) Optionally, depend on a device, HAL implementation or a board support crate.
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! # add a device crate, or
|
//! $ # add a device crate, OR
|
||||||
//! $ cargo add stm32f30x
|
//! $ cargo add stm32f30x
|
||||||
//!
|
//!
|
||||||
//! # add a board support crate
|
//! $ # add a HAL implementation crate, OR
|
||||||
|
//! $ cargo add stm32f30x-hal
|
||||||
|
//!
|
||||||
|
//! $ # add a board support crate
|
||||||
//! $ cargo add f3
|
//! $ cargo add f3
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Write the application or start from one of the examples
|
//! 7) Write the application or start from one of the examples
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! $ rm -r src/* && cp examples/hello.rs src/main.rs
|
//! $ rm -r src/* && cp examples/hello.rs src/main.rs
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! - Build the application
|
//! 8) Build the application
|
||||||
//!
|
//!
|
||||||
//! ``` text
|
//! ``` text
|
||||||
//! # if not installed
|
//! $ cargo build --release
|
||||||
//! $ cargo install xargo
|
|
||||||
//!
|
|
||||||
//! # NOTE this command requires `arm-none-eabi-ld` to be in $PATH
|
|
||||||
//! $ xargo build --release
|
|
||||||
//!
|
//!
|
||||||
|
//! $ # sanity check
|
||||||
//! $ arm-none-eabi-readelf -A target/thumbv7em-none-eabihf/release/demo
|
//! $ arm-none-eabi-readelf -A target/thumbv7em-none-eabihf/release/demo
|
||||||
//! Attribute Section: aeabi
|
//! Attribute Section: aeabi
|
||||||
//! File Attributes
|
//! File Attributes
|
||||||
@@ -95,9 +114,236 @@
|
|||||||
//! Tag_ABI_FP_16bit_format: IEEE 754
|
//! Tag_ABI_FP_16bit_format: IEEE 754
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
|
//! 9) Flash and debug the program
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ # Launch OpenOCD on a terminal
|
||||||
|
//! $ openocd -f (..)
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ # Start a debug session in another terminal
|
||||||
|
//! $ arm-none-eabi-gdb target/thumbv7em-none-eabihf/release/demo
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Alternatively, you can use `cargo run` to build, flash and debug the program in a single step.
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo run --example hello
|
||||||
|
//! > # drops you into a GDB session
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//! # Examples
|
//! # Examples
|
||||||
//!
|
//!
|
||||||
//! Check the [examples module](./examples/index.html)
|
//! Check the [examples module][examples]
|
||||||
|
//!
|
||||||
|
//! [examples]: ./examples/index.html
|
||||||
|
//!
|
||||||
|
//! # Troubleshooting
|
||||||
|
//!
|
||||||
|
//! This section contains fixes for common errors encountered when the
|
||||||
|
//! `cortex-m-quickstart` template is misused.
|
||||||
|
//!
|
||||||
|
//! ## Used the standard `main` interface
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo)
|
||||||
|
//!
|
||||||
|
//! error: requires `start` lang_item
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Use `#![no_main]` and `entry!` as shown in the [examples].
|
||||||
|
//!
|
||||||
|
//! ## Forgot to launch an OpenOCD instance
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ arm-none-eabi-gdb target/..
|
||||||
|
//! Reading symbols from hello...done.
|
||||||
|
//! .gdbinit:1: Error in sourced command file:
|
||||||
|
//! :3333: Connection timed out.
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Launch OpenOCD on other terminal. See [Usage] section.
|
||||||
|
//!
|
||||||
|
//! [Usage]: ./index.html#usage
|
||||||
|
//!
|
||||||
|
//! ## Didn't modify the `memory.x` linker script
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! Compiling demo v0.1.0 (file:///home/japaric/tmp/demo)
|
||||||
|
//! error: linking with `arm-none-eabi-ld` failed: exit code: 1
|
||||||
|
//! |
|
||||||
|
//! = note: "arm-none-eabi-gcc" "-L" (..)
|
||||||
|
//! (..)
|
||||||
|
//! (..)/ld: region `FLASH' overflowed by XXX bytes
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Specify your device memory layout in the `memory.x` linker script. See [Usage]
|
||||||
|
//! section.
|
||||||
|
//!
|
||||||
|
//! ## Didn't set a default build target and forgot to pass `--target` to Cargo
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! (..)
|
||||||
|
//! error: language item required, but not found: `eh_personality`
|
||||||
|
//!
|
||||||
|
//! error: aborting due to previous error
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Set a default build target in the `.cargo/config` file (see [Usage] section), or call
|
||||||
|
//! Cargo with `--target` flag: `cargo build --target thumbv7em-none-eabi`.
|
||||||
|
//!
|
||||||
|
//! ## Overwrote the original `.cargo/config` file
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! error: linking with `arm-none-eabi-gcc` failed: exit code: 1
|
||||||
|
//! |
|
||||||
|
//! = note: (..)
|
||||||
|
//! (..)
|
||||||
|
//! (..)/crt0.o: In function `_start':
|
||||||
|
//! (.text+0x90): undefined reference to `memset'
|
||||||
|
//! (..)/crt0.o: In function `_start':
|
||||||
|
//! (.text+0xd0): undefined reference to `atexit'
|
||||||
|
//! (..)/crt0.o: In function `_start':
|
||||||
|
//! (.text+0xd4): undefined reference to `__libc_init_array'
|
||||||
|
//! (..)/crt0.o: In function `_start':
|
||||||
|
//! (.text+0xe4): undefined reference to `exit'
|
||||||
|
//! (..)/crt0.o: In function `_start':
|
||||||
|
//! (.text+0x100): undefined reference to `__libc_fini_array'
|
||||||
|
//! collect2: error: ld returned 1 exit status
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: You probably overwrote the original `.cargo/config` instead of appending the default
|
||||||
|
//! build target (e.g. `cat >` instead of `cat >>`). The less error prone way to fix this is to
|
||||||
|
//! remove the `.cargo` directory, clone a new copy of the template and then copy the `.cargo`
|
||||||
|
//! directory from that fresh template into your current project. Don't forget to *append* the
|
||||||
|
//! default build target to `.cargo/config`.
|
||||||
|
//!
|
||||||
|
//! ## Called OpenOCD with wrong arguments
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ openocd -f ..
|
||||||
|
//! (..)
|
||||||
|
//! Error: open failed
|
||||||
|
//! in procedure 'init'
|
||||||
|
//! in procedure 'ocd_bouncer'
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Correct the OpenOCD arguments. Check the `/usr/share/openocd/scripts` directory (exact
|
||||||
|
//! location varies per distribution / OS) for a list of scripts that can be used.
|
||||||
|
//!
|
||||||
|
//! ## Forgot to install the `rust-std` component
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! error[E0463]: can't find crate for `core`
|
||||||
|
//! |
|
||||||
|
//! = note: the `thumbv7m-none-eabi` target may not be installed
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: call `rustup target add thumbv7m-none-eabi` but with the name of your target
|
||||||
|
//!
|
||||||
|
//! ## Used an old nightly
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! Compiling cortex-m-rt v0.2.0
|
||||||
|
//! error[E0463]: can't find crate for `core`
|
||||||
|
//! |
|
||||||
|
//! = note: the `thumbv7em-none-eabihf` target may not be installed
|
||||||
|
//!
|
||||||
|
//! error: aborting due to previous error
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Use a more recent nightly
|
||||||
|
//!
|
||||||
|
//! ## Used the stable toolchain
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo build
|
||||||
|
//! error[E0463]: can't find crate for `core`
|
||||||
|
//! |
|
||||||
|
//! = note: the `thumbv7em-none-eabihf` target may not be installed
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: We are not there yet! Switch to the nightly toolchain with `rustup default nightly`.
|
||||||
|
//!
|
||||||
|
//! ## Used `gdb` instead of `arm-none-eabi-gdb`
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ gdb target/..
|
||||||
|
//! Reading symbols from hello...done.
|
||||||
|
//! warning: Architecture rejected target-supplied description
|
||||||
|
//! warning: Cannot convert floating-point register value to ..
|
||||||
|
//! value has been optimized out
|
||||||
|
//! Cannot write the dashboard
|
||||||
|
//! Traceback (most recent call last):
|
||||||
|
//! File "<string>", line 353, in render
|
||||||
|
//! File "<string>", line 846, in lines
|
||||||
|
//! gdb.error: Frame is invalid.
|
||||||
|
//! 0x00000000 in ?? ()
|
||||||
|
//! semihosting is enabled
|
||||||
|
//! Loading section .text, size 0xd88 lma 0x8000000
|
||||||
|
//! Start address 0x8000000, load size 3464
|
||||||
|
//! .gdbinit:6: Error in sourced command file:
|
||||||
|
//! Remote connection closed
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Solution: Use `arm-none-eabi-gdb target/..`
|
||||||
|
//!
|
||||||
|
//! # Used a named piped for `itm.fifo`
|
||||||
|
//!
|
||||||
|
//! Error message:
|
||||||
|
//!
|
||||||
|
//! ``` text
|
||||||
|
//! $ cargo run [--example ..]
|
||||||
|
//!
|
||||||
|
//! Reading symbols from target/thumbv7em-none-eabihf/debug/cortex-m-quickstart...done.
|
||||||
|
//! cortex_m_rt::reset_handler ()
|
||||||
|
//! at $REGISTRY/cortex-m-rt-0.3.12/src/lib.rs:330
|
||||||
|
//! 330 unsafe extern "C" fn reset_handler() -> ! {
|
||||||
|
//! semihosting is enabled
|
||||||
|
//! Ignoring packet error, continuing...
|
||||||
|
//! Ignoring packet error, continuing...
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Note that when you reach this point OpenOCD will become unresponsive and you'll have to kill it
|
||||||
|
//! and start a new OpenOCD process before you can invoke `cargo run` / start GDB.
|
||||||
|
//!
|
||||||
|
//! Cause: You uncommented the `monitor tpiu ..` line in `.gdbinit` and are using a named pipe to
|
||||||
|
//! receive the ITM data (i.e. you ran `mkfifo itm.fifo`). This error occurs when `itmdump -f
|
||||||
|
//! itm.fifo` (or equivalent, e.g. `cat itm.fifo`) is not running.
|
||||||
|
//!
|
||||||
|
//! Solution: Run `itmdump -f itm.fifo` (or equivalently `cat itm.fifo`) *before* invoking `cargo
|
||||||
|
//! run` / starting GDB. Note that sometimes `itmdump` will exit when the GDB session ends. In that
|
||||||
|
//! case you'll have to run `itmdump` before you start the next GDB session.
|
||||||
|
//!
|
||||||
|
//! Alternative solution: Use a plain text file instead of a named pipe. In this scenario you omit
|
||||||
|
//! the `mkfifo itm.dump` command. You can use `itmdump`'s *follow* mode (-F) to get named pipe like
|
||||||
|
//! output.
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user