diff options
51 files changed, 4476 insertions, 0 deletions
diff --git a/.vscode/settings.json b/.vscode/settings.json index 48d0957e6..e4814ff27 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json | |||
| @@ -28,6 +28,11 @@ | |||
| 28 | // To work on the examples, comment the line above and all of the cargo.features lines, | 28 | // To work on the examples, comment the line above and all of the cargo.features lines, |
| 29 | // then uncomment ONE line below to select the chip you want to work on. | 29 | // then uncomment ONE line below to select the chip you want to work on. |
| 30 | // This makes rust-analyzer work on the example crate and all its dependencies. | 30 | // This makes rust-analyzer work on the example crate and all its dependencies. |
| 31 | // "examples/mspm0c1104/Cargo.toml", | ||
| 32 | // "examples/mspm0g3507/Cargo.toml", | ||
| 33 | // "examples/mspm0g3519/Cargo.toml", | ||
| 34 | // "examples/mspm0l1306/Cargo.toml", | ||
| 35 | // "examples/mspm0l2228/Cargo.toml", | ||
| 31 | // "examples/nrf52840-rtic/Cargo.toml", | 36 | // "examples/nrf52840-rtic/Cargo.toml", |
| 32 | // "examples/nrf5340/Cargo.toml", | 37 | // "examples/nrf5340/Cargo.toml", |
| 33 | // "examples/nrf-rtos-trace/Cargo.toml", | 38 | // "examples/nrf-rtos-trace/Cargo.toml", |
diff --git a/embassy-mspm0/Cargo.toml b/embassy-mspm0/Cargo.toml new file mode 100644 index 000000000..0f4092d8a --- /dev/null +++ b/embassy-mspm0/Cargo.toml | |||
| @@ -0,0 +1,125 @@ | |||
| 1 | [package] | ||
| 2 | name = "embassy-mspm0" | ||
| 3 | version = "0.1.0" | ||
| 4 | edition = "2021" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | description = "Embassy Hardware Abstraction Layer (HAL) for Texas Instruments MSPM0 series microcontrollers" | ||
| 7 | keywords = ["embedded", "async", "mspm0", "hal", "embedded-hal"] | ||
| 8 | categories = ["embedded", "hardware-support", "no-std", "asynchronous"] | ||
| 9 | repository = "https://github.com/embassy-rs/embassy" | ||
| 10 | documentation = "https://docs.embassy.dev/embassy-mspm0" | ||
| 11 | |||
| 12 | [package.metadata.docs.rs] | ||
| 13 | features = ["defmt", "unstable-pac", "time-driver-any", "time", "mspm0g3507"] | ||
| 14 | rustdoc-args = ["--cfg", "docsrs"] | ||
| 15 | |||
| 16 | [dependencies] | ||
| 17 | embassy-sync = { version = "0.6.2", path = "../embassy-sync" } | ||
| 18 | embassy-time = { version = "0.4.0", path = "../embassy-time", optional = true } | ||
| 19 | # TODO: Support other tick rates | ||
| 20 | embassy-time-driver = { version = "0.2", path = "../embassy-time-driver", optional = true, features = ["tick-hz-32_768"] } | ||
| 21 | embassy-time-queue-utils = { version = "0.1", path = "../embassy-time-queue-utils", optional = true } | ||
| 22 | embassy-futures = { version = "0.1.0", path = "../embassy-futures" } | ||
| 23 | embassy-hal-internal = { version = "0.2.0", path = "../embassy-hal-internal", features = ["cortex-m", "prio-bits-2"] } | ||
| 24 | embassy-embedded-hal = { version = "0.3.0", path = "../embassy-embedded-hal", default-features = false } | ||
| 25 | embassy-executor = { version = "0.7.0", path = "../embassy-executor", optional = true } | ||
| 26 | |||
| 27 | embedded-hal = { version = "1.0" } | ||
| 28 | embedded-hal-async = { version = "1.0" } | ||
| 29 | |||
| 30 | defmt = { version = "0.3", optional = true } | ||
| 31 | log = { version = "0.4.14", optional = true } | ||
| 32 | cortex-m-rt = ">=0.6.15,<0.8" | ||
| 33 | cortex-m = "0.7.6" | ||
| 34 | critical-section = "1.2.0" | ||
| 35 | |||
| 36 | # mspm0-metapac = { version = "" } | ||
| 37 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d" } | ||
| 38 | |||
| 39 | [build-dependencies] | ||
| 40 | proc-macro2 = "1.0.94" | ||
| 41 | quote = "1.0.40" | ||
| 42 | |||
| 43 | # mspm0-metapac = { version = "", default-features = false, features = ["metadata"] } | ||
| 44 | mspm0-metapac = { git = "https://github.com/mspm0-rs/mspm0-data-generated/", tag = "mspm0-data-9faa5239a8eab04946086158f2a7fdff5a6a179d", default-features = false, features = ["metadata"] } | ||
| 45 | |||
| 46 | [features] | ||
| 47 | default = ["rt"] | ||
| 48 | |||
| 49 | ## Enable `mspm0-metapac`'s `rt` feature | ||
| 50 | rt = ["mspm0-metapac/rt"] | ||
| 51 | |||
| 52 | ## Use [`defmt`](https://docs.rs/defmt/latest/defmt/) for logging | ||
| 53 | defmt = [ | ||
| 54 | "dep:defmt", | ||
| 55 | "embassy-sync/defmt", | ||
| 56 | "embassy-embedded-hal/defmt", | ||
| 57 | "embassy-hal-internal/defmt", | ||
| 58 | "embassy-time?/defmt", | ||
| 59 | ] | ||
| 60 | |||
| 61 | ## Re-export mspm0-metapac at `mspm0::pac`. | ||
| 62 | ## This is unstable because semver-minor (non-breaking) releases of embassy-mspm0 may major-bump (breaking) the mspm0-metapac version. | ||
| 63 | ## If this is an issue for you, you're encouraged to directly depend on a fixed version of the PAC. | ||
| 64 | ## There are no plans to make this stable. | ||
| 65 | unstable-pac = [] | ||
| 66 | |||
| 67 | #! ## Time | ||
| 68 | |||
| 69 | # Features starting with `_` are for internal use only. They're not intended | ||
| 70 | # to be enabled by other crates, and are not covered by semver guarantees. | ||
| 71 | _time-driver = ["dep:embassy-time-driver", "dep:embassy-time-queue-utils"] | ||
| 72 | |||
| 73 | # Use any time driver | ||
| 74 | time-driver-any = ["_time-driver"] | ||
| 75 | ## Use TIMG0 as time driver | ||
| 76 | time-driver-timg0 = ["_time-driver"] | ||
| 77 | ## Use TIMG1 as time driver | ||
| 78 | time-driver-timg1 = ["_time-driver"] | ||
| 79 | ## Use TIMG2 as time driver | ||
| 80 | time-driver-timg2 = ["_time-driver"] | ||
| 81 | ## Use TIMG3 as time driver | ||
| 82 | time-driver-timg3 = ["_time-driver"] | ||
| 83 | ## Use TIMG4 as time driver | ||
| 84 | time-driver-timg4 = ["_time-driver"] | ||
| 85 | ## Use TIMG5 as time driver | ||
| 86 | time-driver-timg5 = ["_time-driver"] | ||
| 87 | ## Use TIMG6 as time driver | ||
| 88 | time-driver-timg6 = ["_time-driver"] | ||
| 89 | ## Use TIMG7 as time driver | ||
| 90 | time-driver-timg7 = ["_time-driver"] | ||
| 91 | ## Use TIMG8 as time driver | ||
| 92 | time-driver-timg8 = ["_time-driver"] | ||
| 93 | ## Use TIMG9 as time driver | ||
| 94 | time-driver-timg9 = ["_time-driver"] | ||
| 95 | ## Use TIMG10 as time driver | ||
| 96 | time-driver-timg10 = ["_time-driver"] | ||
| 97 | ## Use TIMG11 as time driver | ||
| 98 | time-driver-timg11 = ["_time-driver"] | ||
| 99 | # TODO: Support TIMG12 and TIMG13 | ||
| 100 | ## Use TIMG14 as time driver | ||
| 101 | time-driver-timg14 = ["_time-driver"] | ||
| 102 | ## Use TIMA0 as time driver | ||
| 103 | time-driver-tima0 = ["_time-driver"] | ||
| 104 | ## Use TIMA1 as time driver | ||
| 105 | time-driver-tima1 = ["_time-driver"] | ||
| 106 | |||
| 107 | #! ## Chip-selection features | ||
| 108 | #! Select your chip by specifying the model as a feature, e.g. `mspm0g3507`. | ||
| 109 | #! Check the `Cargo.toml` for the latest list of supported chips. | ||
| 110 | #! | ||
| 111 | #! **Important:** Do not forget to adapt the target chip in your toolchain, | ||
| 112 | #! e.g. in `.cargo/config.toml`. | ||
| 113 | |||
| 114 | mspm0c110x = [ "mspm0-metapac/mspm0c110x" ] | ||
| 115 | mspm0g110x = [ "mspm0-metapac/mspm0g110x" ] | ||
| 116 | mspm0g150x = [ "mspm0-metapac/mspm0g150x" ] | ||
| 117 | mspm0g151x = [ "mspm0-metapac/mspm0g151x" ] | ||
| 118 | mspm0g310x = [ "mspm0-metapac/mspm0g310x" ] | ||
| 119 | mspm0g350x = [ "mspm0-metapac/mspm0g350x" ] | ||
| 120 | mspm0g351x = [ "mspm0-metapac/mspm0g351x" ] | ||
| 121 | mspm0l110x = [ "mspm0-metapac/mspm0l110x" ] | ||
| 122 | mspm0l122x = [ "mspm0-metapac/mspm0l122x" ] | ||
| 123 | mspm0l130x = [ "mspm0-metapac/mspm0l130x" ] | ||
| 124 | mspm0l134x = [ "mspm0-metapac/mspm0l134x" ] | ||
| 125 | mspm0l222x = [ "mspm0-metapac/mspm0l222x" ] | ||
diff --git a/embassy-mspm0/build.rs b/embassy-mspm0/build.rs new file mode 100644 index 000000000..ffbe15c56 --- /dev/null +++ b/embassy-mspm0/build.rs | |||
| @@ -0,0 +1,616 @@ | |||
| 1 | use std::collections::HashMap; | ||
| 2 | use std::io::Write; | ||
| 3 | use std::path::{Path, PathBuf}; | ||
| 4 | use std::process::Command; | ||
| 5 | use std::sync::LazyLock; | ||
| 6 | use std::{env, fs}; | ||
| 7 | |||
| 8 | use common::CfgSet; | ||
| 9 | use mspm0_metapac::metadata::METADATA; | ||
| 10 | use proc_macro2::{Ident, Literal, Span, TokenStream}; | ||
| 11 | use quote::{format_ident, quote}; | ||
| 12 | |||
| 13 | #[path = "./build_common.rs"] | ||
| 14 | mod common; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | generate_code(); | ||
| 18 | } | ||
| 19 | |||
| 20 | fn generate_code() { | ||
| 21 | let mut cfgs = common::CfgSet::new(); | ||
| 22 | common::set_target_cfgs(&mut cfgs); | ||
| 23 | |||
| 24 | cfgs.declare_all(&["gpio_pb", "gpio_pc", "int_group1"]); | ||
| 25 | |||
| 26 | let mut singletons = Vec::new(); | ||
| 27 | |||
| 28 | // Generate singletons for GPIO pins. To only consider pins available on a family, use the name of | ||
| 29 | // the pins from the pincm mappings. | ||
| 30 | for pincm_mapping in METADATA.pincm_mappings.iter() { | ||
| 31 | singletons.push(pincm_mapping.pin.to_string()); | ||
| 32 | } | ||
| 33 | |||
| 34 | for peri in METADATA.peripherals { | ||
| 35 | match peri.kind { | ||
| 36 | // Specially generated. | ||
| 37 | "gpio" => match peri.name { | ||
| 38 | "GPIOB" => cfgs.enable("gpio_pb"), | ||
| 39 | "GPIOC" => cfgs.enable("gpio_pc"), | ||
| 40 | _ => (), | ||
| 41 | }, | ||
| 42 | |||
| 43 | // These peripherals are managed internally by the hal. | ||
| 44 | "iomux" | "cpuss" => {} | ||
| 45 | |||
| 46 | _ => singletons.push(peri.name.to_string()), | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 50 | time_driver(&singletons, &mut cfgs); | ||
| 51 | |||
| 52 | // ======== | ||
| 53 | // Write singletons | ||
| 54 | let mut g = TokenStream::new(); | ||
| 55 | |||
| 56 | let singleton_tokens: Vec<_> = singletons.iter().map(|s| format_ident!("{}", s)).collect(); | ||
| 57 | |||
| 58 | g.extend(quote! { | ||
| 59 | embassy_hal_internal::peripherals_definition!(#(#singleton_tokens),*); | ||
| 60 | }); | ||
| 61 | |||
| 62 | g.extend(quote! { | ||
| 63 | embassy_hal_internal::peripherals_struct!(#(#singleton_tokens),*); | ||
| 64 | }); | ||
| 65 | |||
| 66 | // ======== | ||
| 67 | // Generate GPIO pincm lookup tables. | ||
| 68 | let pincms = METADATA.pincm_mappings.iter().map(|mapping| { | ||
| 69 | let port_letter = mapping.pin.strip_prefix("P").unwrap(); | ||
| 70 | let port_base = (port_letter.chars().next().unwrap() as u8 - b'A') * 32; | ||
| 71 | // This assumes all ports are single letter length. | ||
| 72 | // This is fine unless TI releases a part with 833+ GPIO pins. | ||
| 73 | let pin_number = mapping.pin[2..].parse::<u8>().unwrap(); | ||
| 74 | |||
| 75 | let num = port_base + pin_number; | ||
| 76 | |||
| 77 | // But subtract 1 since pincm indices start from 0, not 1. | ||
| 78 | let pincm = Literal::u8_unsuffixed(mapping.pincm - 1); | ||
| 79 | quote! { | ||
| 80 | #num => #pincm | ||
| 81 | } | ||
| 82 | }); | ||
| 83 | |||
| 84 | g.extend(quote! { | ||
| 85 | #[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."] | ||
| 86 | pub(crate) fn gpio_pincm(pin_port: u8) -> u8 { | ||
| 87 | match pin_port { | ||
| 88 | #(#pincms),*, | ||
| 89 | _ => unreachable!(), | ||
| 90 | } | ||
| 91 | } | ||
| 92 | }); | ||
| 93 | |||
| 94 | for pincm_mapping in METADATA.pincm_mappings.iter() { | ||
| 95 | let name = Ident::new(&pincm_mapping.pin, Span::call_site()); | ||
| 96 | let port_letter = pincm_mapping.pin.strip_prefix("P").unwrap(); | ||
| 97 | let port_letter = port_letter.chars().next().unwrap(); | ||
| 98 | let pin_number = Literal::u8_unsuffixed(pincm_mapping.pin[2..].parse::<u8>().unwrap()); | ||
| 99 | |||
| 100 | let port = Ident::new(&format!("Port{}", port_letter), Span::call_site()); | ||
| 101 | |||
| 102 | // TODO: Feature gate pins that can be used as NRST | ||
| 103 | |||
| 104 | g.extend(quote! { | ||
| 105 | impl_pin!(#name, crate::gpio::Port::#port, #pin_number); | ||
| 106 | }); | ||
| 107 | } | ||
| 108 | |||
| 109 | // Generate timers | ||
| 110 | for peripheral in METADATA | ||
| 111 | .peripherals | ||
| 112 | .iter() | ||
| 113 | .filter(|p| p.name.starts_with("TIM")) | ||
| 114 | { | ||
| 115 | let name = Ident::new(&peripheral.name, Span::call_site()); | ||
| 116 | let timers = &*TIMERS; | ||
| 117 | |||
| 118 | let timer = timers.get(peripheral.name).expect("Timer does not exist"); | ||
| 119 | assert!(timer.bits == 16 || timer.bits == 32); | ||
| 120 | let bits = if timer.bits == 16 { | ||
| 121 | quote! { Bits16 } | ||
| 122 | } else { | ||
| 123 | quote! { Bits32 } | ||
| 124 | }; | ||
| 125 | |||
| 126 | g.extend(quote! { | ||
| 127 | impl_timer!(#name, #bits); | ||
| 128 | }); | ||
| 129 | } | ||
| 130 | |||
| 131 | // Generate interrupt module | ||
| 132 | let interrupts: Vec<Ident> = METADATA | ||
| 133 | .interrupts | ||
| 134 | .iter() | ||
| 135 | .map(|interrupt| Ident::new(interrupt.name, Span::call_site())) | ||
| 136 | .collect(); | ||
| 137 | |||
| 138 | g.extend(quote! { | ||
| 139 | embassy_hal_internal::interrupt_mod! { | ||
| 140 | #(#interrupts),* | ||
| 141 | } | ||
| 142 | }); | ||
| 143 | |||
| 144 | let group_interrupt_enables = METADATA | ||
| 145 | .interrupts | ||
| 146 | .iter() | ||
| 147 | .filter(|interrupt| interrupt.name.contains("GROUP")) | ||
| 148 | .map(|interrupt| { | ||
| 149 | let name = Ident::new(interrupt.name, Span::call_site()); | ||
| 150 | |||
| 151 | quote! { | ||
| 152 | crate::interrupt::typelevel::#name::enable(); | ||
| 153 | } | ||
| 154 | }); | ||
| 155 | |||
| 156 | // Generate interrupt enables for groups | ||
| 157 | g.extend(quote! { | ||
| 158 | pub fn enable_group_interrupts(_cs: critical_section::CriticalSection) { | ||
| 159 | use crate::interrupt::typelevel::Interrupt; | ||
| 160 | |||
| 161 | unsafe { | ||
| 162 | #(#group_interrupt_enables)* | ||
| 163 | } | ||
| 164 | } | ||
| 165 | }); | ||
| 166 | |||
| 167 | let out_dir = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 168 | let out_file = out_dir.join("_generated.rs").to_string_lossy().to_string(); | ||
| 169 | fs::write(&out_file, g.to_string()).unwrap(); | ||
| 170 | rustfmt(&out_file); | ||
| 171 | } | ||
| 172 | |||
| 173 | fn time_driver(singletons: &[String], cfgs: &mut CfgSet) { | ||
| 174 | // Timer features | ||
| 175 | for (timer, desc) in TIMERS.iter() { | ||
| 176 | if desc.bits != 16 { | ||
| 177 | continue; | ||
| 178 | } | ||
| 179 | |||
| 180 | let name = timer.to_lowercase(); | ||
| 181 | cfgs.declare(&format!("time_driver_{}", name)); | ||
| 182 | } | ||
| 183 | |||
| 184 | let time_driver = match env::vars() | ||
| 185 | .map(|(a, _)| a) | ||
| 186 | .filter(|x| x.starts_with("CARGO_FEATURE_TIME_DRIVER_")) | ||
| 187 | .get_one() | ||
| 188 | { | ||
| 189 | Ok(x) => Some( | ||
| 190 | x.strip_prefix("CARGO_FEATURE_TIME_DRIVER_") | ||
| 191 | .unwrap() | ||
| 192 | .to_ascii_lowercase(), | ||
| 193 | ), | ||
| 194 | Err(GetOneError::None) => None, | ||
| 195 | Err(GetOneError::Multiple) => panic!("Multiple time-driver-xxx Cargo features enabled"), | ||
| 196 | }; | ||
| 197 | |||
| 198 | // Verify the selected timer is available | ||
| 199 | let singleton = match time_driver.as_ref().map(|x| x.as_ref()) { | ||
| 200 | None => "", | ||
| 201 | Some("timg0") => "TIMG0", | ||
| 202 | Some("timg1") => "TIMG1", | ||
| 203 | Some("timg2") => "TIMG2", | ||
| 204 | Some("timg3") => "TIMG3", | ||
| 205 | Some("timg4") => "TIMG4", | ||
| 206 | Some("timg5") => "TIMG5", | ||
| 207 | Some("timg6") => "TIMG6", | ||
| 208 | Some("timg7") => "TIMG7", | ||
| 209 | Some("timg8") => "TIMG8", | ||
| 210 | Some("timg9") => "TIMG9", | ||
| 211 | Some("timg10") => "TIMG10", | ||
| 212 | Some("timg11") => "TIMG11", | ||
| 213 | Some("timg14") => "TIMG14", | ||
| 214 | Some("tima0") => "TIMA0", | ||
| 215 | Some("tima1") => "TIMA1", | ||
| 216 | Some("any") => { | ||
| 217 | // Order of timer candidates: | ||
| 218 | // 1. 16-bit, 2 channel | ||
| 219 | // 2. 16-bit, 2 channel with shadow registers | ||
| 220 | // 3. 16-bit, 4 channel | ||
| 221 | // 4. 16-bit with QEI | ||
| 222 | // 5. Advanced timers | ||
| 223 | // | ||
| 224 | // TODO: Select RTC first if available | ||
| 225 | // TODO: 32-bit timers are not considered yet | ||
| 226 | [ | ||
| 227 | // 16-bit, 2 channel | ||
| 228 | "TIMG0", "TIMG1", "TIMG2", "TIMG3", | ||
| 229 | // 16-bit, 2 channel with shadow registers | ||
| 230 | "TIMG4", "TIMG5", "TIMG6", "TIMG7", // 16-bit, 4 channel | ||
| 231 | "TIMG14", // 16-bit with QEI | ||
| 232 | "TIMG8", "TIMG9", "TIMG10", "TIMG11", // Advanced timers | ||
| 233 | "TIMA0", "TIMA1", | ||
| 234 | ] | ||
| 235 | .iter() | ||
| 236 | .find(|tim| singletons.contains(&tim.to_string())) | ||
| 237 | .expect("Could not find any timer") | ||
| 238 | } | ||
| 239 | _ => panic!("unknown time_driver {:?}", time_driver), | ||
| 240 | }; | ||
| 241 | |||
| 242 | if !singleton.is_empty() { | ||
| 243 | cfgs.enable(format!("time_driver_{}", singleton.to_lowercase())); | ||
| 244 | } | ||
| 245 | } | ||
| 246 | |||
| 247 | /// rustfmt a given path. | ||
| 248 | /// Failures are logged to stderr and ignored. | ||
| 249 | fn rustfmt(path: impl AsRef<Path>) { | ||
| 250 | let path = path.as_ref(); | ||
| 251 | match Command::new("rustfmt").args([path]).output() { | ||
| 252 | Err(e) => { | ||
| 253 | eprintln!("failed to exec rustfmt {:?}: {:?}", path, e); | ||
| 254 | } | ||
| 255 | Ok(out) => { | ||
| 256 | if !out.status.success() { | ||
| 257 | eprintln!("rustfmt {:?} failed:", path); | ||
| 258 | eprintln!("=== STDOUT:"); | ||
| 259 | std::io::stderr().write_all(&out.stdout).unwrap(); | ||
| 260 | eprintln!("=== STDERR:"); | ||
| 261 | std::io::stderr().write_all(&out.stderr).unwrap(); | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | #[allow(dead_code)] | ||
| 268 | struct TimerDesc { | ||
| 269 | bits: u8, | ||
| 270 | /// Is there an 8-bit prescaler | ||
| 271 | prescaler: bool, | ||
| 272 | /// Is there a repeat counter | ||
| 273 | repeat_counter: bool, | ||
| 274 | ccp_channels_internal: u8, | ||
| 275 | ccp_channels_external: u8, | ||
| 276 | external_pwm_channels: u8, | ||
| 277 | phase_load: bool, | ||
| 278 | shadow_load: bool, | ||
| 279 | shadow_ccs: bool, | ||
| 280 | deadband: bool, | ||
| 281 | fault_handler: bool, | ||
| 282 | qei_hall: bool, | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Description of all timer instances. | ||
| 286 | const TIMERS: LazyLock<HashMap<String, TimerDesc>> = LazyLock::new(|| { | ||
| 287 | let mut map = HashMap::new(); | ||
| 288 | map.insert( | ||
| 289 | "TIMG0".into(), | ||
| 290 | TimerDesc { | ||
| 291 | bits: 16, | ||
| 292 | prescaler: true, | ||
| 293 | repeat_counter: false, | ||
| 294 | ccp_channels_internal: 2, | ||
| 295 | ccp_channels_external: 2, | ||
| 296 | external_pwm_channels: 2, | ||
| 297 | phase_load: false, | ||
| 298 | shadow_load: false, | ||
| 299 | shadow_ccs: false, | ||
| 300 | deadband: false, | ||
| 301 | fault_handler: false, | ||
| 302 | qei_hall: false, | ||
| 303 | }, | ||
| 304 | ); | ||
| 305 | |||
| 306 | map.insert( | ||
| 307 | "TIMG1".into(), | ||
| 308 | TimerDesc { | ||
| 309 | bits: 16, | ||
| 310 | prescaler: true, | ||
| 311 | repeat_counter: false, | ||
| 312 | ccp_channels_internal: 2, | ||
| 313 | ccp_channels_external: 2, | ||
| 314 | external_pwm_channels: 2, | ||
| 315 | phase_load: false, | ||
| 316 | shadow_load: false, | ||
| 317 | shadow_ccs: false, | ||
| 318 | deadband: false, | ||
| 319 | fault_handler: false, | ||
| 320 | qei_hall: false, | ||
| 321 | }, | ||
| 322 | ); | ||
| 323 | |||
| 324 | map.insert( | ||
| 325 | "TIMG2".into(), | ||
| 326 | TimerDesc { | ||
| 327 | bits: 16, | ||
| 328 | prescaler: true, | ||
| 329 | repeat_counter: false, | ||
| 330 | ccp_channels_internal: 2, | ||
| 331 | ccp_channels_external: 2, | ||
| 332 | external_pwm_channels: 2, | ||
| 333 | phase_load: false, | ||
| 334 | shadow_load: false, | ||
| 335 | shadow_ccs: false, | ||
| 336 | deadband: false, | ||
| 337 | fault_handler: false, | ||
| 338 | qei_hall: false, | ||
| 339 | }, | ||
| 340 | ); | ||
| 341 | |||
| 342 | map.insert( | ||
| 343 | "TIMG3".into(), | ||
| 344 | TimerDesc { | ||
| 345 | bits: 16, | ||
| 346 | prescaler: true, | ||
| 347 | repeat_counter: false, | ||
| 348 | ccp_channels_internal: 2, | ||
| 349 | ccp_channels_external: 2, | ||
| 350 | external_pwm_channels: 2, | ||
| 351 | phase_load: false, | ||
| 352 | shadow_load: false, | ||
| 353 | shadow_ccs: false, | ||
| 354 | deadband: false, | ||
| 355 | fault_handler: false, | ||
| 356 | qei_hall: false, | ||
| 357 | }, | ||
| 358 | ); | ||
| 359 | |||
| 360 | map.insert( | ||
| 361 | "TIMG4".into(), | ||
| 362 | TimerDesc { | ||
| 363 | bits: 16, | ||
| 364 | prescaler: true, | ||
| 365 | repeat_counter: false, | ||
| 366 | ccp_channels_internal: 2, | ||
| 367 | ccp_channels_external: 2, | ||
| 368 | external_pwm_channels: 2, | ||
| 369 | phase_load: false, | ||
| 370 | shadow_load: true, | ||
| 371 | shadow_ccs: true, | ||
| 372 | deadband: false, | ||
| 373 | fault_handler: false, | ||
| 374 | qei_hall: false, | ||
| 375 | }, | ||
| 376 | ); | ||
| 377 | |||
| 378 | map.insert( | ||
| 379 | "TIMG5".into(), | ||
| 380 | TimerDesc { | ||
| 381 | bits: 16, | ||
| 382 | prescaler: true, | ||
| 383 | repeat_counter: false, | ||
| 384 | ccp_channels_internal: 2, | ||
| 385 | ccp_channels_external: 2, | ||
| 386 | external_pwm_channels: 2, | ||
| 387 | phase_load: false, | ||
| 388 | shadow_load: true, | ||
| 389 | shadow_ccs: true, | ||
| 390 | deadband: false, | ||
| 391 | fault_handler: false, | ||
| 392 | qei_hall: false, | ||
| 393 | }, | ||
| 394 | ); | ||
| 395 | |||
| 396 | map.insert( | ||
| 397 | "TIMG6".into(), | ||
| 398 | TimerDesc { | ||
| 399 | bits: 16, | ||
| 400 | prescaler: true, | ||
| 401 | repeat_counter: false, | ||
| 402 | ccp_channels_internal: 2, | ||
| 403 | ccp_channels_external: 2, | ||
| 404 | external_pwm_channels: 2, | ||
| 405 | phase_load: false, | ||
| 406 | shadow_load: true, | ||
| 407 | shadow_ccs: true, | ||
| 408 | deadband: false, | ||
| 409 | fault_handler: false, | ||
| 410 | qei_hall: false, | ||
| 411 | }, | ||
| 412 | ); | ||
| 413 | |||
| 414 | map.insert( | ||
| 415 | "TIMG7".into(), | ||
| 416 | TimerDesc { | ||
| 417 | bits: 16, | ||
| 418 | prescaler: true, | ||
| 419 | repeat_counter: false, | ||
| 420 | ccp_channels_internal: 2, | ||
| 421 | ccp_channels_external: 2, | ||
| 422 | external_pwm_channels: 2, | ||
| 423 | phase_load: false, | ||
| 424 | shadow_load: true, | ||
| 425 | shadow_ccs: true, | ||
| 426 | deadband: false, | ||
| 427 | fault_handler: false, | ||
| 428 | qei_hall: false, | ||
| 429 | }, | ||
| 430 | ); | ||
| 431 | |||
| 432 | map.insert( | ||
| 433 | "TIMG8".into(), | ||
| 434 | TimerDesc { | ||
| 435 | bits: 16, | ||
| 436 | prescaler: true, | ||
| 437 | repeat_counter: false, | ||
| 438 | ccp_channels_internal: 2, | ||
| 439 | ccp_channels_external: 2, | ||
| 440 | external_pwm_channels: 2, | ||
| 441 | phase_load: false, | ||
| 442 | shadow_load: false, | ||
| 443 | shadow_ccs: false, | ||
| 444 | deadband: false, | ||
| 445 | fault_handler: false, | ||
| 446 | qei_hall: true, | ||
| 447 | }, | ||
| 448 | ); | ||
| 449 | |||
| 450 | map.insert( | ||
| 451 | "TIMG9".into(), | ||
| 452 | TimerDesc { | ||
| 453 | bits: 16, | ||
| 454 | prescaler: true, | ||
| 455 | repeat_counter: false, | ||
| 456 | ccp_channels_internal: 2, | ||
| 457 | ccp_channels_external: 2, | ||
| 458 | external_pwm_channels: 2, | ||
| 459 | phase_load: false, | ||
| 460 | shadow_load: false, | ||
| 461 | shadow_ccs: false, | ||
| 462 | deadband: false, | ||
| 463 | fault_handler: false, | ||
| 464 | qei_hall: true, | ||
| 465 | }, | ||
| 466 | ); | ||
| 467 | |||
| 468 | map.insert( | ||
| 469 | "TIMG10".into(), | ||
| 470 | TimerDesc { | ||
| 471 | bits: 16, | ||
| 472 | prescaler: true, | ||
| 473 | repeat_counter: false, | ||
| 474 | ccp_channels_internal: 2, | ||
| 475 | ccp_channels_external: 2, | ||
| 476 | external_pwm_channels: 2, | ||
| 477 | phase_load: false, | ||
| 478 | shadow_load: false, | ||
| 479 | shadow_ccs: false, | ||
| 480 | deadband: false, | ||
| 481 | fault_handler: false, | ||
| 482 | qei_hall: true, | ||
| 483 | }, | ||
| 484 | ); | ||
| 485 | |||
| 486 | map.insert( | ||
| 487 | "TIMG11".into(), | ||
| 488 | TimerDesc { | ||
| 489 | bits: 16, | ||
| 490 | prescaler: true, | ||
| 491 | repeat_counter: false, | ||
| 492 | ccp_channels_internal: 2, | ||
| 493 | ccp_channels_external: 2, | ||
| 494 | external_pwm_channels: 2, | ||
| 495 | phase_load: false, | ||
| 496 | shadow_load: false, | ||
| 497 | shadow_ccs: false, | ||
| 498 | deadband: false, | ||
| 499 | fault_handler: false, | ||
| 500 | qei_hall: true, | ||
| 501 | }, | ||
| 502 | ); | ||
| 503 | |||
| 504 | map.insert( | ||
| 505 | "TIMG12".into(), | ||
| 506 | TimerDesc { | ||
| 507 | bits: 32, | ||
| 508 | prescaler: false, | ||
| 509 | repeat_counter: false, | ||
| 510 | ccp_channels_internal: 2, | ||
| 511 | ccp_channels_external: 2, | ||
| 512 | external_pwm_channels: 2, | ||
| 513 | phase_load: false, | ||
| 514 | shadow_load: false, | ||
| 515 | shadow_ccs: true, | ||
| 516 | deadband: false, | ||
| 517 | fault_handler: false, | ||
| 518 | qei_hall: false, | ||
| 519 | }, | ||
| 520 | ); | ||
| 521 | |||
| 522 | map.insert( | ||
| 523 | "TIMG13".into(), | ||
| 524 | TimerDesc { | ||
| 525 | bits: 32, | ||
| 526 | prescaler: false, | ||
| 527 | repeat_counter: false, | ||
| 528 | ccp_channels_internal: 2, | ||
| 529 | ccp_channels_external: 2, | ||
| 530 | external_pwm_channels: 2, | ||
| 531 | phase_load: false, | ||
| 532 | shadow_load: false, | ||
| 533 | shadow_ccs: true, | ||
| 534 | deadband: false, | ||
| 535 | fault_handler: false, | ||
| 536 | qei_hall: false, | ||
| 537 | }, | ||
| 538 | ); | ||
| 539 | |||
| 540 | map.insert( | ||
| 541 | "TIMG14".into(), | ||
| 542 | TimerDesc { | ||
| 543 | bits: 16, | ||
| 544 | prescaler: true, | ||
| 545 | repeat_counter: false, | ||
| 546 | ccp_channels_internal: 4, | ||
| 547 | ccp_channels_external: 4, | ||
| 548 | external_pwm_channels: 4, | ||
| 549 | phase_load: false, | ||
| 550 | shadow_load: false, | ||
| 551 | shadow_ccs: false, | ||
| 552 | deadband: false, | ||
| 553 | fault_handler: false, | ||
| 554 | qei_hall: false, | ||
| 555 | }, | ||
| 556 | ); | ||
| 557 | |||
| 558 | map.insert( | ||
| 559 | "TIMA0".into(), | ||
| 560 | TimerDesc { | ||
| 561 | bits: 16, | ||
| 562 | prescaler: true, | ||
| 563 | repeat_counter: true, | ||
| 564 | ccp_channels_internal: 4, | ||
| 565 | ccp_channels_external: 2, | ||
| 566 | external_pwm_channels: 8, | ||
| 567 | phase_load: true, | ||
| 568 | shadow_load: true, | ||
| 569 | shadow_ccs: true, | ||
| 570 | deadband: true, | ||
| 571 | fault_handler: true, | ||
| 572 | qei_hall: false, | ||
| 573 | }, | ||
| 574 | ); | ||
| 575 | |||
| 576 | map.insert( | ||
| 577 | "TIMA1".into(), | ||
| 578 | TimerDesc { | ||
| 579 | bits: 16, | ||
| 580 | prescaler: true, | ||
| 581 | repeat_counter: true, | ||
| 582 | ccp_channels_internal: 2, | ||
| 583 | ccp_channels_external: 2, | ||
| 584 | external_pwm_channels: 4, | ||
| 585 | phase_load: true, | ||
| 586 | shadow_load: true, | ||
| 587 | shadow_ccs: true, | ||
| 588 | deadband: true, | ||
| 589 | fault_handler: true, | ||
| 590 | qei_hall: false, | ||
| 591 | }, | ||
| 592 | ); | ||
| 593 | |||
| 594 | map | ||
| 595 | }); | ||
| 596 | |||
| 597 | enum GetOneError { | ||
| 598 | None, | ||
| 599 | Multiple, | ||
| 600 | } | ||
| 601 | |||
| 602 | trait IteratorExt: Iterator { | ||
| 603 | fn get_one(self) -> Result<Self::Item, GetOneError>; | ||
| 604 | } | ||
| 605 | |||
| 606 | impl<T: Iterator> IteratorExt for T { | ||
| 607 | fn get_one(mut self) -> Result<Self::Item, GetOneError> { | ||
| 608 | match self.next() { | ||
| 609 | None => Err(GetOneError::None), | ||
| 610 | Some(res) => match self.next() { | ||
| 611 | Some(_) => Err(GetOneError::Multiple), | ||
| 612 | None => Ok(res), | ||
| 613 | }, | ||
| 614 | } | ||
| 615 | } | ||
| 616 | } | ||
diff --git a/embassy-mspm0/build_common.rs b/embassy-mspm0/build_common.rs new file mode 100644 index 000000000..4f24e6d37 --- /dev/null +++ b/embassy-mspm0/build_common.rs | |||
| @@ -0,0 +1,94 @@ | |||
| 1 | // NOTE: this file is copy-pasted between several Embassy crates, because there is no | ||
| 2 | // straightforward way to share this code: | ||
| 3 | // - it cannot be placed into the root of the repo and linked from each build.rs using `#[path = | ||
| 4 | // "../build_common.rs"]`, because `cargo publish` requires that all files published with a crate | ||
| 5 | // reside in the crate's directory, | ||
| 6 | // - it cannot be symlinked from `embassy-xxx/build_common.rs` to `../build_common.rs`, because | ||
| 7 | // symlinks don't work on Windows. | ||
| 8 | |||
| 9 | use std::collections::HashSet; | ||
| 10 | use std::env; | ||
| 11 | |||
| 12 | /// Helper for emitting cargo instruction for enabling configs (`cargo:rustc-cfg=X`) and declaring | ||
| 13 | /// them (`cargo:rust-check-cfg=cfg(X)`). | ||
| 14 | #[derive(Debug)] | ||
| 15 | pub struct CfgSet { | ||
| 16 | enabled: HashSet<String>, | ||
| 17 | declared: HashSet<String>, | ||
| 18 | } | ||
| 19 | |||
| 20 | impl CfgSet { | ||
| 21 | pub fn new() -> Self { | ||
| 22 | Self { | ||
| 23 | enabled: HashSet::new(), | ||
| 24 | declared: HashSet::new(), | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | /// Enable a config, which can then be used in `#[cfg(...)]` for conditional compilation. | ||
| 29 | /// | ||
| 30 | /// All configs that can potentially be enabled should be unconditionally declared using | ||
| 31 | /// [`Self::declare()`]. | ||
| 32 | pub fn enable(&mut self, cfg: impl AsRef<str>) { | ||
| 33 | if self.enabled.insert(cfg.as_ref().to_owned()) { | ||
| 34 | println!("cargo:rustc-cfg={}", cfg.as_ref()); | ||
| 35 | } | ||
| 36 | } | ||
| 37 | |||
| 38 | pub fn enable_all(&mut self, cfgs: &[impl AsRef<str>]) { | ||
| 39 | for cfg in cfgs.iter() { | ||
| 40 | self.enable(cfg.as_ref()); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | /// Declare a valid config for conditional compilation, without enabling it. | ||
| 45 | /// | ||
| 46 | /// This enables rustc to check that the configs in `#[cfg(...)]` attributes are valid. | ||
| 47 | pub fn declare(&mut self, cfg: impl AsRef<str>) { | ||
| 48 | if self.declared.insert(cfg.as_ref().to_owned()) { | ||
| 49 | println!("cargo:rustc-check-cfg=cfg({})", cfg.as_ref()); | ||
| 50 | } | ||
| 51 | } | ||
| 52 | |||
| 53 | pub fn declare_all(&mut self, cfgs: &[impl AsRef<str>]) { | ||
| 54 | for cfg in cfgs.iter() { | ||
| 55 | self.declare(cfg.as_ref()); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | pub fn set(&mut self, cfg: impl Into<String>, enable: bool) { | ||
| 60 | let cfg = cfg.into(); | ||
| 61 | if enable { | ||
| 62 | self.enable(cfg.clone()); | ||
| 63 | } | ||
| 64 | self.declare(cfg); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | /// Sets configs that describe the target platform. | ||
| 69 | pub fn set_target_cfgs(cfgs: &mut CfgSet) { | ||
| 70 | let target = env::var("TARGET").unwrap(); | ||
| 71 | |||
| 72 | if target.starts_with("thumbv6m-") { | ||
| 73 | cfgs.enable_all(&["cortex_m", "armv6m"]); | ||
| 74 | } else if target.starts_with("thumbv7m-") { | ||
| 75 | cfgs.enable_all(&["cortex_m", "armv7m"]); | ||
| 76 | } else if target.starts_with("thumbv7em-") { | ||
| 77 | cfgs.enable_all(&["cortex_m", "armv7m", "armv7em"]); | ||
| 78 | } else if target.starts_with("thumbv8m.base") { | ||
| 79 | cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_base"]); | ||
| 80 | } else if target.starts_with("thumbv8m.main") { | ||
| 81 | cfgs.enable_all(&["cortex_m", "armv8m", "armv8m_main"]); | ||
| 82 | } | ||
| 83 | cfgs.declare_all(&[ | ||
| 84 | "cortex_m", | ||
| 85 | "armv6m", | ||
| 86 | "armv7m", | ||
| 87 | "armv7em", | ||
| 88 | "armv8m", | ||
| 89 | "armv8m_base", | ||
| 90 | "armv8m_main", | ||
| 91 | ]); | ||
| 92 | |||
| 93 | cfgs.set("has_fpu", target.ends_with("-eabihf")); | ||
| 94 | } | ||
diff --git a/embassy-mspm0/src/fmt.rs b/embassy-mspm0/src/fmt.rs new file mode 100644 index 000000000..8ca61bc39 --- /dev/null +++ b/embassy-mspm0/src/fmt.rs | |||
| @@ -0,0 +1,270 @@ | |||
| 1 | #![macro_use] | ||
| 2 | #![allow(unused)] | ||
| 3 | |||
| 4 | use core::fmt::{Debug, Display, LowerHex}; | ||
| 5 | |||
| 6 | #[cfg(all(feature = "defmt", feature = "log"))] | ||
| 7 | compile_error!("You may not enable both `defmt` and `log` features."); | ||
| 8 | |||
| 9 | #[collapse_debuginfo(yes)] | ||
| 10 | macro_rules! assert { | ||
| 11 | ($($x:tt)*) => { | ||
| 12 | { | ||
| 13 | #[cfg(not(feature = "defmt"))] | ||
| 14 | ::core::assert!($($x)*); | ||
| 15 | #[cfg(feature = "defmt")] | ||
| 16 | ::defmt::assert!($($x)*); | ||
| 17 | } | ||
| 18 | }; | ||
| 19 | } | ||
| 20 | |||
| 21 | #[collapse_debuginfo(yes)] | ||
| 22 | macro_rules! assert_eq { | ||
| 23 | ($($x:tt)*) => { | ||
| 24 | { | ||
| 25 | #[cfg(not(feature = "defmt"))] | ||
| 26 | ::core::assert_eq!($($x)*); | ||
| 27 | #[cfg(feature = "defmt")] | ||
| 28 | ::defmt::assert_eq!($($x)*); | ||
| 29 | } | ||
| 30 | }; | ||
| 31 | } | ||
| 32 | |||
| 33 | #[collapse_debuginfo(yes)] | ||
| 34 | macro_rules! assert_ne { | ||
| 35 | ($($x:tt)*) => { | ||
| 36 | { | ||
| 37 | #[cfg(not(feature = "defmt"))] | ||
| 38 | ::core::assert_ne!($($x)*); | ||
| 39 | #[cfg(feature = "defmt")] | ||
| 40 | ::defmt::assert_ne!($($x)*); | ||
| 41 | } | ||
| 42 | }; | ||
| 43 | } | ||
| 44 | |||
| 45 | #[collapse_debuginfo(yes)] | ||
| 46 | macro_rules! debug_assert { | ||
| 47 | ($($x:tt)*) => { | ||
| 48 | { | ||
| 49 | #[cfg(not(feature = "defmt"))] | ||
| 50 | ::core::debug_assert!($($x)*); | ||
| 51 | #[cfg(feature = "defmt")] | ||
| 52 | ::defmt::debug_assert!($($x)*); | ||
| 53 | } | ||
| 54 | }; | ||
| 55 | } | ||
| 56 | |||
| 57 | #[collapse_debuginfo(yes)] | ||
| 58 | macro_rules! debug_assert_eq { | ||
| 59 | ($($x:tt)*) => { | ||
| 60 | { | ||
| 61 | #[cfg(not(feature = "defmt"))] | ||
| 62 | ::core::debug_assert_eq!($($x)*); | ||
| 63 | #[cfg(feature = "defmt")] | ||
| 64 | ::defmt::debug_assert_eq!($($x)*); | ||
| 65 | } | ||
| 66 | }; | ||
| 67 | } | ||
| 68 | |||
| 69 | #[collapse_debuginfo(yes)] | ||
| 70 | macro_rules! debug_assert_ne { | ||
| 71 | ($($x:tt)*) => { | ||
| 72 | { | ||
| 73 | #[cfg(not(feature = "defmt"))] | ||
| 74 | ::core::debug_assert_ne!($($x)*); | ||
| 75 | #[cfg(feature = "defmt")] | ||
| 76 | ::defmt::debug_assert_ne!($($x)*); | ||
| 77 | } | ||
| 78 | }; | ||
| 79 | } | ||
| 80 | |||
| 81 | #[collapse_debuginfo(yes)] | ||
| 82 | macro_rules! todo { | ||
| 83 | ($($x:tt)*) => { | ||
| 84 | { | ||
| 85 | #[cfg(not(feature = "defmt"))] | ||
| 86 | ::core::todo!($($x)*); | ||
| 87 | #[cfg(feature = "defmt")] | ||
| 88 | ::defmt::todo!($($x)*); | ||
| 89 | } | ||
| 90 | }; | ||
| 91 | } | ||
| 92 | |||
| 93 | #[collapse_debuginfo(yes)] | ||
| 94 | macro_rules! unreachable { | ||
| 95 | ($($x:tt)*) => { | ||
| 96 | { | ||
| 97 | #[cfg(not(feature = "defmt"))] | ||
| 98 | ::core::unreachable!($($x)*); | ||
| 99 | #[cfg(feature = "defmt")] | ||
| 100 | ::defmt::unreachable!($($x)*); | ||
| 101 | } | ||
| 102 | }; | ||
| 103 | } | ||
| 104 | |||
| 105 | #[collapse_debuginfo(yes)] | ||
| 106 | macro_rules! panic { | ||
| 107 | ($($x:tt)*) => { | ||
| 108 | { | ||
| 109 | #[cfg(not(feature = "defmt"))] | ||
| 110 | ::core::panic!($($x)*); | ||
| 111 | #[cfg(feature = "defmt")] | ||
| 112 | ::defmt::panic!($($x)*); | ||
| 113 | } | ||
| 114 | }; | ||
| 115 | } | ||
| 116 | |||
| 117 | #[collapse_debuginfo(yes)] | ||
| 118 | macro_rules! trace { | ||
| 119 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 120 | { | ||
| 121 | #[cfg(feature = "log")] | ||
| 122 | ::log::trace!($s $(, $x)*); | ||
| 123 | #[cfg(feature = "defmt")] | ||
| 124 | ::defmt::trace!($s $(, $x)*); | ||
| 125 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 126 | let _ = ($( & $x ),*); | ||
| 127 | } | ||
| 128 | }; | ||
| 129 | } | ||
| 130 | |||
| 131 | #[collapse_debuginfo(yes)] | ||
| 132 | macro_rules! debug { | ||
| 133 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 134 | { | ||
| 135 | #[cfg(feature = "log")] | ||
| 136 | ::log::debug!($s $(, $x)*); | ||
| 137 | #[cfg(feature = "defmt")] | ||
| 138 | ::defmt::debug!($s $(, $x)*); | ||
| 139 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 140 | let _ = ($( & $x ),*); | ||
| 141 | } | ||
| 142 | }; | ||
| 143 | } | ||
| 144 | |||
| 145 | #[collapse_debuginfo(yes)] | ||
| 146 | macro_rules! info { | ||
| 147 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 148 | { | ||
| 149 | #[cfg(feature = "log")] | ||
| 150 | ::log::info!($s $(, $x)*); | ||
| 151 | #[cfg(feature = "defmt")] | ||
| 152 | ::defmt::info!($s $(, $x)*); | ||
| 153 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 154 | let _ = ($( & $x ),*); | ||
| 155 | } | ||
| 156 | }; | ||
| 157 | } | ||
| 158 | |||
| 159 | #[collapse_debuginfo(yes)] | ||
| 160 | macro_rules! warn { | ||
| 161 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 162 | { | ||
| 163 | #[cfg(feature = "log")] | ||
| 164 | ::log::warn!($s $(, $x)*); | ||
| 165 | #[cfg(feature = "defmt")] | ||
| 166 | ::defmt::warn!($s $(, $x)*); | ||
| 167 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 168 | let _ = ($( & $x ),*); | ||
| 169 | } | ||
| 170 | }; | ||
| 171 | } | ||
| 172 | |||
| 173 | #[collapse_debuginfo(yes)] | ||
| 174 | macro_rules! error { | ||
| 175 | ($s:literal $(, $x:expr)* $(,)?) => { | ||
| 176 | { | ||
| 177 | #[cfg(feature = "log")] | ||
| 178 | ::log::error!($s $(, $x)*); | ||
| 179 | #[cfg(feature = "defmt")] | ||
| 180 | ::defmt::error!($s $(, $x)*); | ||
| 181 | #[cfg(not(any(feature = "log", feature="defmt")))] | ||
| 182 | let _ = ($( & $x ),*); | ||
| 183 | } | ||
| 184 | }; | ||
| 185 | } | ||
| 186 | |||
| 187 | #[cfg(feature = "defmt")] | ||
| 188 | #[collapse_debuginfo(yes)] | ||
| 189 | macro_rules! unwrap { | ||
| 190 | ($($x:tt)*) => { | ||
| 191 | ::defmt::unwrap!($($x)*) | ||
| 192 | }; | ||
| 193 | } | ||
| 194 | |||
| 195 | #[cfg(not(feature = "defmt"))] | ||
| 196 | #[collapse_debuginfo(yes)] | ||
| 197 | macro_rules! unwrap { | ||
| 198 | ($arg:expr) => { | ||
| 199 | match $crate::fmt::Try::into_result($arg) { | ||
| 200 | ::core::result::Result::Ok(t) => t, | ||
| 201 | ::core::result::Result::Err(e) => { | ||
| 202 | ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | }; | ||
| 206 | ($arg:expr, $($msg:expr),+ $(,)? ) => { | ||
| 207 | match $crate::fmt::Try::into_result($arg) { | ||
| 208 | ::core::result::Result::Ok(t) => t, | ||
| 209 | ::core::result::Result::Err(e) => { | ||
| 210 | ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | } | ||
| 214 | } | ||
| 215 | |||
| 216 | #[derive(Debug, Copy, Clone, Eq, PartialEq)] | ||
| 217 | pub struct NoneError; | ||
| 218 | |||
| 219 | pub trait Try { | ||
| 220 | type Ok; | ||
| 221 | type Error; | ||
| 222 | fn into_result(self) -> Result<Self::Ok, Self::Error>; | ||
| 223 | } | ||
| 224 | |||
| 225 | impl<T> Try for Option<T> { | ||
| 226 | type Ok = T; | ||
| 227 | type Error = NoneError; | ||
| 228 | |||
| 229 | #[inline] | ||
| 230 | fn into_result(self) -> Result<T, NoneError> { | ||
| 231 | self.ok_or(NoneError) | ||
| 232 | } | ||
| 233 | } | ||
| 234 | |||
| 235 | impl<T, E> Try for Result<T, E> { | ||
| 236 | type Ok = T; | ||
| 237 | type Error = E; | ||
| 238 | |||
| 239 | #[inline] | ||
| 240 | fn into_result(self) -> Self { | ||
| 241 | self | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | pub(crate) struct Bytes<'a>(pub &'a [u8]); | ||
| 246 | |||
| 247 | impl<'a> Debug for Bytes<'a> { | ||
| 248 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 249 | write!(f, "{:#02x?}", self.0) | ||
| 250 | } | ||
| 251 | } | ||
| 252 | |||
| 253 | impl<'a> Display for Bytes<'a> { | ||
| 254 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 255 | write!(f, "{:#02x?}", self.0) | ||
| 256 | } | ||
| 257 | } | ||
| 258 | |||
| 259 | impl<'a> LowerHex for Bytes<'a> { | ||
| 260 | fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { | ||
| 261 | write!(f, "{:#02x?}", self.0) | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | #[cfg(feature = "defmt")] | ||
| 266 | impl<'a> defmt::Format for Bytes<'a> { | ||
| 267 | fn format(&self, fmt: defmt::Formatter) { | ||
| 268 | defmt::write!(fmt, "{:02x}", self.0) | ||
| 269 | } | ||
| 270 | } | ||
diff --git a/embassy-mspm0/src/gpio.rs b/embassy-mspm0/src/gpio.rs new file mode 100644 index 000000000..fd4dc55ab --- /dev/null +++ b/embassy-mspm0/src/gpio.rs | |||
| @@ -0,0 +1,1070 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | use core::convert::Infallible; | ||
| 4 | use core::future::Future; | ||
| 5 | use core::pin::Pin as FuturePin; | ||
| 6 | use core::task::{Context, Poll}; | ||
| 7 | |||
| 8 | use embassy_hal_internal::{impl_peripheral, into_ref, Peripheral, PeripheralRef}; | ||
| 9 | use embassy_sync::waitqueue::AtomicWaker; | ||
| 10 | #[cfg(all(feature = "rt", feature = "mspm0c110x"))] | ||
| 11 | use crate::pac::interrupt; | ||
| 12 | |||
| 13 | use crate::pac::{ | ||
| 14 | self, | ||
| 15 | gpio::{self, vals::*}, | ||
| 16 | }; | ||
| 17 | |||
| 18 | /// Represents a digital input or output level. | ||
| 19 | #[derive(Debug, Eq, PartialEq, Clone, Copy)] | ||
| 20 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 21 | pub enum Level { | ||
| 22 | /// Logical low. | ||
| 23 | Low, | ||
| 24 | /// Logical high. | ||
| 25 | High, | ||
| 26 | } | ||
| 27 | |||
| 28 | impl From<bool> for Level { | ||
| 29 | fn from(val: bool) -> Self { | ||
| 30 | match val { | ||
| 31 | true => Self::High, | ||
| 32 | false => Self::Low, | ||
| 33 | } | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | impl From<Level> for bool { | ||
| 38 | fn from(level: Level) -> bool { | ||
| 39 | match level { | ||
| 40 | Level::Low => false, | ||
| 41 | Level::High => true, | ||
| 42 | } | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | /// Represents a pull setting for an input. | ||
| 47 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||
| 48 | pub enum Pull { | ||
| 49 | /// No pull. | ||
| 50 | None, | ||
| 51 | /// Internal pull-up resistor. | ||
| 52 | Up, | ||
| 53 | /// Internal pull-down resistor. | ||
| 54 | Down, | ||
| 55 | } | ||
| 56 | |||
| 57 | /// A GPIO bank with up to 32 pins. | ||
| 58 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] | ||
| 59 | pub enum Port { | ||
| 60 | /// Port A. | ||
| 61 | PortA = 0, | ||
| 62 | |||
| 63 | /// Port B. | ||
| 64 | #[cfg(gpio_pb)] | ||
| 65 | PortB = 1, | ||
| 66 | |||
| 67 | /// Port C. | ||
| 68 | #[cfg(gpio_pc)] | ||
| 69 | PortC = 2, | ||
| 70 | } | ||
| 71 | |||
| 72 | /// GPIO flexible pin. | ||
| 73 | /// | ||
| 74 | /// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain | ||
| 75 | /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output | ||
| 76 | /// mode. | ||
| 77 | pub struct Flex<'d> { | ||
| 78 | pin: PeripheralRef<'d, AnyPin>, | ||
| 79 | } | ||
| 80 | |||
| 81 | impl<'d> Flex<'d> { | ||
| 82 | /// Wrap the pin in a `Flex`. | ||
| 83 | /// | ||
| 84 | /// The pin remains disconnected. The initial output level is unspecified, but can be changed | ||
| 85 | /// before the pin is put into output mode. | ||
| 86 | #[inline] | ||
| 87 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self { | ||
| 88 | into_ref!(pin); | ||
| 89 | |||
| 90 | // Pin will be in disconnected state. | ||
| 91 | Self { | ||
| 92 | pin: pin.map_into(), | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | /// Set the pin's pull. | ||
| 97 | #[inline] | ||
| 98 | pub fn set_pull(&mut self, pull: Pull) { | ||
| 99 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 100 | |||
| 101 | pincm.modify(|w| { | ||
| 102 | w.set_pipd(matches!(pull, Pull::Down)); | ||
| 103 | w.set_pipu(matches!(pull, Pull::Up)); | ||
| 104 | }); | ||
| 105 | } | ||
| 106 | |||
| 107 | /// Put the pin into input mode. | ||
| 108 | /// | ||
| 109 | /// The pull setting is left unchanged. | ||
| 110 | #[inline] | ||
| 111 | pub fn set_as_input(&mut self) { | ||
| 112 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 113 | |||
| 114 | pincm.modify(|w| { | ||
| 115 | w.set_pf(GPIO_PF); | ||
| 116 | w.set_hiz1(false); | ||
| 117 | w.set_pc(true); | ||
| 118 | w.set_inena(true); | ||
| 119 | }); | ||
| 120 | |||
| 121 | self.pin.block().doeclr31_0().write(|w| { | ||
| 122 | w.set_dio(self.pin.bit_index(), true); | ||
| 123 | }); | ||
| 124 | } | ||
| 125 | |||
| 126 | /// Put the pin into output mode. | ||
| 127 | /// | ||
| 128 | /// The pin level will be whatever was set before (or low by default). If you want it to begin | ||
| 129 | /// at a specific level, call `set_high`/`set_low` on the pin first. | ||
| 130 | #[inline] | ||
| 131 | pub fn set_as_output(&mut self) { | ||
| 132 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 133 | |||
| 134 | pincm.modify(|w| { | ||
| 135 | w.set_pf(GPIO_PF); | ||
| 136 | w.set_hiz1(false); | ||
| 137 | w.set_pc(true); | ||
| 138 | w.set_inena(false); | ||
| 139 | }); | ||
| 140 | |||
| 141 | self.pin.block().doeset31_0().write(|w| { | ||
| 142 | w.set_dio(self.pin.bit_index(), true); | ||
| 143 | }); | ||
| 144 | } | ||
| 145 | |||
| 146 | /// Put the pin into input + open-drain output mode. | ||
| 147 | /// | ||
| 148 | /// The hardware will drive the line low if you set it to low, and will leave it floating if you set | ||
| 149 | /// it to high, in which case you can read the input to figure out whether another device | ||
| 150 | /// is driving the line low. | ||
| 151 | /// | ||
| 152 | /// The pin level will be whatever was set before (or low by default). If you want it to begin | ||
| 153 | /// at a specific level, call `set_high`/`set_low` on the pin first. | ||
| 154 | /// | ||
| 155 | /// The internal weak pull-up and pull-down resistors will be disabled. | ||
| 156 | #[inline] | ||
| 157 | pub fn set_as_input_output(&mut self) { | ||
| 158 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 159 | |||
| 160 | pincm.modify(|w| { | ||
| 161 | w.set_pf(GPIO_PF); | ||
| 162 | w.set_hiz1(true); | ||
| 163 | w.set_pc(true); | ||
| 164 | w.set_inena(false); | ||
| 165 | }); | ||
| 166 | |||
| 167 | self.set_pull(Pull::None); | ||
| 168 | } | ||
| 169 | |||
| 170 | /// Set the pin as "disconnected", ie doing nothing and consuming the lowest | ||
| 171 | /// amount of power possible. | ||
| 172 | /// | ||
| 173 | /// This is currently the same as [`Self::set_as_analog()`] but is semantically different | ||
| 174 | /// really. Drivers should `set_as_disconnected()` pins when dropped. | ||
| 175 | /// | ||
| 176 | /// Note that this also disables the internal weak pull-up and pull-down resistors. | ||
| 177 | #[inline] | ||
| 178 | pub fn set_as_disconnected(&mut self) { | ||
| 179 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 180 | |||
| 181 | pincm.modify(|w| { | ||
| 182 | w.set_pf(DISCONNECT_PF); | ||
| 183 | w.set_hiz1(false); | ||
| 184 | w.set_pc(false); | ||
| 185 | w.set_inena(false); | ||
| 186 | }); | ||
| 187 | |||
| 188 | self.set_pull(Pull::None); | ||
| 189 | self.set_inversion(false); | ||
| 190 | } | ||
| 191 | |||
| 192 | /// Configure the logic inversion of this pin. | ||
| 193 | /// | ||
| 194 | /// Logic inversion applies to both the input and output path of this pin. | ||
| 195 | #[inline] | ||
| 196 | pub fn set_inversion(&mut self, invert: bool) { | ||
| 197 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 198 | |||
| 199 | pincm.modify(|w| { | ||
| 200 | w.set_inv(invert); | ||
| 201 | }); | ||
| 202 | } | ||
| 203 | |||
| 204 | // TODO: drive strength, hysteresis, wakeup enable, wakeup compare | ||
| 205 | |||
| 206 | /// Put the pin into the PF mode, unchecked. | ||
| 207 | /// | ||
| 208 | /// This puts the pin into the PF mode, with the request number. This is completely unchecked, | ||
| 209 | /// it can attach the pin to literally any peripheral, so use with care. In addition the pin | ||
| 210 | /// peripheral is connected in the iomux. | ||
| 211 | /// | ||
| 212 | /// The peripheral attached to the pin depends on the part in use. Consult the datasheet | ||
| 213 | /// or technical reference manual for additional details. | ||
| 214 | #[inline] | ||
| 215 | pub fn set_pf_unchecked(&mut self, pf: u8) { | ||
| 216 | // Per SLAU893, PF is only 5 bits | ||
| 217 | assert!((pf & 0x3F) != 0, "PF is out of range"); | ||
| 218 | |||
| 219 | let pincm = pac::IOMUX.pincm(self.pin.pin_cm() as usize); | ||
| 220 | |||
| 221 | pincm.modify(|w| { | ||
| 222 | w.set_pf(pf); | ||
| 223 | // If the PF is manually set, connect the pin | ||
| 224 | w.set_pc(true); | ||
| 225 | }); | ||
| 226 | } | ||
| 227 | |||
| 228 | /// Get whether the pin input level is high. | ||
| 229 | #[inline] | ||
| 230 | pub fn is_high(&self) -> bool { | ||
| 231 | !self.is_low() | ||
| 232 | } | ||
| 233 | |||
| 234 | /// Get whether the pin input level is low. | ||
| 235 | #[inline] | ||
| 236 | pub fn is_low(&self) -> bool { | ||
| 237 | self.pin.block().din31_0().read().dio(self.pin.bit_index()) | ||
| 238 | } | ||
| 239 | |||
| 240 | /// Returns current pin level | ||
| 241 | #[inline] | ||
| 242 | pub fn get_level(&self) -> Level { | ||
| 243 | self.is_high().into() | ||
| 244 | } | ||
| 245 | |||
| 246 | /// Set the output as high. | ||
| 247 | #[inline] | ||
| 248 | pub fn set_high(&mut self) { | ||
| 249 | self.pin.block().doutset31_0().write(|w| { | ||
| 250 | w.set_dio(self.pin.bit_index() as usize, true); | ||
| 251 | }); | ||
| 252 | } | ||
| 253 | |||
| 254 | /// Set the output as low. | ||
| 255 | #[inline] | ||
| 256 | pub fn set_low(&mut self) { | ||
| 257 | self.pin.block().doutclr31_0().write(|w| { | ||
| 258 | w.set_dio(self.pin.bit_index(), true); | ||
| 259 | }); | ||
| 260 | } | ||
| 261 | |||
| 262 | /// Toggle pin output | ||
| 263 | #[inline] | ||
| 264 | pub fn toggle(&mut self) { | ||
| 265 | self.pin.block().douttgl31_0().write(|w| { | ||
| 266 | w.set_dio(self.pin.bit_index(), true); | ||
| 267 | }) | ||
| 268 | } | ||
| 269 | |||
| 270 | /// Set the output level. | ||
| 271 | #[inline] | ||
| 272 | pub fn set_level(&mut self, level: Level) { | ||
| 273 | match level { | ||
| 274 | Level::Low => self.set_low(), | ||
| 275 | Level::High => self.set_high(), | ||
| 276 | } | ||
| 277 | } | ||
| 278 | |||
| 279 | /// Get the current pin input level. | ||
| 280 | #[inline] | ||
| 281 | pub fn get_output_level(&self) -> Level { | ||
| 282 | self.is_high().into() | ||
| 283 | } | ||
| 284 | |||
| 285 | /// Is the output level high? | ||
| 286 | #[inline] | ||
| 287 | pub fn is_set_high(&self) -> bool { | ||
| 288 | !self.is_set_low() | ||
| 289 | } | ||
| 290 | |||
| 291 | /// Is the output level low? | ||
| 292 | #[inline] | ||
| 293 | pub fn is_set_low(&self) -> bool { | ||
| 294 | (self.pin.block().dout31_0().read().0 & self.pin.bit_index() as u32) == 0 | ||
| 295 | } | ||
| 296 | |||
| 297 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 298 | #[inline] | ||
| 299 | pub async fn wait_for_high(&mut self) { | ||
| 300 | if self.is_high() { | ||
| 301 | return; | ||
| 302 | } | ||
| 303 | |||
| 304 | self.wait_for_rising_edge().await | ||
| 305 | } | ||
| 306 | |||
| 307 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 308 | #[inline] | ||
| 309 | pub async fn wait_for_low(&mut self) { | ||
| 310 | if self.is_low() { | ||
| 311 | return; | ||
| 312 | } | ||
| 313 | |||
| 314 | self.wait_for_falling_edge().await | ||
| 315 | } | ||
| 316 | |||
| 317 | /// Wait for the pin to undergo a transition from low to high. | ||
| 318 | #[inline] | ||
| 319 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 320 | InputFuture::new(self.pin.reborrow(), Polarity::RISE).await | ||
| 321 | } | ||
| 322 | |||
| 323 | /// Wait for the pin to undergo a transition from high to low. | ||
| 324 | #[inline] | ||
| 325 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 326 | InputFuture::new(self.pin.reborrow(), Polarity::FALL).await | ||
| 327 | } | ||
| 328 | |||
| 329 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 330 | #[inline] | ||
| 331 | pub async fn wait_for_any_edge(&mut self) { | ||
| 332 | InputFuture::new(self.pin.reborrow(), Polarity::RISE_FALL).await | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | impl<'d> Drop for Flex<'d> { | ||
| 337 | #[inline] | ||
| 338 | fn drop(&mut self) { | ||
| 339 | self.set_as_disconnected(); | ||
| 340 | } | ||
| 341 | } | ||
| 342 | |||
| 343 | /// GPIO input driver. | ||
| 344 | pub struct Input<'d> { | ||
| 345 | pin: Flex<'d>, | ||
| 346 | } | ||
| 347 | |||
| 348 | impl<'d> Input<'d> { | ||
| 349 | /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. | ||
| 350 | #[inline] | ||
| 351 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self { | ||
| 352 | let mut pin = Flex::new(pin); | ||
| 353 | pin.set_as_input(); | ||
| 354 | pin.set_pull(pull); | ||
| 355 | Self { pin } | ||
| 356 | } | ||
| 357 | |||
| 358 | /// Get whether the pin input level is high. | ||
| 359 | #[inline] | ||
| 360 | pub fn is_high(&self) -> bool { | ||
| 361 | self.pin.is_high() | ||
| 362 | } | ||
| 363 | |||
| 364 | /// Get whether the pin input level is low. | ||
| 365 | #[inline] | ||
| 366 | pub fn is_low(&self) -> bool { | ||
| 367 | self.pin.is_low() | ||
| 368 | } | ||
| 369 | |||
| 370 | /// Get the current pin input level. | ||
| 371 | #[inline] | ||
| 372 | pub fn get_level(&self) -> Level { | ||
| 373 | self.pin.get_level() | ||
| 374 | } | ||
| 375 | |||
| 376 | /// Configure the logic inversion of this pin. | ||
| 377 | /// | ||
| 378 | /// Logic inversion applies to the input path of this pin. | ||
| 379 | #[inline] | ||
| 380 | pub fn set_inversion(&mut self, invert: bool) { | ||
| 381 | self.pin.set_inversion(invert) | ||
| 382 | } | ||
| 383 | |||
| 384 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 385 | #[inline] | ||
| 386 | pub async fn wait_for_high(&mut self) { | ||
| 387 | self.pin.wait_for_high().await | ||
| 388 | } | ||
| 389 | |||
| 390 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 391 | #[inline] | ||
| 392 | pub async fn wait_for_low(&mut self) { | ||
| 393 | self.pin.wait_for_low().await | ||
| 394 | } | ||
| 395 | |||
| 396 | /// Wait for the pin to undergo a transition from low to high. | ||
| 397 | #[inline] | ||
| 398 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 399 | self.pin.wait_for_rising_edge().await | ||
| 400 | } | ||
| 401 | |||
| 402 | /// Wait for the pin to undergo a transition from high to low. | ||
| 403 | #[inline] | ||
| 404 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 405 | self.pin.wait_for_falling_edge().await | ||
| 406 | } | ||
| 407 | |||
| 408 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 409 | #[inline] | ||
| 410 | pub async fn wait_for_any_edge(&mut self) { | ||
| 411 | self.pin.wait_for_any_edge().await | ||
| 412 | } | ||
| 413 | } | ||
| 414 | |||
| 415 | /// GPIO output driver. | ||
| 416 | /// | ||
| 417 | /// Note that pins will **return to their floating state** when `Output` is dropped. | ||
| 418 | /// If pins should retain their state indefinitely, either keep ownership of the | ||
| 419 | /// `Output`, or pass it to [`core::mem::forget`]. | ||
| 420 | pub struct Output<'d> { | ||
| 421 | pin: Flex<'d>, | ||
| 422 | } | ||
| 423 | |||
| 424 | impl<'d> Output<'d> { | ||
| 425 | /// Create GPIO output driver for a [Pin] with the provided [Level] configuration. | ||
| 426 | #[inline] | ||
| 427 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self { | ||
| 428 | let mut pin = Flex::new(pin); | ||
| 429 | pin.set_as_output(); | ||
| 430 | pin.set_level(initial_output); | ||
| 431 | Self { pin } | ||
| 432 | } | ||
| 433 | |||
| 434 | /// Set the output as high. | ||
| 435 | #[inline] | ||
| 436 | pub fn set_high(&mut self) { | ||
| 437 | self.pin.set_high(); | ||
| 438 | } | ||
| 439 | |||
| 440 | /// Set the output as low. | ||
| 441 | #[inline] | ||
| 442 | pub fn set_low(&mut self) { | ||
| 443 | self.pin.set_low(); | ||
| 444 | } | ||
| 445 | |||
| 446 | /// Set the output level. | ||
| 447 | #[inline] | ||
| 448 | pub fn set_level(&mut self, level: Level) { | ||
| 449 | self.pin.set_level(level) | ||
| 450 | } | ||
| 451 | |||
| 452 | /// Is the output pin set as high? | ||
| 453 | #[inline] | ||
| 454 | pub fn is_set_high(&self) -> bool { | ||
| 455 | self.pin.is_set_high() | ||
| 456 | } | ||
| 457 | |||
| 458 | /// Is the output pin set as low? | ||
| 459 | #[inline] | ||
| 460 | pub fn is_set_low(&self) -> bool { | ||
| 461 | self.pin.is_set_low() | ||
| 462 | } | ||
| 463 | |||
| 464 | /// What level output is set to | ||
| 465 | #[inline] | ||
| 466 | pub fn get_output_level(&self) -> Level { | ||
| 467 | self.pin.get_output_level() | ||
| 468 | } | ||
| 469 | |||
| 470 | /// Toggle pin output | ||
| 471 | #[inline] | ||
| 472 | pub fn toggle(&mut self) { | ||
| 473 | self.pin.toggle(); | ||
| 474 | } | ||
| 475 | |||
| 476 | /// Configure the logic inversion of this pin. | ||
| 477 | /// | ||
| 478 | /// Logic inversion applies to the input path of this pin. | ||
| 479 | #[inline] | ||
| 480 | pub fn set_inversion(&mut self, invert: bool) { | ||
| 481 | self.pin.set_inversion(invert) | ||
| 482 | } | ||
| 483 | } | ||
| 484 | |||
| 485 | /// GPIO output open-drain driver. | ||
| 486 | /// | ||
| 487 | /// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped. | ||
| 488 | /// If pins should retain their state indefinitely, either keep ownership of the | ||
| 489 | /// `OutputOpenDrain`, or pass it to [`core::mem::forget`]. | ||
| 490 | pub struct OutputOpenDrain<'d> { | ||
| 491 | pin: Flex<'d>, | ||
| 492 | } | ||
| 493 | |||
| 494 | impl<'d> OutputOpenDrain<'d> { | ||
| 495 | /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level]. | ||
| 496 | #[inline] | ||
| 497 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level) -> Self { | ||
| 498 | let mut pin = Flex::new(pin); | ||
| 499 | pin.set_level(initial_output); | ||
| 500 | pin.set_as_input_output(); | ||
| 501 | Self { pin } | ||
| 502 | } | ||
| 503 | |||
| 504 | /// Get whether the pin input level is high. | ||
| 505 | #[inline] | ||
| 506 | pub fn is_high(&self) -> bool { | ||
| 507 | !self.pin.is_low() | ||
| 508 | } | ||
| 509 | |||
| 510 | /// Get whether the pin input level is low. | ||
| 511 | #[inline] | ||
| 512 | pub fn is_low(&self) -> bool { | ||
| 513 | self.pin.is_low() | ||
| 514 | } | ||
| 515 | |||
| 516 | /// Get the current pin input level. | ||
| 517 | #[inline] | ||
| 518 | pub fn get_level(&self) -> Level { | ||
| 519 | self.pin.get_level() | ||
| 520 | } | ||
| 521 | |||
| 522 | /// Set the output as high. | ||
| 523 | #[inline] | ||
| 524 | pub fn set_high(&mut self) { | ||
| 525 | self.pin.set_high(); | ||
| 526 | } | ||
| 527 | |||
| 528 | /// Set the output as low. | ||
| 529 | #[inline] | ||
| 530 | pub fn set_low(&mut self) { | ||
| 531 | self.pin.set_low(); | ||
| 532 | } | ||
| 533 | |||
| 534 | /// Set the output level. | ||
| 535 | #[inline] | ||
| 536 | pub fn set_level(&mut self, level: Level) { | ||
| 537 | self.pin.set_level(level); | ||
| 538 | } | ||
| 539 | |||
| 540 | /// Get whether the output level is set to high. | ||
| 541 | #[inline] | ||
| 542 | pub fn is_set_high(&self) -> bool { | ||
| 543 | self.pin.is_set_high() | ||
| 544 | } | ||
| 545 | |||
| 546 | /// Get whether the output level is set to low. | ||
| 547 | #[inline] | ||
| 548 | pub fn is_set_low(&self) -> bool { | ||
| 549 | self.pin.is_set_low() | ||
| 550 | } | ||
| 551 | |||
| 552 | /// Get the current output level. | ||
| 553 | #[inline] | ||
| 554 | pub fn get_output_level(&self) -> Level { | ||
| 555 | self.pin.get_output_level() | ||
| 556 | } | ||
| 557 | |||
| 558 | /// Toggle pin output | ||
| 559 | #[inline] | ||
| 560 | pub fn toggle(&mut self) { | ||
| 561 | self.pin.toggle() | ||
| 562 | } | ||
| 563 | |||
| 564 | /// Configure the logic inversion of this pin. | ||
| 565 | /// | ||
| 566 | /// Logic inversion applies to the input path of this pin. | ||
| 567 | #[inline] | ||
| 568 | pub fn set_inversion(&mut self, invert: bool) { | ||
| 569 | self.pin.set_inversion(invert) | ||
| 570 | } | ||
| 571 | |||
| 572 | /// Wait until the pin is high. If it is already high, return immediately. | ||
| 573 | #[inline] | ||
| 574 | pub async fn wait_for_high(&mut self) { | ||
| 575 | self.pin.wait_for_high().await | ||
| 576 | } | ||
| 577 | |||
| 578 | /// Wait until the pin is low. If it is already low, return immediately. | ||
| 579 | #[inline] | ||
| 580 | pub async fn wait_for_low(&mut self) { | ||
| 581 | self.pin.wait_for_low().await | ||
| 582 | } | ||
| 583 | |||
| 584 | /// Wait for the pin to undergo a transition from low to high. | ||
| 585 | #[inline] | ||
| 586 | pub async fn wait_for_rising_edge(&mut self) { | ||
| 587 | self.pin.wait_for_rising_edge().await | ||
| 588 | } | ||
| 589 | |||
| 590 | /// Wait for the pin to undergo a transition from high to low. | ||
| 591 | #[inline] | ||
| 592 | pub async fn wait_for_falling_edge(&mut self) { | ||
| 593 | self.pin.wait_for_falling_edge().await | ||
| 594 | } | ||
| 595 | |||
| 596 | /// Wait for the pin to undergo any transition, i.e low to high OR high to low. | ||
| 597 | #[inline] | ||
| 598 | pub async fn wait_for_any_edge(&mut self) { | ||
| 599 | self.pin.wait_for_any_edge().await | ||
| 600 | } | ||
| 601 | } | ||
| 602 | |||
| 603 | /// Type-erased GPIO pin | ||
| 604 | pub struct AnyPin { | ||
| 605 | pin_port: u8, | ||
| 606 | } | ||
| 607 | |||
| 608 | impl AnyPin { | ||
| 609 | /// Create an [AnyPin] for a specific pin. | ||
| 610 | /// | ||
| 611 | /// # Safety | ||
| 612 | /// - `pin_port` should not in use by another driver. | ||
| 613 | #[inline] | ||
| 614 | pub unsafe fn steal(pin_port: u8) -> Self { | ||
| 615 | Self { pin_port } | ||
| 616 | } | ||
| 617 | } | ||
| 618 | |||
| 619 | impl_peripheral!(AnyPin); | ||
| 620 | |||
| 621 | impl Pin for AnyPin {} | ||
| 622 | impl SealedPin for AnyPin { | ||
| 623 | #[inline] | ||
| 624 | fn pin_port(&self) -> u8 { | ||
| 625 | self.pin_port | ||
| 626 | } | ||
| 627 | } | ||
| 628 | |||
| 629 | /// Interface for a Pin that can be configured by an [Input] or [Output] driver, or converted to an [AnyPin]. | ||
| 630 | #[allow(private_bounds)] | ||
| 631 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static { | ||
| 632 | fn degrade(self) -> AnyPin { | ||
| 633 | AnyPin { | ||
| 634 | pin_port: self.pin_port(), | ||
| 635 | } | ||
| 636 | } | ||
| 637 | |||
| 638 | /// The index of this pin in PINCM (pin control management) registers. | ||
| 639 | #[inline] | ||
| 640 | fn pin_cm(&self) -> u8 { | ||
| 641 | self._pin_cm() | ||
| 642 | } | ||
| 643 | } | ||
| 644 | |||
| 645 | impl<'d> embedded_hal::digital::ErrorType for Flex<'d> { | ||
| 646 | type Error = Infallible; | ||
| 647 | } | ||
| 648 | |||
| 649 | impl<'d> embedded_hal::digital::InputPin for Flex<'d> { | ||
| 650 | #[inline] | ||
| 651 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 652 | Ok((*self).is_high()) | ||
| 653 | } | ||
| 654 | |||
| 655 | #[inline] | ||
| 656 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 657 | Ok((*self).is_low()) | ||
| 658 | } | ||
| 659 | } | ||
| 660 | |||
| 661 | impl<'d> embedded_hal::digital::OutputPin for Flex<'d> { | ||
| 662 | #[inline] | ||
| 663 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 664 | Ok(self.set_low()) | ||
| 665 | } | ||
| 666 | |||
| 667 | #[inline] | ||
| 668 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 669 | Ok(self.set_high()) | ||
| 670 | } | ||
| 671 | } | ||
| 672 | |||
| 673 | impl<'d> embedded_hal::digital::StatefulOutputPin for Flex<'d> { | ||
| 674 | #[inline] | ||
| 675 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 676 | Ok((*self).is_set_high()) | ||
| 677 | } | ||
| 678 | |||
| 679 | #[inline] | ||
| 680 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 681 | Ok((*self).is_set_low()) | ||
| 682 | } | ||
| 683 | } | ||
| 684 | |||
| 685 | impl<'d> embedded_hal_async::digital::Wait for Flex<'d> { | ||
| 686 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 687 | self.wait_for_high().await; | ||
| 688 | Ok(()) | ||
| 689 | } | ||
| 690 | |||
| 691 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 692 | self.wait_for_low().await; | ||
| 693 | Ok(()) | ||
| 694 | } | ||
| 695 | |||
| 696 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 697 | self.wait_for_rising_edge().await; | ||
| 698 | Ok(()) | ||
| 699 | } | ||
| 700 | |||
| 701 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 702 | self.wait_for_falling_edge().await; | ||
| 703 | Ok(()) | ||
| 704 | } | ||
| 705 | |||
| 706 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 707 | self.wait_for_any_edge().await; | ||
| 708 | Ok(()) | ||
| 709 | } | ||
| 710 | } | ||
| 711 | |||
| 712 | impl<'d> embedded_hal::digital::ErrorType for Input<'d> { | ||
| 713 | type Error = Infallible; | ||
| 714 | } | ||
| 715 | |||
| 716 | impl<'d> embedded_hal::digital::InputPin for Input<'d> { | ||
| 717 | #[inline] | ||
| 718 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 719 | Ok((*self).is_high()) | ||
| 720 | } | ||
| 721 | |||
| 722 | #[inline] | ||
| 723 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 724 | Ok((*self).is_low()) | ||
| 725 | } | ||
| 726 | } | ||
| 727 | |||
| 728 | impl<'d> embedded_hal_async::digital::Wait for Input<'d> { | ||
| 729 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 730 | self.wait_for_high().await; | ||
| 731 | Ok(()) | ||
| 732 | } | ||
| 733 | |||
| 734 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 735 | self.wait_for_low().await; | ||
| 736 | Ok(()) | ||
| 737 | } | ||
| 738 | |||
| 739 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 740 | self.wait_for_rising_edge().await; | ||
| 741 | Ok(()) | ||
| 742 | } | ||
| 743 | |||
| 744 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 745 | self.wait_for_falling_edge().await; | ||
| 746 | Ok(()) | ||
| 747 | } | ||
| 748 | |||
| 749 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 750 | self.wait_for_any_edge().await; | ||
| 751 | Ok(()) | ||
| 752 | } | ||
| 753 | } | ||
| 754 | |||
| 755 | impl<'d> embedded_hal::digital::ErrorType for Output<'d> { | ||
| 756 | type Error = Infallible; | ||
| 757 | } | ||
| 758 | |||
| 759 | impl<'d> embedded_hal::digital::OutputPin for Output<'d> { | ||
| 760 | #[inline] | ||
| 761 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 762 | Ok(self.set_low()) | ||
| 763 | } | ||
| 764 | |||
| 765 | #[inline] | ||
| 766 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 767 | Ok(self.set_high()) | ||
| 768 | } | ||
| 769 | } | ||
| 770 | |||
| 771 | impl<'d> embedded_hal::digital::StatefulOutputPin for Output<'d> { | ||
| 772 | #[inline] | ||
| 773 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 774 | Ok((*self).is_set_high()) | ||
| 775 | } | ||
| 776 | |||
| 777 | #[inline] | ||
| 778 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 779 | Ok((*self).is_set_low()) | ||
| 780 | } | ||
| 781 | } | ||
| 782 | |||
| 783 | impl<'d> embedded_hal::digital::ErrorType for OutputOpenDrain<'d> { | ||
| 784 | type Error = Infallible; | ||
| 785 | } | ||
| 786 | |||
| 787 | impl<'d> embedded_hal::digital::InputPin for OutputOpenDrain<'d> { | ||
| 788 | #[inline] | ||
| 789 | fn is_high(&mut self) -> Result<bool, Self::Error> { | ||
| 790 | Ok((*self).is_high()) | ||
| 791 | } | ||
| 792 | |||
| 793 | #[inline] | ||
| 794 | fn is_low(&mut self) -> Result<bool, Self::Error> { | ||
| 795 | Ok((*self).is_low()) | ||
| 796 | } | ||
| 797 | } | ||
| 798 | |||
| 799 | impl<'d> embedded_hal::digital::OutputPin for OutputOpenDrain<'d> { | ||
| 800 | #[inline] | ||
| 801 | fn set_low(&mut self) -> Result<(), Self::Error> { | ||
| 802 | Ok(self.set_low()) | ||
| 803 | } | ||
| 804 | |||
| 805 | #[inline] | ||
| 806 | fn set_high(&mut self) -> Result<(), Self::Error> { | ||
| 807 | Ok(self.set_high()) | ||
| 808 | } | ||
| 809 | } | ||
| 810 | |||
| 811 | impl<'d> embedded_hal::digital::StatefulOutputPin for OutputOpenDrain<'d> { | ||
| 812 | #[inline] | ||
| 813 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { | ||
| 814 | Ok((*self).is_set_high()) | ||
| 815 | } | ||
| 816 | |||
| 817 | #[inline] | ||
| 818 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { | ||
| 819 | Ok((*self).is_set_low()) | ||
| 820 | } | ||
| 821 | } | ||
| 822 | |||
| 823 | impl<'d> embedded_hal_async::digital::Wait for OutputOpenDrain<'d> { | ||
| 824 | async fn wait_for_high(&mut self) -> Result<(), Self::Error> { | ||
| 825 | self.wait_for_high().await; | ||
| 826 | Ok(()) | ||
| 827 | } | ||
| 828 | |||
| 829 | async fn wait_for_low(&mut self) -> Result<(), Self::Error> { | ||
| 830 | self.wait_for_low().await; | ||
| 831 | Ok(()) | ||
| 832 | } | ||
| 833 | |||
| 834 | async fn wait_for_rising_edge(&mut self) -> Result<(), Self::Error> { | ||
| 835 | self.wait_for_rising_edge().await; | ||
| 836 | Ok(()) | ||
| 837 | } | ||
| 838 | |||
| 839 | async fn wait_for_falling_edge(&mut self) -> Result<(), Self::Error> { | ||
| 840 | self.wait_for_falling_edge().await; | ||
| 841 | Ok(()) | ||
| 842 | } | ||
| 843 | |||
| 844 | async fn wait_for_any_edge(&mut self) -> Result<(), Self::Error> { | ||
| 845 | self.wait_for_any_edge().await; | ||
| 846 | Ok(()) | ||
| 847 | } | ||
| 848 | } | ||
| 849 | |||
| 850 | /// The pin function to disconnect peripherals from the pin. | ||
| 851 | /// | ||
| 852 | /// This is also the pin function used to connect to analog peripherals, such as an ADC. | ||
| 853 | const DISCONNECT_PF: u8 = 0; | ||
| 854 | |||
| 855 | /// The pin function for the GPIO peripheral. | ||
| 856 | /// | ||
| 857 | /// This is fixed to `1` for every part. | ||
| 858 | const GPIO_PF: u8 = 1; | ||
| 859 | |||
| 860 | macro_rules! impl_pin { | ||
| 861 | ($name: ident, $port: expr, $pin_num: expr) => { | ||
| 862 | impl crate::gpio::Pin for crate::peripherals::$name {} | ||
| 863 | impl crate::gpio::SealedPin for crate::peripherals::$name { | ||
| 864 | #[inline] | ||
| 865 | fn pin_port(&self) -> u8 { | ||
| 866 | ($port as u8) * 32 + $pin_num | ||
| 867 | } | ||
| 868 | } | ||
| 869 | |||
| 870 | impl From<crate::peripherals::$name> for crate::gpio::AnyPin { | ||
| 871 | fn from(val: crate::peripherals::$name) -> Self { | ||
| 872 | crate::gpio::Pin::degrade(val) | ||
| 873 | } | ||
| 874 | } | ||
| 875 | }; | ||
| 876 | } | ||
| 877 | |||
| 878 | // TODO: Possible micro-op for C110X, not every pin is instantiated even on the 20 pin parts. | ||
| 879 | // This would mean cfg guarding to just cfg guarding every pin instance. | ||
| 880 | static PORTA_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | ||
| 881 | #[cfg(gpio_pb)] | ||
| 882 | static PORTB_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | ||
| 883 | #[cfg(gpio_pc)] | ||
| 884 | static PORTC_WAKERS: [AtomicWaker; 32] = [const { AtomicWaker::new() }; 32]; | ||
| 885 | |||
| 886 | pub(crate) trait SealedPin { | ||
| 887 | fn pin_port(&self) -> u8; | ||
| 888 | |||
| 889 | fn port(&self) -> Port { | ||
| 890 | match self.pin_port() / 32 { | ||
| 891 | 0 => Port::PortA, | ||
| 892 | #[cfg(gpio_pb)] | ||
| 893 | 1 => Port::PortB, | ||
| 894 | #[cfg(gpio_pc)] | ||
| 895 | 2 => Port::PortC, | ||
| 896 | _ => unreachable!(), | ||
| 897 | } | ||
| 898 | } | ||
| 899 | |||
| 900 | fn waker(&self) -> &AtomicWaker { | ||
| 901 | match self.port() { | ||
| 902 | Port::PortA => &PORTA_WAKERS[self.bit_index()], | ||
| 903 | #[cfg(gpio_pb)] | ||
| 904 | Port::PortB => &PORTB_WAKERS[self.bit_index()], | ||
| 905 | #[cfg(gpio_pc)] | ||
| 906 | Port::PortC => &PORTC_WAKERS[self.bit_index()], | ||
| 907 | } | ||
| 908 | } | ||
| 909 | |||
| 910 | fn _pin_cm(&self) -> u8 { | ||
| 911 | // Some parts like the MSPM0L222x have pincm mappings all over the place. | ||
| 912 | crate::gpio_pincm(self.pin_port()) | ||
| 913 | } | ||
| 914 | |||
| 915 | fn bit_index(&self) -> usize { | ||
| 916 | (self.pin_port() % 32) as usize | ||
| 917 | } | ||
| 918 | |||
| 919 | #[inline] | ||
| 920 | fn block(&self) -> gpio::Gpio { | ||
| 921 | match self.pin_port() / 32 { | ||
| 922 | 0 => pac::GPIOA, | ||
| 923 | #[cfg(gpio_pb)] | ||
| 924 | 1 => pac::GPIOB, | ||
| 925 | #[cfg(gpio_pc)] | ||
| 926 | 2 => pac::GPIOC, | ||
| 927 | _ => unreachable!(), | ||
| 928 | } | ||
| 929 | } | ||
| 930 | } | ||
| 931 | |||
| 932 | #[must_use = "futures do nothing unless you `.await` or poll them"] | ||
| 933 | struct InputFuture<'d> { | ||
| 934 | pin: PeripheralRef<'d, AnyPin>, | ||
| 935 | } | ||
| 936 | |||
| 937 | impl<'d> InputFuture<'d> { | ||
| 938 | fn new(pin: PeripheralRef<'d, AnyPin>, polarity: Polarity) -> Self { | ||
| 939 | let block = pin.block(); | ||
| 940 | |||
| 941 | // First clear the bit for this event. Otherwise previous edge events may be recorded. | ||
| 942 | block.cpu_int().iclr().write(|w| { | ||
| 943 | w.set_dio(pin.bit_index(), true); | ||
| 944 | }); | ||
| 945 | |||
| 946 | // Selecting which polarity events happens is a RMW operation. | ||
| 947 | // | ||
| 948 | // Guard with a critical section in case two different threads try to select events at the | ||
| 949 | // same time. | ||
| 950 | critical_section::with(|_cs| { | ||
| 951 | // Tell the hardware which pin event we want to receive. | ||
| 952 | if pin.bit_index() >= 16 { | ||
| 953 | block.polarity31_16().modify(|w| { | ||
| 954 | w.set_dio(pin.bit_index() - 16, polarity); | ||
| 955 | }); | ||
| 956 | } else { | ||
| 957 | block.polarity15_0().modify(|w| { | ||
| 958 | w.set_dio(pin.bit_index(), polarity); | ||
| 959 | }); | ||
| 960 | }; | ||
| 961 | }); | ||
| 962 | |||
| 963 | Self { pin } | ||
| 964 | } | ||
| 965 | } | ||
| 966 | |||
| 967 | impl<'d> Future for InputFuture<'d> { | ||
| 968 | type Output = (); | ||
| 969 | |||
| 970 | fn poll(self: FuturePin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 971 | // We need to register/re-register the waker for each poll because any | ||
| 972 | // calls to wake will deregister the waker. | ||
| 973 | let waker = self.pin.waker(); | ||
| 974 | waker.register(cx.waker()); | ||
| 975 | |||
| 976 | // The interrupt handler will mask the interrupt if the event has occurred. | ||
| 977 | if self | ||
| 978 | .pin | ||
| 979 | .block() | ||
| 980 | .cpu_int() | ||
| 981 | .ris() | ||
| 982 | .read() | ||
| 983 | .dio(self.pin.bit_index()) | ||
| 984 | { | ||
| 985 | return Poll::Ready(()); | ||
| 986 | } | ||
| 987 | |||
| 988 | // Unmasking the interrupt is a RMW operation. | ||
| 989 | // | ||
| 990 | // Guard with a critical section in case two different threads try to unmask at the same time. | ||
| 991 | critical_section::with(|_cs| { | ||
| 992 | self.pin.block().cpu_int().imask().modify(|w| { | ||
| 993 | w.set_dio(self.pin.bit_index(), true); | ||
| 994 | }); | ||
| 995 | }); | ||
| 996 | |||
| 997 | Poll::Pending | ||
| 998 | } | ||
| 999 | } | ||
| 1000 | |||
| 1001 | pub(crate) fn init(gpio: gpio::Gpio) { | ||
| 1002 | gpio.gprcm().rstctl().write(|w| { | ||
| 1003 | w.set_resetstkyclr(true); | ||
| 1004 | w.set_resetassert(true); | ||
| 1005 | w.set_key(ResetKey::KEY); | ||
| 1006 | }); | ||
| 1007 | |||
| 1008 | gpio.gprcm().pwren().write(|w| { | ||
| 1009 | w.set_enable(true); | ||
| 1010 | w.set_key(PwrenKey::KEY); | ||
| 1011 | }); | ||
| 1012 | |||
| 1013 | gpio.evt_mode().modify(|w| { | ||
| 1014 | // The CPU will clear it's own interrupts | ||
| 1015 | w.set_cpu_cfg(EvtCfg::SOFTWARE); | ||
| 1016 | }); | ||
| 1017 | } | ||
| 1018 | |||
| 1019 | #[cfg(feature = "rt")] | ||
| 1020 | fn irq_handler(gpio: gpio::Gpio, wakers: &[AtomicWaker; 32]) { | ||
| 1021 | // Only consider pins which have interrupts unmasked. | ||
| 1022 | let bits = gpio.cpu_int().mis().read().0; | ||
| 1023 | |||
| 1024 | for i in BitIter(bits) { | ||
| 1025 | wakers[i as usize].wake(); | ||
| 1026 | |||
| 1027 | // Notify the future that an edge event has occurred by masking the interrupt for this pin. | ||
| 1028 | gpio.cpu_int().imask().modify(|w| { | ||
| 1029 | w.set_dio(i as usize, false); | ||
| 1030 | }); | ||
| 1031 | } | ||
| 1032 | } | ||
| 1033 | |||
| 1034 | struct BitIter(u32); | ||
| 1035 | |||
| 1036 | impl Iterator for BitIter { | ||
| 1037 | type Item = u32; | ||
| 1038 | |||
| 1039 | fn next(&mut self) -> Option<Self::Item> { | ||
| 1040 | match self.0.trailing_zeros() { | ||
| 1041 | 32 => None, | ||
| 1042 | b => { | ||
| 1043 | self.0 &= !(1 << b); | ||
| 1044 | Some(b) | ||
| 1045 | } | ||
| 1046 | } | ||
| 1047 | } | ||
| 1048 | } | ||
| 1049 | |||
| 1050 | // C110x has a dedicated interrupt just for GPIOA, as it does not have a GROUP1 interrupt. | ||
| 1051 | #[cfg(all(feature = "rt", feature = "mspm0c110x"))] | ||
| 1052 | #[interrupt] | ||
| 1053 | fn GPIOA() { | ||
| 1054 | gpioa_interrupt(); | ||
| 1055 | } | ||
| 1056 | |||
| 1057 | #[cfg(feature = "rt")] | ||
| 1058 | pub(crate) fn gpioa_interrupt() { | ||
| 1059 | irq_handler(pac::GPIOA, &PORTA_WAKERS); | ||
| 1060 | } | ||
| 1061 | |||
| 1062 | #[cfg(all(feature = "rt", gpio_pb))] | ||
| 1063 | pub(crate) fn gpiob_interrupt() { | ||
| 1064 | irq_handler(pac::GPIOB, &PORTB_WAKERS); | ||
| 1065 | } | ||
| 1066 | |||
| 1067 | #[cfg(all(feature = "rt", gpio_pc))] | ||
| 1068 | pub(crate) fn gpioc_interrupt() { | ||
| 1069 | irq_handler(pac::GPIOC, &PORTC_WAKERS); | ||
| 1070 | } | ||
diff --git a/embassy-mspm0/src/int_group/c110x.rs b/embassy-mspm0/src/int_group/c110x.rs new file mode 100644 index 000000000..c503af631 --- /dev/null +++ b/embassy-mspm0/src/int_group/c110x.rs | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | use crate::pac; | ||
| 2 | use crate::pac::interrupt; | ||
| 3 | |||
| 4 | #[cfg(feature = "rt")] | ||
| 5 | #[interrupt] | ||
| 6 | fn GROUP0() { | ||
| 7 | use mspm0_metapac::Group0; | ||
| 8 | |||
| 9 | let group = pac::CPUSS.int_group(1); | ||
| 10 | |||
| 11 | // TODO: Decompose to direct u8 | ||
| 12 | let iidx = group.iidx().read().stat().to_bits(); | ||
| 13 | |||
| 14 | let Ok(group) = pac::Group0::try_from(iidx as u8) else { | ||
| 15 | debug!("Invalid IIDX for group 0: {}", iidx); | ||
| 16 | return; | ||
| 17 | }; | ||
| 18 | |||
| 19 | match group { | ||
| 20 | Group0::WWDT0 => todo!("implement WWDT0"), | ||
| 21 | Group0::DEBUGSS => todo!("implement DEBUGSS"), | ||
| 22 | Group0::FLASHCTL => todo!("implement FLASHCTL"), | ||
| 23 | Group0::SYSCTL => todo!("implement SYSCTL"), | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/embassy-mspm0/src/int_group/g350x.rs b/embassy-mspm0/src/int_group/g350x.rs new file mode 100644 index 000000000..818dd6e1e --- /dev/null +++ b/embassy-mspm0/src/int_group/g350x.rs | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | use crate::pac; | ||
| 2 | use crate::pac::interrupt; | ||
| 3 | |||
| 4 | #[cfg(feature = "rt")] | ||
| 5 | #[interrupt] | ||
| 6 | fn GROUP0() { | ||
| 7 | use mspm0_metapac::Group0; | ||
| 8 | |||
| 9 | let group = pac::CPUSS.int_group(1); | ||
| 10 | |||
| 11 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 12 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 13 | |||
| 14 | let Ok(group) = pac::Group0::try_from(iidx as u8) else { | ||
| 15 | debug!("Invalid IIDX for group 0: {}", iidx); | ||
| 16 | return; | ||
| 17 | }; | ||
| 18 | |||
| 19 | match group { | ||
| 20 | Group0::WWDT0 => todo!("implement WWDT0"), | ||
| 21 | Group0::WWDT1 => todo!("implement WWDT1"), | ||
| 22 | Group0::DEBUGSS => todo!("implement DEBUGSS"), | ||
| 23 | Group0::FLASHCTL => todo!("implement FLASHCTL"), | ||
| 24 | Group0::SYSCTL => todo!("implement SYSCTL"), | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | #[cfg(feature = "rt")] | ||
| 29 | #[interrupt] | ||
| 30 | fn GROUP1() { | ||
| 31 | use mspm0_metapac::Group1; | ||
| 32 | |||
| 33 | let group = pac::CPUSS.int_group(1); | ||
| 34 | |||
| 35 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 36 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 37 | |||
| 38 | let Ok(group) = pac::Group1::try_from(iidx as u8) else { | ||
| 39 | debug!("Invalid IIDX for group 1: {}", iidx); | ||
| 40 | return; | ||
| 41 | }; | ||
| 42 | |||
| 43 | match group { | ||
| 44 | Group1::GPIOA => crate::gpio::gpioa_interrupt(), | ||
| 45 | Group1::GPIOB => crate::gpio::gpiob_interrupt(), | ||
| 46 | Group1::COMP0 => todo!("implement COMP0"), | ||
| 47 | Group1::COMP1 => todo!("implement COMP1"), | ||
| 48 | Group1::COMP2 => todo!("implement COMP2"), | ||
| 49 | Group1::TRNG => todo!("implement TRNG"), | ||
| 50 | } | ||
| 51 | } | ||
diff --git a/embassy-mspm0/src/int_group/g351x.rs b/embassy-mspm0/src/int_group/g351x.rs new file mode 100644 index 000000000..b43e0a9db --- /dev/null +++ b/embassy-mspm0/src/int_group/g351x.rs | |||
| @@ -0,0 +1,52 @@ | |||
| 1 | use crate::pac; | ||
| 2 | use crate::pac::interrupt; | ||
| 3 | |||
| 4 | #[cfg(feature = "rt")] | ||
| 5 | #[interrupt] | ||
| 6 | fn GROUP0() { | ||
| 7 | use mspm0_metapac::Group0; | ||
| 8 | |||
| 9 | let group = pac::CPUSS.int_group(1); | ||
| 10 | |||
| 11 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 12 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 13 | |||
| 14 | let Ok(group) = pac::Group0::try_from(iidx as u8) else { | ||
| 15 | debug!("Invalid IIDX for group 0: {}", iidx); | ||
| 16 | return; | ||
| 17 | }; | ||
| 18 | |||
| 19 | match group { | ||
| 20 | Group0::WWDT0 => todo!("implement WWDT0"), | ||
| 21 | Group0::WWDT1 => todo!("implement WWDT1"), | ||
| 22 | Group0::DEBUGSS => todo!("implement DEBUGSS"), | ||
| 23 | Group0::FLASHCTL => todo!("implement FLASHCTL"), | ||
| 24 | Group0::SYSCTL => todo!("implement SYSCTL"), | ||
| 25 | } | ||
| 26 | } | ||
| 27 | |||
| 28 | #[cfg(feature = "rt")] | ||
| 29 | #[interrupt] | ||
| 30 | fn GROUP1() { | ||
| 31 | use mspm0_metapac::Group1; | ||
| 32 | |||
| 33 | let group = pac::CPUSS.int_group(1); | ||
| 34 | |||
| 35 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 36 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 37 | |||
| 38 | let Ok(group) = pac::Group1::try_from(iidx as u8) else { | ||
| 39 | debug!("Invalid IIDX for group 1: {}", iidx); | ||
| 40 | return; | ||
| 41 | }; | ||
| 42 | |||
| 43 | match group { | ||
| 44 | Group1::GPIOA => crate::gpio::gpioa_interrupt(), | ||
| 45 | Group1::GPIOB => crate::gpio::gpiob_interrupt(), | ||
| 46 | Group1::COMP0 => todo!("implement COMP0"), | ||
| 47 | Group1::COMP1 => todo!("implement COMP1"), | ||
| 48 | Group1::COMP2 => todo!("implement COMP2"), | ||
| 49 | Group1::TRNG => todo!("implement TRNG"), | ||
| 50 | Group1::GPIOC => crate::gpio::gpioc_interrupt(), | ||
| 51 | } | ||
| 52 | } | ||
diff --git a/embassy-mspm0/src/int_group/l130x.rs b/embassy-mspm0/src/int_group/l130x.rs new file mode 100644 index 000000000..6d033cc56 --- /dev/null +++ b/embassy-mspm0/src/int_group/l130x.rs | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | use crate::pac; | ||
| 2 | use crate::pac::interrupt; | ||
| 3 | |||
| 4 | #[cfg(feature = "rt")] | ||
| 5 | #[interrupt] | ||
| 6 | fn GROUP0() { | ||
| 7 | use mspm0_metapac::Group0; | ||
| 8 | |||
| 9 | let group = pac::CPUSS.int_group(1); | ||
| 10 | |||
| 11 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 12 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 13 | |||
| 14 | let Ok(group) = pac::Group0::try_from(iidx as u8) else { | ||
| 15 | debug!("Invalid IIDX for group 0: {}", iidx); | ||
| 16 | return; | ||
| 17 | }; | ||
| 18 | |||
| 19 | match group { | ||
| 20 | Group0::WWDT0 => todo!("implement WWDT0"), | ||
| 21 | Group0::DEBUGSS => todo!("implement DEBUGSS"), | ||
| 22 | Group0::FLASHCTL => todo!("implement FLASHCTL"), | ||
| 23 | Group0::SYSCTL => todo!("implement SYSCTL"), | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | #[cfg(feature = "rt")] | ||
| 28 | #[interrupt] | ||
| 29 | fn GROUP1() { | ||
| 30 | use mspm0_metapac::Group1; | ||
| 31 | |||
| 32 | let group = pac::CPUSS.int_group(1); | ||
| 33 | |||
| 34 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 35 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 36 | |||
| 37 | let Ok(group) = pac::Group1::try_from(iidx as u8) else { | ||
| 38 | debug!("Invalid IIDX for group 1: {}", iidx); | ||
| 39 | return; | ||
| 40 | }; | ||
| 41 | |||
| 42 | match group { | ||
| 43 | Group1::GPIOA => crate::gpio::gpioa_interrupt(), | ||
| 44 | Group1::COMP0 => todo!("implement COMP0"), | ||
| 45 | } | ||
| 46 | } | ||
diff --git a/embassy-mspm0/src/int_group/l222x.rs b/embassy-mspm0/src/int_group/l222x.rs new file mode 100644 index 000000000..703e16e78 --- /dev/null +++ b/embassy-mspm0/src/int_group/l222x.rs | |||
| @@ -0,0 +1,49 @@ | |||
| 1 | use crate::pac; | ||
| 2 | use crate::pac::interrupt; | ||
| 3 | |||
| 4 | #[cfg(feature = "rt")] | ||
| 5 | #[interrupt] | ||
| 6 | fn GROUP0() { | ||
| 7 | use mspm0_metapac::Group0; | ||
| 8 | |||
| 9 | let group = pac::CPUSS.int_group(1); | ||
| 10 | |||
| 11 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 12 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 13 | |||
| 14 | let Ok(group) = pac::Group0::try_from(iidx as u8) else { | ||
| 15 | debug!("Invalid IIDX for group 0: {}", iidx); | ||
| 16 | return; | ||
| 17 | }; | ||
| 18 | |||
| 19 | match group { | ||
| 20 | Group0::WWDT0 => todo!("implement WWDT0"), | ||
| 21 | Group0::DEBUGSS => todo!("implement DEBUGSS"), | ||
| 22 | Group0::FLASHCTL => todo!("implement FLASHCTL"), | ||
| 23 | Group0::SYSCTL => todo!("implement SYSCTL"), | ||
| 24 | } | ||
| 25 | } | ||
| 26 | |||
| 27 | #[cfg(feature = "rt")] | ||
| 28 | #[interrupt] | ||
| 29 | fn GROUP1() { | ||
| 30 | use mspm0_metapac::Group1; | ||
| 31 | |||
| 32 | let group = pac::CPUSS.int_group(1); | ||
| 33 | |||
| 34 | // Must subtract by 1 since NO_INTR is value 0 | ||
| 35 | let iidx = group.iidx().read().stat().to_bits() - 1; | ||
| 36 | |||
| 37 | let Ok(group) = pac::Group1::try_from(iidx as u8) else { | ||
| 38 | debug!("Invalid IIDX for group 1: {}", iidx); | ||
| 39 | return; | ||
| 40 | }; | ||
| 41 | |||
| 42 | match group { | ||
| 43 | Group1::GPIOA => crate::gpio::gpioa_interrupt(), | ||
| 44 | Group1::GPIOB => crate::gpio::gpiob_interrupt(), | ||
| 45 | Group1::COMP0 => todo!("implement COMP0"), | ||
| 46 | Group1::TRNG => todo!("implement TRNG"), | ||
| 47 | Group1::GPIOC => crate::gpio::gpioc_interrupt(), | ||
| 48 | } | ||
| 49 | } | ||
diff --git a/embassy-mspm0/src/lib.rs b/embassy-mspm0/src/lib.rs new file mode 100644 index 000000000..ee629f063 --- /dev/null +++ b/embassy-mspm0/src/lib.rs | |||
| @@ -0,0 +1,112 @@ | |||
| 1 | #![no_std] | ||
| 2 | // Doc feature labels can be tested locally by running RUSTDOCFLAGS="--cfg=docsrs" cargo +nightly doc | ||
| 3 | #![cfg_attr( | ||
| 4 | docsrs, | ||
| 5 | feature(doc_auto_cfg, doc_cfg_hide), | ||
| 6 | doc(cfg_hide(doc, docsrs)) | ||
| 7 | )] | ||
| 8 | |||
| 9 | // This mod MUST go first, so that the others see its macros. | ||
| 10 | pub(crate) mod fmt; | ||
| 11 | |||
| 12 | pub mod gpio; | ||
| 13 | pub mod timer; | ||
| 14 | |||
| 15 | #[cfg(feature = "_time-driver")] | ||
| 16 | mod time_driver; | ||
| 17 | |||
| 18 | // Interrupt group handlers. | ||
| 19 | #[cfg_attr(feature = "mspm0c110x", path = "int_group/c110x.rs")] | ||
| 20 | #[cfg_attr(feature = "mspm0g110x", path = "int_group/g110x.rs")] | ||
| 21 | #[cfg_attr(feature = "mspm0g150x", path = "int_group/g150x.rs")] | ||
| 22 | #[cfg_attr(feature = "mspm0g151x", path = "int_group/g151x.rs")] | ||
| 23 | #[cfg_attr(feature = "mspm0g310x", path = "int_group/g310x.rs")] | ||
| 24 | #[cfg_attr(feature = "mspm0g350x", path = "int_group/g350x.rs")] | ||
| 25 | #[cfg_attr(feature = "mspm0g351x", path = "int_group/g351x.rs")] | ||
| 26 | #[cfg_attr(feature = "mspm0l110x", path = "int_group/l110x.rs")] | ||
| 27 | #[cfg_attr(feature = "mspm0l122x", path = "int_group/l122x.rs")] | ||
| 28 | #[cfg_attr(feature = "mspm0l130x", path = "int_group/l130x.rs")] | ||
| 29 | #[cfg_attr(feature = "mspm0l134x", path = "int_group/l134x.rs")] | ||
| 30 | #[cfg_attr(feature = "mspm0l222x", path = "int_group/l222x.rs")] | ||
| 31 | mod int_group; | ||
| 32 | |||
| 33 | pub(crate) mod _generated { | ||
| 34 | #![allow(dead_code)] | ||
| 35 | #![allow(unused_imports)] | ||
| 36 | #![allow(non_snake_case)] | ||
| 37 | #![allow(missing_docs)] | ||
| 38 | |||
| 39 | include!(concat!(env!("OUT_DIR"), "/_generated.rs")); | ||
| 40 | } | ||
| 41 | |||
| 42 | // Reexports | ||
| 43 | pub use _generated::{peripherals, Peripherals}; | ||
| 44 | pub use embassy_hal_internal::{into_ref, Peripheral, PeripheralRef}; | ||
| 45 | #[cfg(feature = "unstable-pac")] | ||
| 46 | pub use mspm0_metapac as pac; | ||
| 47 | #[cfg(not(feature = "unstable-pac"))] | ||
| 48 | pub(crate) use mspm0_metapac as pac; | ||
| 49 | |||
| 50 | pub use crate::_generated::interrupt; | ||
| 51 | pub(crate) use _generated::gpio_pincm; | ||
| 52 | |||
| 53 | |||
| 54 | /// `embassy-mspm0` global configuration. | ||
| 55 | #[non_exhaustive] | ||
| 56 | #[derive(Clone, Copy)] | ||
| 57 | pub struct Config { | ||
| 58 | // TODO | ||
| 59 | } | ||
| 60 | |||
| 61 | impl Default for Config { | ||
| 62 | fn default() -> Self { | ||
| 63 | Self { | ||
| 64 | // TODO | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | pub fn init(_config: Config) -> Peripherals { | ||
| 70 | critical_section::with(|cs| { | ||
| 71 | let peripherals = Peripherals::take_with_cs(cs); | ||
| 72 | |||
| 73 | // TODO: Further clock configuration | ||
| 74 | |||
| 75 | pac::SYSCTL.mclkcfg().modify(|w| { | ||
| 76 | // Enable MFCLK | ||
| 77 | w.set_usemftick(true); | ||
| 78 | // MDIV must be disabled if MFCLK is enabled. | ||
| 79 | w.set_mdiv(0); | ||
| 80 | }); | ||
| 81 | |||
| 82 | // Enable MFCLK for peripheral use | ||
| 83 | // | ||
| 84 | // TODO: Optional? | ||
| 85 | pac::SYSCTL.genclken().modify(|w| { | ||
| 86 | w.set_mfpclken(true); | ||
| 87 | }); | ||
| 88 | |||
| 89 | pac::SYSCTL.borthreshold().modify(|w| { | ||
| 90 | w.set_level(0); | ||
| 91 | }); | ||
| 92 | |||
| 93 | gpio::init(pac::GPIOA); | ||
| 94 | #[cfg(gpio_pb)] | ||
| 95 | gpio::init(pac::GPIOB); | ||
| 96 | #[cfg(gpio_pc)] | ||
| 97 | gpio::init(pac::GPIOC); | ||
| 98 | |||
| 99 | _generated::enable_group_interrupts(cs); | ||
| 100 | |||
| 101 | #[cfg(feature = "mspm0c110x")] | ||
| 102 | unsafe { | ||
| 103 | use crate::_generated::interrupt::typelevel::Interrupt; | ||
| 104 | crate::interrupt::typelevel::GPIOA::enable(); | ||
| 105 | } | ||
| 106 | |||
| 107 | #[cfg(feature = "_time-driver")] | ||
| 108 | time_driver::init(cs); | ||
| 109 | |||
| 110 | peripherals | ||
| 111 | }) | ||
| 112 | } | ||
diff --git a/embassy-mspm0/src/time_driver.rs b/embassy-mspm0/src/time_driver.rs new file mode 100644 index 000000000..3af7a5edb --- /dev/null +++ b/embassy-mspm0/src/time_driver.rs | |||
| @@ -0,0 +1,437 @@ | |||
| 1 | use core::{ | ||
| 2 | cell::{Cell, RefCell}, | ||
| 3 | sync::atomic::{compiler_fence, AtomicU32, Ordering}, | ||
| 4 | task::Waker, | ||
| 5 | }; | ||
| 6 | |||
| 7 | use critical_section::{CriticalSection, Mutex}; | ||
| 8 | use embassy_time_driver::Driver; | ||
| 9 | use embassy_time_queue_utils::Queue; | ||
| 10 | use mspm0_metapac::{ | ||
| 11 | interrupt, | ||
| 12 | tim::{ | ||
| 13 | vals::{Cm, Cvae, CxC, EvtCfg, PwrenKey, Ratio, Repeat, ResetKey}, | ||
| 14 | Counterregs16, Tim, | ||
| 15 | }, | ||
| 16 | }; | ||
| 17 | |||
| 18 | use crate::peripherals; | ||
| 19 | use crate::timer::SealedTimer; | ||
| 20 | |||
| 21 | // Currently TIMG12 and TIMG13 are excluded because those are 32-bit timers. | ||
| 22 | #[cfg(time_driver_timg0)] | ||
| 23 | type T = peripherals::TIMG0; | ||
| 24 | #[cfg(time_driver_timg1)] | ||
| 25 | type T = peripherals::TIMG1; | ||
| 26 | #[cfg(time_driver_timg2)] | ||
| 27 | type T = peripherals::TIMG2; | ||
| 28 | #[cfg(time_driver_timg3)] | ||
| 29 | type T = peripherals::TIMG3; | ||
| 30 | #[cfg(time_driver_timg4)] | ||
| 31 | type T = peripherals::TIMG4; | ||
| 32 | #[cfg(time_driver_timg5)] | ||
| 33 | type T = peripherals::TIMG5; | ||
| 34 | #[cfg(time_driver_timg6)] | ||
| 35 | type T = peripherals::TIMG6; | ||
| 36 | #[cfg(time_driver_timg7)] | ||
| 37 | type T = peripherals::TIMG7; | ||
| 38 | #[cfg(time_driver_timg8)] | ||
| 39 | type T = peripherals::TIMG8; | ||
| 40 | #[cfg(time_driver_timg9)] | ||
| 41 | type T = peripherals::TIMG9; | ||
| 42 | #[cfg(time_driver_timg10)] | ||
| 43 | type T = peripherals::TIMG10; | ||
| 44 | #[cfg(time_driver_timg11)] | ||
| 45 | type T = peripherals::TIMG11; | ||
| 46 | #[cfg(time_driver_timg14)] | ||
| 47 | type T = peripherals::TIMG14; | ||
| 48 | #[cfg(time_driver_tima0)] | ||
| 49 | type T = peripherals::TIMA0; | ||
| 50 | #[cfg(time_driver_tima1)] | ||
| 51 | type T = peripherals::TIMA1; | ||
| 52 | |||
| 53 | // TODO: RTC | ||
| 54 | |||
| 55 | fn regs() -> Tim { | ||
| 56 | unsafe { Tim::from_ptr(T::regs()) } | ||
| 57 | } | ||
| 58 | |||
| 59 | fn regs_counter(tim: Tim) -> Counterregs16 { | ||
| 60 | unsafe { Counterregs16::from_ptr(tim.counterregs(0).as_ptr()) } | ||
| 61 | } | ||
| 62 | |||
| 63 | /// Clock timekeeping works with something we call "periods", which are time intervals | ||
| 64 | /// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods. | ||
| 65 | fn calc_now(period: u32, counter: u16) -> u64 { | ||
| 66 | ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64) | ||
| 67 | } | ||
| 68 | |||
| 69 | /// The TIMx driver uses one of the `TIMG` or `TIMA` timer instances to implement a timer with a 32.768 kHz | ||
| 70 | /// tick rate. (TODO: Allow setting the tick rate) | ||
| 71 | /// | ||
| 72 | /// This driver defines a period to be 2^15 ticks. 16-bit timers of course count to 2^16 ticks. | ||
| 73 | /// | ||
| 74 | /// To generate a period every 2^15 ticks, the CC0 value is set to 2^15 and the load value set to 2^16. | ||
| 75 | /// Incrementing the period on a CCU0 and load results in the a period of 2^15 ticks. | ||
| 76 | /// | ||
| 77 | /// For a specific timestamp, load the lower 16 bits into the CC1 value. When the period where the timestamp | ||
| 78 | /// should be enabled is reached, then the CCU1 (CC1 up) interrupt runs to actually wake the timer. | ||
| 79 | /// | ||
| 80 | /// TODO: Compensate for per part variance. This can supposedly be done with the FCC system. | ||
| 81 | /// TODO: Allow using 32-bit timers (TIMG12 and TIMG13). | ||
| 82 | struct TimxDriver { | ||
| 83 | /// Number of 2^15 periods elapsed since boot. | ||
| 84 | period: AtomicU32, | ||
| 85 | /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled. | ||
| 86 | alarm: Mutex<Cell<u64>>, | ||
| 87 | queue: Mutex<RefCell<Queue>>, | ||
| 88 | } | ||
| 89 | |||
| 90 | impl TimxDriver { | ||
| 91 | #[inline(never)] | ||
| 92 | fn init(&'static self, _cs: CriticalSection) { | ||
| 93 | // Clock config | ||
| 94 | // TODO: Configurable tick rate up to 4 MHz (32 kHz for now) | ||
| 95 | let regs = regs(); | ||
| 96 | |||
| 97 | // Reset timer | ||
| 98 | regs.gprcm(0).rstctl().write(|w| { | ||
| 99 | w.set_resetassert(true); | ||
| 100 | w.set_key(ResetKey::KEY); | ||
| 101 | w.set_resetstkyclr(true); | ||
| 102 | }); | ||
| 103 | |||
| 104 | // Power up timer | ||
| 105 | regs.gprcm(0).pwren().write(|w| { | ||
| 106 | w.set_enable(true); | ||
| 107 | w.set_key(PwrenKey::KEY); | ||
| 108 | }); | ||
| 109 | |||
| 110 | // Following the instructions according to SLAU847D 23.2.1: TIMCLK Configuration | ||
| 111 | |||
| 112 | // 1. Select TIMCLK source | ||
| 113 | regs.clksel().modify(|w| { | ||
| 114 | // Use LFCLK for a 32.768kHz tick rate | ||
| 115 | w.set_lfclk_sel(true); | ||
| 116 | // TODO: Allow MFCLK for configurable tick rate up to 4 MHz | ||
| 117 | // w.set_mfclk_sel(ClkSel::ENABLE); | ||
| 118 | }); | ||
| 119 | |||
| 120 | // 2. Divide by TIMCLK, we don't need to divide further for the 32kHz tick rate | ||
| 121 | regs.clkdiv().modify(|w| { | ||
| 122 | w.set_ratio(Ratio::DIV_BY_1); | ||
| 123 | }); | ||
| 124 | |||
| 125 | // 3. To be generic across timer instances, we do not use the prescaler. | ||
| 126 | // TODO: mspm0-sdk always sets this, regardless of timer width? | ||
| 127 | regs.commonregs(0).cps().modify(|w| { | ||
| 128 | w.set_pcnt(0); | ||
| 129 | }); | ||
| 130 | |||
| 131 | regs.pdbgctl().modify(|w| { | ||
| 132 | w.set_free(true); | ||
| 133 | }); | ||
| 134 | |||
| 135 | // 4. Enable the TIMCLK. | ||
| 136 | regs.commonregs(0).cclkctl().modify(|w| { | ||
| 137 | w.set_clken(true); | ||
| 138 | }); | ||
| 139 | |||
| 140 | regs.counterregs(0).ctrctl().modify(|w| { | ||
| 141 | // allow counting during debug | ||
| 142 | w.set_repeat(Repeat::REPEAT_3); | ||
| 143 | w.set_cvae(Cvae::ZEROVAL); | ||
| 144 | w.set_cm(Cm::UP); | ||
| 145 | |||
| 146 | // Must explicitly set CZC, CAC and CLC to 0 in order for all the timers to count. | ||
| 147 | // | ||
| 148 | // The reset value of these registers is 0x07, which is a reserved value. | ||
| 149 | // | ||
| 150 | // Looking at a bit representation of the reset value, this appears to be an AND | ||
| 151 | // of 2-input QEI mode and CCCTL_3 ACOND. Given that TIMG14 and TIMA0 have no QEI | ||
| 152 | // and 4 capture and compare channels, this works by accident for those timer units. | ||
| 153 | w.set_czc(CxC::CCTL0); | ||
| 154 | w.set_cac(CxC::CCTL0); | ||
| 155 | w.set_clc(CxC::CCTL0); | ||
| 156 | }); | ||
| 157 | |||
| 158 | // Setup the period | ||
| 159 | let ctr = regs_counter(regs); | ||
| 160 | |||
| 161 | // Middle | ||
| 162 | ctr.cc(0).modify(|w| { | ||
| 163 | w.set_ccval(0x7FFF); | ||
| 164 | }); | ||
| 165 | |||
| 166 | ctr.load().modify(|w| { | ||
| 167 | w.set_ld(u16::MAX); | ||
| 168 | }); | ||
| 169 | |||
| 170 | // Enable the period interrupts | ||
| 171 | // | ||
| 172 | // This does not appear to ever be set for CPU_INT in the TI SDK and is not technically needed. | ||
| 173 | regs.evt_mode().modify(|w| { | ||
| 174 | w.set_evt_cfg(0, EvtCfg::SOFTWARE); | ||
| 175 | }); | ||
| 176 | |||
| 177 | regs.int_event(0).imask().modify(|w| { | ||
| 178 | w.set_l(true); | ||
| 179 | w.set_ccu0(true); | ||
| 180 | }); | ||
| 181 | |||
| 182 | unsafe { T::enable_interrupt() }; | ||
| 183 | |||
| 184 | // Allow the counter to start counting. | ||
| 185 | regs.counterregs(0).ctrctl().modify(|w| { | ||
| 186 | w.set_en(true); | ||
| 187 | }); | ||
| 188 | } | ||
| 189 | |||
| 190 | #[inline(never)] | ||
| 191 | fn next_period(&self) { | ||
| 192 | let r = regs(); | ||
| 193 | |||
| 194 | // We only modify the period from the timer interrupt, so we know this can't race. | ||
| 195 | let period = self.period.load(Ordering::Relaxed) + 1; | ||
| 196 | self.period.store(period, Ordering::Relaxed); | ||
| 197 | let t = (period as u64) << 15; | ||
| 198 | |||
| 199 | critical_section::with(move |cs| { | ||
| 200 | r.int_event(0).imask().modify(move |w| { | ||
| 201 | let alarm = self.alarm.borrow(cs); | ||
| 202 | let at = alarm.get(); | ||
| 203 | |||
| 204 | if at < t + 0xC000 { | ||
| 205 | // just enable it. `set_alarm` has already set the correct CC1 val. | ||
| 206 | w.set_ccu1(true); | ||
| 207 | } | ||
| 208 | }) | ||
| 209 | }); | ||
| 210 | } | ||
| 211 | |||
| 212 | #[inline(never)] | ||
| 213 | fn on_interrupt(&self) { | ||
| 214 | let r = regs(); | ||
| 215 | |||
| 216 | critical_section::with(|cs| { | ||
| 217 | let mis = r.int_event(0).mis().read(); | ||
| 218 | |||
| 219 | // Advance to next period if overflowed | ||
| 220 | if mis.l() { | ||
| 221 | self.next_period(); | ||
| 222 | |||
| 223 | r.int_event(0).iclr().write(|w| { | ||
| 224 | w.set_l(true); | ||
| 225 | }); | ||
| 226 | } | ||
| 227 | |||
| 228 | if mis.ccu0() { | ||
| 229 | self.next_period(); | ||
| 230 | |||
| 231 | r.int_event(0).iclr().write(|w| { | ||
| 232 | w.set_ccu0(true); | ||
| 233 | }); | ||
| 234 | } | ||
| 235 | |||
| 236 | if mis.ccu1() { | ||
| 237 | r.int_event(0).iclr().write(|w| { | ||
| 238 | w.set_ccu1(true); | ||
| 239 | }); | ||
| 240 | |||
| 241 | self.trigger_alarm(cs); | ||
| 242 | } | ||
| 243 | }); | ||
| 244 | } | ||
| 245 | |||
| 246 | fn trigger_alarm(&self, cs: CriticalSection) { | ||
| 247 | let mut next = self | ||
| 248 | .queue | ||
| 249 | .borrow(cs) | ||
| 250 | .borrow_mut() | ||
| 251 | .next_expiration(self.now()); | ||
| 252 | |||
| 253 | while !self.set_alarm(cs, next) { | ||
| 254 | next = self | ||
| 255 | .queue | ||
| 256 | .borrow(cs) | ||
| 257 | .borrow_mut() | ||
| 258 | .next_expiration(self.now()); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool { | ||
| 263 | let r = regs(); | ||
| 264 | let ctr = regs_counter(r); | ||
| 265 | |||
| 266 | self.alarm.borrow(cs).set(timestamp); | ||
| 267 | |||
| 268 | let t = self.now(); | ||
| 269 | |||
| 270 | if timestamp <= t { | ||
| 271 | // If alarm timestamp has passed the alarm will not fire. | ||
| 272 | // Disarm the alarm and return `false` to indicate that. | ||
| 273 | r.int_event(0).imask().modify(|w| w.set_ccu1(false)); | ||
| 274 | |||
| 275 | self.alarm.borrow(cs).set(u64::MAX); | ||
| 276 | |||
| 277 | return false; | ||
| 278 | } | ||
| 279 | |||
| 280 | // Write the CC1 value regardless of whether we're going to enable it now or not. | ||
| 281 | // This way, when we enable it later, the right value is already set. | ||
| 282 | ctr.cc(1).write(|w| { | ||
| 283 | w.set_ccval(timestamp as u16); | ||
| 284 | }); | ||
| 285 | |||
| 286 | // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. | ||
| 287 | let diff = timestamp - t; | ||
| 288 | r.int_event(0).imask().modify(|w| w.set_ccu1(diff < 0xC000)); | ||
| 289 | |||
| 290 | // Reevaluate if the alarm timestamp is still in the future | ||
| 291 | let t = self.now(); | ||
| 292 | if timestamp <= t { | ||
| 293 | // If alarm timestamp has passed since we set it, we have a race condition and | ||
| 294 | // the alarm may or may not have fired. | ||
| 295 | // Disarm the alarm and return `false` to indicate that. | ||
| 296 | // It is the caller's responsibility to handle this ambiguity. | ||
| 297 | r.int_event(0).imask().modify(|w| w.set_ccu1(false)); | ||
| 298 | |||
| 299 | self.alarm.borrow(cs).set(u64::MAX); | ||
| 300 | |||
| 301 | return false; | ||
| 302 | } | ||
| 303 | |||
| 304 | // We're confident the alarm will ring in the future. | ||
| 305 | true | ||
| 306 | } | ||
| 307 | } | ||
| 308 | |||
| 309 | impl Driver for TimxDriver { | ||
| 310 | fn now(&self) -> u64 { | ||
| 311 | let regs = regs(); | ||
| 312 | |||
| 313 | let period = self.period.load(Ordering::Relaxed); | ||
| 314 | // Ensure the compiler does not read the counter before the period. | ||
| 315 | compiler_fence(Ordering::Acquire); | ||
| 316 | |||
| 317 | let counter = regs_counter(regs).ctr().read().cctr() as u16; | ||
| 318 | |||
| 319 | calc_now(period, counter) | ||
| 320 | } | ||
| 321 | |||
| 322 | fn schedule_wake(&self, at: u64, waker: &Waker) { | ||
| 323 | critical_section::with(|cs| { | ||
| 324 | let mut queue = self.queue.borrow(cs).borrow_mut(); | ||
| 325 | |||
| 326 | if queue.schedule_wake(at, waker) { | ||
| 327 | let mut next = queue.next_expiration(self.now()); | ||
| 328 | |||
| 329 | while !self.set_alarm(cs, next) { | ||
| 330 | next = queue.next_expiration(self.now()); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | }); | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | embassy_time_driver::time_driver_impl!(static DRIVER: TimxDriver = TimxDriver { | ||
| 338 | period: AtomicU32::new(0), | ||
| 339 | alarm: Mutex::new(Cell::new(u64::MAX)), | ||
| 340 | queue: Mutex::new(RefCell::new(Queue::new())) | ||
| 341 | }); | ||
| 342 | |||
| 343 | pub(crate) fn init(cs: CriticalSection) { | ||
| 344 | DRIVER.init(cs); | ||
| 345 | } | ||
| 346 | |||
| 347 | #[cfg(time_driver_timg0)] | ||
| 348 | #[interrupt] | ||
| 349 | fn TIMG0() { | ||
| 350 | DRIVER.on_interrupt(); | ||
| 351 | } | ||
| 352 | |||
| 353 | #[cfg(time_driver_timg1)] | ||
| 354 | #[interrupt] | ||
| 355 | fn TIMG1() { | ||
| 356 | DRIVER.on_interrupt(); | ||
| 357 | } | ||
| 358 | |||
| 359 | #[cfg(time_driver_timg2)] | ||
| 360 | #[interrupt] | ||
| 361 | fn TIMG2() { | ||
| 362 | DRIVER.on_interrupt(); | ||
| 363 | } | ||
| 364 | |||
| 365 | #[cfg(time_driver_timg3)] | ||
| 366 | #[interrupt] | ||
| 367 | fn TIMG3() { | ||
| 368 | DRIVER.on_interrupt(); | ||
| 369 | } | ||
| 370 | |||
| 371 | #[cfg(time_driver_timg4)] | ||
| 372 | #[interrupt] | ||
| 373 | fn TIMG4() { | ||
| 374 | DRIVER.on_interrupt(); | ||
| 375 | } | ||
| 376 | |||
| 377 | #[cfg(time_driver_timg5)] | ||
| 378 | #[interrupt] | ||
| 379 | fn TIMG5() { | ||
| 380 | DRIVER.on_interrupt(); | ||
| 381 | } | ||
| 382 | |||
| 383 | #[cfg(time_driver_timg6)] | ||
| 384 | #[interrupt] | ||
| 385 | fn TIMG6() { | ||
| 386 | DRIVER.on_interrupt(); | ||
| 387 | } | ||
| 388 | |||
| 389 | #[cfg(time_driver_timg7)] | ||
| 390 | #[interrupt] | ||
| 391 | fn TIMG7() { | ||
| 392 | DRIVER.on_interrupt(); | ||
| 393 | } | ||
| 394 | |||
| 395 | #[cfg(time_driver_timg8)] | ||
| 396 | #[interrupt] | ||
| 397 | fn TIMG8() { | ||
| 398 | DRIVER.on_interrupt(); | ||
| 399 | } | ||
| 400 | |||
| 401 | #[cfg(time_driver_timg9)] | ||
| 402 | #[interrupt] | ||
| 403 | fn TIMG9() { | ||
| 404 | DRIVER.on_interrupt(); | ||
| 405 | } | ||
| 406 | |||
| 407 | #[cfg(time_driver_timg10)] | ||
| 408 | #[interrupt] | ||
| 409 | fn TIMG10() { | ||
| 410 | DRIVER.on_interrupt(); | ||
| 411 | } | ||
| 412 | |||
| 413 | #[cfg(time_driver_timg11)] | ||
| 414 | #[interrupt] | ||
| 415 | fn TIMG11() { | ||
| 416 | DRIVER.on_interrupt(); | ||
| 417 | } | ||
| 418 | |||
| 419 | // TODO: TIMG12 and TIMG13 | ||
| 420 | |||
| 421 | #[cfg(time_driver_timg14)] | ||
| 422 | #[interrupt] | ||
| 423 | fn TIMG14() { | ||
| 424 | DRIVER.on_interrupt(); | ||
| 425 | } | ||
| 426 | |||
| 427 | #[cfg(time_driver_tima0)] | ||
| 428 | #[interrupt] | ||
| 429 | fn TIMA0() { | ||
| 430 | DRIVER.on_interrupt(); | ||
| 431 | } | ||
| 432 | |||
| 433 | #[cfg(time_driver_tima1)] | ||
| 434 | #[interrupt] | ||
| 435 | fn TIMA1() { | ||
| 436 | DRIVER.on_interrupt(); | ||
| 437 | } | ||
diff --git a/embassy-mspm0/src/timer.rs b/embassy-mspm0/src/timer.rs new file mode 100644 index 000000000..4441e5640 --- /dev/null +++ b/embassy-mspm0/src/timer.rs | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | #![macro_use] | ||
| 2 | |||
| 3 | /// Amount of bits of a timer. | ||
| 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | ||
| 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 6 | pub enum TimerBits { | ||
| 7 | /// 16 bits. | ||
| 8 | Bits16, | ||
| 9 | /// 32 bits. | ||
| 10 | Bits32, | ||
| 11 | } | ||
| 12 | |||
| 13 | #[allow(private_bounds)] | ||
| 14 | pub trait Timer: SealedTimer + 'static { | ||
| 15 | /// Amount of bits this timer has. | ||
| 16 | const BITS: TimerBits; | ||
| 17 | } | ||
| 18 | |||
| 19 | pub(crate) trait SealedTimer { | ||
| 20 | /// Registers for this timer. | ||
| 21 | /// | ||
| 22 | /// This is a raw pointer to the register block. The actual register block layout varies depending on the | ||
| 23 | /// timer type. | ||
| 24 | fn regs() -> *mut (); | ||
| 25 | |||
| 26 | /// Enable the interrupt corresponding to this timer. | ||
| 27 | unsafe fn enable_interrupt(); | ||
| 28 | } | ||
| 29 | |||
| 30 | macro_rules! impl_timer { | ||
| 31 | ($name: ident, $bits: ident) => { | ||
| 32 | impl crate::timer::SealedTimer for crate::peripherals::$name { | ||
| 33 | fn regs() -> *mut () { | ||
| 34 | crate::pac::$name.as_ptr() | ||
| 35 | } | ||
| 36 | |||
| 37 | unsafe fn enable_interrupt() { | ||
| 38 | use embassy_hal_internal::interrupt::InterruptExt; | ||
| 39 | crate::interrupt::$name.unpend(); | ||
| 40 | crate::interrupt::$name.enable(); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | impl crate::timer::Timer for crate::peripherals::$name { | ||
| 45 | const BITS: crate::timer::TimerBits = crate::timer::TimerBits::$bits; | ||
| 46 | } | ||
| 47 | }; | ||
| 48 | } | ||
diff --git a/examples/mspm0c1104/.cargo/config.toml b/examples/mspm0c1104/.cargo/config.toml new file mode 100644 index 000000000..204a56b1c --- /dev/null +++ b/examples/mspm0c1104/.cargo/config.toml | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace MSPM0C1104 with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip MSPM0C1104 --protocol=swd" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv6m-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "debug" | ||
| 10 | # defmt's buffer needs to be shrunk since the MSPM0C1104 only has 1KB of ram. | ||
| 11 | DEFMT_RTT_BUFFER_SIZE = "72" | ||
diff --git a/examples/mspm0c1104/Cargo.toml b/examples/mspm0c1104/Cargo.toml new file mode 100644 index 000000000..35c9b1358 --- /dev/null +++ b/examples/mspm0c1104/Cargo.toml | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-mspm0-c1104-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0c110x", "rt", "time-driver-any"] } | ||
| 9 | embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-128", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 10 | embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 12 | panic-halt = "0.2.0" | ||
| 13 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 14 | cortex-m-rt = { version = "0.7.0"} | ||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3.2", features = ["print-defmt"] } | ||
| 18 | panic-semihosting = "0.6.0" | ||
| 19 | |||
| 20 | # The chip only has 1KB of ram, so we must optimize binaries regardless | ||
| 21 | [profile.dev] | ||
| 22 | debug = 2 | ||
| 23 | opt-level = "z" | ||
| 24 | lto = true | ||
| 25 | codegen-units = 1 | ||
| 26 | # strip = true | ||
| 27 | |||
| 28 | [profile.release] | ||
| 29 | debug = 2 | ||
| 30 | opt-level = "z" | ||
| 31 | lto = true | ||
| 32 | codegen-units = 1 | ||
diff --git a/examples/mspm0c1104/README.md b/examples/mspm0c1104/README.md new file mode 100644 index 000000000..e5c9f961d --- /dev/null +++ b/examples/mspm0c1104/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # Examples for MSPM0C110x family | ||
| 2 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0C1104](https://www.ti.com/tool/LP-MSPM0C1104) board. | ||
| 14 | |||
| 15 | 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. | ||
| 16 | |||
| 17 | * [ ] 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) | ||
| 18 | * [ ] 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. | ||
| 19 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 20 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 21 | |||
| 22 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 23 | |||
| 24 | * Which example you are trying to run | ||
| 25 | * Which chip and board you are using | ||
| 26 | |||
| 27 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/mspm0c1104/build.rs b/examples/mspm0c1104/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0c1104/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/mspm0c1104/memory.x b/examples/mspm0c1104/memory.x new file mode 100644 index 000000000..a9108835a --- /dev/null +++ b/examples/mspm0c1104/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 16K | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 1K | ||
| 5 | } | ||
diff --git a/examples/mspm0c1104/src/bin/blinky.rs b/examples/mspm0c1104/src/bin/blinky.rs new file mode 100644 index 000000000..264ea3eb5 --- /dev/null +++ b/examples/mspm0c1104/src/bin/blinky.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Level, Output}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_halt as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) -> ! { | ||
| 15 | info!("Hello world!"); | ||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let mut led1 = Output::new(p.PA22, Level::Low); | ||
| 19 | led1.set_inversion(true); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | Timer::after_millis(400).await; | ||
| 23 | |||
| 24 | info!("Toggle"); | ||
| 25 | led1.toggle(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/mspm0c1104/src/bin/button.rs b/examples/mspm0c1104/src/bin/button.rs new file mode 100644 index 000000000..988170ef9 --- /dev/null +++ b/examples/mspm0c1104/src/bin/button.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Input, Level, Output, Pull}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use {defmt_rtt as _, panic_halt as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) -> ! { | ||
| 14 | info!("Hello world!"); | ||
| 15 | |||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let led1 = p.PA22; | ||
| 19 | let s2 = p.PA16; | ||
| 20 | |||
| 21 | let mut led1 = Output::new(led1, Level::Low); | ||
| 22 | |||
| 23 | let mut s2 = Input::new(s2, Pull::Up); | ||
| 24 | |||
| 25 | // led1 is active low | ||
| 26 | led1.set_high(); | ||
| 27 | |||
| 28 | loop { | ||
| 29 | s2.wait_for_falling_edge().await; | ||
| 30 | |||
| 31 | info!("Switch 2 was pressed"); | ||
| 32 | |||
| 33 | led1.toggle(); | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/mspm0g3507/.cargo/config.toml b/examples/mspm0g3507/.cargo/config.toml new file mode 100644 index 000000000..34c720cdd --- /dev/null +++ b/examples/mspm0g3507/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace MSPM0G3507 with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip MSPM0G3507 --protocol=swd" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv6m-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "debug" | ||
diff --git a/examples/mspm0g3507/Cargo.toml b/examples/mspm0g3507/Cargo.toml new file mode 100644 index 000000000..c1f304174 --- /dev/null +++ b/examples/mspm0g3507/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-mspm0-g3507-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g350x", "rt", "time-driver-any"] } | ||
| 9 | embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-4096", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 10 | embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 12 | panic-halt = "0.2.0" | ||
| 13 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 14 | cortex-m-rt = { version = "0.7.0"} | ||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3.2", features = ["print-defmt"] } | ||
| 18 | panic-semihosting = "0.6.0" | ||
| 19 | |||
| 20 | [profile.release] | ||
| 21 | debug = 2 | ||
diff --git a/examples/mspm0g3507/README.md b/examples/mspm0g3507/README.md new file mode 100644 index 000000000..5e8a83212 --- /dev/null +++ b/examples/mspm0g3507/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # Examples for MSPM0C350x family | ||
| 2 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0G3507](https://www.ti.com/tool/LP-MSPM0G3507) board. | ||
| 14 | |||
| 15 | 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. | ||
| 16 | |||
| 17 | * [ ] 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) | ||
| 18 | * [ ] 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. | ||
| 19 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 20 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 21 | |||
| 22 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 23 | |||
| 24 | * Which example you are trying to run | ||
| 25 | * Which chip and board you are using | ||
| 26 | |||
| 27 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/mspm0g3507/build.rs b/examples/mspm0g3507/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0g3507/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/mspm0g3507/memory.x b/examples/mspm0g3507/memory.x new file mode 100644 index 000000000..37e381fbd --- /dev/null +++ b/examples/mspm0g3507/memory.x | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 128K | ||
| 4 | /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ | ||
| 5 | RAM : ORIGIN = 0x20200000, LENGTH = 32K | ||
| 6 | } | ||
diff --git a/examples/mspm0g3507/src/bin/blinky.rs b/examples/mspm0g3507/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0g3507/src/bin/blinky.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Level, Output}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_halt as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) -> ! { | ||
| 15 | info!("Hello world!"); | ||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let mut led1 = Output::new(p.PA0, Level::Low); | ||
| 19 | led1.set_inversion(true); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | Timer::after_millis(400).await; | ||
| 23 | |||
| 24 | info!("Toggle"); | ||
| 25 | led1.toggle(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/mspm0g3507/src/bin/button.rs b/examples/mspm0g3507/src/bin/button.rs new file mode 100644 index 000000000..1d9a37c5c --- /dev/null +++ b/examples/mspm0g3507/src/bin/button.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Input, Level, Output, Pull}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use {defmt_rtt as _, panic_halt as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) -> ! { | ||
| 14 | info!("Hello world!"); | ||
| 15 | |||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let led1 = p.PA0; | ||
| 19 | let s2 = p.PB21; | ||
| 20 | |||
| 21 | let mut led1 = Output::new(led1, Level::Low); | ||
| 22 | |||
| 23 | let mut s2 = Input::new(s2, Pull::Up); | ||
| 24 | |||
| 25 | // led1 is active low | ||
| 26 | led1.set_high(); | ||
| 27 | |||
| 28 | loop { | ||
| 29 | s2.wait_for_falling_edge().await; | ||
| 30 | |||
| 31 | info!("Switch 2 was pressed"); | ||
| 32 | |||
| 33 | led1.toggle(); | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/mspm0g3519/.cargo/config.toml b/examples/mspm0g3519/.cargo/config.toml new file mode 100644 index 000000000..1a4768682 --- /dev/null +++ b/examples/mspm0g3519/.cargo/config.toml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace MSPM0G3519 with your chip as listed in `probe-rs chip list` | ||
| 3 | # TODO: Remove description path after new chiptool release | ||
| 4 | runner = "probe-rs run --restore-unwritten --verify --chip MSPM0G3519 --protocol=swd --chip-description-path ./MSPM0GX51X_Series.yaml" | ||
| 5 | |||
| 6 | [build] | ||
| 7 | target = "thumbv6m-none-eabi" | ||
| 8 | |||
| 9 | [env] | ||
| 10 | DEFMT_LOG = "trace" | ||
diff --git a/examples/mspm0g3519/Cargo.toml b/examples/mspm0g3519/Cargo.toml new file mode 100644 index 000000000..fc6f0e31b --- /dev/null +++ b/examples/mspm0g3519/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-mspm0-g3519-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0g351x", "rt", "time-driver-any"] } | ||
| 9 | embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-16384", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 10 | embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 12 | panic-halt = "0.2.0" | ||
| 13 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 14 | cortex-m-rt = { version = "0.7.0"} | ||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3.2", features = ["print-defmt"] } | ||
| 18 | panic-semihosting = "0.6.0" | ||
| 19 | |||
| 20 | [profile.release] | ||
| 21 | debug = 2 | ||
diff --git a/examples/mspm0g3519/MSPM0GX51X_Series.yaml b/examples/mspm0g3519/MSPM0GX51X_Series.yaml new file mode 100644 index 000000000..375623b94 --- /dev/null +++ b/examples/mspm0g3519/MSPM0GX51X_Series.yaml | |||
| @@ -0,0 +1,424 @@ | |||
| 1 | name: MSPM0GX51X Series | ||
| 2 | manufacturer: | ||
| 3 | id: 0x17 | ||
| 4 | cc: 0x0 | ||
| 5 | generated_from_pack: true | ||
| 6 | pack_file_release: 1.0.0 | ||
| 7 | variants: | ||
| 8 | - name: MSPM0G1518 | ||
| 9 | cores: | ||
| 10 | - name: main | ||
| 11 | type: armv6m | ||
| 12 | core_access_options: !Arm | ||
| 13 | ap: 0 | ||
| 14 | memory_map: | ||
| 15 | - !Nvm | ||
| 16 | name: IROM1 | ||
| 17 | range: | ||
| 18 | start: 0x0 | ||
| 19 | end: 0x40000 | ||
| 20 | cores: | ||
| 21 | - main | ||
| 22 | access: | ||
| 23 | write: false | ||
| 24 | boot: true | ||
| 25 | - !Generic | ||
| 26 | name: IROM2 | ||
| 27 | range: | ||
| 28 | start: 0x400000 | ||
| 29 | end: 0x440000 | ||
| 30 | cores: | ||
| 31 | - main | ||
| 32 | access: | ||
| 33 | write: false | ||
| 34 | - !Generic | ||
| 35 | name: IRAM1 | ||
| 36 | range: | ||
| 37 | start: 0x20000000 | ||
| 38 | end: 0x20010000 | ||
| 39 | cores: | ||
| 40 | - main | ||
| 41 | - !Generic | ||
| 42 | name: IRAM_Parity | ||
| 43 | range: | ||
| 44 | start: 0x20100000 | ||
| 45 | end: 0x20110000 | ||
| 46 | cores: | ||
| 47 | - main | ||
| 48 | - !Ram | ||
| 49 | name: IRAM_No_Parity | ||
| 50 | range: | ||
| 51 | start: 0x20200000 | ||
| 52 | end: 0x20220000 | ||
| 53 | cores: | ||
| 54 | - main | ||
| 55 | - !Generic | ||
| 56 | name: IRAM_Parity_Code | ||
| 57 | range: | ||
| 58 | start: 0x20300000 | ||
| 59 | end: 0x20310000 | ||
| 60 | cores: | ||
| 61 | - main | ||
| 62 | - !Generic | ||
| 63 | name: NonMain_ECC | ||
| 64 | range: | ||
| 65 | start: 0x41c00000 | ||
| 66 | end: 0x41c00800 | ||
| 67 | cores: | ||
| 68 | - main | ||
| 69 | access: | ||
| 70 | write: false | ||
| 71 | execute: false | ||
| 72 | - !Generic | ||
| 73 | name: Factory_ECC | ||
| 74 | range: | ||
| 75 | start: 0x41c40000 | ||
| 76 | end: 0x41c40200 | ||
| 77 | cores: | ||
| 78 | - main | ||
| 79 | access: | ||
| 80 | write: false | ||
| 81 | execute: false | ||
| 82 | - !Generic | ||
| 83 | name: Data | ||
| 84 | range: | ||
| 85 | start: 0x41d00000 | ||
| 86 | end: 0x41d04000 | ||
| 87 | cores: | ||
| 88 | - main | ||
| 89 | access: | ||
| 90 | write: false | ||
| 91 | execute: false | ||
| 92 | flash_algorithms: | ||
| 93 | - mspm0gx51x_main_512kb | ||
| 94 | - mspm0gx51x_nonmain | ||
| 95 | - mspm0gx51x_data_16kb | ||
| 96 | - name: MSPM0G1519 | ||
| 97 | cores: | ||
| 98 | - name: main | ||
| 99 | type: armv6m | ||
| 100 | core_access_options: !Arm | ||
| 101 | ap: 0 | ||
| 102 | memory_map: | ||
| 103 | - !Nvm | ||
| 104 | name: IROM1 | ||
| 105 | range: | ||
| 106 | start: 0x0 | ||
| 107 | end: 0x80000 | ||
| 108 | cores: | ||
| 109 | - main | ||
| 110 | access: | ||
| 111 | write: false | ||
| 112 | boot: true | ||
| 113 | - !Generic | ||
| 114 | name: IROM2 | ||
| 115 | range: | ||
| 116 | start: 0x400000 | ||
| 117 | end: 0x480000 | ||
| 118 | cores: | ||
| 119 | - main | ||
| 120 | access: | ||
| 121 | write: false | ||
| 122 | - !Generic | ||
| 123 | name: IRAM1 | ||
| 124 | range: | ||
| 125 | start: 0x20000000 | ||
| 126 | end: 0x20010000 | ||
| 127 | cores: | ||
| 128 | - main | ||
| 129 | - !Generic | ||
| 130 | name: IRAM_Parity | ||
| 131 | range: | ||
| 132 | start: 0x20100000 | ||
| 133 | end: 0x20110000 | ||
| 134 | cores: | ||
| 135 | - main | ||
| 136 | - !Ram | ||
| 137 | name: IRAM_No_Parity | ||
| 138 | range: | ||
| 139 | start: 0x20200000 | ||
| 140 | end: 0x20220000 | ||
| 141 | cores: | ||
| 142 | - main | ||
| 143 | - !Generic | ||
| 144 | name: IRAM_Parity_Code | ||
| 145 | range: | ||
| 146 | start: 0x20300000 | ||
| 147 | end: 0x20310000 | ||
| 148 | cores: | ||
| 149 | - main | ||
| 150 | - !Generic | ||
| 151 | name: NonMain_ECC | ||
| 152 | range: | ||
| 153 | start: 0x41c00000 | ||
| 154 | end: 0x41c00800 | ||
| 155 | cores: | ||
| 156 | - main | ||
| 157 | access: | ||
| 158 | write: false | ||
| 159 | execute: false | ||
| 160 | - !Generic | ||
| 161 | name: Factory_ECC | ||
| 162 | range: | ||
| 163 | start: 0x41c40000 | ||
| 164 | end: 0x41c40200 | ||
| 165 | cores: | ||
| 166 | - main | ||
| 167 | access: | ||
| 168 | write: false | ||
| 169 | execute: false | ||
| 170 | - !Generic | ||
| 171 | name: Data | ||
| 172 | range: | ||
| 173 | start: 0x41d00000 | ||
| 174 | end: 0x41d04000 | ||
| 175 | cores: | ||
| 176 | - main | ||
| 177 | access: | ||
| 178 | write: false | ||
| 179 | execute: false | ||
| 180 | flash_algorithms: | ||
| 181 | - mspm0gx51x_main_512kb | ||
| 182 | - mspm0gx51x_nonmain | ||
| 183 | - mspm0gx51x_data_16kb | ||
| 184 | - name: MSPM0G3518 | ||
| 185 | cores: | ||
| 186 | - name: main | ||
| 187 | type: armv6m | ||
| 188 | core_access_options: !Arm | ||
| 189 | ap: 0 | ||
| 190 | memory_map: | ||
| 191 | - !Nvm | ||
| 192 | name: IROM1 | ||
| 193 | range: | ||
| 194 | start: 0x0 | ||
| 195 | end: 0x40000 | ||
| 196 | cores: | ||
| 197 | - main | ||
| 198 | access: | ||
| 199 | write: false | ||
| 200 | boot: true | ||
| 201 | - !Generic | ||
| 202 | name: IROM2 | ||
| 203 | range: | ||
| 204 | start: 0x400000 | ||
| 205 | end: 0x440000 | ||
| 206 | cores: | ||
| 207 | - main | ||
| 208 | access: | ||
| 209 | write: false | ||
| 210 | - !Generic | ||
| 211 | name: IRAM1 | ||
| 212 | range: | ||
| 213 | start: 0x20000000 | ||
| 214 | end: 0x20010000 | ||
| 215 | cores: | ||
| 216 | - main | ||
| 217 | - !Generic | ||
| 218 | name: IRAM_Parity | ||
| 219 | range: | ||
| 220 | start: 0x20100000 | ||
| 221 | end: 0x20110000 | ||
| 222 | cores: | ||
| 223 | - main | ||
| 224 | - !Ram | ||
| 225 | name: IRAM_No_Parity | ||
| 226 | range: | ||
| 227 | start: 0x20200000 | ||
| 228 | end: 0x20220000 | ||
| 229 | cores: | ||
| 230 | - main | ||
| 231 | - !Generic | ||
| 232 | name: IRAM_Parity_Code | ||
| 233 | range: | ||
| 234 | start: 0x20300000 | ||
| 235 | end: 0x20310000 | ||
| 236 | cores: | ||
| 237 | - main | ||
| 238 | - !Generic | ||
| 239 | name: NonMain_ECC | ||
| 240 | range: | ||
| 241 | start: 0x41c00000 | ||
| 242 | end: 0x41c00800 | ||
| 243 | cores: | ||
| 244 | - main | ||
| 245 | access: | ||
| 246 | write: false | ||
| 247 | execute: false | ||
| 248 | - !Generic | ||
| 249 | name: Factory_ECC | ||
| 250 | range: | ||
| 251 | start: 0x41c40000 | ||
| 252 | end: 0x41c40200 | ||
| 253 | cores: | ||
| 254 | - main | ||
| 255 | access: | ||
| 256 | write: false | ||
| 257 | execute: false | ||
| 258 | - !Generic | ||
| 259 | name: Data | ||
| 260 | range: | ||
| 261 | start: 0x41d00000 | ||
| 262 | end: 0x41d04000 | ||
| 263 | cores: | ||
| 264 | - main | ||
| 265 | access: | ||
| 266 | write: false | ||
| 267 | execute: false | ||
| 268 | flash_algorithms: | ||
| 269 | - mspm0gx51x_main_512kb | ||
| 270 | - mspm0gx51x_nonmain | ||
| 271 | - mspm0gx51x_data_16kb | ||
| 272 | - name: MSPM0G3519 | ||
| 273 | cores: | ||
| 274 | - name: main | ||
| 275 | type: armv6m | ||
| 276 | core_access_options: !Arm | ||
| 277 | ap: 0 | ||
| 278 | memory_map: | ||
| 279 | - !Nvm | ||
| 280 | name: IROM1 | ||
| 281 | range: | ||
| 282 | start: 0x0 | ||
| 283 | end: 0x80000 | ||
| 284 | cores: | ||
| 285 | - main | ||
| 286 | access: | ||
| 287 | write: false | ||
| 288 | boot: true | ||
| 289 | - !Generic | ||
| 290 | name: IROM2 | ||
| 291 | range: | ||
| 292 | start: 0x400000 | ||
| 293 | end: 0x480000 | ||
| 294 | cores: | ||
| 295 | - main | ||
| 296 | access: | ||
| 297 | write: false | ||
| 298 | - !Generic | ||
| 299 | name: IRAM1 | ||
| 300 | range: | ||
| 301 | start: 0x20000000 | ||
| 302 | end: 0x20010000 | ||
| 303 | cores: | ||
| 304 | - main | ||
| 305 | - !Generic | ||
| 306 | name: IRAM_Parity | ||
| 307 | range: | ||
| 308 | start: 0x20100000 | ||
| 309 | end: 0x20110000 | ||
| 310 | cores: | ||
| 311 | - main | ||
| 312 | - !Ram | ||
| 313 | name: IRAM_No_Parity | ||
| 314 | range: | ||
| 315 | start: 0x20200000 | ||
| 316 | end: 0x20220000 | ||
| 317 | cores: | ||
| 318 | - main | ||
| 319 | - !Generic | ||
| 320 | name: IRAM_Parity_Code | ||
| 321 | range: | ||
| 322 | start: 0x20300000 | ||
| 323 | end: 0x20310000 | ||
| 324 | cores: | ||
| 325 | - main | ||
| 326 | - !Generic | ||
| 327 | name: NonMain_ECC | ||
| 328 | range: | ||
| 329 | start: 0x41c00000 | ||
| 330 | end: 0x41c00800 | ||
| 331 | cores: | ||
| 332 | - main | ||
| 333 | access: | ||
| 334 | write: false | ||
| 335 | execute: false | ||
| 336 | - !Generic | ||
| 337 | name: Factory_ECC | ||
| 338 | range: | ||
| 339 | start: 0x41c40000 | ||
| 340 | end: 0x41c40200 | ||
| 341 | cores: | ||
| 342 | - main | ||
| 343 | access: | ||
| 344 | write: false | ||
| 345 | execute: false | ||
| 346 | - !Generic | ||
| 347 | name: Data | ||
| 348 | range: | ||
| 349 | start: 0x41d00000 | ||
| 350 | end: 0x41d04000 | ||
| 351 | cores: | ||
| 352 | - main | ||
| 353 | access: | ||
| 354 | write: false | ||
| 355 | execute: false | ||
| 356 | flash_algorithms: | ||
| 357 | - mspm0gx51x_main_512kb | ||
| 358 | - mspm0gx51x_nonmain | ||
| 359 | - mspm0gx51x_data_16kb | ||
| 360 | flash_algorithms: | ||
| 361 | - name: mspm0gx51x_main_512kb | ||
| 362 | description: MSPM0GX51X MAIN 512KB | ||
| 363 | default: true | ||
| 364 | instructions: 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 | ||
| 365 | load_address: 0x20200008 | ||
| 366 | pc_init: 0x1d | ||
| 367 | pc_uninit: 0x99 | ||
| 368 | pc_program_page: 0x19d | ||
| 369 | pc_erase_sector: 0xcd | ||
| 370 | pc_erase_all: 0x9d | ||
| 371 | data_section_offset: 0x16e4 | ||
| 372 | flash_properties: | ||
| 373 | address_range: | ||
| 374 | start: 0x0 | ||
| 375 | end: 0x80000 | ||
| 376 | page_size: 0x400 | ||
| 377 | erased_byte_value: 0xff | ||
| 378 | program_page_timeout: 500 | ||
| 379 | erase_sector_timeout: 3000 | ||
| 380 | sectors: | ||
| 381 | - size: 0x400 | ||
| 382 | address: 0x0 | ||
| 383 | - name: mspm0gx51x_nonmain | ||
| 384 | description: MSPM0GX51X NON-MAIN | ||
| 385 | instructions: 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AAELQApJCmwAIAAqANBwRwhKEmhSB/rVCGjABQTUCGiABQPVAyBwRwIgcEcBIHBHAAELQBDtAOAHScprACABKgfRBkoSaFIHA9UIaIACAdUCIHBHASBwRwQBC0AQ7QDgELUISxxrASIiQAjRBkwgQBhgIUBZYNhqBEkBQ9liUEJQQRC9GCALQMD/PwAQAAB2ELUIS5xqASIiQAjRBkwgQBhgIUAZYFhqBEkBQ1liUEJQQRC9ICALQMD/PwBAAAB2ACIDCYtCLNMDCotCEdMAI5xGTuADRgtDPNQAIkMIi0Ix0wMJi0Ic0wMKi0IB05RGP+DDCYtCAdPLAcAaUkGDCYtCAdOLAcAaUkFDCYtCAdNLAcAaUkEDCYtCAdMLAcAaUkHDCItCAdPLAMAaUkGDCItCAdOLAMAaUkFDCItCAdNLAMAaUkFBGgDSAUZSQRBGcEdd4MoPANBJQgMQANNAQlNAnEYAIgMJi0It0wMKi0IS04kB/CISugMKi0IM04kBkhGLQgjTiQGSEYtCBNOJATrQkhEA4IkJwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJB2dJDCItCAdNLAMAaUkFBGgDSAUZSQRBGY0ZbEAHTQEIAKwDVSUJwR2NGWxAA00BCAbUFSQAoAtxJHAhAAOAIRsBGwEYCvQC/////fwAAAAS7qruqu6q7qv//////////u6q7qruqu6r//7uqu6q7qv///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////9B/+hoAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEFgIVAgEDAgOoEv//r5YTdg9yY1+9tEpaCmPDnxKvMPlQpu5clxvhiOicQFH/////////////////////////////////////////////SADJWPEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA== | ||
| 386 | load_address: 0x20200008 | ||
| 387 | pc_init: 0x1d | ||
| 388 | pc_uninit: 0xb5 | ||
| 389 | pc_program_page: 0x1a9 | ||
| 390 | pc_erase_sector: 0x159 | ||
| 391 | pc_erase_all: 0x211 | ||
| 392 | data_section_offset: 0x1b84 | ||
| 393 | flash_properties: | ||
| 394 | address_range: | ||
| 395 | start: 0x41c00000 | ||
| 396 | end: 0x41c00400 | ||
| 397 | page_size: 0x40 | ||
| 398 | erased_byte_value: 0xff | ||
| 399 | program_page_timeout: 500 | ||
| 400 | erase_sector_timeout: 3000 | ||
| 401 | sectors: | ||
| 402 | - size: 0x400 | ||
| 403 | address: 0x0 | ||
| 404 | - name: mspm0gx51x_data_16kb | ||
| 405 | description: MSPM0GX51X DATA 16KB | ||
| 406 | instructions: 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 | ||
| 407 | load_address: 0x20200008 | ||
| 408 | pc_init: 0x1d | ||
| 409 | pc_uninit: 0x99 | ||
| 410 | pc_program_page: 0x19d | ||
| 411 | pc_erase_sector: 0xcd | ||
| 412 | pc_erase_all: 0x9d | ||
| 413 | data_section_offset: 0x16e4 | ||
| 414 | flash_properties: | ||
| 415 | address_range: | ||
| 416 | start: 0x0 | ||
| 417 | end: 0x4000 | ||
| 418 | page_size: 0x400 | ||
| 419 | erased_byte_value: 0xff | ||
| 420 | program_page_timeout: 500 | ||
| 421 | erase_sector_timeout: 3000 | ||
| 422 | sectors: | ||
| 423 | - size: 0x400 | ||
| 424 | address: 0x0 | ||
diff --git a/examples/mspm0g3519/README.md b/examples/mspm0g3519/README.md new file mode 100644 index 000000000..5034b1913 --- /dev/null +++ b/examples/mspm0g3519/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # Examples for MSPM0G351x family | ||
| 2 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0G3519](https://www.ti.com/tool/LP-MSPM0G3519) board. | ||
| 14 | |||
| 15 | 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. | ||
| 16 | |||
| 17 | * [ ] 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) | ||
| 18 | * [ ] 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. | ||
| 19 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 20 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 21 | |||
| 22 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 23 | |||
| 24 | * Which example you are trying to run | ||
| 25 | * Which chip and board you are using | ||
| 26 | |||
| 27 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/mspm0g3519/build.rs b/examples/mspm0g3519/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0g3519/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/mspm0g3519/memory.x b/examples/mspm0g3519/memory.x new file mode 100644 index 000000000..e6e0ec9e9 --- /dev/null +++ b/examples/mspm0g3519/memory.x | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 512K | ||
| 4 | /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ | ||
| 5 | RAM : ORIGIN = 0x20200000, LENGTH = 128K | ||
| 6 | } | ||
diff --git a/examples/mspm0g3519/src/bin/blinky.rs b/examples/mspm0g3519/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0g3519/src/bin/blinky.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Level, Output}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_halt as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) -> ! { | ||
| 15 | info!("Hello world!"); | ||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let mut led1 = Output::new(p.PA0, Level::Low); | ||
| 19 | led1.set_inversion(true); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | Timer::after_millis(400).await; | ||
| 23 | |||
| 24 | info!("Toggle"); | ||
| 25 | led1.toggle(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/mspm0g3519/src/bin/button.rs b/examples/mspm0g3519/src/bin/button.rs new file mode 100644 index 000000000..2bdb2bcb1 --- /dev/null +++ b/examples/mspm0g3519/src/bin/button.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Input, Level, Output, Pull}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use {defmt_rtt as _, panic_halt as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) -> ! { | ||
| 14 | info!("Hello world!"); | ||
| 15 | |||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let led1 = p.PA0; | ||
| 19 | let s2 = p.PB3; | ||
| 20 | |||
| 21 | let mut led1 = Output::new(led1, Level::Low); | ||
| 22 | |||
| 23 | let mut s2 = Input::new(s2, Pull::Up); | ||
| 24 | |||
| 25 | // led1 is active low | ||
| 26 | led1.set_high(); | ||
| 27 | |||
| 28 | loop { | ||
| 29 | s2.wait_for_falling_edge().await; | ||
| 30 | |||
| 31 | info!("Switch 2 was pressed"); | ||
| 32 | |||
| 33 | led1.toggle(); | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/mspm0l1306/.cargo/config.toml b/examples/mspm0l1306/.cargo/config.toml new file mode 100644 index 000000000..93f148a71 --- /dev/null +++ b/examples/mspm0l1306/.cargo/config.toml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace MSPM0L1306 with your chip as listed in `probe-rs chip list` | ||
| 3 | runner = "probe-rs run --chip MSPM0L1306 --protocol=swd" | ||
| 4 | |||
| 5 | [build] | ||
| 6 | target = "thumbv6m-none-eabi" | ||
| 7 | |||
| 8 | [env] | ||
| 9 | DEFMT_LOG = "trace" | ||
diff --git a/examples/mspm0l1306/Cargo.toml b/examples/mspm0l1306/Cargo.toml new file mode 100644 index 000000000..6b87916b8 --- /dev/null +++ b/examples/mspm0l1306/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-mspm0-l1306-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l130x", "rt", "time-driver-any"] } | ||
| 9 | embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 10 | embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 12 | panic-halt = "0.2.0" | ||
| 13 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 14 | cortex-m-rt = { version = "0.7.0"} | ||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3.2", features = ["print-defmt"] } | ||
| 18 | panic-semihosting = "0.6.0" | ||
| 19 | |||
| 20 | [profile.release] | ||
| 21 | debug = 2 | ||
diff --git a/examples/mspm0l1306/README.md b/examples/mspm0l1306/README.md new file mode 100644 index 000000000..5a55d721e --- /dev/null +++ b/examples/mspm0l1306/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # Examples for MSPM0L130x family | ||
| 2 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0L1306](https://www.ti.com/tool/LP-MSPM0L1306) board. | ||
| 14 | |||
| 15 | 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. | ||
| 16 | |||
| 17 | * [ ] 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) | ||
| 18 | * [ ] 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. | ||
| 19 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 20 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 21 | |||
| 22 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 23 | |||
| 24 | * Which example you are trying to run | ||
| 25 | * Which chip and board you are using | ||
| 26 | |||
| 27 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/mspm0l1306/build.rs b/examples/mspm0l1306/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0l1306/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/mspm0l1306/memory.x b/examples/mspm0l1306/memory.x new file mode 100644 index 000000000..d93b61f44 --- /dev/null +++ b/examples/mspm0l1306/memory.x | |||
| @@ -0,0 +1,5 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 64K | ||
| 4 | RAM : ORIGIN = 0x20000000, LENGTH = 4K | ||
| 5 | } | ||
diff --git a/examples/mspm0l1306/src/bin/blinky.rs b/examples/mspm0l1306/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0l1306/src/bin/blinky.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Level, Output}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_halt as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) -> ! { | ||
| 15 | info!("Hello world!"); | ||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let mut led1 = Output::new(p.PA0, Level::Low); | ||
| 19 | led1.set_inversion(true); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | Timer::after_millis(400).await; | ||
| 23 | |||
| 24 | info!("Toggle"); | ||
| 25 | led1.toggle(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/mspm0l1306/src/bin/button.rs b/examples/mspm0l1306/src/bin/button.rs new file mode 100644 index 000000000..2813518c2 --- /dev/null +++ b/examples/mspm0l1306/src/bin/button.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Input, Level, Output, Pull}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use {defmt_rtt as _, panic_halt as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) -> ! { | ||
| 14 | info!("Hello world!"); | ||
| 15 | |||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let led1 = p.PA0; | ||
| 19 | let s2 = p.PA14; | ||
| 20 | |||
| 21 | let mut led1 = Output::new(led1, Level::Low); | ||
| 22 | |||
| 23 | let mut s2 = Input::new(s2, Pull::Up); | ||
| 24 | |||
| 25 | // led1 is active low | ||
| 26 | led1.set_high(); | ||
| 27 | |||
| 28 | loop { | ||
| 29 | s2.wait_for_falling_edge().await; | ||
| 30 | |||
| 31 | info!("Switch 2 was pressed"); | ||
| 32 | |||
| 33 | led1.toggle(); | ||
| 34 | } | ||
| 35 | } | ||
diff --git a/examples/mspm0l2228/.cargo/config.toml b/examples/mspm0l2228/.cargo/config.toml new file mode 100644 index 000000000..4284749e9 --- /dev/null +++ b/examples/mspm0l2228/.cargo/config.toml | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | [target.'cfg(all(target_arch = "arm", target_os = "none"))'] | ||
| 2 | # replace MSPM0L2228 with your chip as listed in `probe-rs chip list` | ||
| 3 | # TODO: Remove description path after new chiptool release | ||
| 4 | runner = "probe-rs run --restore-unwritten --verify --chip MSPM0L2228 --protocol=swd --chip-description-path ./MSPM0L122X_L222X_Series.yaml" | ||
| 5 | |||
| 6 | [build] | ||
| 7 | target = "thumbv6m-none-eabi" | ||
| 8 | |||
| 9 | [env] | ||
| 10 | DEFMT_LOG = "trace" | ||
diff --git a/examples/mspm0l2228/Cargo.toml b/examples/mspm0l2228/Cargo.toml new file mode 100644 index 000000000..9474c2ced --- /dev/null +++ b/examples/mspm0l2228/Cargo.toml | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | [package] | ||
| 2 | edition = "2021" | ||
| 3 | name = "embassy-mspm0-l2228-examples" | ||
| 4 | version = "0.1.0" | ||
| 5 | license = "MIT OR Apache-2.0" | ||
| 6 | |||
| 7 | [dependencies] | ||
| 8 | embassy-mspm0 = { version = "0.1.0", path = "../../embassy-mspm0", features = ["mspm0l222x", "rt", "time-driver-any"] } | ||
| 9 | embassy-executor = { version = "0.7.0", path = "../../embassy-executor", features = ["task-arena-size-1024", "arch-cortex-m", "executor-thread", "executor-interrupt"] } | ||
| 10 | embassy-sync = { version = "0.6.2", path = "../../embassy-sync", features = ["defmt"] } | ||
| 11 | embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt"] } | ||
| 12 | panic-halt = "0.2.0" | ||
| 13 | cortex-m = { version = "0.7.6", features = ["inline-asm", "critical-section-single-core"] } | ||
| 14 | cortex-m-rt = { version = "0.7.0"} | ||
| 15 | defmt = "0.3" | ||
| 16 | defmt-rtt = "0.4" | ||
| 17 | panic-probe = { version = "0.3.2", features = ["print-defmt"] } | ||
| 18 | panic-semihosting = "0.6.0" | ||
| 19 | |||
| 20 | [profile.release] | ||
| 21 | debug = 2 | ||
diff --git a/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml b/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml new file mode 100644 index 000000000..ac52fda2e --- /dev/null +++ b/examples/mspm0l2228/MSPM0L122X_L222X_Series.yaml | |||
| @@ -0,0 +1,239 @@ | |||
| 1 | name: MSPM0L122X_L222X Series | ||
| 2 | manufacturer: | ||
| 3 | id: 0x17 | ||
| 4 | cc: 0x0 | ||
| 5 | generated_from_pack: true | ||
| 6 | pack_file_release: 1.1.1 | ||
| 7 | variants: | ||
| 8 | - name: MSPM0L1227 | ||
| 9 | cores: | ||
| 10 | - name: main | ||
| 11 | type: armv6m | ||
| 12 | core_access_options: !Arm | ||
| 13 | ap: 0 | ||
| 14 | memory_map: | ||
| 15 | - !Nvm | ||
| 16 | name: IROM1 | ||
| 17 | range: | ||
| 18 | start: 0x0 | ||
| 19 | end: 0x20000 | ||
| 20 | cores: | ||
| 21 | - main | ||
| 22 | access: | ||
| 23 | write: false | ||
| 24 | boot: true | ||
| 25 | - !Ram | ||
| 26 | name: IRAM1 | ||
| 27 | range: | ||
| 28 | start: 0x20200000 | ||
| 29 | end: 0x20208000 | ||
| 30 | cores: | ||
| 31 | - main | ||
| 32 | - !Generic | ||
| 33 | name: NonMain | ||
| 34 | range: | ||
| 35 | start: 0x41c00000 | ||
| 36 | end: 0x41c00200 | ||
| 37 | cores: | ||
| 38 | - main | ||
| 39 | access: | ||
| 40 | write: false | ||
| 41 | execute: false | ||
| 42 | - !Generic | ||
| 43 | name: Factory | ||
| 44 | range: | ||
| 45 | start: 0x41c40000 | ||
| 46 | end: 0x41c40080 | ||
| 47 | cores: | ||
| 48 | - main | ||
| 49 | access: | ||
| 50 | write: false | ||
| 51 | execute: false | ||
| 52 | flash_algorithms: | ||
| 53 | - mspm0l122x_l222x_main_256kb | ||
| 54 | - mspm0l122x_l222x_nonmain | ||
| 55 | - name: MSPM0L1228 | ||
| 56 | cores: | ||
| 57 | - name: main | ||
| 58 | type: armv6m | ||
| 59 | core_access_options: !Arm | ||
| 60 | ap: 0 | ||
| 61 | memory_map: | ||
| 62 | - !Nvm | ||
| 63 | name: IROM1 | ||
| 64 | range: | ||
| 65 | start: 0x0 | ||
| 66 | end: 0x40000 | ||
| 67 | cores: | ||
| 68 | - main | ||
| 69 | access: | ||
| 70 | write: false | ||
| 71 | boot: true | ||
| 72 | - !Ram | ||
| 73 | name: IRAM1 | ||
| 74 | range: | ||
| 75 | start: 0x20200000 | ||
| 76 | end: 0x20208000 | ||
| 77 | cores: | ||
| 78 | - main | ||
| 79 | - !Generic | ||
| 80 | name: NonMain | ||
| 81 | range: | ||
| 82 | start: 0x41c00000 | ||
| 83 | end: 0x41c00200 | ||
| 84 | cores: | ||
| 85 | - main | ||
| 86 | access: | ||
| 87 | write: false | ||
| 88 | execute: false | ||
| 89 | - !Generic | ||
| 90 | name: Factory | ||
| 91 | range: | ||
| 92 | start: 0x41c40000 | ||
| 93 | end: 0x41c40080 | ||
| 94 | cores: | ||
| 95 | - main | ||
| 96 | access: | ||
| 97 | write: false | ||
| 98 | execute: false | ||
| 99 | flash_algorithms: | ||
| 100 | - mspm0l122x_l222x_main_256kb | ||
| 101 | - mspm0l122x_l222x_nonmain | ||
| 102 | - name: MSPM0L2227 | ||
| 103 | cores: | ||
| 104 | - name: main | ||
| 105 | type: armv6m | ||
| 106 | core_access_options: !Arm | ||
| 107 | ap: 0 | ||
| 108 | memory_map: | ||
| 109 | - !Nvm | ||
| 110 | name: IROM1 | ||
| 111 | range: | ||
| 112 | start: 0x0 | ||
| 113 | end: 0x20000 | ||
| 114 | cores: | ||
| 115 | - main | ||
| 116 | access: | ||
| 117 | write: false | ||
| 118 | boot: true | ||
| 119 | - !Ram | ||
| 120 | name: IRAM1 | ||
| 121 | range: | ||
| 122 | start: 0x20200000 | ||
| 123 | end: 0x20208000 | ||
| 124 | cores: | ||
| 125 | - main | ||
| 126 | - !Generic | ||
| 127 | name: NonMain | ||
| 128 | range: | ||
| 129 | start: 0x41c00000 | ||
| 130 | end: 0x41c00200 | ||
| 131 | cores: | ||
| 132 | - main | ||
| 133 | access: | ||
| 134 | write: false | ||
| 135 | execute: false | ||
| 136 | - !Generic | ||
| 137 | name: Factory | ||
| 138 | range: | ||
| 139 | start: 0x41c40000 | ||
| 140 | end: 0x41c40080 | ||
| 141 | cores: | ||
| 142 | - main | ||
| 143 | access: | ||
| 144 | write: false | ||
| 145 | execute: false | ||
| 146 | flash_algorithms: | ||
| 147 | - mspm0l122x_l222x_main_256kb | ||
| 148 | - mspm0l122x_l222x_nonmain | ||
| 149 | - name: MSPM0L2228 | ||
| 150 | cores: | ||
| 151 | - name: main | ||
| 152 | type: armv6m | ||
| 153 | core_access_options: !Arm | ||
| 154 | ap: 0 | ||
| 155 | memory_map: | ||
| 156 | - !Nvm | ||
| 157 | name: IROM1 | ||
| 158 | range: | ||
| 159 | start: 0x0 | ||
| 160 | end: 0x40000 | ||
| 161 | cores: | ||
| 162 | - main | ||
| 163 | access: | ||
| 164 | write: false | ||
| 165 | boot: true | ||
| 166 | - !Ram | ||
| 167 | name: IRAM1 | ||
| 168 | range: | ||
| 169 | start: 0x20200000 | ||
| 170 | end: 0x20208000 | ||
| 171 | cores: | ||
| 172 | - main | ||
| 173 | - !Generic | ||
| 174 | name: NonMain | ||
| 175 | range: | ||
| 176 | start: 0x41c00000 | ||
| 177 | end: 0x41c00200 | ||
| 178 | cores: | ||
| 179 | - main | ||
| 180 | access: | ||
| 181 | write: false | ||
| 182 | execute: false | ||
| 183 | - !Generic | ||
| 184 | name: Factory | ||
| 185 | range: | ||
| 186 | start: 0x41c40000 | ||
| 187 | end: 0x41c40080 | ||
| 188 | cores: | ||
| 189 | - main | ||
| 190 | access: | ||
| 191 | write: false | ||
| 192 | execute: false | ||
| 193 | flash_algorithms: | ||
| 194 | - mspm0l122x_l222x_main_256kb | ||
| 195 | - mspm0l122x_l222x_nonmain | ||
| 196 | flash_algorithms: | ||
| 197 | - name: mspm0l122x_l222x_main_256kb | ||
| 198 | description: MSPM0L122X_222X MAIN 256KB | ||
| 199 | default: true | ||
| 200 | instructions: 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 | ||
| 201 | load_address: 0x20200008 | ||
| 202 | pc_init: 0x1d | ||
| 203 | pc_uninit: 0x5d | ||
| 204 | pc_program_page: 0x145 | ||
| 205 | pc_erase_sector: 0x61 | ||
| 206 | pc_erase_all: 0x131 | ||
| 207 | data_section_offset: 0x12dc | ||
| 208 | flash_properties: | ||
| 209 | address_range: | ||
| 210 | start: 0x0 | ||
| 211 | end: 0x40000 | ||
| 212 | page_size: 0x400 | ||
| 213 | erased_byte_value: 0xff | ||
| 214 | program_page_timeout: 500 | ||
| 215 | erase_sector_timeout: 3000 | ||
| 216 | sectors: | ||
| 217 | - size: 0x400 | ||
| 218 | address: 0x0 | ||
| 219 | - name: mspm0l122x_l222x_nonmain | ||
| 220 | description: MSPM0L122X_222X NON-MAIN | ||
| 221 | instructions: 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A0gBaIkD/NRwR8BGAAELQAQCC0ABIAAEBEkKaIJDCmADSAFoyQb81HBHwEYEAQtABAILQAAiAwmLQizTAwqLQhHTACOcRk7gA0YLQzzUACJDCItCMdMDCYtCHNMDCotCAdOURj/gwwmLQgHTywHAGlJBgwmLQgHTiwHAGlJBQwmLQgHTSwHAGlJBAwmLQgHTCwHAGlJBwwiLQgHTywDAGlJBgwiLQgHTiwDAGlJBQwiLQgHTSwDAGlJBQRoA0gFGUkEQRnBHXeDKDwDQSUIDEADTQEJTQJxGACIDCYtCLdMDCotCEtOJAfwiEroDCotCDNOJAZIRi0II04kBkhGLQgTTiQE60JIRAOCJCcMJi0IB08sBwBpSQYMJi0IB04sBwBpSQUMJi0IB00sBwBpSQQMJi0IB0wsBwBpSQcMIi0IB08sAwBpSQYMIi0IB04sAwBpSQdnSQwiLQgHTSwDAGlJBQRoA0gFGUkEQRmNGWxAB00BCACsA1UlCcEdjRlsQANNAQgG1BUkAKALcSRwIQADgCEbARsBGAr0Av////38CAAABu6q7qruqu6r//////////7uqu6q7qruq//+7qruqu6r///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////+yIGk/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAABoCGQIBAwIDshL//6+WE3YPcmNfvbRKWgpjw58SrzD5UKbuXJcb4YjonEBR/////////////////////////////////////////////0gA0UsBbwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= | ||
| 222 | load_address: 0x20200008 | ||
| 223 | pc_init: 0x1d | ||
| 224 | pc_uninit: 0x7d | ||
| 225 | pc_program_page: 0x18d | ||
| 226 | pc_erase_sector: 0x121 | ||
| 227 | pc_erase_all: 0x79 | ||
| 228 | data_section_offset: 0x1774 | ||
| 229 | flash_properties: | ||
| 230 | address_range: | ||
| 231 | start: 0x41c00000 | ||
| 232 | end: 0x41c00200 | ||
| 233 | page_size: 0x40 | ||
| 234 | erased_byte_value: 0xff | ||
| 235 | program_page_timeout: 500 | ||
| 236 | erase_sector_timeout: 3000 | ||
| 237 | sectors: | ||
| 238 | - size: 0x200 | ||
| 239 | address: 0x0 | ||
diff --git a/examples/mspm0l2228/README.md b/examples/mspm0l2228/README.md new file mode 100644 index 000000000..c73fa13b6 --- /dev/null +++ b/examples/mspm0l2228/README.md | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | # Examples for MSPM0L222x family | ||
| 2 | |||
| 3 | Run individual examples with | ||
| 4 | ``` | ||
| 5 | cargo run --bin <module-name> | ||
| 6 | ``` | ||
| 7 | for example | ||
| 8 | ``` | ||
| 9 | cargo run --bin blinky | ||
| 10 | ``` | ||
| 11 | |||
| 12 | ## Checklist before running examples | ||
| 13 | A large number of the examples are written for the [LP-MSPM0L2228](https://www.ti.com/tool/LP-MSPM0L2228) board. | ||
| 14 | |||
| 15 | 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. | ||
| 16 | |||
| 17 | * [ ] 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) | ||
| 18 | * [ ] 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. | ||
| 19 | * [ ] If your board has a special clock or power configuration, make sure that it is set up appropriately. | ||
| 20 | * [ ] If your board has different pin mapping, update any pin numbers or peripherals in the given example code to match your schematic | ||
| 21 | |||
| 22 | If you are unsure, please drop by the Embassy Matrix chat for support, and let us know: | ||
| 23 | |||
| 24 | * Which example you are trying to run | ||
| 25 | * Which chip and board you are using | ||
| 26 | |||
| 27 | Embassy Chat: https://matrix.to/#/#embassy-rs:matrix.org | ||
diff --git a/examples/mspm0l2228/build.rs b/examples/mspm0l2228/build.rs new file mode 100644 index 000000000..30691aa97 --- /dev/null +++ b/examples/mspm0l2228/build.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | //! This build script copies the `memory.x` file from the crate root into | ||
| 2 | //! a directory where the linker can always find it at build time. | ||
| 3 | //! For many projects this is optional, as the linker always searches the | ||
| 4 | //! project root directory -- wherever `Cargo.toml` is. However, if you | ||
| 5 | //! are using a workspace or have a more complicated build setup, this | ||
| 6 | //! build script becomes required. Additionally, by requesting that | ||
| 7 | //! Cargo re-run the build script whenever `memory.x` is changed, | ||
| 8 | //! updating `memory.x` ensures a rebuild of the application with the | ||
| 9 | //! new memory settings. | ||
| 10 | |||
| 11 | use std::env; | ||
| 12 | use std::fs::File; | ||
| 13 | use std::io::Write; | ||
| 14 | use std::path::PathBuf; | ||
| 15 | |||
| 16 | fn main() { | ||
| 17 | // Put `memory.x` in our output directory and ensure it's | ||
| 18 | // on the linker search path. | ||
| 19 | let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap()); | ||
| 20 | File::create(out.join("memory.x")) | ||
| 21 | .unwrap() | ||
| 22 | .write_all(include_bytes!("memory.x")) | ||
| 23 | .unwrap(); | ||
| 24 | println!("cargo:rustc-link-search={}", out.display()); | ||
| 25 | |||
| 26 | // By default, Cargo will re-run a build script whenever | ||
| 27 | // any file in the project changes. By specifying `memory.x` | ||
| 28 | // here, we ensure the build script is only re-run when | ||
| 29 | // `memory.x` is changed. | ||
| 30 | println!("cargo:rerun-if-changed=memory.x"); | ||
| 31 | |||
| 32 | println!("cargo:rustc-link-arg-bins=--nmagic"); | ||
| 33 | println!("cargo:rustc-link-arg-bins=-Tlink.x"); | ||
| 34 | println!("cargo:rustc-link-arg-bins=-Tdefmt.x"); | ||
| 35 | } | ||
diff --git a/examples/mspm0l2228/memory.x b/examples/mspm0l2228/memory.x new file mode 100644 index 000000000..aba414a88 --- /dev/null +++ b/examples/mspm0l2228/memory.x | |||
| @@ -0,0 +1,6 @@ | |||
| 1 | MEMORY | ||
| 2 | { | ||
| 3 | FLASH : ORIGIN = 0x00000000, LENGTH = 256K | ||
| 4 | /* Select non-parity range of SRAM due to SRAM_ERR_01 errata in SLAZ758 */ | ||
| 5 | RAM : ORIGIN = 0x20200000, LENGTH = 32K | ||
| 6 | } | ||
diff --git a/examples/mspm0l2228/src/bin/blinky.rs b/examples/mspm0l2228/src/bin/blinky.rs new file mode 100644 index 000000000..11eee2d80 --- /dev/null +++ b/examples/mspm0l2228/src/bin/blinky.rs | |||
| @@ -0,0 +1,27 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Level, Output}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use embassy_time::Timer; | ||
| 11 | use {defmt_rtt as _, panic_halt as _}; | ||
| 12 | |||
| 13 | #[embassy_executor::main] | ||
| 14 | async fn main(_spawner: Spawner) -> ! { | ||
| 15 | info!("Hello world!"); | ||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let mut led1 = Output::new(p.PA0, Level::Low); | ||
| 19 | led1.set_inversion(true); | ||
| 20 | |||
| 21 | loop { | ||
| 22 | Timer::after_millis(400).await; | ||
| 23 | |||
| 24 | info!("Toggle"); | ||
| 25 | led1.toggle(); | ||
| 26 | } | ||
| 27 | } | ||
diff --git a/examples/mspm0l2228/src/bin/button.rs b/examples/mspm0l2228/src/bin/button.rs new file mode 100644 index 000000000..f26929dde --- /dev/null +++ b/examples/mspm0l2228/src/bin/button.rs | |||
| @@ -0,0 +1,35 @@ | |||
| 1 | #![no_std] | ||
| 2 | #![no_main] | ||
| 3 | |||
| 4 | use defmt::*; | ||
| 5 | use embassy_executor::Spawner; | ||
| 6 | use embassy_mspm0::{ | ||
| 7 | gpio::{Input, Level, Output, Pull}, | ||
| 8 | Config, | ||
| 9 | }; | ||
| 10 | use {defmt_rtt as _, panic_halt as _}; | ||
| 11 | |||
| 12 | #[embassy_executor::main] | ||
| 13 | async fn main(_spawner: Spawner) -> ! { | ||
| 14 | info!("Hello world!"); | ||
| 15 | |||
| 16 | let p = embassy_mspm0::init(Config::default()); | ||
| 17 | |||
| 18 | let led1 = p.PA0; | ||
| 19 | let s2 = p.PB8; | ||
| 20 | |||
| 21 | let mut led1 = Output::new(led1, Level::Low); | ||
| 22 | |||
| 23 | let mut s2 = Input::new(s2, Pull::Up); | ||
| 24 | |||
| 25 | // led1 is active low | ||
| 26 | led1.set_high(); | ||
| 27 | |||
| 28 | loop { | ||
| 29 | s2.wait_for_falling_edge().await; | ||
| 30 | |||
| 31 | info!("Switch 2 was pressed"); | ||
| 32 | |||
| 33 | led1.toggle(); | ||
| 34 | } | ||
| 35 | } | ||
