Skip to content

Commit

Permalink
feat(example): add stm32f4 example
Browse files Browse the repository at this point in the history
Signed-off-by: Haobo Gu <[email protected]>
  • Loading branch information
HaoboGu committed Jan 19, 2024
1 parent 8c665f9 commit fff5a80
Show file tree
Hide file tree
Showing 9 changed files with 323 additions and 3 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
[workspace]
resolver = "2"
members = ["rmk", "boards/*"]
members = [
"rmk",
"boards/rp2040",
# Uncomment to choose one chip you want to use
"boards/stm32h7",
#"boards/stm32f4"
]
default-members = ["boards/stm32h7", "rmk"]

# Profile dev: optimize for fast compiling with debug info
Expand Down
36 changes: 36 additions & 0 deletions boards/stm32f4/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
# uncomment ONE of these three option to make `cargo run` start a GDB session
# which option to pick depends on your system
runner = "probe-rs run --chip STM32F411CEUx"
# runner = "gdb-multiarch -q -x openocd.gdb"
# runner = "gdb -q -x openocd.gdb"

rustflags = [
# Previously, the linker arguments --nmagic and -Tlink.x were set here.
# They are now set by build.rs instead. The linker argument can still
# only be set here, if a custom linker is needed.

# By default, the LLD linker is used, which is shipped with the Rust
# toolchain. If you run into problems with LLD, you can switch to the
# GNU linker by uncommenting this line:
# "-C", "linker=arm-none-eabi-ld",

# If you need to link to pre-compiled C libraries provided by a C toolchain
# use GCC as the linker by uncommenting the three lines below:
# "-C", "linker=arm-none-eabi-gcc",
# "-C", "link-arg=-Wl,-Tlink.x",
# "-C", "link-arg=-nostartfiles",
]

[build]
# Pick ONE of these default compilation targets
# 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)
# target = "thumbv8m.base-none-eabi" # Cortex-M23
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

[env]
DEFMT_LOG = "info"
57 changes: 57 additions & 0 deletions boards/stm32f4/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
cargo-features = ["per-package-target"]

[package]
name = "rmk-stm32f4"
version = "0.1.0"
authors = ["Haobo Gu <[email protected]>"]
description = "Keyboard firmware written in Rust"
homepage = "https://github.com/haobogu/rmk"
repository = "https://github.com/haobogu/rmk"
readme = "../../README.md"
edition = "2021"
license = "MIT OR Apache-2.0"

forced-target = "thumbv7em-none-eabihf"

[dependencies]
rmk = { version = "0.1.0", path = "../../rmk", features = [
"eeprom",
"col2row",
] }
cortex-m = { version = "0.7.7", features = ['critical-section-single-core'] }
cortex-m-rt = "0.7.3"
embassy-time = { version = "0.3", git = "https://github.com/embassy-rs/embassy", features = [
# "tick-hz-1_000_000",
"tick-hz-32_768",
"defmt",
] }
embassy-stm32 = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy", features = [
"stm32f411ce",
"defmt",
"time-driver-any",
"exti",
"time",
] }
embassy-executor = { version = "0.5.0", git = "https://github.com/embassy-rs/embassy", features = [
"defmt",
"arch-cortex-m",
"executor-thread",
"executor-interrupt",
"integrated-timers",
] }
embassy-futures = { version = "0.1.0", git = "https://github.com/embassy-rs/embassy" }
rtt-target = "0.5.0"
log = "0.4.19"
packed_struct = { version = "0.10.1", default-features = false }
embedded-storage = { version = "0.3" }
static_cell = { version = "2" }

# defmt deps
defmt = "0.3.5"
defmt-rtt = "0.4.0"
panic-probe = {version = "0.3", features = ["print-defmt"] }

[[bin]]
name = "rmk-stm32f4"
test = false
bench = false
48 changes: 48 additions & 0 deletions boards/stm32f4/build.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//! This build script copies the `memory.x` file from the crate root into
//! a directory where the linker can always find it at build time.
//! For many projects this is optional, as the linker always searches the
//! project root directory -- wherever `Cargo.toml` is. However, if you
//! are using a workspace or have a more complicated build setup, this
//! build script becomes required. Additionally, by requesting that
//! Cargo re-run the build script whenever `memory.x` is changed,
//! updating `memory.x` ensures a rebuild of the application with the
//! new memory settings.
//!
//! The build script also sets the linker flags to tell it which link script to use.
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::PathBuf;

fn main() {
// Put `memory.x` in our output directory and ensure it's
// on the linker search path.
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
File::create(out.join("memory.x"))
.unwrap()
.write_all(include_bytes!("memory.x"))
.unwrap();
println!("cargo:rustc-link-search={}", out.display());

// By default, Cargo will re-run a build script whenever
// any file in the project changes. By specifying `memory.x`
// here, we ensure the build script is only re-run when
// `memory.x` is changed.
println!("cargo:rerun-if-changed=memory.x");

// Specify linker arguments.

// `--nmagic` is required if memory section addresses are not aligned to 0x10000,
// for example the FLASH and RAM sections in your `memory.x`.
// See https://github.com/rust-embedded/cortex-m-quickstart/pull/95
println!("cargo:rustc-link-arg=--nmagic");

// Set the linker script to the one provided by cortex-m-rt.
println!("cargo:rustc-link-arg=-Tlink.x");

// Set the extra linker script from defmt
println!("cargo:rustc-link-arg=-Tdefmt.x");

println!("cargo:rustc-linker=flip-link");
}
11 changes: 11 additions & 0 deletions boards/stm32f4/memory.x
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
MEMORY
{
/* NOTE K = KiBi = 1024 bytes */
FLASH : ORIGIN = 0x08000000, LENGTH = 128K
RAM : ORIGIN = 0x20000000, LENGTH = 128K
}

/* 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);
21 changes: 21 additions & 0 deletions boards/stm32f4/src/keymap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use rmk::action::KeyAction;
use rmk::{a, k, layer, mo};
pub(crate) const COL: usize = 3;
pub(crate) const ROW: usize = 4;
pub(crate) const NUM_LAYER: usize = 2;

#[rustfmt::skip]
pub static KEYMAP: [[[KeyAction; COL]; ROW]; NUM_LAYER] = [
layer!([
[k!(AudioVolUp), k!(B), k!(AudioVolDown)],
[k!(Kp4), k!(LShift), k!(Kp6)],
[mo!(1), k!(Kp2), k!(Kp3)],
[mo!(1), a!(No), k!(Kp0)]
]),
layer!([
[k!(Kp7), k!(Kp8), k!(Kp9)],
[k!(Kp4), k!(LCtrl), k!(Kp6)],
[mo!(1), k!(Kp2), k!(Kp3)],
[mo!(1), a!(No), k!(Kp0)]
]),
];
32 changes: 32 additions & 0 deletions boards/stm32f4/src/macros.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// DEPRECIATED
macro_rules! _config_matrix_pins {
(input: [$($in_port:ident.$in_pin:ident), *], output: [$($out_port:ident.$out_pin:ident), +]) => {
{
$(
let $in_pin = $in_port.$in_pin.into_pull_down_input().erase();
)*
$(
let mut $out_pin = $out_port.$out_pin.into_push_pull_output().erase();
)+
$(
$out_pin.set_low();
)+
let output_pins = [$($out_pin), +];
let input_pins = [$($in_pin), +];
(input_pins, output_pins)
}
};
}

macro_rules! config_matrix_pins_stm32 {
(peripherals: $p:ident, input: [$($in_pin:ident), *], output: [$($out_pin:ident), +]) => {
{
let mut output_pins = [$(Output::new($p.$out_pin, embassy_stm32::gpio::Level::Low, embassy_stm32::gpio::Speed::VeryHigh).degrade()), +];
let input_pins = [$(Input::new($p.$in_pin, embassy_stm32::gpio::Pull::Down).degrade()), +];
output_pins.iter_mut().for_each(|p| {
p.set_low();
});
(input_pins, output_pins)
}
};
}
109 changes: 109 additions & 0 deletions boards/stm32f4/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#![no_main]
#![no_std]
#![feature(type_alias_impl_trait)]
#![allow(dead_code)]

#[macro_use]
mod macros;
mod keymap;

use core::{cell::RefCell, sync::atomic::AtomicBool};
use defmt::*;
use defmt_rtt as _;
use embassy_executor::Spawner;
use embassy_futures::join::join;
use embassy_stm32::{
bind_interrupts,
flash::{Blocking, Flash},
gpio::{AnyPin, Input, Output},
peripherals::USB_OTG_FS,
usb_otg::{Driver, InterruptHandler},
Config,
};
use embassy_time::Timer;
use panic_probe as _;
use rmk::{eeprom::EepromStorageConfig, initialize_keyboard_and_usb_device, keymap::KeyMap};
use static_cell::StaticCell;

use crate::keymap::{COL, NUM_LAYER, ROW};

bind_interrupts!(struct Irqs {
OTG_FS => InterruptHandler<USB_OTG_FS>;
});

static SUSPENDED: AtomicBool = AtomicBool::new(false);
const FLASH_SECTOR_7_ADDR: u32 = 0x60000;
const EEPROM_SIZE: usize = 128;

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
info!("start!");
// RCC config
let config = Config::default();

// Initialize peripherals
let p = embassy_stm32::init(config);

// Usb config
static EP_OUT_BUFFER: StaticCell<[u8; 1024]> = StaticCell::new();
let mut usb_config = embassy_stm32::usb_otg::Config::default();
usb_config.vbus_detection = false;
let driver = Driver::new_fs(
p.USB_OTG_FS,
Irqs,
p.PA12,
p.PA11,
&mut EP_OUT_BUFFER.init([0; 1024])[..],
usb_config,
);

// Pin config
let (input_pins, output_pins) = config_matrix_pins_stm32!(peripherals: p, input: [PD9, PD8, PB13, PB12], output: [PE13, PE14, PE15]);

// Keymap + eeprom config
static MY_KEYMAP: StaticCell<
RefCell<KeyMap<Flash<'_, Blocking>, EEPROM_SIZE, ROW, COL, NUM_LAYER>>,
> = StaticCell::new();
let eeprom_storage_config = EepromStorageConfig {
start_addr: FLASH_SECTOR_7_ADDR,
storage_size: 0x20000, // uses last sector, 128KB for eeprom
page_size: 8,
};
// Use internal flash to emulate eeprom
let f = Flash::new_blocking(p.FLASH);
let keymap = MY_KEYMAP.init(RefCell::new(KeyMap::new(
crate::keymap::KEYMAP,
Some(f),
eeprom_storage_config,
None,
)));

// Initialize all utilities: keyboard, usb and keymap
let (mut keyboard, mut usb_device, vial) = initialize_keyboard_and_usb_device::<
Driver<'_, USB_OTG_FS>,
Input<'_, AnyPin>,
Output<'_, AnyPin>,
Flash<'_, Blocking>,
EEPROM_SIZE,
ROW,
COL,
NUM_LAYER,
>(driver, input_pins, output_pins, keymap);

let usb_fut = usb_device.device.run();
let keyboard_fut = async {
loop {
let _ = keyboard.keyboard_task().await;
keyboard.send_report(&mut usb_device.keyboard_hid).await;
keyboard.send_media_report(&mut usb_device.other_hid).await;
}
};

let via_fut = async {
loop {
vial.process_via_report(&mut usb_device.via_hid).await;
Timer::after_millis(1).await;
}
};
join(usb_fut, join(keyboard_fut, via_fut)).await;
}

0 comments on commit fff5a80

Please sign in to comment.