mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-12-26 03:49:34 +01:00
Auto merge of #50 - japaric:singletons, r=japaric
Peripherals as scoped singletons See this RFC for details: japaric/svd2rust#157 - The first commit adapts this crate to the changes in japaric/cortex-m#65 and japaric/svd2rust#158 - ~~The second commit is an alternative implementation of RFC #47 (there's another implementation in #49. This second commit is not required for RFC157 but let us experiment with safe DMA abstractions.~~ postponed ### TODO - [x] un-bless peripherals as resources. Peripherals as resources were special cased: if resource listed in e.g. `app.tasks.FOO.resources` didn't appear in `app.resources` then it was assumed to be a peripheral and special code was generated for it. This is no longer required under RFC157. ~~This depends on PR japaric/rtfm-syntax#2~~ postponed
This commit is contained in:
commit
e78ca98c42
7 changed files with 176 additions and 233 deletions
|
@ -10,13 +10,13 @@ keywords = ["arm", "cortex-m"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "cortex-m-rtfm"
|
name = "cortex-m-rtfm"
|
||||||
repository = "https://github.com/japaric/cortex-m-rtfm"
|
repository = "https://github.com/japaric/cortex-m-rtfm"
|
||||||
version = "0.2.2"
|
version = "0.3.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cortex-m = "0.3.1"
|
cortex-m = { git = "https://github.com/japaric/cortex-m" }
|
||||||
untagged-option = "0.1.1"
|
untagged-option = "0.1.1"
|
||||||
rtfm-core = "0.1.0"
|
rtfm-core = "0.1.0"
|
||||||
cortex-m-rtfm-macros = "0.2.1"
|
cortex-m-rtfm-macros = { path = "macros" }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
|
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]
|
||||||
compiletest_rs = "0.3.3"
|
compiletest_rs = "0.3.3"
|
||||||
|
@ -27,7 +27,8 @@ version = "0.3.3"
|
||||||
|
|
||||||
[dev-dependencies.stm32f103xx]
|
[dev-dependencies.stm32f103xx]
|
||||||
features = ["rt"]
|
features = ["rt"]
|
||||||
version = "0.7.5"
|
git = "https://github.com/japaric/stm32f103xx"
|
||||||
|
# version = "0.8.0"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
lto = true
|
lto = true
|
||||||
|
|
|
@ -12,6 +12,11 @@ use stm32f103xx::{SPI1, GPIOA};
|
||||||
app! {
|
app! {
|
||||||
device: stm32f103xx,
|
device: stm32f103xx,
|
||||||
|
|
||||||
|
resources: {
|
||||||
|
static GPIOA: GPIOA;
|
||||||
|
static SPI1: SPI1;
|
||||||
|
},
|
||||||
|
|
||||||
tasks: {
|
tasks: {
|
||||||
EXTI0: {
|
EXTI0: {
|
||||||
path: exti0,
|
path: exti0,
|
||||||
|
@ -27,7 +32,12 @@ app! {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(_p: init::Peripherals) {}
|
fn init(p: init::Peripherals) -> init::LateResourceValues {
|
||||||
|
init::LateResourceValues {
|
||||||
|
GPIOA: p.device.GPIOA,
|
||||||
|
SPI1: p.device.SPI1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn idle() -> ! {
|
fn idle() -> ! {
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -7,8 +7,9 @@ extern crate cortex_m;
|
||||||
extern crate cortex_m_rtfm as rtfm;
|
extern crate cortex_m_rtfm as rtfm;
|
||||||
extern crate stm32f103xx;
|
extern crate stm32f103xx;
|
||||||
|
|
||||||
use cortex_m::peripheral::SystClkSource;
|
use cortex_m::peripheral::syst::SystClkSource;
|
||||||
use rtfm::{app, Threshold};
|
use rtfm::{app, Threshold};
|
||||||
|
use stm32f103xx::GPIOC;
|
||||||
|
|
||||||
app! {
|
app! {
|
||||||
device: stm32f103xx,
|
device: stm32f103xx,
|
||||||
|
@ -35,9 +36,8 @@ app! {
|
||||||
|
|
||||||
// These are the resources this task has access to.
|
// These are the resources this task has access to.
|
||||||
//
|
//
|
||||||
// A resource can be a peripheral like `GPIOC` or a static variable
|
// The resources listed here must also appear in `app.resources`
|
||||||
// like `ON`
|
resources: [ON],
|
||||||
resources: [GPIOC, ON],
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,19 +47,20 @@ fn init(p: init::Peripherals, r: init::Resources) {
|
||||||
r.ON;
|
r.ON;
|
||||||
|
|
||||||
// power on GPIOC
|
// power on GPIOC
|
||||||
p.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
|
p.device.RCC.apb2enr.modify(|_, w| w.iopcen().enabled());
|
||||||
|
|
||||||
// configure PC13 as output
|
// configure PC13 as output
|
||||||
p.GPIOC.bsrr.write(|w| w.bs13().set());
|
p.device.GPIOC.bsrr.write(|w| w.bs13().set());
|
||||||
p.GPIOC
|
p.device
|
||||||
|
.GPIOC
|
||||||
.crh
|
.crh
|
||||||
.modify(|_, w| w.mode13().output().cnf13().push());
|
.modify(|_, w| w.mode13().output().cnf13().push());
|
||||||
|
|
||||||
// configure the system timer to generate one interrupt every second
|
// configure the system timer to generate one interrupt every second
|
||||||
p.SYST.set_clock_source(SystClkSource::Core);
|
p.core.SYST.set_clock_source(SystClkSource::Core);
|
||||||
p.SYST.set_reload(8_000_000); // 1s
|
p.core.SYST.set_reload(8_000_000); // 1s
|
||||||
p.SYST.enable_interrupt();
|
p.core.SYST.enable_interrupt();
|
||||||
p.SYST.enable_counter();
|
p.core.SYST.enable_counter();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idle() -> ! {
|
fn idle() -> ! {
|
||||||
|
@ -74,15 +75,22 @@ fn idle() -> ! {
|
||||||
//
|
//
|
||||||
// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
|
// `r` is the set of resources this task has access to. `SYS_TICK::Resources`
|
||||||
// has one field per resource declared in `app!`.
|
// has one field per resource declared in `app!`.
|
||||||
|
#[allow(unsafe_code)]
|
||||||
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
|
fn sys_tick(_t: &mut Threshold, r: SYS_TICK::Resources) {
|
||||||
// toggle state
|
// toggle state
|
||||||
**r.ON = !**r.ON;
|
**r.ON = !**r.ON;
|
||||||
|
|
||||||
if **r.ON {
|
if **r.ON {
|
||||||
// set the pin PC13 high
|
// set the pin PC13 high
|
||||||
r.GPIOC.bsrr.write(|w| w.bs13().set());
|
// NOTE(unsafe) atomic write to a stateless register
|
||||||
|
unsafe {
|
||||||
|
(*GPIOC::ptr()).bsrr.write(|w| w.bs13().set());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// set the pin PC13 low
|
// set the pin PC13 low
|
||||||
r.GPIOC.bsrr.write(|w| w.br13().reset());
|
// NOTE(unsafe) atomic write to a stateless register
|
||||||
|
unsafe {
|
||||||
|
(*GPIOC::ptr()).bsrr.write(|w| w.br13().reset());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,9 @@ app! {
|
||||||
// this function.
|
// this function.
|
||||||
fn init(p: init::Peripherals) {
|
fn init(p: init::Peripherals) {
|
||||||
// This function has access to all the peripherals of the device
|
// This function has access to all the peripherals of the device
|
||||||
p.GPIOA;
|
p.core.SYST;
|
||||||
p.RCC;
|
p.device.GPIOA;
|
||||||
|
p.device.RCC;
|
||||||
// ..
|
// ..
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,16 +63,15 @@ pub fn app(app: check::App) -> Result<App> {
|
||||||
tasks: app.tasks
|
tasks: app.tasks
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(k, v)| {
|
.map(|(k, v)| {
|
||||||
let v = ::check::task(k.as_ref(), v)
|
let v =
|
||||||
.chain_err(|| format!("checking task `{}`", k))?;
|
::check::task(k.as_ref(), v).chain_err(|| format!("checking task `{}`", k))?;
|
||||||
|
|
||||||
Ok((k, v))
|
Ok((k, v))
|
||||||
})
|
})
|
||||||
.collect::<Result<_>>()?,
|
.collect::<Result<_>>()?,
|
||||||
};
|
};
|
||||||
|
|
||||||
::check::resources(&app)
|
::check::resources(&app).chain_err(|| "checking `resources`")?;
|
||||||
.chain_err(|| "checking `resources`")?;
|
|
||||||
|
|
||||||
Ok(app)
|
Ok(app)
|
||||||
}
|
}
|
||||||
|
@ -93,6 +92,17 @@ fn resources(app: &App) -> Result<()> {
|
||||||
bail!("resource `{}` is unused", resource);
|
bail!("resource `{}` is unused", resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (name, task) in &app.tasks {
|
||||||
|
for resource in &task.resources {
|
||||||
|
ensure!(
|
||||||
|
app.resources.contains_key(&resource),
|
||||||
|
"task {} contains an undeclared resource with name {}",
|
||||||
|
name,
|
||||||
|
resource
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,12 +27,7 @@ pub fn app(app: &App, ownerships: &Ownerships) -> Tokens {
|
||||||
quote!(#(#root)*)
|
quote!(#(#root)*)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn idle(
|
fn idle(app: &App, ownerships: &Ownerships, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
app: &App,
|
|
||||||
ownerships: &Ownerships,
|
|
||||||
main: &mut Vec<Tokens>,
|
|
||||||
root: &mut Vec<Tokens>,
|
|
||||||
) {
|
|
||||||
let krate = krate();
|
let krate = krate();
|
||||||
|
|
||||||
let mut mod_items = vec![];
|
let mut mod_items = vec![];
|
||||||
|
@ -45,8 +40,6 @@ fn idle(
|
||||||
}
|
}
|
||||||
|
|
||||||
if !app.idle.resources.is_empty() {
|
if !app.idle.resources.is_empty() {
|
||||||
let device = &app.device;
|
|
||||||
|
|
||||||
let mut needs_reexport = false;
|
let mut needs_reexport = false;
|
||||||
for name in &app.idle.resources {
|
for name in &app.idle.resources {
|
||||||
if ownerships[name].is_owned() {
|
if ownerships[name].is_owned() {
|
||||||
|
@ -66,7 +59,10 @@ fn idle(
|
||||||
let mut rfields = vec![];
|
let mut rfields = vec![];
|
||||||
for name in &app.idle.resources {
|
for name in &app.idle.resources {
|
||||||
if ownerships[name].is_owned() {
|
if ownerships[name].is_owned() {
|
||||||
if let Some(resource) = app.resources.get(name) {
|
let resource = app.resources.get(name).expect(&format!(
|
||||||
|
"BUG: resource {} assigned to `idle` has no definition",
|
||||||
|
name
|
||||||
|
));
|
||||||
let ty = &resource.ty;
|
let ty = &resource.ty;
|
||||||
|
|
||||||
rfields.push(quote! {
|
rfields.push(quote! {
|
||||||
|
@ -83,15 +79,6 @@ fn idle(
|
||||||
#name: #super_::#_name.as_mut(),
|
#name: #super_::#_name.as_mut(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
rfields.push(quote! {
|
|
||||||
pub #name: &'static mut ::#device::#name,
|
|
||||||
});
|
|
||||||
|
|
||||||
rexprs.push(quote! {
|
|
||||||
#name: &mut *::#device::#name.get(),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
rfields.push(quote! {
|
rfields.push(quote! {
|
||||||
pub #name: #super_::_resource::#name,
|
pub #name: #super_::_resource::#name,
|
||||||
|
@ -161,12 +148,20 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
let device = &app.device;
|
let device = &app.device;
|
||||||
let krate = krate();
|
let krate = krate();
|
||||||
|
|
||||||
let mut tys = vec![quote!(#device::Peripherals)];
|
let mut tys = vec![quote!(init::Peripherals)];
|
||||||
let mut exprs = vec![quote!(#device::Peripherals::all())];
|
let mut exprs = vec![
|
||||||
|
quote!{
|
||||||
|
init::Peripherals {
|
||||||
|
core: ::#device::CorePeripherals::steal(),
|
||||||
|
device: ::#device::Peripherals::steal(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
];
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
let mut mod_items = vec![];
|
let mut mod_items = vec![];
|
||||||
|
|
||||||
let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources.iter()
|
let (init_resources, late_resources): (Vec<_>, Vec<_>) = app.resources
|
||||||
|
.iter()
|
||||||
.partition(|&(_, res)| res.expr.is_some());
|
.partition(|&(_, res)| res.expr.is_some());
|
||||||
|
|
||||||
if !init_resources.is_empty() {
|
if !init_resources.is_empty() {
|
||||||
|
@ -255,7 +250,10 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
root.push(quote! {
|
root.push(quote! {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
mod init {
|
mod init {
|
||||||
pub use ::#device::Peripherals;
|
pub struct Peripherals {
|
||||||
|
pub core: ::#device::CorePeripherals,
|
||||||
|
pub device: ::#device::Peripherals,
|
||||||
|
}
|
||||||
|
|
||||||
#(#mod_items)*
|
#(#mod_items)*
|
||||||
}
|
}
|
||||||
|
@ -268,7 +266,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
Kind::Exception(ref e) => {
|
Kind::Exception(ref e) => {
|
||||||
if exceptions.is_empty() {
|
if exceptions.is_empty() {
|
||||||
exceptions.push(quote! {
|
exceptions.push(quote! {
|
||||||
let scb = &*#device::SCB.get();
|
let scb = &*#device::SCB::ptr();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,7 +282,7 @@ fn init(app: &App, main: &mut Vec<Tokens>, root: &mut Vec<Tokens>) {
|
||||||
// Interrupt. These can be enabled / disabled through the NVIC
|
// Interrupt. These can be enabled / disabled through the NVIC
|
||||||
if interrupts.is_empty() {
|
if interrupts.is_empty() {
|
||||||
interrupts.push(quote! {
|
interrupts.push(quote! {
|
||||||
let nvic = &*#device::NVIC.get();
|
let nvic = &*#device::NVIC::ptr();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,7 +353,9 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
// For owned resources we don't need claim() or borrow()
|
// For owned resources we don't need claim() or borrow()
|
||||||
}
|
}
|
||||||
Ownership::Shared { ceiling } => {
|
Ownership::Shared { ceiling } => {
|
||||||
if let Some(resource) = app.resources.get(name) {
|
let resource = app.resources
|
||||||
|
.get(name)
|
||||||
|
.expect(&format!("BUG: resource {} has no definition", name));
|
||||||
let ty = &resource.ty;
|
let ty = &resource.ty;
|
||||||
let res_rvalue = if resource.expr.is_some() {
|
let res_rvalue = if resource.expr.is_some() {
|
||||||
quote!(#_name)
|
quote!(#_name)
|
||||||
|
@ -428,81 +428,6 @@ fn resources(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
impl_items.push(quote! {
|
|
||||||
type Data = #device::#name;
|
|
||||||
|
|
||||||
fn borrow<'cs>(
|
|
||||||
&'cs self,
|
|
||||||
t: &'cs #krate::Threshold,
|
|
||||||
) -> &'cs #krate::Static<#device::#name> {
|
|
||||||
assert!(t.value() >= #ceiling);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
#krate::Static::ref_(&*#device::#name.get())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn borrow_mut<'cs>(
|
|
||||||
&'cs mut self,
|
|
||||||
t: &'cs #krate::Threshold,
|
|
||||||
) -> &'cs mut #krate::Static<#device::#name> {
|
|
||||||
assert!(t.value() >= #ceiling);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
#krate::Static::ref_mut(
|
|
||||||
&mut *#device::#name.get(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn claim<R, F>(
|
|
||||||
&self,
|
|
||||||
t: &mut #krate::Threshold,
|
|
||||||
f: F,
|
|
||||||
) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(
|
|
||||||
&#krate::Static<#device::#name>,
|
|
||||||
&mut #krate::Threshold) -> R
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
#krate::claim(
|
|
||||||
#krate::Static::ref_(
|
|
||||||
&*#device::#name.get(),
|
|
||||||
),
|
|
||||||
#ceiling,
|
|
||||||
#device::NVIC_PRIO_BITS,
|
|
||||||
t,
|
|
||||||
f,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn claim_mut<R, F>(
|
|
||||||
&mut self,
|
|
||||||
t: &mut #krate::Threshold,
|
|
||||||
f: F,
|
|
||||||
) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(
|
|
||||||
&mut #krate::Static<#device::#name>,
|
|
||||||
&mut #krate::Threshold) -> R
|
|
||||||
{
|
|
||||||
unsafe {
|
|
||||||
#krate::claim(
|
|
||||||
#krate::Static::ref_mut(
|
|
||||||
&mut *#device::#name.get(),
|
|
||||||
),
|
|
||||||
#ceiling,
|
|
||||||
#device::NVIC_PRIO_BITS,
|
|
||||||
t,
|
|
||||||
f,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
impls.push(quote! {
|
impls.push(quote! {
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
@ -560,9 +485,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
let _name = Ident::new(format!("_{}", name.as_ref()));
|
let _name = Ident::new(format!("_{}", name.as_ref()));
|
||||||
|
|
||||||
match ownerships[name] {
|
match ownerships[name] {
|
||||||
Ownership::Shared { ceiling }
|
Ownership::Shared { ceiling } if ceiling > task.priority => {
|
||||||
if ceiling > task.priority =>
|
|
||||||
{
|
|
||||||
needs_threshold = true;
|
needs_threshold = true;
|
||||||
|
|
||||||
fields.push(quote! {
|
fields.push(quote! {
|
||||||
|
@ -577,7 +500,10 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
lifetime = Some(quote!('a));
|
lifetime = Some(quote!('a));
|
||||||
if let Some(resource) = app.resources.get(name) {
|
let resource = app.resources
|
||||||
|
.get(name)
|
||||||
|
.expect(&format!("BUG: resource {} has no definition", name));
|
||||||
|
|
||||||
needs_reexport = true;
|
needs_reexport = true;
|
||||||
let ty = &resource.ty;
|
let ty = &resource.ty;
|
||||||
|
|
||||||
|
@ -594,18 +520,6 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
#name: ::#krate::Static::ref_mut(::#_name.as_mut()),
|
#name: ::#krate::Static::ref_mut(::#_name.as_mut()),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
fields.push(quote! {
|
|
||||||
pub #name:
|
|
||||||
&'a mut ::#krate::Static<::#device::#name>,
|
|
||||||
});
|
|
||||||
|
|
||||||
exprs.push(quote! {
|
|
||||||
#name: ::#krate::Static::ref_mut(
|
|
||||||
&mut *::#device::#name.get(),
|
|
||||||
),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -666,8 +580,7 @@ fn tasks(app: &App, ownerships: &Ownerships, root: &mut Vec<Tokens>) {
|
||||||
|
|
||||||
let path = &task.path;
|
let path = &task.path;
|
||||||
let _name = Ident::new(format!("_{}", name));
|
let _name = Ident::new(format!("_{}", name));
|
||||||
let export_name =
|
let export_name = Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
|
||||||
Lit::Str(name.as_ref().to_owned(), StrStyle::Cooked);
|
|
||||||
root.push(quote! {
|
root.push(quote! {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
|
|
|
@ -160,6 +160,6 @@ where
|
||||||
I: Nr,
|
I: Nr,
|
||||||
{
|
{
|
||||||
// NOTE(safe) atomic write
|
// NOTE(safe) atomic write
|
||||||
let nvic = unsafe { &*cortex_m::peripheral::NVIC.get() };
|
let nvic = unsafe { &*cortex_m::peripheral::NVIC::ptr() };
|
||||||
nvic.set_pending(interrupt);
|
nvic.set_pending(interrupt);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue