Skip to content

Commit e03d2cc

Browse files
Merge pull request #67 from stm32-rs/improve_examples
Improve examples
2 parents 3e1ec5d + 632cf4d commit e03d2cc

File tree

6 files changed

+151
-87
lines changed

6 files changed

+151
-87
lines changed

.github/workflows/build.yml

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,21 +97,14 @@ jobs:
9797
strategy:
9898
matrix:
9999
example:
100-
- name: arp
101-
example: arp
102-
features: defmt
103-
- name: ip
104-
example: ip
105-
features: defmt,smoltcp-phy,smoltcp/defmt,smoltcp/socket-tcp
106-
- name: pktgen
107-
example: pktgen
108-
features: defmt
109-
- name: rtic-echo
110-
example: rtic-echo
111-
features: rtic-echo-example
112-
- name: rtic-echo with nucleo pins
113-
example: rtic-echo
114-
features: rtic-echo-example,example-nucleo-pins
100+
- example: arp
101+
features: ""
102+
- example: ip
103+
features: smoltcp-phy
104+
- example: pktgen
105+
features: ""
106+
- example: rtic-echo
107+
features: smoltcp-phy
115108
mcu:
116109
- stm32f107
117110
- stm32f429
@@ -120,19 +113,22 @@ jobs:
120113
- stable
121114
target:
122115
- thumbv7m-none-eabi
116+
pins:
117+
- nucleo
118+
- default
123119
steps:
124120
- name: Checkout
125121
uses: actions/checkout@v3
126122

127-
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }})
123+
- name: Install Rust ${{ matrix.toolchain }} with target (${{ matrix.target }}) and pins ${{ matrix.pins }}
128124
run: |
129125
rustup set profile minimal
130126
rustup override set ${{ matrix.toolchain }}
131127
rustup target add ${{ matrix.target }}
132128
133-
- name: Build example ${{ matrix.example.name }} for ${{ matrix.mcu }}
129+
- name: Build example ${{ matrix.example.example }} for ${{ matrix.mcu }}
134130
run: |
135-
cargo build --release --target=${{ matrix.target }} --example ${{ matrix.example.example}} --features ${{ matrix.mcu }},${{ matrix.example.features }}
131+
STM32_ETH_EXAMPLE_PINS=${{ matrix.pins }} cargo build --release --target=${{ matrix.target }} --example ${{ matrix.example.example}} --features ${{ matrix.mcu }},${{ matrix.example.features }}
136132
137133
# Refs: https://github.com/rust-lang/crater/blob/9ab6f9697c901c4a44025cf0a39b73ad5b37d198/.github/workflows/bors.yml#L125-L149
138134
#

Cargo.toml

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,6 @@ stm32f779 = ["stm32f7xx-hal/stm32f779", "device-selected", "fence"]
6363

6464
smoltcp-phy = ["smoltcp"]
6565

66-
# Example features
67-
example-nucleo-pins = [ ]
68-
rtic-echo-example = [ "defmt", "smoltcp-phy", "smoltcp/defmt", "smoltcp/medium-ethernet", "smoltcp/socket-tcp" ]
69-
7066
[dev-dependencies]
7167
cortex-m = { version = "0.7", features = ["critical-section-single-core"] }
7268
cortex-m-rt = "0.7"
@@ -75,25 +71,23 @@ cortex-m-rtic = "1.0"
7571
defmt-rtt = "0.4"
7672
panic-probe = { version = "0.3", features = [ "print-defmt" ] }
7773
systick-monotonic = "1.0"
78-
smoltcp = { version = "0.8", features = [ "medium-ethernet", "proto-ipv4", "socket-udp" ], default-features = false }
74+
smoltcp = { version = "0.8", features = [ "medium-ethernet", "proto-ipv4", "socket-udp", "socket-tcp", "defmt" ], default-features = false }
7975

8076
[[example]]
8177
name = "pktgen"
8278
required-features = [ "defmt" ]
8379

8480
[[example]]
8581
name = "ip"
86-
required-features = [
87-
"defmt", "smoltcp-phy", "smoltcp/defmt", "smoltcp/socket-tcp"
88-
]
82+
required-features = [ "defmt", "smoltcp-phy" ]
8983

9084
[[example]]
9185
name = "arp"
9286
required-features = [ "defmt" ]
9387

9488
[[example]]
9589
name = "rtic-echo"
96-
required-features = [ "rtic-echo-example" ]
90+
required-features = [ "defmt" , "smoltcp-phy" ]
9791

9892
[profile.release]
9993
debug = 2

README.md

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* STM32F4xx
99
* STM32F7xx
1010

11-
Please send pull requests.
11+
Pull requests are welcome :)
1212

1313
## Usage
1414

@@ -92,38 +92,34 @@ The examples should run and compile on any MCU that has an 802.3 compatible PHY
9292

9393
The examples use `defmt` and `defmt_rtt` for logging, and `panic_probe` over `defmt_rtt` for printing panic backtraces.
9494

95-
To run or build them, the following steps should be taken:
95+
##### Alternative pin configuration & HSE
9696

97-
1. Determine the correct compilation target for the MCU that you're using. For `stm32f107`, it is `thumbv7m-none-eabi`. For all others, it is `thumbv7em-none-eabihf`.
98-
2. Determine the MCU feature necessary for running on your MCU, e.g. `stm32f745`.
99-
3. Determine the Additional required features (see section below) necessary to build the example.
100-
4. Follow the rest of the instructions in the ["Building examples"](#building-examples) or ["Running examples"](#running-examples) subsections.
97+
If the board you're developing for has a High Speed External oscillator connected to the correct pins, the HSE configuration can be activated by setting the `STM32_ETH_EXAMPLE_HSE` environment variable to one of `oscillator` or `bypass` when compiling.
10198

102-
### Additional required features
103-
104-
Besides the feature selecting the correct MCU to be used when building and/or running an example, the following additional features are required:
105-
106-
| Example | Additional required features |
107-
| ----------- | ---------------------------------------------------- |
108-
| `arp` | `defmt` |
109-
| `ip` | `defmt,smoltcp-phy,smoltcp/defmt,smoltcp/socket-tcp` |
110-
| `pktgen` | `defmt` |
111-
| `rtic-echo` | `rtic-echo-example` |
112-
113-
#### 144-pin nucleo boards
114-
115-
For `stm32` 144-pin nucleo boards that contain an MCU supported by this crate the `example-nucleo-pins` feature should be activated. This causes the examples to use PG11 as TX_EN and PG13 as TXD0, instead of PB11 and PB12, which is the configuration used on these boards.
99+
If the board you're developing for uses the nucleo pinout (PG11 and PG13 instead of PB11 and PB12), the pin configuration can be changed by setting the `STM32_ETH_EXAMPLE_PINS` environment variable to `nucleo` when compiling.
116100

117101
### Building examples
118-
Run the following command:
102+
To build an example, run the following command:
119103
```bash
120-
cargo build --release --example <example> --features <MCU feature>,<additional required features> --target <MCU compilation target>
104+
cargo build --release --example <example> \
105+
--features <MCU feature>,<additional required features> \
106+
--target <MCU compilation target>
121107
```
122108

123109
For example, if we wish to build the `ip` example for an `stm32f429`, we should run the following command:
124110

125111
```bash
126-
cargo build --release --example ip --features stm32f429,defmt,smoltcp-phy,smoltcp/defmt,smoltcp/socket-tcp --target thumbv7em-none-eabihf
112+
cargo build --release --example ip \
113+
--features stm32f429,smoltcp-phy \
114+
--target thumbv7em-none-eabihf
115+
```
116+
117+
If we wish to build the `arp` example for a Nucleo-F767ZI with a HSE oscillator:
118+
119+
```bash
120+
STM32_ETH_EXAMPLE_HSE=bypass STM32_ETH_EXAMPLE_PINS=nucleo \
121+
cargo build --release --example arp \
122+
--features stm32f767
127123
```
128124

129125
### Running examples
@@ -135,15 +131,27 @@ Ensure that `probe-run` can attach to your MCU
135131

136132
Then, run the following command:
137133
```bash
138-
DEFMT_LOG=info PROBE_RUN_CHIP=<probe-run chip> cargo run --release --example <example> --features <MCU feature>,<additional required features> --target <MCU compilation target>
134+
DEFMT_LOG=info PROBE_RUN_CHIP=<probe-run chip> \
135+
cargo run --release --example <example> \
136+
--features <MCU feature>,<additional required features> \
137+
--target <MCU compilation target>
139138
```
140139

141140
For example, if we wish to run the `rtic-echo` example on an `STM32F107RCT6`, we should run the following command:
142141

143142
```bash
144-
DEFMT_LOG=info PROBE_RUN_CHIP=STM32F107RC cargo run --release --example rtic-echo --features stm32f107,rtic-echo-example --target thumbv7m-none-eabi
143+
DEFMT_LOG=info PROBE_RUN_CHIP=STM32F107RC \
144+
cargo run --release --example rtic-echo \
145+
--features stm32f107,smoltcp-phy \
146+
--target thumbv7m-none-eabi
145147
```
146148

147-
### Other pin configurations
149+
Or, if we want to run the `arp` example on a Nucleo-F767ZI with a HSE oscillator:
148150

149-
If the usage of different pins is required, the types and `setup_pins` function in `examples/common.rs` should be edited. If the pin configuration is for a `nucleo` board or other commonly used board, a PR with the changes is most welcome.
151+
```bash
152+
DEFMT_LOG=info PROBE_RUN_CHIP=STM32F767ZGTx \
153+
STM32_ETH_EXAMPLE_PINS=nucleo STM32_ETH_EXAMPLE_HSE=oscillator \
154+
cargo run --release --example arp \
155+
--features stm32f767 \
156+
--target thumbv7em-none-eabihf
157+
```

build.rs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
11
fn main() {
22
#[cfg(feature = "stm32f1xx-hal")]
3-
println!("cargo:rustc-link-search=memory.x")
3+
println!("cargo:rustc-link-search=memory.x");
4+
5+
let hse = std::env::var("STM32_ETH_EXAMPLE_HSE");
6+
7+
if let Ok(hse) = hse {
8+
if hse == "bypass" {
9+
println!("cargo:rustc-cfg=hse=\"bypass\"")
10+
} else if hse == "oscillator" {
11+
println!("cargo:rustc-cfg=hse=\"oscillator\"");
12+
} else if hse != "off" {
13+
panic!("Invalid STM32_ETH_EXAMPLE_HSE value. Allowed values: bypass, oscillator, off")
14+
}
15+
}
16+
17+
let example_pins = std::env::var("STM32_ETH_EXAMPLE_PINS");
18+
19+
if let Ok(pins) = example_pins {
20+
if pins == "nucleo" {
21+
println!("cargo:rustc-cfg=pins=\"nucleo\"")
22+
} else if pins != "default" {
23+
panic!("Invalid STM32_ETH_EXAMPLE_PINS value. Allowed values: nucleo, default");
24+
}
25+
}
26+
27+
println!("cargo:rerun-if-env-changed=STM32_ETH_EXAMPLE_HSE");
28+
println!("cargo:rerun-if-env-changed=STM32_ETH_EXAMPLE_PINS");
429
}

examples/common.rs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,37 @@ pub fn setup_peripherals(p: stm32_eth::stm32::Peripherals) -> (Clocks, Gpio, Eth
3636
{
3737
let rcc = p.RCC.constrain();
3838

39-
let clocks = rcc.cfgr.sysclk(100.MHz()).hclk(100.MHz()).freeze();
39+
let clocks = rcc.cfgr.sysclk(100.MHz()).hclk(100.MHz());
40+
41+
#[cfg(feature = "stm32f4xx-hal")]
42+
let clocks = {
43+
if cfg!(hse = "bypass") {
44+
clocks.use_hse(8.MHz()).bypass_hse_oscillator()
45+
} else if cfg!(hse = "oscillator") {
46+
clocks.use_hse(8.MHz())
47+
} else {
48+
clocks
49+
}
50+
};
51+
52+
#[cfg(feature = "stm32f7xx-hal")]
53+
let clocks = {
54+
if cfg!(hse = "bypass") {
55+
clocks.hse(stm32_eth::hal::rcc::HSEClock::new(
56+
8.MHz(),
57+
stm32_eth::hal::rcc::HSEClockMode::Bypass,
58+
))
59+
} else if cfg!(hse = "oscillator") {
60+
clocks.hse(stm32_eth::hal::rcc::HSEClock::new(
61+
8.MHz(),
62+
stm32_eth::hal::rcc::HSEClockMode::Oscillator,
63+
))
64+
} else {
65+
clocks
66+
}
67+
};
68+
69+
let clocks = clocks.freeze();
4070

4171
let gpio = Gpio {
4272
gpioa: p.GPIOA.split(),
@@ -55,11 +85,15 @@ pub fn setup_peripherals(p: stm32_eth::stm32::Peripherals) -> (Clocks, Gpio, Eth
5585
let rcc = p.RCC.constrain();
5686
let mut flash = p.FLASH.constrain();
5787

58-
let clocks = rcc
59-
.cfgr
60-
.sysclk(72.MHz())
61-
.hclk(72.MHz())
62-
.freeze(&mut flash.acr);
88+
let clocks = rcc.cfgr.sysclk(72.MHz()).hclk(72.MHz());
89+
90+
let clocks = if cfg!(hse = "bypass") || cfg!(hse = "oscillator") {
91+
clocks.use_hse(8.MHz())
92+
} else {
93+
clocks
94+
};
95+
96+
let clocks = clocks.freeze(&mut flash.acr);
6397

6498
let gpio = Gpio {
6599
gpioa: p.GPIOA.split(),
@@ -90,14 +124,14 @@ mod pins {
90124
pub type RxD0 = PC4<Input>;
91125
pub type RxD1 = PC5<Input>;
92126

93-
#[cfg(not(feature = "example-nucleo-pins"))]
127+
#[cfg(not(pins = "nucleo"))]
94128
pub type TxEn = PB11<Input>;
95-
#[cfg(not(feature = "example-nucleo-pins"))]
129+
#[cfg(not(pins = "nucleo"))]
96130
pub type TxD0 = PB12<Input>;
97131

98-
#[cfg(all(feature = "example-nucleo-pins"))]
132+
#[cfg(pins = "nucleo")]
99133
pub type TxEn = PG11<Input>;
100-
#[cfg(feature = "example-nucleo-pins")]
134+
#[cfg(pins = "nucleo")]
101135
pub type TxD0 = PG13<Input>;
102136

103137
pub type Mdio = PA2<Alternate<11>>;
@@ -124,13 +158,13 @@ mod pins {
124158
let rx_d0 = gpioc.pc4.into_floating_input();
125159
let rx_d1 = gpioc.pc5.into_floating_input();
126160

127-
#[cfg(not(feature = "example-nucleo-pins"))]
161+
#[cfg(not(pins = "nucleo"))]
128162
let (tx_en, tx_d0) = (
129163
gpiob.pb11.into_floating_input(),
130164
gpiob.pb12.into_floating_input(),
131165
);
132166

133-
#[cfg(feature = "example-nucleo-pins")]
167+
#[cfg(pins = "nucleo")]
134168
let (tx_en, tx_d0) = {
135169
(
136170
gpiog.pg11.into_floating_input(),

examples/ip.rs

Lines changed: 27 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
//! For build and run instructions, see README.md
55
//!
6-
//! This example starts a TCP listening server that should transmit `Hello` to
7-
//! any connecting client, and then close the connection.
6+
//! This example starts a TCP listening server at the address 10.0.0.1/24, on port 80, that
7+
//! should transmit `Hello` to any connecting client, and then close the connection.
88
99
use defmt_rtt as _;
1010
use panic_probe as _;
@@ -78,33 +78,40 @@ fn main() -> ! {
7878
);
7979
let server_handle = iface.add_socket(server_socket);
8080

81-
defmt::info!("Ready, listening at {}", ip_addr);
8281
loop {
8382
let time: u64 = cortex_m::interrupt::free(|cs| *TIME.borrow(cs).borrow());
8483
cortex_m::interrupt::free(|cs| {
8584
let mut eth_pending = ETH_PENDING.borrow(cs).borrow_mut();
8685
*eth_pending = false;
8786
});
88-
match iface.poll(Instant::from_millis(time as i64)) {
89-
Ok(true) => {
90-
let socket = iface.get_socket::<TcpSocket>(server_handle);
91-
if !socket.is_open() {
92-
if let Err(e) = socket.listen(80) {
93-
defmt::error!("TCP listen error: {:?}", e)
94-
}
95-
}
9687

97-
if socket.can_send() {
98-
if let Err(e) = socket.send_slice(b"hello\n").map(|_| socket.close()) {
99-
defmt::info!("TCP send error: {:?}", e);
88+
iface.poll(Instant::from_millis(time as i64)).ok();
89+
90+
let socket = iface.get_socket::<TcpSocket>(server_handle);
91+
92+
if !socket.is_listening() && !socket.is_open() {
93+
socket.abort();
94+
if let Err(e) = socket.listen(80) {
95+
defmt::error!("TCP listen error: {:?}", e)
96+
} else {
97+
defmt::info!("Listening at {}:80...", ip_addr);
98+
}
99+
} else {
100+
match socket.send_slice(b"hello\n") {
101+
Ok(_) => {
102+
while iface.get_socket::<TcpSocket>(server_handle).send_queue() != 0 {
103+
// Poll to get the message out of the door
104+
iface.poll(Instant::from_millis(time as i64 + 1)).ok();
100105
}
106+
107+
// Abort the connection
108+
let socket = iface.get_socket::<TcpSocket>(server_handle);
109+
socket.abort();
110+
defmt::info!("Transmitted hello! Closing socket...");
111+
112+
iface.poll(Instant::from_millis(time as i64 + 1)).ok();
101113
}
102-
}
103-
Ok(false) => {}
104-
Err(e) =>
105-
// Ignore malformed packets
106-
{
107-
defmt::info!("Error: {:?}", e);
114+
Err(_) => {}
108115
}
109116
}
110117
}

0 commit comments

Comments
 (0)