Merge pull request #3966 from i509VCB/mspm0-init

Embassy for MSPM0
This commit is contained in:
Ulf Lilleengen 2025-03-21 13:32:14 +00:00 committed by GitHub
commit e29be82c8b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 3780 additions and 0 deletions

1
.github/ci/doc.sh vendored
View File

@ -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

View File

@ -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",

View File

@ -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
View File

@ -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

View File

@ -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
View 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
View 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),
},
}
}
}

View 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
View 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

File diff suppressed because it is too large Load Diff

View 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"),
}
}

View 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"),
}
}

View 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(),
}
}

View 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"),
}
}

View 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
View 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
})
}

View 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();
}

View 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;
}
};
}

View 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"

View 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

View 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

View 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");
}

View File

@ -0,0 +1,5 @@
MEMORY
{
FLASH : ORIGIN = 0x00000000, LENGTH = 16K
RAM : ORIGIN = 0x20000000, LENGTH = 1K
}

View 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();
}
}

View 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();
}
}

View 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"

View 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

View 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

View 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");
}

View 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
}

View 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();
}
}

View 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();
}
}

View 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"

View 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

View 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

View 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");
}

View 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
}

View 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();
}
}

View 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();
}
}

View 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"

View 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

View 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

View 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");
}

View File

@ -0,0 +1,5 @@
MEMORY
{
FLASH : ORIGIN = 0x00000000, LENGTH = 64K
RAM : ORIGIN = 0x20000000, LENGTH = 4K
}

View 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();
}
}

View 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();
}
}

View 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"

View 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

View 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

View 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");
}

View 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
}

View 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();
}
}

View 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();
}
}