STM32H7 embassy example
This commit is contained in:
1 parent
394ffec6c9
commit
8660dbae90
22 files changed
+2396
-141
No files matched your search
@@ -17,4 +17,5 @@ members = [
|
||||
exclude = [
|
||||
"examples/stm32f3-disco-rtic",
|
||||
"examples/stm32h7-nucleo-rtic",
|
||||
"examples/stm32h7-nucleo-embassy",
|
||||
]
|
||||
@@ -59,6 +59,9 @@ All examples and their helper crates are located inside the
|
||||
Simple example using sat-rs components on a bare-metal system with constrained resources.
|
||||
This example uses the [RTIC](https://github.com/rtic-rs/rtic) framework on the NUCLEO-H753ZI
|
||||
board.
|
||||
* [`stm32h7-nucleo-embassy`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/stm32h7-nucleo-embassy):
|
||||
Same as `stm32h7-nucleo-rtic`, but using the [embassy](https://embassy.dev/) executor instead
|
||||
of RTIC.
|
||||
* [`embedded-client`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/embedded-client) and
|
||||
[`embedded-types`](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/embedded-types): Client and shared telecommand and telemetry
|
||||
definitions for the embedded examples.
|
||||
|
||||
@@ -281,7 +281,7 @@ async fn send_tm(
|
||||
response: stm32f3::Response,
|
||||
current_seq_count: u14,
|
||||
) -> Result<(), TmSendError> {
|
||||
let sp_header = SpHeader::new_for_unseg_tc(stm32f3::PUS_APID, current_seq_count, 0);
|
||||
let sp_header = SpHeader::new_for_unseg_tm(stm32f3::PUS_APID, current_seq_count, 0);
|
||||
let tm_header = TmHeader {
|
||||
tc_packet_id: Some(tc_packet_id),
|
||||
uptime_millis: embassy_time::Instant::now().as_millis(),
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
runner = "probe-rs run --chip STM32H753ZITx"
|
||||
# runner = ["probe-rs", "run", "--chip", "$CHIP", "--log-format", "{L} {s}"]
|
||||
|
||||
rustflags = [
|
||||
"-C", "linker=flip-link",
|
||||
"-C", "link-arg=-Tlink.x",
|
||||
"-C", "link-arg=-Tdefmt.x",
|
||||
# This is needed if your flash or ram addresses are not aligned to 0x10000 in memory.x
|
||||
# See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
|
||||
"-C", "link-arg=--nmagic",
|
||||
# Can be useful for debugging.
|
||||
# "-Clink-args=-Map=app.map"
|
||||
]
|
||||
|
||||
[build]
|
||||
# (`thumbv6m-*` is compatible with all ARM Cortex-M chips but using the right
|
||||
# target improves performance)
|
||||
# target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
|
||||
# target = "thumbv7m-none-eabi" # Cortex-M3
|
||||
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
|
||||
target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
|
||||
|
||||
[alias]
|
||||
rb = "run --bin"
|
||||
rrb = "run --release --bin"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "info"
|
||||
@@ -0,0 +1,4 @@
|
||||
/target
|
||||
/.cargo/config.toml
|
||||
/.vscode
|
||||
/app.map
|
||||
+1547
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,75 @@
|
||||
[package]
|
||||
name = "stm32h7-nucleo-embassy"
|
||||
edition = "2024"
|
||||
version = "0.1.0"
|
||||
default-run = "stm32h7-nucleo-embassy"
|
||||
|
||||
[lib]
|
||||
harness = false
|
||||
|
||||
# needed for each integration test
|
||||
[[test]]
|
||||
name = "integration"
|
||||
harness = false
|
||||
|
||||
[dependencies]
|
||||
embedded-types = { path = "../embedded-types", features = ["defmt"] }
|
||||
|
||||
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
|
||||
arbitrary-int = "2"
|
||||
cortex-m-rt = "0.7"
|
||||
defmt = "1"
|
||||
defmt-rtt = "1"
|
||||
panic-probe = { version = "1", features = ["print-defmt"] }
|
||||
embedded-alloc = "0.7"
|
||||
static_cell = "2"
|
||||
spacepackets = { version = "0.18", default-features = false, features = ["defmt"] }
|
||||
postcard = "1"
|
||||
|
||||
embassy-stm32 = { version = "0.6", features = ["stm32h753zi", "memory-x", "defmt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.10", features = ["platform-cortex-m", "executor-thread", "defmt"] }
|
||||
embassy-time = { version = "0.5", features = ["defmt-timestamp-uptime-ms"] }
|
||||
embassy-net = { version = "0.9", features = ["medium-ethernet", "proto-ipv4", "tcp", "udp", "auto-icmp-echo-reply", "dhcpv4", "defmt"] }
|
||||
embassy-sync = "0.8"
|
||||
embassy-futures = "0.1"
|
||||
|
||||
[dev-dependencies]
|
||||
defmt-test = "0.5"
|
||||
|
||||
# cargo build/run
|
||||
[profile.dev]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 's' # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo test
|
||||
[profile.test]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = true # <-
|
||||
incremental = false
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = true # <-
|
||||
|
||||
# cargo build/run --release
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
|
||||
# cargo test --release
|
||||
[profile.bench]
|
||||
codegen-units = 1
|
||||
debug = 2
|
||||
debug-assertions = false # <-
|
||||
incremental = false
|
||||
lto = 'fat'
|
||||
opt-level = 3 # <-
|
||||
overflow-checks = false # <-
|
||||
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
@@ -0,0 +1,109 @@
|
||||
sat-rs embassy example for the STM32H753ZI-Nucleo board
|
||||
=======
|
||||
|
||||
This example application shows how the [sat-rs library](https://egit.irs.uni-stuttgart.de/rust/sat-rs)
|
||||
can be used on an embedded target.
|
||||
It also shows how a relatively simple OBSW could be built when no standard runtime is available.
|
||||
It uses the [embassy](https://embassy.dev/) executor as the concurrency framework and the
|
||||
[defmt](https://defmt.ferrous-systems.com/) framework for logging.
|
||||
|
||||
This is the embassy variant of the
|
||||
[`stm32h7-nucleo-rtic`](../stm32h7-nucleo-rtic) example. Both provide the same functionality.
|
||||
|
||||
The STM32H753ZIT device was picked because it is one of the more powerful Cortex-M based STM32
|
||||
devices. It has more RAM available and allows commanding via Ethernet. The example is written for
|
||||
the NUCLEO-H753ZI board, which uses the MB1364 Nucleo-144 board layout.
|
||||
|
||||
## Pre-Requisites
|
||||
|
||||
Make sure the following tools are installed:
|
||||
|
||||
1. [`probe-rs`](https://probe.rs/): Application used to flash and debug the MCU.
|
||||
2. Optional and recommended: [VS Code](https://code.visualstudio.com/) with
|
||||
[probe-rs plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger)
|
||||
for debugging.
|
||||
|
||||
## Preparing Rust and the repository
|
||||
|
||||
Building an application requires the `thumbv7em-none-eabihf` cross-compiler toolchain.
|
||||
If you have not installed it yet, you can do so with
|
||||
|
||||
```sh
|
||||
rustup target add thumbv7em-none-eabihf
|
||||
```
|
||||
|
||||
A default `.cargo` config file is provided as `.cargo/config.toml.template`. The build script
|
||||
copies it to `.cargo/config.toml` if that file does not exist yet. The copy is not tracked by git,
|
||||
so you can change settings like the runner for your setup.
|
||||
|
||||
Cargo reads the configuration before the build script runs, so the very first build on a fresh
|
||||
checkout does not use it yet and might fail. Simply run the build again, or copy the file
|
||||
manually beforehand:
|
||||
|
||||
```sh
|
||||
cp .cargo/config.toml.template .cargo/config.toml
|
||||
```
|
||||
|
||||
The configuration file also sets the target so it does not always have to be specified with
|
||||
the `--target` argument.
|
||||
|
||||
## Building
|
||||
|
||||
After that, assuming that you have a `.cargo/config.toml` setting the correct build target,
|
||||
you can simply build the application with
|
||||
|
||||
```sh
|
||||
cargo build
|
||||
```
|
||||
|
||||
## Flashing from the command line
|
||||
|
||||
You can flash the application from the command line using `probe-rs`:
|
||||
|
||||
```sh
|
||||
probe-rs run --chip STM32H753ZITx
|
||||
```
|
||||
|
||||
## Debugging with VS Code
|
||||
|
||||
The Nucleo board comes with an on-board ST-Link so all that is required to flash and debug
|
||||
the board is a USB cable. The code in this repository was debugged using [`probe-rs`](https://probe.rs/docs/tools/debuggerA)
|
||||
and the VS Code [`probe-rs` plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger).
|
||||
Make sure to install this plugin first.
|
||||
|
||||
## Commanding the board
|
||||
|
||||
The board is commanded via UDP on port 7301. It gets its IP address via DHCP, so it needs to be
|
||||
connected to a network with a DHCP server. The network configuration including the IP address is
|
||||
logged after startup. According to the board user manual UM2407, jumper JP6 and solder bridge SB72
|
||||
must be ON when using Ethernet. The telecommands are CCSDS space packets with a
|
||||
[`postcard`](https://docs.rs/postcard) serialized payload.
|
||||
|
||||
The [`embedded-client`](../embedded-client) application is used to command the board. Set the
|
||||
address of the board inside `embedded-client/config.toml`, for example:
|
||||
|
||||
```toml
|
||||
[interface]
|
||||
udp_addr = "192.168.1.50:7301"
|
||||
```
|
||||
|
||||
Then run the client from inside the `embedded-client` directory. For example, you can send a ping
|
||||
to the MCU using
|
||||
|
||||
```sh
|
||||
cargo run --bin stm32h7-client -- --ping
|
||||
```
|
||||
|
||||
and set the LED blink frequency to 500 ms using
|
||||
|
||||
```sh
|
||||
cargo run --bin stm32h7-client -- --set-led-frequency 500
|
||||
```
|
||||
|
||||
You can also pass the board address with `--udp-addr` instead of setting it inside the
|
||||
configuration file.
|
||||
|
||||
## Resources
|
||||
|
||||
- [STM32H743ZI Ethernet link checker example](https://github.com/stm32-rs/stm32h7xx-hal/blob/master/examples/ethernet-nucleo-h743zi2.rs)
|
||||
- [smoltcp DHCP client](https://github.com/smoltcp-rs/smoltcp/blob/main/examples/dhcp_client.rs)
|
||||
@@ -0,0 +1,14 @@
|
||||
use std::path::PathBuf;
|
||||
use std::{env, fs};
|
||||
|
||||
fn main() {
|
||||
let manifest_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap());
|
||||
let cargo_dir = manifest_dir.join(".cargo");
|
||||
let config = cargo_dir.join("config.toml");
|
||||
let config_template = cargo_dir.join("config.toml.template");
|
||||
|
||||
if !config.exists() && config_template.exists() {
|
||||
fs::create_dir_all(&cargo_dir).unwrap();
|
||||
fs::copy(&config_template, &config).unwrap();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
targets = ["thumbv7em-none-eabihf"]
|
||||
@@ -0,0 +1,43 @@
|
||||
//! Blinks an LED
|
||||
//!
|
||||
//! This assumes that LD1 (green) is connected to PB0, LD2 (yellow) to PE1 and LD3 (red) to
|
||||
//! PB14. This assumption is true for the MB1364 Nucleo-144 board, for example the
|
||||
//! NUCLEO-H753ZI.
|
||||
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_stm32::gpio;
|
||||
use stm32h7_nucleo_embassy as _;
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
let p = embassy_stm32::init(Default::default());
|
||||
defmt::info!("Hello World!");
|
||||
let ld1 = gpio::Output::new(p.PB0, gpio::Level::High, gpio::Speed::Low);
|
||||
let ld2 = gpio::Output::new(p.PE1, gpio::Level::High, gpio::Speed::Low);
|
||||
let ld3 = gpio::Output::new(p.PB14, gpio::Level::High, gpio::Speed::Low);
|
||||
|
||||
spawner.spawn(blink(ld1, ld2, ld3).expect("spawning blink task failed"));
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn blink(
|
||||
mut ld1: gpio::Output<'static>,
|
||||
mut ld2: gpio::Output<'static>,
|
||||
mut ld3: gpio::Output<'static>,
|
||||
) {
|
||||
loop {
|
||||
defmt::info!("high");
|
||||
ld1.set_high();
|
||||
ld2.set_high();
|
||||
ld3.set_high();
|
||||
embassy_time::Timer::after_millis(500).await;
|
||||
|
||||
defmt::info!("low");
|
||||
ld1.set_low();
|
||||
ld2.set_low();
|
||||
ld3.set_low();
|
||||
embassy_time::Timer::after_millis(500).await;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
// global logger + panicking-behavior + memory layout
|
||||
use stm32h7_nucleo_embassy as _;
|
||||
|
||||
#[cortex_m_rt::entry]
|
||||
fn main() -> ! {
|
||||
loop {
|
||||
defmt::println!("Hello, world!");
|
||||
cortex_m::asm::delay(100_000_000);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
|
||||
use defmt_rtt as _;
|
||||
use embassy_stm32 as _;
|
||||
use panic_probe as _;
|
||||
|
||||
// same panicking *behavior* as `panic-probe` but doesn't print a panic message
|
||||
// this prevents the panic message being printed *twice* when `defmt::panic` is invoked
|
||||
#[defmt::panic_handler]
|
||||
fn panic() -> ! {
|
||||
cortex_m::asm::udf()
|
||||
}
|
||||
|
||||
/// Hardfault handler.
|
||||
///
|
||||
/// Terminates the application and makes a semihosting-capable debug tool exit
|
||||
/// with an error. This seems better than the default, which is to spin in a
|
||||
/// loop.
|
||||
#[cortex_m_rt::exception]
|
||||
unsafe fn HardFault(_frame: &cortex_m_rt::ExceptionFrame) -> ! {
|
||||
panic!("unexpected hard fault");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[defmt_test::tests]
|
||||
mod unit_tests {
|
||||
use defmt::assert;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert!(true)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,296 @@
|
||||
#![no_main]
|
||||
#![no_std]
|
||||
extern crate alloc;
|
||||
|
||||
use core::mem::MaybeUninit;
|
||||
use core::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use arbitrary_int::u14;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_futures::select::{Either3, select3};
|
||||
use embassy_net::StackResources;
|
||||
use embassy_net::udp::{PacketMetadata, UdpSocket};
|
||||
use embassy_stm32::{bind_interrupts, eth, gpio, peripherals, rng};
|
||||
use embassy_sync::blocking_mutex::raw::NoopRawMutex;
|
||||
use embassy_sync::channel::{Channel, Receiver, Sender};
|
||||
use embassy_time::Timer;
|
||||
use embedded_alloc::LlffHeap as Heap;
|
||||
use embedded_types::{TmHeader, create_tm_packet, stm32h7, tm_size};
|
||||
use spacepackets::{CcsdsPacketCreationError, CcsdsPacketIdAndPsc, CcsdsPacketReader, SpHeader};
|
||||
use static_cell::{ConstStaticCell, StaticCell};
|
||||
// global logger + panicking-behavior + memory layout
|
||||
use stm32h7_nucleo_embassy as _;
|
||||
|
||||
const DEFAULT_BLINK_FREQ_MS: u32 = 1000;
|
||||
const PORT: u16 = 7301;
|
||||
const MTU: usize = 1500;
|
||||
|
||||
const HEAP_SIZE: usize = 131_072;
|
||||
|
||||
#[global_allocator]
|
||||
static HEAP: Heap = Heap::empty();
|
||||
|
||||
/// Locally administered MAC address
|
||||
const MAC_ADDRESS: [u8; 6] = [0x02, 0x00, 0x11, 0x22, 0x33, 0x44];
|
||||
|
||||
const TC_QUEUE_DEPTH: usize = 32;
|
||||
const TM_QUEUE_DEPTH: usize = 32;
|
||||
|
||||
static BLINK_FREQ_MS: AtomicU32 = AtomicU32::new(DEFAULT_BLINK_FREQ_MS);
|
||||
|
||||
bind_interrupts!(struct Irqs {
|
||||
ETH => eth::InterruptHandler;
|
||||
HASH_RNG => rng::InterruptHandler<peripherals::RNG>;
|
||||
});
|
||||
|
||||
type Device = eth::Ethernet<
|
||||
'static,
|
||||
peripherals::ETH,
|
||||
eth::GenericPhy<eth::Sma<'static, peripherals::ETH_SMA>>,
|
||||
>;
|
||||
|
||||
type TcSender = Sender<'static, NoopRawMutex, Vec<u8>, TC_QUEUE_DEPTH>;
|
||||
type TcReceiver = Receiver<'static, NoopRawMutex, Vec<u8>, TC_QUEUE_DEPTH>;
|
||||
type TmSender = Sender<'static, NoopRawMutex, Vec<u8>, TM_QUEUE_DEPTH>;
|
||||
type TmReceiver = Receiver<'static, NoopRawMutex, Vec<u8>, TM_QUEUE_DEPTH>;
|
||||
|
||||
struct BlinkyLeds {
|
||||
led1: gpio::Output<'static>,
|
||||
led2: gpio::Output<'static>,
|
||||
}
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(spawner: Spawner) {
|
||||
defmt::println!("Starting sat-rs demo application for the STM32H753ZIT");
|
||||
|
||||
static mut HEAP_MEM: [MaybeUninit<u8>; HEAP_SIZE] = [MaybeUninit::uninit(); HEAP_SIZE];
|
||||
unsafe { HEAP.init(&raw mut HEAP_MEM as usize, HEAP_SIZE) }
|
||||
|
||||
let mut config = embassy_stm32::Config::default();
|
||||
{
|
||||
use embassy_stm32::rcc::*;
|
||||
config.rcc.hsi = Some(HSIPrescaler::DIV1);
|
||||
config.rcc.csi = true;
|
||||
config.rcc.hsi48 = Some(Default::default()); // needed for RNG
|
||||
config.rcc.pll1 = Some(Pll {
|
||||
source: PllSource::HSI,
|
||||
prediv: PllPreDiv::DIV4,
|
||||
mul: PllMul::MUL50,
|
||||
divp: Some(PllDiv::DIV2),
|
||||
divq: None,
|
||||
divr: None,
|
||||
});
|
||||
config.rcc.sys = Sysclk::PLL1_P; // 400 Mhz
|
||||
config.rcc.ahb_pre = AHBPrescaler::DIV2; // 200 Mhz
|
||||
config.rcc.apb1_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb2_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb3_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.apb4_pre = APBPrescaler::DIV2; // 100 Mhz
|
||||
config.rcc.voltage_scale = VoltageScale::Scale1;
|
||||
}
|
||||
let periphs = embassy_stm32::init(config);
|
||||
|
||||
let link_led = gpio::Output::new(periphs.PB0, gpio::Level::Low, gpio::Speed::Medium);
|
||||
// Criss-cross pattern looks cooler.
|
||||
let leds = BlinkyLeds {
|
||||
led1: gpio::Output::new(periphs.PE1, gpio::Level::High, gpio::Speed::Medium),
|
||||
led2: gpio::Output::new(periphs.PB14, gpio::Level::Low, gpio::Speed::Medium),
|
||||
};
|
||||
|
||||
static PACKETS: StaticCell<eth::PacketQueue<4, 4>> = StaticCell::new();
|
||||
// warning: Not all STM32H7 devices have the exact same pins here
|
||||
// for STM32H747XIH, replace p.PB13 for PG12
|
||||
let device = eth::Ethernet::new(
|
||||
PACKETS.init(eth::PacketQueue::<4, 4>::new()),
|
||||
periphs.ETH,
|
||||
Irqs,
|
||||
periphs.PA1, // ref_clk
|
||||
periphs.PA7, // CRS_DV: Carrier Sense
|
||||
periphs.PC4, // RX_D0: Received Bit 0
|
||||
periphs.PC5, // RX_D1: Received Bit 1
|
||||
periphs.PG13, // TX_D0: Transmit Bit 0
|
||||
periphs.PB13, // TX_D1: Transmit Bit 1
|
||||
periphs.PG11, // TX_EN: Transmit Enable
|
||||
MAC_ADDRESS,
|
||||
periphs.ETH_SMA,
|
||||
periphs.PA2, // mdio
|
||||
periphs.PC1, // mdc
|
||||
);
|
||||
|
||||
let net_config = embassy_net::Config::dhcpv4(embassy_net::DhcpConfig::default());
|
||||
|
||||
// Generate random seed.
|
||||
let mut rng = rng::Rng::new(periphs.RNG, Irqs);
|
||||
let mut seed = [0; 8];
|
||||
rng.fill_bytes(&mut seed);
|
||||
let seed = u64::from_le_bytes(seed);
|
||||
|
||||
static RESOURCES: StaticCell<StackResources<3>> = StaticCell::new();
|
||||
let (stack, runner) = embassy_net::new(
|
||||
device,
|
||||
net_config,
|
||||
RESOURCES.init(StackResources::new()),
|
||||
seed,
|
||||
);
|
||||
|
||||
static TC_CHANNEL: ConstStaticCell<Channel<NoopRawMutex, Vec<u8>, TC_QUEUE_DEPTH>> =
|
||||
ConstStaticCell::new(Channel::new());
|
||||
let tc_channel = TC_CHANNEL.take();
|
||||
static TM_CHANNEL: ConstStaticCell<Channel<NoopRawMutex, Vec<u8>, TM_QUEUE_DEPTH>> =
|
||||
ConstStaticCell::new(Channel::new());
|
||||
let tm_channel = TM_CHANNEL.take();
|
||||
|
||||
spawner.spawn(net_stack_task(runner).expect("spawning net stack task failed"));
|
||||
spawner.spawn(
|
||||
udp_task(stack, link_led, tc_channel.sender(), tm_channel.receiver())
|
||||
.expect("spawning UDP task failed"),
|
||||
);
|
||||
spawner.spawn(blinky(leds).expect("spawning blinky task failed"));
|
||||
spawner.spawn(
|
||||
tc_handler(tc_channel.receiver(), tm_channel.sender())
|
||||
.expect("spawning TC handler task failed"),
|
||||
);
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn blinky(mut leds: BlinkyLeds) {
|
||||
loop {
|
||||
leds.led1.toggle();
|
||||
leds.led2.toggle();
|
||||
Timer::after_millis(BLINK_FREQ_MS.load(Ordering::Relaxed) as u64).await;
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn net_stack_task(mut runner: embassy_net::Runner<'static, Device>) -> ! {
|
||||
runner.run().await
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn udp_task(
|
||||
stack: embassy_net::Stack<'static>,
|
||||
mut link_led: gpio::Output<'static>,
|
||||
tc_tx: TcSender,
|
||||
tm_rx: TmReceiver,
|
||||
) {
|
||||
// Task futures are allocated statically, so these buffers do not live on the stack.
|
||||
let mut rx_udp_meta = [PacketMetadata::EMPTY; 8];
|
||||
let mut tx_udp_meta = [PacketMetadata::EMPTY; 8];
|
||||
let mut rx_udp_buf = [0; MTU];
|
||||
let mut tx_udp_buf = [0; MTU];
|
||||
let mut rx_buffer = [0; MTU];
|
||||
|
||||
loop {
|
||||
stack.wait_link_up().await;
|
||||
link_led.set_high();
|
||||
defmt::info!("Network link is up");
|
||||
|
||||
// Ensure DHCP configuration is up before trying connect
|
||||
stack.wait_config_up().await;
|
||||
defmt::info!("Network task initialized, config: {}", stack.config_v4());
|
||||
|
||||
let mut udp = UdpSocket::new(
|
||||
stack,
|
||||
&mut rx_udp_meta,
|
||||
&mut rx_udp_buf,
|
||||
&mut tx_udp_meta,
|
||||
&mut tx_udp_buf,
|
||||
);
|
||||
defmt::info!("UDP socket bound to port {}", PORT);
|
||||
udp.bind(PORT).expect("failed to bind UDP socket");
|
||||
let mut remote_endpoint = None;
|
||||
loop {
|
||||
match select3(
|
||||
udp.recv_from(&mut rx_buffer),
|
||||
tm_rx.receive(),
|
||||
stack.wait_link_down(),
|
||||
)
|
||||
.await
|
||||
{
|
||||
Either3::First(Ok((len, meta))) => {
|
||||
remote_endpoint = Some(meta.endpoint);
|
||||
defmt::debug!("UDP RX {}, Meta: {}", len, meta);
|
||||
tc_tx.send(rx_buffer[0..len].to_vec()).await;
|
||||
}
|
||||
Either3::First(Err(e)) => {
|
||||
defmt::warn!("udp receive error: {}", e);
|
||||
Timer::after_millis(100).await;
|
||||
}
|
||||
// TM is only generated as a response to a TC, so the endpoint is usually known.
|
||||
Either3::Second(packet) => match remote_endpoint {
|
||||
Some(endpoint) => match udp.send_to(&packet, endpoint).await {
|
||||
Ok(_) => defmt::debug!("UDP TX: {} bytes to: {}", packet.len(), endpoint),
|
||||
Err(e) => defmt::warn!("udp send error: {}", e),
|
||||
},
|
||||
None => defmt::warn!("dropping TM, no remote endpoint known"),
|
||||
},
|
||||
Either3::Third(()) => {
|
||||
defmt::warn!("Network link is down");
|
||||
link_led.set_low();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[embassy_executor::task]
|
||||
async fn tc_handler(tc_rx: TcReceiver, tm_tx: TmSender) {
|
||||
let mut sequence_count = u14::new(0);
|
||||
loop {
|
||||
let tc = tc_rx.receive().await;
|
||||
defmt::info!("Received from UDP client: {}", tc.as_slice());
|
||||
let packet = match CcsdsPacketReader::new_with_checksum(&tc) {
|
||||
Ok(packet) => packet,
|
||||
Err(e) => {
|
||||
defmt::warn!("Failed to parse received TC packet: {}", e);
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let tc_packet_id = CcsdsPacketIdAndPsc {
|
||||
packet_id: packet.packet_id(),
|
||||
psc: packet.psc(),
|
||||
};
|
||||
let Ok(request) = postcard::from_bytes::<stm32h7::Request>(packet.packet_data()) else {
|
||||
defmt::warn!("Failed to deserialize TC request");
|
||||
continue;
|
||||
};
|
||||
let response = match request {
|
||||
stm32h7::Request::Ping => {
|
||||
defmt::info!("Received Ping request");
|
||||
stm32h7::Response::Ok
|
||||
}
|
||||
stm32h7::Request::ChangeBlinkFrequency(duration) => {
|
||||
defmt::info!(
|
||||
"Received blinky frequency change request: {} ms",
|
||||
duration.as_millis()
|
||||
);
|
||||
let freq_ms = u32::try_from(duration.as_millis()).unwrap_or(u32::MAX);
|
||||
BLINK_FREQ_MS.store(freq_ms, Ordering::Relaxed);
|
||||
stm32h7::Response::Ok
|
||||
}
|
||||
};
|
||||
if let Err(e) = send_tm(tc_packet_id, response, sequence_count, &tm_tx).await {
|
||||
defmt::warn!("Failed to send TM response: {}", e);
|
||||
}
|
||||
sequence_count = sequence_count.wrapping_add(u14::new(1));
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_tm(
|
||||
tc_packet_id: CcsdsPacketIdAndPsc,
|
||||
response: stm32h7::Response,
|
||||
sequence_count: u14,
|
||||
sender: &TmSender,
|
||||
) -> Result<(), CcsdsPacketCreationError> {
|
||||
let sp_header = SpHeader::new_for_unseg_tm(stm32h7::PUS_APID, sequence_count, 0);
|
||||
let tm_header = TmHeader {
|
||||
tc_packet_id: Some(tc_packet_id),
|
||||
uptime_millis: embassy_time::Instant::now().as_millis(),
|
||||
};
|
||||
let mut packet = alloc::vec![0; tm_size(&tm_header, &response)];
|
||||
create_tm_packet(&mut packet, sp_header, tm_header, response)?;
|
||||
sender.send(packet).await;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use stm32h7_nucleo_embassy as _; // memory layout + panic handler
|
||||
|
||||
// See https://crates.io/crates/defmt-test/0.3.0 for more documentation (e.g. about the 'state'
|
||||
// feature)
|
||||
#[defmt_test::tests]
|
||||
mod tests {
|
||||
use defmt::assert;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert!(true)
|
||||
}
|
||||
}
|
||||
@@ -68,15 +68,6 @@ the board is a USB cable. The code in this repository was debugged using [`probe
|
||||
and the VS Code [`probe-rs` plugin](https://marketplace.visualstudio.com/items?itemName=probe-rs.probe-rs-debugger).
|
||||
Make sure to install this plugin first.
|
||||
|
||||
Sample configuration files are provided inside the `vscode` folder.
|
||||
Use `cp vscode .vscode -r` to use them for your project.
|
||||
|
||||
Some sample configuration files for VS Code were provided as well. You can simply use `Run` and `Debug`
|
||||
to automatically rebuild and flash your application.
|
||||
|
||||
The `tasks.json` and `launch.json` files are generic and you can use them immediately by opening
|
||||
the folder in VS code or adding it to a workspace.
|
||||
|
||||
## Commanding the board
|
||||
|
||||
The board is commanded via UDP on port 7301. It gets its IP address via DHCP, so it needs to be
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
/* Taken from https://github.com/stm32-rs/stm32h7xx-hal/pull/299, adapted slightly to work with */
|
||||
/* flip-link */
|
||||
MEMORY
|
||||
{
|
||||
/* This file is intended for parts in the STM32H743/743v/753/753v families (RM0433), */
|
||||
/* with the exception of the STM32H742/742v parts which have a different RAM layout. */
|
||||
/* - FLASH and RAM are mandatory memory sections. */
|
||||
/* - The sum of all non-FLASH sections must add to 1060K total device RAM. */
|
||||
/* - The FLASH section size must match your device, see table below. */
|
||||
|
||||
/* FLASH */
|
||||
/* Flash is divided in two independent banks (except 750xB). */
|
||||
/* Select the appropriate FLASH size for your device. */
|
||||
/* - STM32H750xB 128K (only FLASH1) */
|
||||
/* - STM32H750xB 1M (512K + 512K) */
|
||||
/* - STM32H743xI/753xI 2M ( 1M + 1M) */
|
||||
FLASH1 : ORIGIN = 0x08000000, LENGTH = 1M
|
||||
FLASH2 : ORIGIN = 0x08100000, LENGTH = 1M
|
||||
|
||||
/* Data TCM */
|
||||
/* - Two contiguous 64KB RAMs. */
|
||||
/* - Used for interrupt handlers, stacks and general RAM. */
|
||||
/* - Zero wait-states. */
|
||||
/* - The DTCM is taken as the origin of the base ram. (See below.) */
|
||||
/* This is also where the interrupt table and such will live, */
|
||||
/* which is required for deterministic performance. */
|
||||
/* Need a region called RAM */
|
||||
/* DTCM : ORIGIN = 0x20000000, LENGTH = 128K */
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 128K
|
||||
|
||||
/* Instruction TCM */
|
||||
/* - Used for latency-critical interrupt handlers etc. */
|
||||
/* - Zero wait-states. */
|
||||
ITCM : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
|
||||
/* AXI SRAM */
|
||||
/* - AXISRAM is in D1 and accessible by all system masters except BDMA. */
|
||||
/* - Suitable for application data not stored in DTCM. */
|
||||
/* - Zero wait-states. */
|
||||
AXISRAM : ORIGIN = 0x24000000, LENGTH = 512K
|
||||
|
||||
/* AHB SRAM */
|
||||
/* - SRAM1-3 are in D2 and accessible by all system masters except BDMA. */
|
||||
/* Suitable for use as DMA buffers. */
|
||||
/* - SRAM4 is in D3 and additionally accessible by the BDMA. Used for BDMA */
|
||||
/* buffers, for storing application data in lower-power modes. */
|
||||
/* - Zero wait-states. */
|
||||
SRAM1 : ORIGIN = 0x30000000, LENGTH = 128K
|
||||
SRAM2 : ORIGIN = 0x30020000, LENGTH = 128K
|
||||
SRAM3 : ORIGIN = 0x30040000, LENGTH = 32K
|
||||
SRAM4 : ORIGIN = 0x38000000, LENGTH = 64K
|
||||
|
||||
/* Backup SRAM */
|
||||
BSRAM : ORIGIN = 0x38800000, LENGTH = 4K
|
||||
}
|
||||
|
||||
/*
|
||||
/* Assign the memory regions defined above for use. */
|
||||
/*
|
||||
|
||||
/* Provide the mandatory FLASH and RAM definitions for cortex-m-rt's linker script. */
|
||||
/* These do not work with flip-link */
|
||||
REGION_ALIAS(FLASH, FLASH1);
|
||||
/* REGION_ALIAS(RAM, DTCM); */
|
||||
|
||||
/* The location of the stack can be overridden using the `_stack_start` symbol. */
|
||||
/* - Set the stack location at the end of RAM, using all remaining space. */
|
||||
_stack_start = ORIGIN(RAM) + LENGTH(RAM);
|
||||
|
||||
/* The location of the .text section can be overridden using the */
|
||||
/* `_stext` symbol. By default it will place after .vector_table. */
|
||||
/* _stext = ORIGIN(FLASH) + 0x40c; */
|
||||
|
||||
/* Define sections for placing symbols into the extra memory regions above. */
|
||||
/* This makes them accessible from code. */
|
||||
/* - ITCM, DTCM and AXISRAM connect to a 64-bit wide bus -> align to 8 bytes. */
|
||||
/* - All other memories connect to a 32-bit wide bus -> align to 4 bytes. */
|
||||
SECTIONS {
|
||||
.flash2 (NOLOAD) : ALIGN(4) {
|
||||
*(.flash2 .flash2.*);
|
||||
. = ALIGN(4);
|
||||
} > FLASH2
|
||||
|
||||
.itcm (NOLOAD) : ALIGN(8) {
|
||||
*(.itcm .itcm.*);
|
||||
. = ALIGN(8);
|
||||
} > ITCM
|
||||
|
||||
.axisram (NOLOAD) : ALIGN(8) {
|
||||
*(.axisram .axisram.*);
|
||||
. = ALIGN(8);
|
||||
} > AXISRAM
|
||||
|
||||
.sram1 (NOLOAD) : ALIGN(8) {
|
||||
*(.sram1 .sram1.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM1
|
||||
|
||||
.sram2 (NOLOAD) : ALIGN(8) {
|
||||
*(.sram2 .sram2.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM2
|
||||
|
||||
.sram3 (NOLOAD) : ALIGN(4) {
|
||||
*(.sram3 .sram3.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM3
|
||||
|
||||
.sram4 (NOLOAD) : ALIGN(4) {
|
||||
*(.sram4 .sram4.*);
|
||||
. = ALIGN(4);
|
||||
} > SRAM4
|
||||
|
||||
.bsram (NOLOAD) : ALIGN(4) {
|
||||
*(.bsram .bsram.*);
|
||||
. = ALIGN(4);
|
||||
} > BSRAM
|
||||
|
||||
};
|
||||
@@ -371,7 +371,7 @@ mod app {
|
||||
TM_QUEUE_DEPTH,
|
||||
>,
|
||||
) -> Result<(), CcsdsPacketCreationError> {
|
||||
let sp_header = SpHeader::new_for_unseg_tc(stm32h7::PUS_APID, current_seq_count, 0);
|
||||
let sp_header = SpHeader::new_for_unseg_tm(stm32h7::PUS_APID, current_seq_count, 0);
|
||||
let tm_header = TmHeader {
|
||||
tc_packet_id: Some(tc_packet_id),
|
||||
uptime_millis: embassy_time::Instant::now().as_millis(),
|
||||
|
||||
@@ -11,13 +11,17 @@ test:
|
||||
cargo nextest run --all-features
|
||||
cargo test --doc --all-features
|
||||
|
||||
embedded: embedded-stm32h7 embedded-stm32f3
|
||||
embedded: embedded-stm32h7 embedded-stm32h7-embassy embedded-stm32f3
|
||||
cargo check -p satrs --target=thumbv7em-none-eabihf --no-default-features
|
||||
|
||||
[working-directory:"examples/stm32h7-nucleo-rtic"]
|
||||
embedded-stm32h7:
|
||||
cargo build --target=thumbv7em-none-eabihf --release
|
||||
|
||||
[working-directory:"examples/stm32h7-nucleo-embassy"]
|
||||
embedded-stm32h7-embassy:
|
||||
cargo build --target=thumbv7em-none-eabihf --release
|
||||
|
||||
[working-directory:"examples/stm32f3-disco-rtic"]
|
||||
embedded-stm32f3:
|
||||
cargo build --target=thumbv7em-none-eabihf --release
|
||||
|
||||
@@ -39,12 +39,8 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! You can check [integration test](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs/tests/pus_events.rs)
|
||||
//! for a concrete example using multi-threading where events are routed to
|
||||
//! different threads.
|
||||
//!
|
||||
//! The [example-std](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std)
|
||||
//! also contains a full event manager instance and exposes a test event via the PUS test service.
|
||||
//! contains a full event manager instance and exposes a test event via the PUS test service.
|
||||
//! The [PUS event](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std/src/legacy/pus/event.rs)
|
||||
//! module and the generic [events module](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std/src/legacy/events.rs)
|
||||
//! show how the event management modules can be integrated into a more complex software.
|
||||
|
||||
@@ -41,12 +41,8 @@
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! You can check [integration test](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/satrs/tests/pus_events.rs)
|
||||
//! for a concrete example using multi-threading where events are routed to
|
||||
//! different threads.
|
||||
//!
|
||||
//! The [example-std](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std)
|
||||
//! also contains a full event manager instance and exposes a test event via the PUS test service.
|
||||
//! contains a full event manager instance and exposes a test event via the PUS test service.
|
||||
//! The [PUS event](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std/src/legacy/pus/event.rs)
|
||||
//! module and the generic [events module](https://egit.irs.uni-stuttgart.de/rust/sat-rs/src/branch/main/examples/example-std/src/legacy/events.rs)
|
||||
//! show how the event management modules can be integrated into a more complex software.
|
||||
|
||||
Reference in new issue
Block a user