mirror of
https://github.com/embassy-rs/embassy.git
synced 2025-09-26 20:00:27 +00:00
commit
e29be82c8b
1
.github/ci/doc.sh
vendored
1
.github/ci/doc.sh
vendored
@ -25,6 +25,7 @@ docserver-builder -i ./embassy-executor -o webroot/crates/embassy-executor/git.z
|
||||
docserver-builder -i ./embassy-futures -o webroot/crates/embassy-futures/git.zup
|
||||
docserver-builder -i ./embassy-nrf -o webroot/crates/embassy-nrf/git.zup
|
||||
docserver-builder -i ./embassy-rp -o webroot/crates/embassy-rp/git.zup
|
||||
docserver-builder -i ./embassy-mspm0 -o webroot/crates/embassy-mspm0/git.zup
|
||||
docserver-builder -i ./embassy-sync -o webroot/crates/embassy-sync/git.zup
|
||||
docserver-builder -i ./cyw43 -o webroot/crates/cyw43/git.zup
|
||||
docserver-builder -i ./cyw43-pio -o webroot/crates/cyw43-pio/git.zup
|
||||
|
5
.vscode/settings.json
vendored
5
.vscode/settings.json
vendored
@ -28,6 +28,11 @@
|
||||
// To work on the examples, comment the line above and all of the cargo.features lines,
|
||||
// then uncomment ONE line below to select the chip you want to work on.
|
||||
// This makes rust-analyzer work on the example crate and all its dependencies.
|
||||
// "examples/mspm0c1104/Cargo.toml",
|
||||
// "examples/mspm0g3507/Cargo.toml",
|
||||
// "examples/mspm0g3519/Cargo.toml",
|
||||
// "examples/mspm0l1306/Cargo.toml",
|
||||
// "examples/mspm0l2228/Cargo.toml",
|
||||
// "examples/nrf52840-rtic/Cargo.toml",
|
||||
// "examples/nrf5340/Cargo.toml",
|
||||
// "examples/nrf-rtos-trace/Cargo.toml",
|
||||
|
@ -15,6 +15,7 @@ Rust's <a href="https://rust-lang.github.io/async-book/">async/await</a> allows
|
||||
- <a href="https://docs.embassy.dev/embassy-stm32/">embassy-stm32</a>, for all STM32 microcontroller families.
|
||||
- <a href="https://docs.embassy.dev/embassy-nrf/">embassy-nrf</a>, for the Nordic Semiconductor nRF52, nRF53, nRF54 and nRF91 series.
|
||||
- <a href="https://docs.embassy.dev/embassy-rp/">embassy-rp</a>, for the Raspberry Pi RP2040 and RP23xx microcontrollers.
|
||||
- <a href="https://docs.embassy.dev/embassy-mspm0/">embassy-mspm0</a>, for the Texas Instruments MSPM0 microcontrollers.
|
||||
- <a href="https://github.com/esp-rs">esp-rs</a>, for the Espressif Systems ESP32 series of chips.
|
||||
- Embassy HAL support for Espressif chips, as well as Async WiFi, Bluetooth and ESP-NOW, is being developed in the [esp-rs/esp-hal](https://github.com/esp-rs/esp-hal) repository.
|
||||
- <a href="https://github.com/ch32-rs/ch32-hal">ch32-hal</a>, for the WCH 32-bit RISC-V(CH32V) series of chips.
|
||||
|
14
ci.sh
14
ci.sh
@ -170,6 +170,11 @@ cargo batch \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u073mb,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-stm32/Cargo.toml --target thumbv6m-none-eabi --features stm32u083rc,defmt,exti,time-driver-any,time \
|
||||
--- build --release --manifest-path embassy-nxp/Cargo.toml --target thumbv8m.main-none-eabihf \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0c110x,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g350x,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0g351x,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l130x,defmt,time-driver-any \
|
||||
--- build --release --manifest-path embassy-mspm0/Cargo.toml --target thumbv6m-none-eabi --features mspm0l222x,defmt,time-driver-any \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features ''\
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'log' \
|
||||
--- build --release --manifest-path cyw43/Cargo.toml --target thumbv6m-none-eabi --features 'defmt' \
|
||||
@ -239,6 +244,10 @@ cargo batch \
|
||||
--- build --release --manifest-path examples/stm32wba/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/stm32wba \
|
||||
--- build --release --manifest-path examples/stm32wl/Cargo.toml --target thumbv7em-none-eabi --artifact-dir out/examples/stm32wl \
|
||||
--- build --release --manifest-path examples/lpc55s69/Cargo.toml --target thumbv8m.main-none-eabihf --artifact-dir out/examples/lpc55s69 \
|
||||
--- build --release --manifest-path examples/mspm0g3507/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3507 \
|
||||
--- build --release --manifest-path examples/mspm0g3519/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0g3519 \
|
||||
--- build --release --manifest-path examples/mspm0l1306/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l1306 \
|
||||
--- build --release --manifest-path examples/mspm0l2228/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0l2228 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv7em-none-eabi --features embassy-nrf/nrf52840,skip-include --artifact-dir out/examples/boot/nrf52840 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9160-ns,skip-include --artifact-dir out/examples/boot/nrf9160 \
|
||||
--- build --release --manifest-path examples/boot/application/nrf/Cargo.toml --target thumbv8m.main-none-eabihf --features embassy-nrf/nrf9120-ns,skip-include --artifact-dir out/examples/boot/nrf9120 \
|
||||
@ -303,6 +312,11 @@ cargo batch \
|
||||
$BUILD_EXTRA
|
||||
|
||||
|
||||
# MSPM0C1104 must be built seperately since cargo batch does not consider env vars set in `.cargo/config.toml`.
|
||||
# Since the target has 1KB of ram, we need to limit defmt's buffer size.
|
||||
DEFMT_RTT_BUFFER_SIZE="72" cargo batch \
|
||||
--- build --release --manifest-path examples/mspm0c1104/Cargo.toml --target thumbv6m-none-eabi --artifact-dir out/examples/mspm0c1104 \
|
||||
|
||||
# temporarily disabled, these boards are dead.
|
||||
rm -rf out/tests/stm32f103c8
|
||||
rm -rf out/tests/nrf52840-dk
|
||||
|
@ -29,6 +29,7 @@ The Embassy project maintains HALs for select hardware, but you can still use HA
|
||||
* link:https://docs.embassy.dev/embassy-stm32/[embassy-stm32], for all STM32 microcontroller families.
|
||||
* link:https://docs.embassy.dev/embassy-nrf/[embassy-nrf], for the Nordic Semiconductor nRF52, nRF53, nRF91 series.
|
||||
* link:https://docs.embassy.dev/embassy-rp/[embassy-rp], for the Raspberry Pi RP2040 microcontroller.
|
||||
* link:https://docs.embassy.dev/embassy-mspm0/[embassy-mspm0], for the Texas Instruments MSPM0 microcontrollers.
|
||||
* link:https://github.com/esp-rs[esp-rs], for the Espressif Systems ESP32 series of chips.
|
||||
* link:https://github.com/ch32-rs/ch32-hal[ch32-hal], for the WCH 32-bit RISC-V(CH32V) series of chips.
|
||||
* link:https://github.com/AlexCharlton/mpfs-hal[mpfs-hal], for the Microchip PolarFire SoC.
|
||||
|
131
embassy-mspm0/Cargo.toml
Normal file
131
embassy-mspm0/Cargo.toml
Normal file
@ -0,0 +1,131 @@
|
||||
[package]
|
||||
name = "embassy-mspm0"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers"
|
||||
keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"]
|
||||
categories = ["embedded", "hardware-support", "no-std", "asynchronous"]
|
||||
repository = "https://github.com/embassy-rs/embassy"
|
||||
documentation = "https://docs.embassy.dev/embassy-mspm0"
|
||||
|
||||
[package.metadata.embassy_docs]
|
||||
src_base = "https://github.com/embassy-rs/embassy/blob/embassy-mspm0-v$VERSION/embassy-mspm0/src/"
|
||||
src_base_git = "https://github.com/embassy-rs/embassy/blob/$COMMIT/embassy-mspm0/src/"
|
||||
|
||||
features = ["defmt", "unstable-pac", "time-driver-any"]
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"]
|
||||
rustdoc-args = ["--cfg", "docsrs"]
|
||||
|
||||
[dependencies]
|
||||
embassy-sync = { version = "0.6.2", path = "../embassy-sync" }
|
||||
embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true }
|
||||
# TODO: Support other tick rates
|
||||
embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true, features = ["tick-hz-32_768"] }
|
||||
embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true }
|
||||
embassy-futures = { version = "0.1.0", path = "../embassy-futures" }
|
||||
embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] }
|
||||
embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false }
|
||||
embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true }
|
||||
|
||||
embedded-hal = { version = "1.0" }
|
||||
embedded-hal-async = { version = "1.0" }
|
||||
|
||||
defmt = { version = "0.3", optional = true }
|
||||
log = { version = "0.4.14", optional = true }
|
||||
cortex-m-rt = ">=0.6.15,<0.8"
|
||||
cortex-m = "0.7.6"
|
||||
critical-section = "1.2.0"
|
||||
|
||||
# mspm0-metapac = { version = "" }
|
||||
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d" }
|
||||
|
||||
[build-dependencies]
|
||||
proc-macro2 = "1.0.94"
|
||||
quote = "1.0.40"
|
||||
|
||||
# mspm0-metapac = { version = "", default-features = false, features = ["metadata"] }
|
||||
mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d", default-features = false, features = ["metadata"] }
|
||||
|
||||
[features]
|
||||
default = ["rt"]
|
||||
|
||||
## Enable `mspm0-metapac`'s `rt` feature
|
||||
rt = ["mspm0-metapac/rt"]
|
||||
|
||||
## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging
|
||||
defmt = [
|
||||
"dep:defmt",
|
||||
"embassy-sync/defmt",
|
||||
"embassy-embedded-hal/defmt",
|
||||
"embassy-hal-internal/defmt",
|
||||
"embassy-time?/defmt",
|
||||
]
|
||||
|
||||
## Re-export mspm0-metapac at `mspm0::pac`.
|
||||
## This is unstable because semver-minor (non-breaking) releases of embassy-mspm0 may major-bump (breaking) the mspm0-metapac version.
|
||||
## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC.
|
||||
## There are no plans to make this stable.
|
||||
unstable-pac = []
|
||||
|
||||
#! ## Time
|
||||
|
||||
# Features starting with `_` are for internal use only. They're not intended
|
||||
# to be enabled by other crates, and are not covered by semver guarantees.
|
||||
_time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"]
|
||||
|
||||
# Use any time driver
|
||||
time-driver-any = ["_time-driver"]
|
||||
## Use TIMG0 as time driver
|
||||
time-driver-timg0 = ["_time-driver"]
|
||||
## Use TIMG1 as time driver
|
||||
time-driver-timg1 = ["_time-driver"]
|
||||
## Use TIMG2 as time driver
|
||||
time-driver-timg2 = ["_time-driver"]
|
||||
## Use TIMG3 as time driver
|
||||
time-driver-timg3 = ["_time-driver"]
|
||||
## Use TIMG4 as time driver
|
||||
time-driver-timg4 = ["_time-driver"]
|
||||
## Use TIMG5 as time driver
|
||||
time-driver-timg5 = ["_time-driver"]
|
||||
## Use TIMG6 as time driver
|
||||
time-driver-timg6 = ["_time-driver"]
|
||||
## Use TIMG7 as time driver
|
||||
time-driver-timg7 = ["_time-driver"]
|
||||
## Use TIMG8 as time driver
|
||||
time-driver-timg8 = ["_time-driver"]
|
||||
## Use TIMG9 as time driver
|
||||
time-driver-timg9 = ["_time-driver"]
|
||||
## Use TIMG10 as time driver
|
||||
time-driver-timg10 = ["_time-driver"]
|
||||
## Use TIMG11 as time driver
|
||||
time-driver-timg11 = ["_time-driver"]
|
||||
# TODO: Support TIMG12 and TIMG13
|
||||
## Use TIMG14 as time driver
|
||||
time-driver-timg14 = ["_time-driver"]
|
||||
## Use TIMA0 as time driver
|
||||
time-driver-tima0 = ["_time-driver"]
|
||||
## Use TIMA1 as time driver
|
||||
time-driver-tima1 = ["_time-driver"]
|
||||
|
||||
#! ## Chip-selection features
|
||||
#! Select your chip by specifying the model as a feature, e.g. `mspm0g350x`.
|
||||
#! Check the `Cargo.toml` for the latest list of supported chips.
|
||||
#!
|
||||
#! **Important:** Do not forget to adapt the target chip in your toolchain,
|
||||
#! e.g. in `.cargo/config.toml`.
|
||||
|
||||
mspm0c110x = [ "mspm0-metapac/mspm0c110x" ]
|
||||
mspm0g110x = [ "mspm0-metapac/mspm0g110x" ]
|
||||
mspm0g150x = [ "mspm0-metapac/mspm0g150x" ]
|
||||
mspm0g151x = [ "mspm0-metapac/mspm0g151x" ]
|
||||
mspm0g310x = [ "mspm0-metapac/mspm0g310x" ]
|
||||
mspm0g350x = [ "mspm0-metapac/mspm0g350x" ]
|
||||
mspm0g351x = [ "mspm0-metapac/mspm0g351x" ]
|
||||
mspm0l110x = [ "mspm0-metapac/mspm0l110x" ]
|
||||
mspm0l122x = [ "mspm0-metapac/mspm0l122x" ]
|
||||
mspm0l130x = [ "mspm0-metapac/mspm0l130x" ]
|
||||
mspm0l134x = [ "mspm0-metapac/mspm0l134x" ]
|
||||
mspm0l222x = [ "mspm0-metapac/mspm0l222x" ]
|
611
embassy-mspm0/build.rs
Normal file
611
embassy-mspm0/build.rs
Normal file
@ -0,0 +1,611 @@
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::sync::LazyLock;
|
||||
use std::{env, fs};
|
||||
|
||||
use common::CfgSet;
|
||||
use mspm0_metapac::metadata::METADATA;
|
||||
use proc_macro2::{Ident, Literal, Span, TokenStream};
|
||||
use quote::{format_ident, quote};
|
||||
|
||||
#[path = "./build_common.rs"]
|
||||
mod common;
|
||||
|
||||
fn main() {
|
||||
generate_code();
|
||||
}
|
||||
|
||||
fn generate_code() {
|
||||
let mut cfgs = common::CfgSet::new();
|
||||
common::set_target_cfgs(&mut cfgs);
|
||||
|
||||
cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]);
|
||||
|
||||
let mut singletons = Vec::new();
|
||||
|
||||
// Generate singletons for GPIO pins. To only consider pins available on a family, use the name of
|
||||
// the pins from the pincm mappings.
|
||||
for pincm_mapping in METADATA.pincm_mappings.iter() {
|
||||
singletons.push(pincm_mapping.pin.to_string());
|
||||
}
|
||||
|
||||
for peri in METADATA.peripherals {
|
||||
match peri.kind {
|
||||
// Specially generated.
|
||||
"gpio" => match peri.name {
|
||||
"GPIOB" => cfgs.enable("gpio_pb"),
|
||||
"GPIOC" => cfgs.enable("gpio_pc"),
|
||||
_ => (),
|
||||
},
|
||||
|
||||
// These peripherals are managed internally by the hal.
|
||||
"iomux" | "cpuss" => {}
|
||||
|
||||
_ => singletons.push(peri.name.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
time_driver(&singletons, &mut cfgs);
|
||||
|
||||
// ========
|
||||
// Write singletons
|
||||
let mut g = TokenStream::new();
|
||||
|
||||
let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect();
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*);
|
||||
});
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*);
|
||||
});
|
||||
|
||||
// ========
|
||||
// Generate GPIO pincm lookup tables.
|
||||
let pincms = METADATA.pincm_mappings.iter().map(|mapping| {
|
||||
let port_letter = mapping.pin.strip_prefix("P").unwrap();
|
||||
let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32;
|
||||
// This assumes all ports are single letter length.
|
||||
// This is fine unless TI releases a part with 833+ GPIO pins.
|
||||
let pin_number = mapping.pin[2..].parse::<u8>().unwrap();
|
||||
|
||||
let num = port_base + pin_number;
|
||||
|
||||
// But subtract 1 since pincm indices start from 0, not 1.
|
||||
let pincm = Literal::u8_unsuffixed(mapping.pincm - 1);
|
||||
quote! {
|
||||
#num => #pincm
|
||||
}
|
||||
});
|
||||
|
||||
g.extend(quote! {
|
||||
#[doc = "Get the mapping from GPIO pin port to IOMUX PINCM index. This is required since the mapping from IO to PINCM index is not consistent across parts."]
|
||||
pub(crate) fn gpio_pincm(pin_port: u8) -> u8 {
|
||||
match pin_port {
|
||||
#(#pincms),*,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for pincm_mapping in METADATA.pincm_mappings.iter() {
|
||||
let name = Ident::new(&pincm_mapping.pin, Span::call_site());
|
||||
let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap();
|
||||
let port_letter = port_letter.chars().next().unwrap();
|
||||
let pin_number = Literal::u8_unsuffixed(pincm_mapping.pin[2..].parse::<u8>().unwrap());
|
||||
|
||||
let port = Ident::new(&format!("Port{}", port_letter), Span::call_site());
|
||||
|
||||
// TODO: Feature gate pins that can be used as NRST
|
||||
|
||||
g.extend(quote! {
|
||||
impl_pin!(#name, crate::gpio::Port::#port, #pin_number);
|
||||
});
|
||||
}
|
||||
|
||||
// Generate timers
|
||||
for peripheral in METADATA.peripherals.iter().filter(|p| p.name.starts_with("TIM")) {
|
||||
let name = Ident::new(&peripheral.name, Span::call_site());
|
||||
let timers = &*TIMERS;
|
||||
|
||||
let timer = timers.get(peripheral.name).expect("Timer does not exist");
|
||||
assert!(timer.bits == 16 || timer.bits == 32);
|
||||
let bits = if timer.bits == 16 {
|
||||
quote! { Bits16 }
|
||||
} else {
|
||||
quote! { Bits32 }
|
||||
};
|
||||
|
||||
g.extend(quote! {
|
||||
impl_timer!(#name, #bits);
|
||||
});
|
||||
}
|
||||
|
||||
// Generate interrupt module
|
||||
let interrupts: Vec<Ident> = METADATA
|
||||
.interrupts
|
||||
.iter()
|
||||
.map(|interrupt| Ident::new(interrupt.name, Span::call_site()))
|
||||
.collect();
|
||||
|
||||
g.extend(quote! {
|
||||
embassy_hal_internal::interrupt_mod! {
|
||||
#(#interrupts),*
|
||||
}
|
||||
});
|
||||
|
||||
let group_interrupt_enables = METADATA
|
||||
.interrupts
|
||||
.iter()
|
||||
.filter(|interrupt| interrupt.name.contains("GROUP"))
|
||||
.map(|interrupt| {
|
||||
let name = Ident::new(interrupt.name, Span::call_site());
|
||||
|
||||
quote! {
|
||||
crate::interrupt::typelevel::#name::enable();
|
||||
}
|
||||
});
|
||||
|
||||
// Generate interrupt enables for groups
|
||||
g.extend(quote! {
|
||||
pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) {
|
||||
use crate::interrupt::typelevel::Interrupt;
|
||||
|
||||
unsafe {
|
||||
#(#group_interrupt_enables)*
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
|
||||
let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string();
|
||||
fs::write(&out_file, g.to_string()).unwrap();
|
||||
rustfmt(&out_file);
|
||||
}
|
||||
|
||||
fn time_driver(singletons: &[String], cfgs: &mut CfgSet) {
|
||||
// Timer features
|
||||
for (timer, desc) in TIMERS.iter() {
|
||||
if desc.bits != 16 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let name = timer.to_lowercase();
|
||||
cfgs.declare(&format!("time_driver_{}", name));
|
||||
}
|
||||
|
||||
let time_driver = match env::vars()
|
||||
.map(|(a, _)| a)
|
||||
.filter(|x| x.starts_with("CARGO_FEATURE_TIME_DRIVER_"))
|
||||
.get_one()
|
||||
{
|
||||
Ok(x) => Some(
|
||||
x.strip_prefix("CARGO_FEATURE_TIME_DRIVER_")
|
||||
.unwrap()
|
||||
.to_ascii_lowercase(),
|
||||
),
|
||||
Err(GetOneError::None) => None,
|
||||
Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"),
|
||||
};
|
||||
|
||||
// Verify the selected timer is available
|
||||
let singleton = match time_driver.as_ref().map(|x| x.as_ref()) {
|
||||
None => "",
|
||||
Some("timg0") => "TIMG0",
|
||||
Some("timg1") => "TIMG1",
|
||||
Some("timg2") => "TIMG2",
|
||||
Some("timg3") => "TIMG3",
|
||||
Some("timg4") => "TIMG4",
|
||||
Some("timg5") => "TIMG5",
|
||||
Some("timg6") => "TIMG6",
|
||||
Some("timg7") => "TIMG7",
|
||||
Some("timg8") => "TIMG8",
|
||||
Some("timg9") => "TIMG9",
|
||||
Some("timg10") => "TIMG10",
|
||||
Some("timg11") => "TIMG11",
|
||||
Some("timg14") => "TIMG14",
|
||||
Some("tima0") => "TIMA0",
|
||||
Some("tima1") => "TIMA1",
|
||||
Some("any") => {
|
||||
// Order of timer candidates:
|
||||
// 1. 16-bit, 2 channel
|
||||
// 2. 16-bit, 2 channel with shadow registers
|
||||
// 3. 16-bit, 4 channel
|
||||
// 4. 16-bit with QEI
|
||||
// 5. Advanced timers
|
||||
//
|
||||
// TODO: Select RTC first if available
|
||||
// TODO: 32-bit timers are not considered yet
|
||||
[
|
||||
// 16-bit, 2 channel
|
||||
"TIMG0", "TIMG1", "TIMG2", "TIMG3", // 16-bit, 2 channel with shadow registers
|
||||
"TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel
|
||||
"TIMG14", // 16-bit with QEI
|
||||
"TIMG8", "TIMG9", "TIMG10", "TIMG11", // Advanced timers
|
||||
"TIMA0", "TIMA1",
|
||||
]
|
||||
.iter()
|
||||
.find(|tim| singletons.contains(&tim.to_string()))
|
||||
.expect("Could not find any timer")
|
||||
}
|
||||
_ => panic!("unknown time_driver {:?}", time_driver),
|
||||
};
|
||||
|
||||
if !singleton.is_empty() {
|
||||
cfgs.enable(format!("time_driver_{}", singleton.to_lowercase()));
|
||||
}
|
||||
}
|
||||
|
||||
/// rustfmt a given path.
|
||||
/// Failures are logged to stderr and ignored.
|
||||
fn rustfmt(path: impl AsRef<Path>) {
|
||||
let path = path.as_ref();
|
||||
match Command::new("rustfmt").args([path]).output() {
|
||||
Err(e) => {
|
||||
eprintln!("failed to exec rustfmt {:?}: {:?}", path, e);
|
||||
}
|
||||
Ok(out) => {
|
||||
if !out.status.success() {
|
||||
eprintln!("rustfmt {:?} failed:", path);
|
||||
eprintln!("=== STDOUT:");
|
||||
std::io::stderr().write_all(&out.stdout).unwrap();
|
||||
eprintln!("=== STDERR:");
|
||||
std::io::stderr().write_all(&out.stderr).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct TimerDesc {
|
||||
bits: u8,
|
||||
/// Is there an 8-bit prescaler
|
||||
prescaler: bool,
|
||||
/// Is there a repeat counter
|
||||
repeat_counter: bool,
|
||||
ccp_channels_internal: u8,
|
||||
ccp_channels_external: u8,
|
||||
external_pwm_channels: u8,
|
||||
phase_load: bool,
|
||||
shadow_load: bool,
|
||||
shadow_ccs: bool,
|
||||
deadband: bool,
|
||||
fault_handler: bool,
|
||||
qei_hall: bool,
|
||||
}
|
||||
|
||||
/// Description of all timer instances.
|
||||
const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| {
|
||||
let mut map = HashMap::new();
|
||||
map.insert(
|
||||
"TIMG0".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG1".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG2".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG3".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG4".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG5".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG6".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG7".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG8".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: true,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG9".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: true,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG10".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: true,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG11".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: true,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG12".into(),
|
||||
TimerDesc {
|
||||
bits: 32,
|
||||
prescaler: false,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG13".into(),
|
||||
TimerDesc {
|
||||
bits: 32,
|
||||
prescaler: false,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 2,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: true,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMG14".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: false,
|
||||
ccp_channels_internal: 4,
|
||||
ccp_channels_external: 4,
|
||||
external_pwm_channels: 4,
|
||||
phase_load: false,
|
||||
shadow_load: false,
|
||||
shadow_ccs: false,
|
||||
deadband: false,
|
||||
fault_handler: false,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMA0".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: true,
|
||||
ccp_channels_internal: 4,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 8,
|
||||
phase_load: true,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: true,
|
||||
fault_handler: true,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map.insert(
|
||||
"TIMA1".into(),
|
||||
TimerDesc {
|
||||
bits: 16,
|
||||
prescaler: true,
|
||||
repeat_counter: true,
|
||||
ccp_channels_internal: 2,
|
||||
ccp_channels_external: 2,
|
||||
external_pwm_channels: 4,
|
||||
phase_load: true,
|
||||
shadow_load: true,
|
||||
shadow_ccs: true,
|
||||
deadband: true,
|
||||
fault_handler: true,
|
||||
qei_hall: false,
|
||||
},
|
||||
);
|
||||
|
||||
map
|
||||
});
|
||||
|
||||
enum GetOneError {
|
||||
None,
|
||||
Multiple,
|
||||
}
|
||||
|
||||
trait IteratorExt: Iterator {
|
||||
fn get_one(self) -> Result<Self::Item, GetOneError>;
|
||||
}
|
||||
|
||||
impl<T: Iterator> IteratorExt for T {
|
||||
fn get_one(mut self) -> Result<Self::Item, GetOneError> {
|
||||
match self.next() {
|
||||
None => Err(GetOneError::None),
|
||||
Some(res) => match self.next() {
|
||||
Some(_) => Err(GetOneError::Multiple),
|
||||
None => Ok(res),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
94
embassy-mspm0/build_common.rs
Normal file
94
embassy-mspm0/build_common.rs
Normal file
@ -0,0 +1,94 @@
|
||||
// NOTE: this file is copy-pasted between several Embassy crates, because there is no
|
||||
// straightforward way to share this code:
|
||||
// - it cannot be placed into the root of the repo and linked from each build.rs using `#[path =
|
||||
// "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate
|
||||
// reside in the crate's directory,
|
||||
// - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because
|
||||
// symlinks don't work on Windows.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::env;
|
||||
|
||||
/// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring
|
||||
/// them (`cargo:rust-check-cfg=cfg(X)`).
|
||||
#[derive(Debug)]
|
||||
pub struct CfgSet {
|
||||
enabled: HashSet<String>,
|
||||
declared: HashSet<String>,
|
||||
}
|
||||
|
||||
impl CfgSet {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
enabled: HashSet::new(),
|
||||
declared: HashSet::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation.
|
||||
///
|
||||
/// All configs that can potentially be enabled should be unconditionally declared using
|
||||
/// [`Self::declare()`].
|
||||
pub fn enable(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.enabled.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-cfg={}", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.enable(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
/// Declare a valid config for conditional compilation, without enabling it.
|
||||
///
|
||||
/// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid.
|
||||
pub fn declare(&mut self, cfg: impl AsRef<str>) {
|
||||
if self.declared.insert(cfg.as_ref().to_owned()) {
|
||||
println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) {
|
||||
for cfg in cfgs.iter() {
|
||||
self.declare(cfg.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set(&mut self, cfg: impl Into<String>, enable: bool) {
|
||||
let cfg = cfg.into();
|
||||
if enable {
|
||||
self.enable(cfg.clone());
|
||||
}
|
||||
self.declare(cfg);
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets configs that describe the target platform.
|
||||
pub fn set_target_cfgs(cfgs: &mut CfgSet) {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
|
||||
if target.starts_with("thumbv6m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv6m"]);
|
||||
} else if target.starts_with("thumbv7m-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m"]);
|
||||
} else if target.starts_with("thumbv7em-") {
|
||||
cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]);
|
||||
} else if target.starts_with("thumbv8m.base") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]);
|
||||
} else if target.starts_with("thumbv8m.main") {
|
||||
cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]);
|
||||
}
|
||||
cfgs.declare_all(&[
|
||||
"cortex_m",
|
||||
"armv6m",
|
||||
"armv7m",
|
||||
"armv7em",
|
||||
"armv8m",
|
||||
"armv8m_base",
|
||||
"armv8m_main",
|
||||
]);
|
||||
|
||||
cfgs.set("has_fpu", target.ends_with("-eabihf"));
|
||||
}
|
270
embassy-mspm0/src/fmt.rs
Normal file
270
embassy-mspm0/src/fmt.rs
Normal file
@ -0,0 +1,270 @@
|
||||
#![macro_use]
|
||||
#![allow(unused)]
|
||||
|
||||
use core::fmt::{Debug, Display, LowerHex};
|
||||
|
||||
#[cfg(all(feature = "defmt", feature = "log"))]
|
||||
compile_error!("You may not enable both `defmt` and `log` features.");
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! debug_assert {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! debug_assert_eq {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_eq!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_eq!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! debug_assert_ne {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::debug_assert_ne!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug_assert_ne!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! todo {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::todo!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::todo!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unreachable {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::unreachable!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::unreachable!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! panic {
|
||||
($($x:tt)*) => {
|
||||
{
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
::core::panic!($($x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::panic!($($x)*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! trace {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::trace!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::trace!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! debug {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::debug!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::debug!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! info {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::info!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::info!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! warn {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::warn!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::warn!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! error {
|
||||
($s:literal $(, $x:expr)* $(,)?) => {
|
||||
{
|
||||
#[cfg(feature = "log")]
|
||||
::log::error!($s $(, $x)*);
|
||||
#[cfg(feature = "defmt")]
|
||||
::defmt::error!($s $(, $x)*);
|
||||
#[cfg(not(any(feature = "log", feature="defmt")))]
|
||||
let _ = ($( & $x ),*);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unwrap {
|
||||
($($x:tt)*) => {
|
||||
::defmt::unwrap!($($x)*)
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "defmt"))]
|
||||
#[collapse_debuginfo(yes)]
|
||||
macro_rules! unwrap {
|
||||
($arg:expr) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
|
||||
}
|
||||
}
|
||||
};
|
||||
($arg:expr, $($msg:expr),+ $(,)? ) => {
|
||||
match $crate::fmt::Try::into_result($arg) {
|
||||
::core::result::Result::Ok(t) => t,
|
||||
::core::result::Result::Err(e) => {
|
||||
::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct NoneError;
|
||||
|
||||
pub trait Try {
|
||||
type Ok;
|
||||
type Error;
|
||||
fn into_result(self) -> Result<Self::Ok, Self::Error>;
|
||||
}
|
||||
|
||||
impl<T> Try for Option<T> {
|
||||
type Ok = T;
|
||||
type Error = NoneError;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Result<T, NoneError> {
|
||||
self.ok_or(NoneError)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, E> Try for Result<T, E> {
|
||||
type Ok = T;
|
||||
type Error = E;
|
||||
|
||||
#[inline]
|
||||
fn into_result(self) -> Self {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Bytes<'a>(pub &'a [u8]);
|
||||
|
||||
impl<'a> Debug for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:#02x?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Display for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:#02x?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> LowerHex for Bytes<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "{:#02x?}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "defmt")]
|
||||
impl<'a> defmt::Format for Bytes<'a> {
|
||||
fn format(&self, fmt: defmt::Formatter) {
|
||||
defmt::write!(fmt, "{:02x}", self.0)
|
||||
}
|
||||
}
|
1060
embassy-mspm0/src/gpio.rs
Normal file
1060
embassy-mspm0/src/gpio.rs
Normal file
File diff suppressed because it is too large
Load Diff
25
embassy-mspm0/src/int_group/c110x.rs
Normal file
25
embassy-mspm0/src/int_group/c110x.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use crate::pac;
|
||||
use crate::pac::interrupt;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP0() {
|
||||
use mspm0_metapac::Group0;
|
||||
|
||||
let group = pac::CPUSS.int_group(0);
|
||||
|
||||
// TODO: Decompose to direct u8
|
||||
let iidx = group.iidx().read().stat().to_bits();
|
||||
|
||||
let Ok(group) = pac::Group0::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 0: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group0::WWDT0 => todo!("implement WWDT0"),
|
||||
Group0::DEBUGSS => todo!("implement DEBUGSS"),
|
||||
Group0::FLASHCTL => todo!("implement FLASHCTL"),
|
||||
Group0::SYSCTL => todo!("implement SYSCTL"),
|
||||
}
|
||||
}
|
51
embassy-mspm0/src/int_group/g350x.rs
Normal file
51
embassy-mspm0/src/int_group/g350x.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use crate::pac;
|
||||
use crate::pac::interrupt;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP0() {
|
||||
use mspm0_metapac::Group0;
|
||||
|
||||
let group = pac::CPUSS.int_group(0);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group0::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 0: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group0::WWDT0 => todo!("implement WWDT0"),
|
||||
Group0::WWDT1 => todo!("implement WWDT1"),
|
||||
Group0::DEBUGSS => todo!("implement DEBUGSS"),
|
||||
Group0::FLASHCTL => todo!("implement FLASHCTL"),
|
||||
Group0::SYSCTL => todo!("implement SYSCTL"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP1() {
|
||||
use mspm0_metapac::Group1;
|
||||
|
||||
let group = pac::CPUSS.int_group(1);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group1::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 1: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group1::GPIOA => crate::gpio::gpioa_interrupt(),
|
||||
Group1::GPIOB => crate::gpio::gpiob_interrupt(),
|
||||
Group1::COMP0 => todo!("implement COMP0"),
|
||||
Group1::COMP1 => todo!("implement COMP1"),
|
||||
Group1::COMP2 => todo!("implement COMP2"),
|
||||
Group1::TRNG => todo!("implement TRNG"),
|
||||
}
|
||||
}
|
52
embassy-mspm0/src/int_group/g351x.rs
Normal file
52
embassy-mspm0/src/int_group/g351x.rs
Normal file
@ -0,0 +1,52 @@
|
||||
use crate::pac;
|
||||
use crate::pac::interrupt;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP0() {
|
||||
use mspm0_metapac::Group0;
|
||||
|
||||
let group = pac::CPUSS.int_group(0);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group0::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 0: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group0::WWDT0 => todo!("implement WWDT0"),
|
||||
Group0::WWDT1 => todo!("implement WWDT1"),
|
||||
Group0::DEBUGSS => todo!("implement DEBUGSS"),
|
||||
Group0::FLASHCTL => todo!("implement FLASHCTL"),
|
||||
Group0::SYSCTL => todo!("implement SYSCTL"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP1() {
|
||||
use mspm0_metapac::Group1;
|
||||
|
||||
let group = pac::CPUSS.int_group(1);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group1::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 1: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group1::GPIOA => crate::gpio::gpioa_interrupt(),
|
||||
Group1::GPIOB => crate::gpio::gpiob_interrupt(),
|
||||
Group1::COMP0 => todo!("implement COMP0"),
|
||||
Group1::COMP1 => todo!("implement COMP1"),
|
||||
Group1::COMP2 => todo!("implement COMP2"),
|
||||
Group1::TRNG => todo!("implement TRNG"),
|
||||
Group1::GPIOC => crate::gpio::gpioc_interrupt(),
|
||||
}
|
||||
}
|
46
embassy-mspm0/src/int_group/l130x.rs
Normal file
46
embassy-mspm0/src/int_group/l130x.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use crate::pac;
|
||||
use crate::pac::interrupt;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP0() {
|
||||
use mspm0_metapac::Group0;
|
||||
|
||||
let group = pac::CPUSS.int_group(0);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group0::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 0: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group0::WWDT0 => todo!("implement WWDT0"),
|
||||
Group0::DEBUGSS => todo!("implement DEBUGSS"),
|
||||
Group0::FLASHCTL => todo!("implement FLASHCTL"),
|
||||
Group0::SYSCTL => todo!("implement SYSCTL"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP1() {
|
||||
use mspm0_metapac::Group1;
|
||||
|
||||
let group = pac::CPUSS.int_group(1);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group1::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 1: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group1::GPIOA => crate::gpio::gpioa_interrupt(),
|
||||
Group1::COMP0 => todo!("implement COMP0"),
|
||||
}
|
||||
}
|
49
embassy-mspm0/src/int_group/l222x.rs
Normal file
49
embassy-mspm0/src/int_group/l222x.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::pac;
|
||||
use crate::pac::interrupt;
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP0() {
|
||||
use mspm0_metapac::Group0;
|
||||
|
||||
let group = pac::CPUSS.int_group(0);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group0::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 0: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group0::WWDT0 => todo!("implement WWDT0"),
|
||||
Group0::DEBUGSS => todo!("implement DEBUGSS"),
|
||||
Group0::FLASHCTL => todo!("implement FLASHCTL"),
|
||||
Group0::SYSCTL => todo!("implement SYSCTL"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "rt")]
|
||||
#[interrupt]
|
||||
fn GROUP1() {
|
||||
use mspm0_metapac::Group1;
|
||||
|
||||
let group = pac::CPUSS.int_group(1);
|
||||
|
||||
// Must subtract by 1 since NO_INTR is value 0
|
||||
let iidx = group.iidx().read().stat().to_bits() - 1;
|
||||
|
||||
let Ok(group) = pac::Group1::try_from(iidx as u8) else {
|
||||
debug!("Invalid IIDX for group 1: {}", iidx);
|
||||
return;
|
||||
};
|
||||
|
||||
match group {
|
||||
Group1::GPIOA => crate::gpio::gpioa_interrupt(),
|
||||
Group1::GPIOB => crate::gpio::gpiob_interrupt(),
|
||||
Group1::COMP0 => todo!("implement COMP0"),
|
||||
Group1::TRNG => todo!("implement TRNG"),
|
||||
Group1::GPIOC => crate::gpio::gpioc_interrupt(),
|
||||
}
|
||||
}
|
107
embassy-mspm0/src/lib.rs
Normal file
107
embassy-mspm0/src/lib.rs
Normal file
@ -0,0 +1,107 @@
|
||||
#![no_std]
|
||||
// Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc
|
||||
#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg_hide), doc(cfg_hide(doc, docsrs)))]
|
||||
|
||||
// This mod MUST go first, so that the others see its macros.
|
||||
pub(crate) mod fmt;
|
||||
|
||||
pub mod gpio;
|
||||
pub mod timer;
|
||||
|
||||
#[cfg(feature = "_time-driver")]
|
||||
mod time_driver;
|
||||
|
||||
// Interrupt group handlers.
|
||||
#[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g110x", path = "int_group/g110x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g150x", path = "int_group/g150x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g151x", path = "int_group/g151x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g310x", path = "int_group/g310x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")]
|
||||
#[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")]
|
||||
#[cfg_attr(feature = "mspm0l110x", path = "int_group/l110x.rs")]
|
||||
#[cfg_attr(feature = "mspm0l122x", path = "int_group/l122x.rs")]
|
||||
#[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")]
|
||||
#[cfg_attr(feature = "mspm0l134x", path = "int_group/l134x.rs")]
|
||||
#[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")]
|
||||
mod int_group;
|
||||
|
||||
pub(crate) mod _generated {
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(missing_docs)]
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/_generated.rs"));
|
||||
}
|
||||
|
||||
// Reexports
|
||||
pub(crate) use _generated::gpio_pincm;
|
||||
pub use _generated::{peripherals, Peripherals};
|
||||
pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef};
|
||||
#[cfg(feature = "unstable-pac")]
|
||||
pub use mspm0_metapac as pac;
|
||||
#[cfg(not(feature = "unstable-pac"))]
|
||||
pub(crate) use mspm0_metapac as pac;
|
||||
|
||||
pub use crate::_generated::interrupt;
|
||||
|
||||
/// `embassy-mspm0` global configuration.
|
||||
#[non_exhaustive]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Config {
|
||||
// TODO
|
||||
}
|
||||
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(_config: Config) -> Peripherals {
|
||||
critical_section::with(|cs| {
|
||||
let peripherals = Peripherals::take_with_cs(cs);
|
||||
|
||||
// TODO: Further clock configuration
|
||||
|
||||
pac::SYSCTL.mclkcfg().modify(|w| {
|
||||
// Enable MFCLK
|
||||
w.set_usemftick(true);
|
||||
// MDIV must be disabled if MFCLK is enabled.
|
||||
w.set_mdiv(0);
|
||||
});
|
||||
|
||||
// Enable MFCLK for peripheral use
|
||||
//
|
||||
// TODO: Optional?
|
||||
pac::SYSCTL.genclken().modify(|w| {
|
||||
w.set_mfpclken(true);
|
||||
});
|
||||
|
||||
pac::SYSCTL.borthreshold().modify(|w| {
|
||||
w.set_level(0);
|
||||
});
|
||||
|
||||
gpio::init(pac::GPIOA);
|
||||
#[cfg(gpio_pb)]
|
||||
gpio::init(pac::GPIOB);
|
||||
#[cfg(gpio_pc)]
|
||||
gpio::init(pac::GPIOC);
|
||||
|
||||
_generated::enable_group_interrupts(cs);
|
||||
|
||||
#[cfg(feature = "mspm0c110x")]
|
||||
unsafe {
|
||||
use crate::_generated::interrupt::typelevel::Interrupt;
|
||||
crate::interrupt::typelevel::GPIOA::enable();
|
||||
}
|
||||
|
||||
#[cfg(feature = "_time-driver")]
|
||||
time_driver::init(cs);
|
||||
|
||||
peripherals
|
||||
})
|
||||
}
|
423
embassy-mspm0/src/time_driver.rs
Normal file
423
embassy-mspm0/src/time_driver.rs
Normal file
@ -0,0 +1,423 @@
|
||||
use core::cell::{Cell, RefCell};
|
||||
use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
|
||||
use core::task::Waker;
|
||||
|
||||
use critical_section::{CriticalSection, Mutex};
|
||||
use embassy_time_driver::Driver;
|
||||
use embassy_time_queue_utils::Queue;
|
||||
use mspm0_metapac::interrupt;
|
||||
use mspm0_metapac::tim::vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey};
|
||||
use mspm0_metapac::tim::{Counterregs16, Tim};
|
||||
|
||||
use crate::peripherals;
|
||||
use crate::timer::SealedTimer;
|
||||
|
||||
// Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers.
|
||||
#[cfg(time_driver_timg0)]
|
||||
type T = peripherals::TIMG0;
|
||||
#[cfg(time_driver_timg1)]
|
||||
type T = peripherals::TIMG1;
|
||||
#[cfg(time_driver_timg2)]
|
||||
type T = peripherals::TIMG2;
|
||||
#[cfg(time_driver_timg3)]
|
||||
type T = peripherals::TIMG3;
|
||||
#[cfg(time_driver_timg4)]
|
||||
type T = peripherals::TIMG4;
|
||||
#[cfg(time_driver_timg5)]
|
||||
type T = peripherals::TIMG5;
|
||||
#[cfg(time_driver_timg6)]
|
||||
type T = peripherals::TIMG6;
|
||||
#[cfg(time_driver_timg7)]
|
||||
type T = peripherals::TIMG7;
|
||||
#[cfg(time_driver_timg8)]
|
||||
type T = peripherals::TIMG8;
|
||||
#[cfg(time_driver_timg9)]
|
||||
type T = peripherals::TIMG9;
|
||||
#[cfg(time_driver_timg10)]
|
||||
type T = peripherals::TIMG10;
|
||||
#[cfg(time_driver_timg11)]
|
||||
type T = peripherals::TIMG11;
|
||||
#[cfg(time_driver_timg14)]
|
||||
type T = peripherals::TIMG14;
|
||||
#[cfg(time_driver_tima0)]
|
||||
type T = peripherals::TIMA0;
|
||||
#[cfg(time_driver_tima1)]
|
||||
type T = peripherals::TIMA1;
|
||||
|
||||
// TODO: RTC
|
||||
|
||||
fn regs() -> Tim {
|
||||
unsafe { Tim::from_ptr(T::regs()) }
|
||||
}
|
||||
|
||||
fn regs_counter(tim: Tim) -> Counterregs16 {
|
||||
unsafe { Counterregs16::from_ptr(tim.counterregs(0).as_ptr()) }
|
||||
}
|
||||
|
||||
/// Clock timekeeping works with something we call "periods", which are time intervals
|
||||
/// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
|
||||
fn calc_now(period: u32, counter: u16) -> u64 {
|
||||
((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
|
||||
}
|
||||
|
||||
/// The TIMx driver uses one of the `TIMG` or `TIMA` timer instances to implement a timer with a 32.768 kHz
|
||||
/// tick rate. (TODO: Allow setting the tick rate)
|
||||
///
|
||||
/// This driver defines a period to be 2^15 ticks. 16-bit timers of course count to 2^16 ticks.
|
||||
///
|
||||
/// To generate a period every 2^15 ticks, the CC0 value is set to 2^15 and the load value set to 2^16.
|
||||
/// Incrementing the period on a CCU0 and load results in the a period of 2^15 ticks.
|
||||
///
|
||||
/// For a specific timestamp, load the lower 16 bits into the CC1 value. When the period where the timestamp
|
||||
/// should be enabled is reached, then the CCU1 (CC1 up) interrupt runs to actually wake the timer.
|
||||
///
|
||||
/// TODO: Compensate for per part variance. This can supposedly be done with the FCC system.
|
||||
/// TODO: Allow using 32-bit timers (TIMG12 and TIMG13).
|
||||
struct TimxDriver {
|
||||
/// Number of 2^15 periods elapsed since boot.
|
||||
period: AtomicU32,
|
||||
/// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
|
||||
alarm: Mutex<Cell<u64>>,
|
||||
queue: Mutex<RefCell<Queue>>,
|
||||
}
|
||||
|
||||
impl TimxDriver {
|
||||
#[inline(never)]
|
||||
fn init(&'static self, _cs: CriticalSection) {
|
||||
// Clock config
|
||||
// TODO: Configurable tick rate up to 4 MHz (32 kHz for now)
|
||||
let regs = regs();
|
||||
|
||||
// Reset timer
|
||||
regs.gprcm(0).rstctl().write(|w| {
|
||||
w.set_resetassert(true);
|
||||
w.set_key(ResetKey::KEY);
|
||||
w.set_resetstkyclr(true);
|
||||
});
|
||||
|
||||
// Power up timer
|
||||
regs.gprcm(0).pwren().write(|w| {
|
||||
w.set_enable(true);
|
||||
w.set_key(PwrenKey::KEY);
|
||||
});
|
||||
|
||||
// Following the instructions according to SLAU847D 23.2.1: TIMCLK Configuration
|
||||
|
||||
// 1. Select TIMCLK source
|
||||
regs.clksel().modify(|w| {
|
||||
// Use LFCLK for a 32.768kHz tick rate
|
||||
w.set_lfclk_sel(true);
|
||||
// TODO: Allow MFCLK for configurable tick rate up to 4 MHz
|
||||
// w.set_mfclk_sel(ClkSel::ENABLE);
|
||||
});
|
||||
|
||||
// 2. Divide by TIMCLK, we don't need to divide further for the 32kHz tick rate
|
||||
regs.clkdiv().modify(|w| {
|
||||
w.set_ratio(Ratio::DIV_BY_1);
|
||||
});
|
||||
|
||||
// 3. To be generic across timer instances, we do not use the prescaler.
|
||||
// TODO: mspm0-sdk always sets this, regardless of timer width?
|
||||
regs.commonregs(0).cps().modify(|w| {
|
||||
w.set_pcnt(0);
|
||||
});
|
||||
|
||||
regs.pdbgctl().modify(|w| {
|
||||
w.set_free(true);
|
||||
});
|
||||
|
||||
// 4. Enable the TIMCLK.
|
||||
regs.commonregs(0).cclkctl().modify(|w| {
|
||||
w.set_clken(true);
|
||||
});
|
||||
|
||||
regs.counterregs(0).ctrctl().modify(|w| {
|
||||
// allow counting during debug
|
||||
w.set_repeat(Repeat::REPEAT_3);
|
||||
w.set_cvae(Cvae::ZEROVAL);
|
||||
w.set_cm(Cm::UP);
|
||||
|
||||
// Must explicitly set CZC, CAC and CLC to 0 in order for all the timers to count.
|
||||
//
|
||||
// The reset value of these registers is 0x07, which is a reserved value.
|
||||
//
|
||||
// Looking at a bit representation of the reset value, this appears to be an AND
|
||||
// of 2-input QEI mode and CCCTL_3 ACOND. Given that TIMG14 and TIMA0 have no QEI
|
||||
// and 4 capture and compare channels, this works by accident for those timer units.
|
||||
w.set_czc(CxC::CCTL0);
|
||||
w.set_cac(CxC::CCTL0);
|
||||
w.set_clc(CxC::CCTL0);
|
||||
});
|
||||
|
||||
// Setup the period
|
||||
let ctr = regs_counter(regs);
|
||||
|
||||
// Middle
|
||||
ctr.cc(0).modify(|w| {
|
||||
w.set_ccval(0x7FFF);
|
||||
});
|
||||
|
||||
ctr.load().modify(|w| {
|
||||
w.set_ld(u16::MAX);
|
||||
});
|
||||
|
||||
// Enable the period interrupts
|
||||
//
|
||||
// This does not appear to ever be set for CPU_INT in the TI SDK and is not technically needed.
|
||||
regs.evt_mode().modify(|w| {
|
||||
w.set_evt_cfg(0, EvtCfg::SOFTWARE);
|
||||
});
|
||||
|
||||
regs.int_event(0).imask().modify(|w| {
|
||||
w.set_l(true);
|
||||
w.set_ccu0(true);
|
||||
});
|
||||
|
||||
unsafe { T::enable_interrupt() };
|
||||
|
||||
// Allow the counter to start counting.
|
||||
regs.counterregs(0).ctrctl().modify(|w| {
|
||||
w.set_en(true);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn next_period(&self) {
|
||||
let r = regs();
|
||||
|
||||
// We only modify the period from the timer interrupt, so we know this can't race.
|
||||
let period = self.period.load(Ordering::Relaxed) + 1;
|
||||
self.period.store(period, Ordering::Relaxed);
|
||||
let t = (period as u64) << 15;
|
||||
|
||||
critical_section::with(move |cs| {
|
||||
r.int_event(0).imask().modify(move |w| {
|
||||
let alarm = self.alarm.borrow(cs);
|
||||
let at = alarm.get();
|
||||
|
||||
if at < t + 0xC000 {
|
||||
// just enable it. `set_alarm` has already set the correct CC1 val.
|
||||
w.set_ccu1(true);
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[inline(never)]
|
||||
fn on_interrupt(&self) {
|
||||
let r = regs();
|
||||
|
||||
critical_section::with(|cs| {
|
||||
let mis = r.int_event(0).mis().read();
|
||||
|
||||
// Advance to next period if overflowed
|
||||
if mis.l() {
|
||||
self.next_period();
|
||||
|
||||
r.int_event(0).iclr().write(|w| {
|
||||
w.set_l(true);
|
||||
});
|
||||
}
|
||||
|
||||
if mis.ccu0() {
|
||||
self.next_period();
|
||||
|
||||
r.int_event(0).iclr().write(|w| {
|
||||
w.set_ccu0(true);
|
||||
});
|
||||
}
|
||||
|
||||
if mis.ccu1() {
|
||||
r.int_event(0).iclr().write(|w| {
|
||||
w.set_ccu1(true);
|
||||
});
|
||||
|
||||
self.trigger_alarm(cs);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn trigger_alarm(&self, cs: CriticalSection) {
|
||||
let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
|
||||
|
||||
while !self.set_alarm(cs, next) {
|
||||
next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
|
||||
}
|
||||
}
|
||||
|
||||
fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
|
||||
let r = regs();
|
||||
let ctr = regs_counter(r);
|
||||
|
||||
self.alarm.borrow(cs).set(timestamp);
|
||||
|
||||
let t = self.now();
|
||||
|
||||
if timestamp <= t {
|
||||
// If alarm timestamp has passed the alarm will not fire.
|
||||
// Disarm the alarm and return `false` to indicate that.
|
||||
r.int_event(0).imask().modify(|w| w.set_ccu1(false));
|
||||
|
||||
self.alarm.borrow(cs).set(u64::MAX);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Write the CC1 value regardless of whether we're going to enable it now or not.
|
||||
// This way, when we enable it later, the right value is already set.
|
||||
ctr.cc(1).write(|w| {
|
||||
w.set_ccval(timestamp as u16);
|
||||
});
|
||||
|
||||
// Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
|
||||
let diff = timestamp - t;
|
||||
r.int_event(0).imask().modify(|w| w.set_ccu1(diff < 0xC000));
|
||||
|
||||
// Reevaluate if the alarm timestamp is still in the future
|
||||
let t = self.now();
|
||||
if timestamp <= t {
|
||||
// If alarm timestamp has passed since we set it, we have a race condition and
|
||||
// the alarm may or may not have fired.
|
||||
// Disarm the alarm and return `false` to indicate that.
|
||||
// It is the caller's responsibility to handle this ambiguity.
|
||||
r.int_event(0).imask().modify(|w| w.set_ccu1(false));
|
||||
|
||||
self.alarm.borrow(cs).set(u64::MAX);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're confident the alarm will ring in the future.
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl Driver for TimxDriver {
|
||||
fn now(&self) -> u64 {
|
||||
let regs = regs();
|
||||
|
||||
let period = self.period.load(Ordering::Relaxed);
|
||||
// Ensure the compiler does not read the counter before the period.
|
||||
compiler_fence(Ordering::Acquire);
|
||||
|
||||
let counter = regs_counter(regs).ctr().read().cctr() as u16;
|
||||
|
||||
calc_now(period, counter)
|
||||
}
|
||||
|
||||
fn schedule_wake(&self, at: u64, waker: &Waker) {
|
||||
critical_section::with(|cs| {
|
||||
let mut queue = self.queue.borrow(cs).borrow_mut();
|
||||
|
||||
if queue.schedule_wake(at, waker) {
|
||||
let mut next = queue.next_expiration(self.now());
|
||||
|
||||
while !self.set_alarm(cs, next) {
|
||||
next = queue.next_expiration(self.now());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
embassy_time_driver::time_driver_impl!(static DRIVER: TimxDriver = TimxDriver {
|
||||
period: AtomicU32::new(0),
|
||||
alarm: Mutex::new(Cell::new(u64::MAX)),
|
||||
queue: Mutex::new(RefCell::new(Queue::new()))
|
||||
});
|
||||
|
||||
pub(crate) fn init(cs: CriticalSection) {
|
||||
DRIVER.init(cs);
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg0)]
|
||||
#[interrupt]
|
||||
fn TIMG0() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg1)]
|
||||
#[interrupt]
|
||||
fn TIMG1() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg2)]
|
||||
#[interrupt]
|
||||
fn TIMG2() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg3)]
|
||||
#[interrupt]
|
||||
fn TIMG3() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg4)]
|
||||
#[interrupt]
|
||||
fn TIMG4() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg5)]
|
||||
#[interrupt]
|
||||
fn TIMG5() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg6)]
|
||||
#[interrupt]
|
||||
fn TIMG6() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg7)]
|
||||
#[interrupt]
|
||||
fn TIMG7() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg8)]
|
||||
#[interrupt]
|
||||
fn TIMG8() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg9)]
|
||||
#[interrupt]
|
||||
fn TIMG9() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg10)]
|
||||
#[interrupt]
|
||||
fn TIMG10() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_timg11)]
|
||||
#[interrupt]
|
||||
fn TIMG11() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
// TODO: TIMG12 and TIMG13
|
||||
|
||||
#[cfg(time_driver_timg14)]
|
||||
#[interrupt]
|
||||
fn TIMG14() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_tima0)]
|
||||
#[interrupt]
|
||||
fn TIMA0() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
||||
|
||||
#[cfg(time_driver_tima1)]
|
||||
#[interrupt]
|
||||
fn TIMA1() {
|
||||
DRIVER.on_interrupt();
|
||||
}
|
48
embassy-mspm0/src/timer.rs
Normal file
48
embassy-mspm0/src/timer.rs
Normal file
@ -0,0 +1,48 @@
|
||||
#![macro_use]
|
||||
|
||||
/// Amount of bits of a timer.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum TimerBits {
|
||||
/// 16 bits.
|
||||
Bits16,
|
||||
/// 32 bits.
|
||||
Bits32,
|
||||
}
|
||||
|
||||
#[allow(private_bounds)]
|
||||
pub trait Timer: SealedTimer + 'static {
|
||||
/// Amount of bits this timer has.
|
||||
const BITS: TimerBits;
|
||||
}
|
||||
|
||||
pub(crate) trait SealedTimer {
|
||||
/// Registers for this timer.
|
||||
///
|
||||
/// This is a raw pointer to the register block. The actual register block layout varies depending on the
|
||||
/// timer type.
|
||||
fn regs() -> *mut ();
|
||||
|
||||
/// Enable the interrupt corresponding to this timer.
|
||||
unsafe fn enable_interrupt();
|
||||
}
|
||||
|
||||
macro_rules! impl_timer {
|
||||
($name: ident, $bits: ident) => {
|
||||
impl crate::timer::SealedTimer for crate::peripherals::$name {
|
||||
fn regs() -> *mut () {
|
||||
crate::pac::$name.as_ptr()
|
||||
}
|
||||
|
||||
unsafe fn enable_interrupt() {
|
||||
use embassy_hal_internal::interrupt::InterruptExt;
|
||||
crate::interrupt::$name.unpend();
|
||||
crate::interrupt::$name.enable();
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::timer::Timer for crate::peripherals::$name {
|
||||
const BITS: crate::timer::TimerBits = crate::timer::TimerBits::$bits;
|
||||
}
|
||||
};
|
||||
}
|
11
examples/mspm0c1104/.cargo/config.toml
Normal file
11
examples/mspm0c1104/.cargo/config.toml
Normal file
@ -0,0 +1,11 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace MSPM0C1104 with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip MSPM0C1104 --protocol=swd"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "debug"
|
||||
# defmt's buffer needs to be shrunk since the MSPM0C1104 only has 1KB of ram.
|
||||
DEFMT_RTT_BUFFER_SIZE = "72"
|
32
examples/mspm0c1104/Cargo.toml
Normal file
32
examples/mspm0c1104/Cargo.toml
Normal file
@ -0,0 +1,32 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-mspm0-c1104-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-128", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.0"}
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
|
||||
panic-semihosting = "0.6.0"
|
||||
|
||||
# The chip only has 1KB of ram, so we must optimize binaries regardless
|
||||
[profile.dev]
|
||||
debug = 0
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
# strip = true
|
||||
|
||||
[profile.release]
|
||||
debug = 0
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
codegen-units = 1
|
27
examples/mspm0c1104/README.md
Normal file
27
examples/mspm0c1104/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Examples for MSPM0C110x family
|
||||
|
||||
Run individual examples with
|
||||
```
|
||||
cargo run --bin <module-name>
|
||||
```
|
||||
for example
|
||||
```
|
||||
cargo run --bin blinky
|
||||
```
|
||||
|
||||
## Checklist before running examples
|
||||
A large number of the examples are written for the [LP-MSPM0C1104](https://www.ti.com/tool/LP-MSPM0C1104) board.
|
||||
|
||||
You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
|
||||
|
||||
* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for C1104 it should be `probe-rs run --chip MSPM0C1104`. (use `probe-rs chip list` to find your chip)
|
||||
* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for C1104 it should be `mspm0c1104`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
|
||||
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
|
||||
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
|
||||
|
||||
If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
|
||||
|
||||
* Which example you are trying to run
|
||||
* Which chip and board you are using
|
||||
|
||||
Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
|
35
examples/mspm0c1104/build.rs
Normal file
35
examples/mspm0c1104/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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.
|
||||
|
||||
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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
5
examples/mspm0c1104/memory.x
Normal file
5
examples/mspm0c1104/memory.x
Normal file
@ -0,0 +1,5 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 16K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 1K
|
||||
}
|
25
examples/mspm0c1104/src/bin/blinky.rs
Normal file
25
examples/mspm0c1104/src/bin/blinky.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Level, Output};
|
||||
use embassy_mspm0::Config;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let mut led1 = Output::new(p.PA22, Level::Low);
|
||||
led1.set_inversion(true);
|
||||
|
||||
loop {
|
||||
Timer::after_millis(400).await;
|
||||
|
||||
info!("Toggle");
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
33
examples/mspm0c1104/src/bin/button.rs
Normal file
33
examples/mspm0c1104/src/bin/button.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_mspm0::Config;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let led1 = p.PA22;
|
||||
let s2 = p.PA16;
|
||||
|
||||
let mut led1 = Output::new(led1, Level::Low);
|
||||
|
||||
let mut s2 = Input::new(s2, Pull::Up);
|
||||
|
||||
// led1 is active low
|
||||
led1.set_high();
|
||||
|
||||
loop {
|
||||
s2.wait_for_falling_edge().await;
|
||||
|
||||
info!("Switch 2 was pressed");
|
||||
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
9
examples/mspm0g3507/.cargo/config.toml
Normal file
9
examples/mspm0g3507/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace MSPM0G3507 with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip MSPM0G3507 --protocol=swd"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "debug"
|
21
examples/mspm0g3507/Cargo.toml
Normal file
21
examples/mspm0g3507/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-mspm0-g3507-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.0"}
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
|
||||
panic-semihosting = "0.6.0"
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
27
examples/mspm0g3507/README.md
Normal file
27
examples/mspm0g3507/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Examples for MSPM0C350x family
|
||||
|
||||
Run individual examples with
|
||||
```
|
||||
cargo run --bin <module-name>
|
||||
```
|
||||
for example
|
||||
```
|
||||
cargo run --bin blinky
|
||||
```
|
||||
|
||||
## Checklist before running examples
|
||||
A large number of the examples are written for the [LP-MSPM0G3507](https://www.ti.com/tool/LP-MSPM0G3507) board.
|
||||
|
||||
You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
|
||||
|
||||
* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3507 it should be `probe-rs run --chip MSPM0G3507`. (use `probe-rs chip list` to find your chip)
|
||||
* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3507 it should be `mspm0g3507`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
|
||||
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
|
||||
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
|
||||
|
||||
If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
|
||||
|
||||
* Which example you are trying to run
|
||||
* Which chip and board you are using
|
||||
|
||||
Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
|
35
examples/mspm0g3507/build.rs
Normal file
35
examples/mspm0g3507/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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.
|
||||
|
||||
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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
6
examples/mspm0g3507/memory.x
Normal file
6
examples/mspm0g3507/memory.x
Normal file
@ -0,0 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 128K
|
||||
/* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
|
||||
RAM : ORIGIN = 0x20200000, LENGTH = 32K
|
||||
}
|
25
examples/mspm0g3507/src/bin/blinky.rs
Normal file
25
examples/mspm0g3507/src/bin/blinky.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Level, Output};
|
||||
use embassy_mspm0::Config;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let mut led1 = Output::new(p.PA0, Level::Low);
|
||||
led1.set_inversion(true);
|
||||
|
||||
loop {
|
||||
Timer::after_millis(400).await;
|
||||
|
||||
info!("Toggle");
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
33
examples/mspm0g3507/src/bin/button.rs
Normal file
33
examples/mspm0g3507/src/bin/button.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_mspm0::Config;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let led1 = p.PA0;
|
||||
let s2 = p.PB21;
|
||||
|
||||
let mut led1 = Output::new(led1, Level::Low);
|
||||
|
||||
let mut s2 = Input::new(s2, Pull::Up);
|
||||
|
||||
// led1 is active low
|
||||
led1.set_high();
|
||||
|
||||
loop {
|
||||
s2.wait_for_falling_edge().await;
|
||||
|
||||
info!("Switch 2 was pressed");
|
||||
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
9
examples/mspm0g3519/.cargo/config.toml
Normal file
9
examples/mspm0g3519/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace MSPM0G3519 with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
21
examples/mspm0g3519/Cargo.toml
Normal file
21
examples/mspm0g3519/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-mspm0-g3519-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.0"}
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
|
||||
panic-semihosting = "0.6.0"
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
27
examples/mspm0g3519/README.md
Normal file
27
examples/mspm0g3519/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Examples for MSPM0G351x family
|
||||
|
||||
Run individual examples with
|
||||
```
|
||||
cargo run --bin <module-name>
|
||||
```
|
||||
for example
|
||||
```
|
||||
cargo run --bin blinky
|
||||
```
|
||||
|
||||
## Checklist before running examples
|
||||
A large number of the examples are written for the [LP-MSPM0G3519](https://www.ti.com/tool/LP-MSPM0G3519) board.
|
||||
|
||||
You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
|
||||
|
||||
* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for G3519 it should be `probe-rs run --chip MSPM0G3519`. (use `probe-rs chip list` to find your chip)
|
||||
* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for G3519 it should be `mspm0g3519`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
|
||||
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
|
||||
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
|
||||
|
||||
If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
|
||||
|
||||
* Which example you are trying to run
|
||||
* Which chip and board you are using
|
||||
|
||||
Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
|
35
examples/mspm0g3519/build.rs
Normal file
35
examples/mspm0g3519/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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.
|
||||
|
||||
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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
6
examples/mspm0g3519/memory.x
Normal file
6
examples/mspm0g3519/memory.x
Normal file
@ -0,0 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 512K
|
||||
/* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
|
||||
RAM : ORIGIN = 0x20200000, LENGTH = 128K
|
||||
}
|
25
examples/mspm0g3519/src/bin/blinky.rs
Normal file
25
examples/mspm0g3519/src/bin/blinky.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Level, Output};
|
||||
use embassy_mspm0::Config;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let mut led1 = Output::new(p.PA0, Level::Low);
|
||||
led1.set_inversion(true);
|
||||
|
||||
loop {
|
||||
Timer::after_millis(400).await;
|
||||
|
||||
info!("Toggle");
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
33
examples/mspm0g3519/src/bin/button.rs
Normal file
33
examples/mspm0g3519/src/bin/button.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_mspm0::Config;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let led1 = p.PA0;
|
||||
let s2 = p.PB3;
|
||||
|
||||
let mut led1 = Output::new(led1, Level::Low);
|
||||
|
||||
let mut s2 = Input::new(s2, Pull::Up);
|
||||
|
||||
// led1 is active low
|
||||
led1.set_high();
|
||||
|
||||
loop {
|
||||
s2.wait_for_falling_edge().await;
|
||||
|
||||
info!("Switch 2 was pressed");
|
||||
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
9
examples/mspm0l1306/.cargo/config.toml
Normal file
9
examples/mspm0l1306/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace MSPM0L1306 with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --chip MSPM0L1306 --protocol=swd"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
21
examples/mspm0l1306/Cargo.toml
Normal file
21
examples/mspm0l1306/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-mspm0-l1306-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.0"}
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
|
||||
panic-semihosting = "0.6.0"
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
27
examples/mspm0l1306/README.md
Normal file
27
examples/mspm0l1306/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Examples for MSPM0L130x family
|
||||
|
||||
Run individual examples with
|
||||
```
|
||||
cargo run --bin <module-name>
|
||||
```
|
||||
for example
|
||||
```
|
||||
cargo run --bin blinky
|
||||
```
|
||||
|
||||
## Checklist before running examples
|
||||
A large number of the examples are written for the [LP-MSPM0L1306](https://www.ti.com/tool/LP-MSPM0L1306) board.
|
||||
|
||||
You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
|
||||
|
||||
* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L1306 it should be `probe-rs run --chip MSPM0L1306`. (use `probe-rs chip list` to find your chip)
|
||||
* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L1306 it should be `mspm0l1306`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
|
||||
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
|
||||
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
|
||||
|
||||
If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
|
||||
|
||||
* Which example you are trying to run
|
||||
* Which chip and board you are using
|
||||
|
||||
Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
|
35
examples/mspm0l1306/build.rs
Normal file
35
examples/mspm0l1306/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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.
|
||||
|
||||
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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
5
examples/mspm0l1306/memory.x
Normal file
5
examples/mspm0l1306/memory.x
Normal file
@ -0,0 +1,5 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 64K
|
||||
RAM : ORIGIN = 0x20000000, LENGTH = 4K
|
||||
}
|
25
examples/mspm0l1306/src/bin/blinky.rs
Normal file
25
examples/mspm0l1306/src/bin/blinky.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Level, Output};
|
||||
use embassy_mspm0::Config;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let mut led1 = Output::new(p.PA0, Level::Low);
|
||||
led1.set_inversion(true);
|
||||
|
||||
loop {
|
||||
Timer::after_millis(400).await;
|
||||
|
||||
info!("Toggle");
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
33
examples/mspm0l1306/src/bin/button.rs
Normal file
33
examples/mspm0l1306/src/bin/button.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_mspm0::Config;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let led1 = p.PA0;
|
||||
let s2 = p.PA14;
|
||||
|
||||
let mut led1 = Output::new(led1, Level::Low);
|
||||
|
||||
let mut s2 = Input::new(s2, Pull::Up);
|
||||
|
||||
// led1 is active low
|
||||
led1.set_high();
|
||||
|
||||
loop {
|
||||
s2.wait_for_falling_edge().await;
|
||||
|
||||
info!("Switch 2 was pressed");
|
||||
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
9
examples/mspm0l2228/.cargo/config.toml
Normal file
9
examples/mspm0l2228/.cargo/config.toml
Normal file
@ -0,0 +1,9 @@
|
||||
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
|
||||
# replace MSPM0L2228 with your chip as listed in `probe-rs chip list`
|
||||
runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd"
|
||||
|
||||
[build]
|
||||
target = "thumbv6m-none-eabi"
|
||||
|
||||
[env]
|
||||
DEFMT_LOG = "trace"
|
21
examples/mspm0l2228/Cargo.toml
Normal file
21
examples/mspm0l2228/Cargo.toml
Normal file
@ -0,0 +1,21 @@
|
||||
[package]
|
||||
edition = "2021"
|
||||
name = "embassy-mspm0-l2228-examples"
|
||||
version = "0.1.0"
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] }
|
||||
embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] }
|
||||
embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] }
|
||||
embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] }
|
||||
panic-halt = "0.2.0"
|
||||
cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] }
|
||||
cortex-m-rt = { version = "0.7.0"}
|
||||
defmt = "0.3"
|
||||
defmt-rtt = "0.4"
|
||||
panic-probe = { version = "0.3.2", features = ["print-defmt"] }
|
||||
panic-semihosting = "0.6.0"
|
||||
|
||||
[profile.release]
|
||||
debug = 2
|
27
examples/mspm0l2228/README.md
Normal file
27
examples/mspm0l2228/README.md
Normal file
@ -0,0 +1,27 @@
|
||||
# Examples for MSPM0L222x family
|
||||
|
||||
Run individual examples with
|
||||
```
|
||||
cargo run --bin <module-name>
|
||||
```
|
||||
for example
|
||||
```
|
||||
cargo run --bin blinky
|
||||
```
|
||||
|
||||
## Checklist before running examples
|
||||
A large number of the examples are written for the [LP-MSPM0L2228](https://www.ti.com/tool/LP-MSPM0L2228) board.
|
||||
|
||||
You might need to adjust `.cargo/config.toml`, `Cargo.toml` and possibly update pin numbers or peripherals to match the specific MCU or board you are using.
|
||||
|
||||
* [ ] Update .cargo/config.toml with the correct probe-rs command to use your specific MCU. For example for L2228 it should be `probe-rs run --chip MSPM0L2228`. (use `probe-rs chip list` to find your chip)
|
||||
* [ ] Update Cargo.toml to have the correct `embassy-mspm0` feature. For example for L2228 it should be `mspm0l2228`. Look in the `Cargo.toml` file of the `embassy-mspm0` project to find the correct feature flag for your chip.
|
||||
* [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately.
|
||||
* [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic
|
||||
|
||||
If you are unsure, please drop by the Embassy Matrix chat for support, and let us know:
|
||||
|
||||
* Which example you are trying to run
|
||||
* Which chip and board you are using
|
||||
|
||||
Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org
|
35
examples/mspm0l2228/build.rs
Normal file
35
examples/mspm0l2228/build.rs
Normal file
@ -0,0 +1,35 @@
|
||||
//! 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.
|
||||
|
||||
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");
|
||||
|
||||
println!("cargo:rustc-link-arg-bins=--nmagic");
|
||||
println!("cargo:rustc-link-arg-bins=-Tlink.x");
|
||||
println!("cargo:rustc-link-arg-bins=-Tdefmt.x");
|
||||
}
|
6
examples/mspm0l2228/memory.x
Normal file
6
examples/mspm0l2228/memory.x
Normal file
@ -0,0 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
FLASH : ORIGIN = 0x00000000, LENGTH = 256K
|
||||
/* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */
|
||||
RAM : ORIGIN = 0x20200000, LENGTH = 32K
|
||||
}
|
25
examples/mspm0l2228/src/bin/blinky.rs
Normal file
25
examples/mspm0l2228/src/bin/blinky.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Level, Output};
|
||||
use embassy_mspm0::Config;
|
||||
use embassy_time::Timer;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let mut led1 = Output::new(p.PA0, Level::Low);
|
||||
led1.set_inversion(true);
|
||||
|
||||
loop {
|
||||
Timer::after_millis(400).await;
|
||||
|
||||
info!("Toggle");
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
33
examples/mspm0l2228/src/bin/button.rs
Normal file
33
examples/mspm0l2228/src/bin/button.rs
Normal file
@ -0,0 +1,33 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use defmt::*;
|
||||
use embassy_executor::Spawner;
|
||||
use embassy_mspm0::gpio::{Input, Level, Output, Pull};
|
||||
use embassy_mspm0::Config;
|
||||
use {defmt_rtt as _, panic_halt as _};
|
||||
|
||||
#[embassy_executor::main]
|
||||
async fn main(_spawner: Spawner) -> ! {
|
||||
info!("Hello world!");
|
||||
|
||||
let p = embassy_mspm0::init(Config::default());
|
||||
|
||||
let led1 = p.PA0;
|
||||
let s2 = p.PB8;
|
||||
|
||||
let mut led1 = Output::new(led1, Level::Low);
|
||||
|
||||
let mut s2 = Input::new(s2, Pull::Up);
|
||||
|
||||
// led1 is active low
|
||||
led1.set_high();
|
||||
|
||||
loop {
|
||||
s2.wait_for_falling_edge().await;
|
||||
|
||||
info!("Switch 2 was pressed");
|
||||
|
||||
led1.toggle();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user