Compare commits

...

4 Commits

Author SHA1 Message Date
9a76ebdbeb Rotating blinky 2025-10-19 19:02:01 +02:00
53c97dcb32 Fix VSCode launch config 2025-10-19 18:28:33 +02:00
1f3162dc6f Add some UART output (via ST-Link VCP) 2025-10-17 08:09:02 +02:00
6e1c5370ba HALified blinky 2025-10-17 07:33:36 +02:00
4 changed files with 214 additions and 47 deletions

18
.vscode/launch.json vendored
View File

@@ -14,7 +14,7 @@
"cwd": "${workspaceRoot}",
"preLaunchTask": "Cargo Build (debug)",
"runToEntryPoint": "main",
"executable": "./target/thumbv7m-none-eabi/debug/{{project-name}}",
"executable": "./target/thumbv7m-none-eabi/debug/embedded-rs",
/* Run `cargo build --example hello` and uncomment this line to run semi-hosting example */
//"executable": "./target/thumbv7m-none-eabi/debug/examples/hello",
"cpu": "cortex-m3",
@@ -29,7 +29,7 @@
"cwd": "${workspaceRoot}",
"preLaunchTask": "Cargo Build (debug)",
"runToEntryPoint": "main",
"executable": "./target/thumbv7em-none-eabihf/debug/{{project-name}}",
"executable": "./target/thumbv7em-none-eabihf/debug/embedded-rs",
/* Run `cargo build --example itm` and uncomment this line to run itm example */
// "executable": "./target/thumbv7em-none-eabihf/debug/examples/itm",
"device": "STM32F303VCT6",
@@ -44,9 +44,17 @@
"swoFrequency": 2000000,
"source": "probe",
"decoders": [
{ "type": "console", "label": "ITM", "port": 0 }
{
"type": "console",
"label": "ITM",
"port": 0
}
]
}
},
"gdbPath": "gdb",
"postLaunchCommands": [
"monitor arm semihosting enable"
]
}
]
}
}

34
.vscode/tasks.json vendored
View File

@@ -10,9 +10,11 @@
* so we can invoke it from the debug launcher.
*/
"label": "Cargo Build (debug)",
"type": "process",
"type": "shell",
"command": "cargo",
"args": ["build"],
"args": [
"build"
],
"problemMatcher": [
"$rustc"
],
@@ -23,9 +25,12 @@
},
{
"label": "Cargo Build (release)",
"type": "process",
"type": "shell",
"command": "cargo",
"args": ["build", "--release"],
"args": [
"build",
"--release"
],
"problemMatcher": [
"$rustc"
],
@@ -34,8 +39,11 @@
{
"label": "Cargo Build Examples (debug)",
"type": "process",
"command": "cargo",
"args": ["build","--examples"],
"command": "shell",
"args": [
"build",
"--examples"
],
"problemMatcher": [
"$rustc"
],
@@ -43,9 +51,13 @@
},
{
"label": "Cargo Build Examples (release)",
"type": "process",
"type": "shell",
"command": "cargo",
"args": ["build","--examples", "--release"],
"args": [
"build",
"--examples",
"--release"
],
"problemMatcher": [
"$rustc"
],
@@ -53,9 +65,11 @@
},
{
"label": "Cargo Clean",
"type": "process",
"type": "shell",
"command": "cargo",
"args": ["clean"],
"args": [
"clean"
],
"problemMatcher": [],
"group": "build"
},

View File

@@ -10,7 +10,10 @@ cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
cortex-m-rt = "0.7"
cortex-m-semihosting = "0.5"
panic-halt = "1.0.0"
# stm32f3 = "0.7.1"
panic-semihosting = "0.6"
stm32f3 = { version = "0.16.0", features = ["stm32f303"] }
stm32f3xx-hal = { version = "0.10.0", features = ["stm32f303xc"] }
switch-hal = "0.4.0"
# Uncomment for the panic example.
# panic-itm = "0.4.1"
@@ -21,9 +24,9 @@ panic-halt = "1.0.0"
# Uncomment for the device example.
# Update `memory.x`, set target to `thumbv7em-none-eabihf` in `.cargo/config`,
# and then use `cargo build --example device` to build it.
[dependencies.stm32f3]
features = ["stm32f303", "rt"]
version = "^0.16.0"
# [dependencies.stm32f3]
# features = ["stm32f303", "rt"]
# version = "^0.16.0"
# this lets you use `cargo fix`!
[[bin]]

View File

@@ -1,51 +1,193 @@
#![no_std]
#![no_main]
use core::fmt::Write;
use core::slice::Iter;
use cortex_m_semihosting::hprintln;
// pick a panicking behavior
use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
// use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
// use panic_halt as _; // you can put a breakpoint on `rust_begin_unwind` to catch panics
// use panic_abort as _; // requires nightly
// use panic_itm as _; // logs messages over ITM; requires ITM support
use panic_semihosting as _; // logs messages to the host stderr; requires a debugger
use cortex_m::peripheral::{syst, Peripherals};
use cortex_m_rt::entry;
use stm32f3::stm32f303;
use stm32f3xx_hal::delay;
use stm32f3xx_hal::serial::Serial;
use stm32f3xx_hal::{
gpio::{self, gpioe},
pac,
prelude::*,
};
use switch_hal::{ActiveHigh, IntoSwitch, OutputSwitch, Switch};
enum Direction {
North,
NorthEast,
East,
SouthEast,
South,
SouthWest,
West,
NorthWest,
}
impl Direction {
pub fn iter() -> Iter<'static, Direction> {
static DIRECTIONS: [Direction; 8] = [
Direction::North,
Direction::NorthEast,
Direction::East,
Direction::SouthEast,
Direction::South,
Direction::SouthWest,
Direction::West,
Direction::NorthWest,
];
DIRECTIONS.iter()
}
}
type Led = Switch<gpioe::PEx<gpio::Output<gpio::PushPull>>, ActiveHigh>;
struct Leds {
ld3: Led,
ld4: Led,
ld5: Led,
ld6: Led,
ld7: Led,
ld8: Led,
ld9: Led,
ld10: Led,
}
impl Leds {
fn new<PE8Mode, PE9Mode, PE10Mode, PE11Mode, PE12Mode, PE13Mode, PE14Mode, PE15Mode>(
pe8: gpioe::PE8<PE8Mode>,
pe9: gpioe::PE9<PE9Mode>,
pe10: gpioe::PE10<PE10Mode>,
pe11: gpioe::PE11<PE11Mode>,
pe12: gpioe::PE12<PE12Mode>,
pe13: gpioe::PE13<PE13Mode>,
pe14: gpioe::PE14<PE14Mode>,
pe15: gpioe::PE15<PE15Mode>,
moder: &mut gpioe::MODER,
otyper: &mut gpioe::OTYPER,
) -> Self {
let mut leds = Self {
ld3: pe9
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld4: pe8
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld5: pe10
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld6: pe15
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld7: pe11
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld8: pe14
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld9: pe12
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
ld10: pe13
.into_push_pull_output(moder, otyper)
.downgrade()
.into_active_high_switch(),
};
for dir in Direction::iter() {
leds.for_direction(dir).off().ok();
}
leds
}
pub fn for_direction(&mut self, direction: &Direction) -> &mut Led {
match direction {
Direction::North => &mut self.ld3,
Direction::NorthEast => &mut self.ld5,
Direction::East => &mut self.ld7,
Direction::SouthEast => &mut self.ld9,
Direction::South => &mut self.ld10,
Direction::SouthWest => &mut self.ld8,
Direction::West => &mut self.ld6,
Direction::NorthWest => &mut self.ld4,
}
}
}
#[entry]
fn main() -> ! {
let cortex_peripherals = Peripherals::take().unwrap();
let dp = pac::Peripherals::take().unwrap();
let mut rcc = dp.RCC.constrain();
let mut flash = dp.FLASH.constrain();
let clocks = rcc.cfgr.sysclk(8.MHz()).freeze(&mut flash.acr);
// The HAL Serial example does this -- but where does Systick come from?
// https://github.com/stm32-rs/stm32f3xx-hal/blob/b0cead18208099b94a085fb634d0db4e75ac6e4d/examples/serial_echo_rtic.rs
// let mono = Systick::new(systick, 8_000_000);
let mut systick = cortex_peripherals.SYST;
systick.set_clock_source(syst::SystClkSource::Core);
systick.set_reload(8_000_000); // 1s
systick.clear_current();
let device_peripherals = stm32f303::Peripherals::take().unwrap();
let rcc = device_peripherals.RCC;
rcc.ahbenr().write(|w| w.iopeen().set_bit());
// PE9: LD3 (red)
// PE8: LD4 (blue)
// PE10: LD5 (orange)
let gpioe = device_peripherals.GPIOE;
gpioe
.moder()
.write(|w| w.moder9().output().moder8().output().moder10().output());
gpioe.bsrr().write(|w| w.bs9().set_bit());
gpioe.bsrr().write(|w| w.bs8().set_bit());
gpioe.bsrr().write(|w| w.bs10().set_bit());
let mut gpioe = dp.GPIOE.split(&mut rcc.ahb);
let mut leds = Leds::new(
gpioe.pe8,
gpioe.pe9,
gpioe.pe10,
gpioe.pe11,
gpioe.pe12,
gpioe.pe13,
gpioe.pe14,
gpioe.pe15,
&mut gpioe.moder,
&mut gpioe.otyper,
);
let mut gpioc = dp.GPIOC.split(&mut rcc.ahb);
let pins = (
gpioc
.pc4
// The specific AF number is fixed by the type arguments for Serial::new():
// impl<Otype> TxPin<USART1> for gpioc::PC4<AF7<Otype>> {}
.into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl),
gpioc
.pc5
.into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrl),
);
let mut uart = Serial::new(dp.USART1, pins, 115200.Bd(), clocks, &mut rcc.apb2);
let mut delay = delay::Delay::new(systick, clocks);
systick.enable_counter();
let mut enabled = true;
loop {
while !systick.has_wrapped() {}
enabled = !enabled;
gpioe.odr().write(|w| {
w.odr8()
.bit(enabled)
.odr9()
.bit(enabled)
.odr10()
.bit(enabled)
});
for dir in Direction::iter() {
let led = leds.for_direction(dir);
if enabled {
led.on().ok();
} else {
led.off().ok();
}
delay.delay_ms(50u16);
}
uart.write_str("Loop\r\n").unwrap();
hprintln!("Loop");
}
}