mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-23 12:12:50 +01:00
esp32c3 support
This commit is contained in:
parent
3b8d787a91
commit
2b2208e217
27 changed files with 525 additions and 60 deletions
|
@ -13,4 +13,8 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
## [v1.0.1]
|
||||||
|
|
||||||
|
- `portable-atomic` used as a drop in replacement for `core::sync::atomic` in code and macros. `portable-atomic` imported with `default-features = false`, as we do not require CAS.
|
||||||
|
|
||||||
## [v1.0.0] - 2023-05-31
|
## [v1.0.0] - 2023-05-31
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rtic-common"
|
name = "rtic-common"
|
||||||
version = "1.0.0"
|
version = "1.0.1"
|
||||||
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [
|
authors = [
|
||||||
|
@ -18,6 +18,7 @@ license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
critical-section = "1"
|
critical-section = "1"
|
||||||
|
portable-atomic = { version = "1", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
|
@ -3,9 +3,9 @@
|
||||||
use core::marker::PhantomPinned;
|
use core::marker::PhantomPinned;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use core::ptr::null_mut;
|
use core::ptr::null_mut;
|
||||||
use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
|
|
||||||
use core::task::Waker;
|
use core::task::Waker;
|
||||||
use critical_section as cs;
|
use critical_section as cs;
|
||||||
|
use portable_atomic::{AtomicBool, AtomicPtr, Ordering};
|
||||||
|
|
||||||
/// A helper definition of a wait queue.
|
/// A helper definition of a wait queue.
|
||||||
pub type WaitQueue = DoublyLinkedList<Waker>;
|
pub type WaitQueue = DoublyLinkedList<Waker>;
|
||||||
|
|
|
@ -7,6 +7,10 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Unstable ESP32-C3 support.
|
||||||
|
|
||||||
## [v2.0.1] - 2023-07-25
|
## [v2.0.1] - 2023-07-25
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
|
@ -33,9 +33,11 @@ default = []
|
||||||
# list of supported codegen backends
|
# list of supported codegen backends
|
||||||
cortex-m-source-masking = []
|
cortex-m-source-masking = []
|
||||||
cortex-m-basepri = []
|
cortex-m-basepri = []
|
||||||
|
riscv-esp32c3 = []
|
||||||
# riscv-clic = []
|
# riscv-clic = []
|
||||||
# riscv-ch32 = []
|
# riscv-ch32 = []
|
||||||
|
|
||||||
|
|
||||||
# backend API test
|
# backend API test
|
||||||
test-template = []
|
test-template = []
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::syntax::ast::App;
|
||||||
use crate::{
|
use crate::{
|
||||||
analyze::Analysis,
|
analyze::Analysis,
|
||||||
codegen::{
|
codegen::{
|
||||||
bindings::{interrupt_entry, interrupt_exit},
|
bindings::{async_entry, interrupt_entry, interrupt_exit, handler_config},
|
||||||
util,
|
util,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -67,14 +67,17 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs;
|
let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs;
|
||||||
let entry_stmts = interrupt_entry(app, analysis);
|
let entry_stmts = interrupt_entry(app, analysis);
|
||||||
let exit_stmts = interrupt_exit(app, analysis);
|
let exit_stmts = interrupt_exit(app, analysis);
|
||||||
|
let async_entry_stmts = async_entry(app, analysis, dispatcher_name.clone());
|
||||||
|
let config = handler_config(app,analysis,dispatcher_name.clone());
|
||||||
items.push(quote!(
|
items.push(quote!(
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[doc = #doc]
|
#[doc = #doc]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#(#attribute)*
|
#(#attribute)*
|
||||||
|
#(#config)*
|
||||||
unsafe fn #dispatcher_name() {
|
unsafe fn #dispatcher_name() {
|
||||||
#(#entry_stmts)*
|
#(#entry_stmts)*
|
||||||
|
#(#async_entry_stmts)*
|
||||||
|
|
||||||
/// The priority of this interrupt handler
|
/// The priority of this interrupt handler
|
||||||
const PRIORITY: u8 = #level;
|
const PRIORITY: u8 = #level;
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
#[cfg(not(any(
|
||||||
|
feature = "cortex-m-source-masking",
|
||||||
|
feature = "cortex-m-basepri",
|
||||||
|
feature = "test-template",
|
||||||
|
feature = "riscv-esp32c3"
|
||||||
|
)))]
|
||||||
|
compile_error!("No backend selected");
|
||||||
|
|
||||||
#[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))]
|
#[cfg(any(feature = "cortex-m-source-masking", feature = "cortex-m-basepri"))]
|
||||||
pub use cortex::*;
|
pub use cortex::*;
|
||||||
|
|
||||||
|
@ -9,3 +17,9 @@ mod cortex;
|
||||||
|
|
||||||
#[cfg(feature = "test-template")]
|
#[cfg(feature = "test-template")]
|
||||||
mod template;
|
mod template;
|
||||||
|
|
||||||
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
|
pub use esp32c3::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
|
mod esp32c3;
|
|
@ -3,7 +3,7 @@ use crate::{
|
||||||
codegen::util,
|
codegen::util,
|
||||||
syntax::{analyze::Analysis as SyntaxAnalysis, ast::App},
|
syntax::{analyze::Analysis as SyntaxAnalysis, ast::App},
|
||||||
};
|
};
|
||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use syn::{parse, Attribute, Ident};
|
use syn::{parse, Attribute, Ident};
|
||||||
|
@ -29,6 +29,10 @@ fn is_exception(name: &Ident) -> bool {
|
||||||
| "SysTick"
|
| "SysTick"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
pub fn interrupt_ident() -> Ident {
|
||||||
|
let span = Span::call_site();
|
||||||
|
Ident::new("interrupt", span)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cortex-m-source-masking")]
|
#[cfg(feature = "cortex-m-source-masking")]
|
||||||
mod source_masking {
|
mod source_masking {
|
||||||
|
@ -323,6 +327,14 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn async_entry(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
_dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
let max = if let Some(max) = analysis.max_async_prio {
|
let max = if let Some(max) = analysis.max_async_prio {
|
||||||
quote!(#max)
|
quote!(#max)
|
||||||
|
@ -338,3 +350,10 @@ pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStrea
|
||||||
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
|
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
|
||||||
)]
|
)]
|
||||||
}
|
}
|
||||||
|
pub fn handler_config(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
_dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
213
rtic-macros/src/codegen/bindings/esp32c3.rs
Normal file
213
rtic-macros/src/codegen/bindings/esp32c3.rs
Normal file
|
@ -0,0 +1,213 @@
|
||||||
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
|
pub use esp32c3::*;
|
||||||
|
|
||||||
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
|
mod esp32c3 {
|
||||||
|
use crate::{
|
||||||
|
analyze::Analysis as CodegenAnalysis,
|
||||||
|
codegen::util,
|
||||||
|
syntax::{analyze::Analysis as SyntaxAnalysis, ast::App},
|
||||||
|
};
|
||||||
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
|
use quote::quote;
|
||||||
|
use std::collections::HashSet;
|
||||||
|
use syn::{parse, Attribute, Ident};
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn impl_mutex(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
cfgs: &[Attribute],
|
||||||
|
resources_prefix: bool,
|
||||||
|
name: &Ident,
|
||||||
|
ty: &TokenStream2,
|
||||||
|
ceiling: u8,
|
||||||
|
ptr: &TokenStream2,
|
||||||
|
) -> TokenStream2 {
|
||||||
|
let path = if resources_prefix {
|
||||||
|
quote!(shared_resources::#name)
|
||||||
|
} else {
|
||||||
|
quote!(#name)
|
||||||
|
};
|
||||||
|
quote!(
|
||||||
|
#(#cfgs)*
|
||||||
|
impl<'a> rtic::Mutex for #path<'a> {
|
||||||
|
type T = #ty;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn lock<RTIC_INTERNAL_R>(&mut self, f: impl FnOnce(&mut #ty) -> RTIC_INTERNAL_R) -> RTIC_INTERNAL_R {
|
||||||
|
/// Priority ceiling
|
||||||
|
const CEILING: u8 = #ceiling;
|
||||||
|
unsafe {
|
||||||
|
rtic::export::lock(
|
||||||
|
#ptr,
|
||||||
|
CEILING,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_ident() -> Ident {
|
||||||
|
let span = Span::call_site();
|
||||||
|
Ident::new("Interrupt", span)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extra_assertions(_: &App, _: &SyntaxAnalysis) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pre_init_checks(app: &App, _: &SyntaxAnalysis) -> Vec<TokenStream2> {
|
||||||
|
let mut stmts = vec![];
|
||||||
|
// check that all dispatchers exists in the `Interrupt` enumeration regardless of whether
|
||||||
|
// they are used or not
|
||||||
|
let rt_err = util::rt_err_ident();
|
||||||
|
|
||||||
|
for name in app.args.dispatchers.keys() {
|
||||||
|
stmts.push(quote!(let _ = #rt_err::Interrupt::#name;));
|
||||||
|
}
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
pub fn pre_init_enable_interrupts(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
|
let mut stmts = vec![];
|
||||||
|
let mut curr_cpu_id:u8 = 1; //cpu interrupt id 0 is reserved
|
||||||
|
let rt_err = util::rt_err_ident();
|
||||||
|
let max_prio: usize = 15; //unfortunately this is not part of pac, but we know that max prio is 15.
|
||||||
|
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
||||||
|
// Unmask interrupts and set their priorities
|
||||||
|
for (&priority, name) in interrupt_ids.chain(
|
||||||
|
app.hardware_tasks
|
||||||
|
.values()
|
||||||
|
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
||||||
|
) {
|
||||||
|
let es = format!(
|
||||||
|
"Maximum priority used by interrupt vector '{name}' is more than supported by hardware"
|
||||||
|
);
|
||||||
|
// Compile time assert that this priority is supported by the device
|
||||||
|
stmts.push(quote!(
|
||||||
|
const _: () = if (#max_prio) <= #priority as usize { ::core::panic!(#es); };
|
||||||
|
));
|
||||||
|
stmts.push(quote!(
|
||||||
|
rtic::export::enable(
|
||||||
|
#rt_err::Interrupt::#name,
|
||||||
|
#priority,
|
||||||
|
#curr_cpu_id,
|
||||||
|
);
|
||||||
|
));
|
||||||
|
curr_cpu_id += 1;
|
||||||
|
}
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn architecture_specific_analysis(
|
||||||
|
app: &App,
|
||||||
|
_analysis: &SyntaxAnalysis,
|
||||||
|
) -> parse::Result<()> {
|
||||||
|
//check if the dispatchers are supported
|
||||||
|
for name in app.args.dispatchers.keys() {
|
||||||
|
let name_s = name.to_string();
|
||||||
|
match &*name_s {
|
||||||
|
"FROM_CPU_INTR0" | "FROM_CPU_INTR1" | "FROM_CPU_INTR2" | "FROM_CPU_INTR3" => {}
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
return Err(parse::Error::new(
|
||||||
|
name.span(),
|
||||||
|
"Only FROM_CPU_INTRX are supported as dispatchers",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that there are enough external interrupts to dispatch the software tasks and the timer
|
||||||
|
// queue handler
|
||||||
|
let mut first = None;
|
||||||
|
let priorities = app
|
||||||
|
.software_tasks
|
||||||
|
.iter()
|
||||||
|
.map(|(name, task)| {
|
||||||
|
first = Some(name);
|
||||||
|
task.args.priority
|
||||||
|
})
|
||||||
|
.filter(|prio| *prio > 0)
|
||||||
|
.collect::<HashSet<_>>();
|
||||||
|
|
||||||
|
let need = priorities.len();
|
||||||
|
let given = app.args.dispatchers.len();
|
||||||
|
if need > given {
|
||||||
|
let s = {
|
||||||
|
format!(
|
||||||
|
"not enough interrupts to dispatch \
|
||||||
|
all software tasks (need: {need}; given: {given})"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// If not enough tasks and first still is None, may cause
|
||||||
|
// "custom attribute panicked" due to unwrap on None
|
||||||
|
return Err(parse::Error::new(first.unwrap().span(), s));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_entry(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn async_entry(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
|
let mut stmts = vec![];
|
||||||
|
stmts.push(quote!(
|
||||||
|
rtic::export::unpend(rtic::export::Interrupt::#dispatcher_name); //simulate cortex-m behavior by unpending the interrupt on entry.
|
||||||
|
));
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
|
let max = if let Some(max) = analysis.max_async_prio {
|
||||||
|
quote!(#max)
|
||||||
|
} else {
|
||||||
|
// No limit
|
||||||
|
let device = &app.args.device;
|
||||||
|
quote!(1 << #device::NVIC_PRIO_BITS)
|
||||||
|
};
|
||||||
|
|
||||||
|
vec![quote!(
|
||||||
|
/// Holds the maximum priority level for use by async HAL drivers.
|
||||||
|
#[no_mangle]
|
||||||
|
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
|
||||||
|
)]
|
||||||
|
}
|
||||||
|
pub fn handler_config(
|
||||||
|
app: &App,
|
||||||
|
analysis: &CodegenAnalysis,
|
||||||
|
dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
|
let mut stmts = vec![];
|
||||||
|
let mut curr_cpu_id = 1;
|
||||||
|
//let mut ret = "";
|
||||||
|
let interrupt_ids = analysis.interrupts.iter().map(|(p, (id, _))| (p, id));
|
||||||
|
for (_, name) in interrupt_ids.chain(
|
||||||
|
app.hardware_tasks
|
||||||
|
.values()
|
||||||
|
.filter_map(|task| Some((&task.args.priority, &task.args.binds))),
|
||||||
|
) {
|
||||||
|
if *name == dispatcher_name{
|
||||||
|
let ret = &("cpu_int_".to_owned()+&curr_cpu_id.to_string()+"_handler");
|
||||||
|
stmts.push(
|
||||||
|
quote!(#[export_name = #ret])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
curr_cpu_id += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stmts
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,21 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn async_prio_limit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
pub fn async_entry(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
_dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn async_prio_limit(app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStream2> {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
pub fn handler_config(
|
||||||
|
_app: &App,
|
||||||
|
_analysis: &CodegenAnalysis,
|
||||||
|
dispatcher_name: Ident,
|
||||||
|
) -> Vec<TokenStream2> {
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use crate::syntax::{ast::App, Context};
|
||||||
use crate::{
|
use crate::{
|
||||||
analyze::Analysis,
|
analyze::Analysis,
|
||||||
codegen::{
|
codegen::{
|
||||||
bindings::{interrupt_entry, interrupt_exit},
|
bindings::{interrupt_entry, interrupt_exit, handler_config},
|
||||||
local_resources_struct, module, shared_resources_struct,
|
local_resources_struct, module, shared_resources_struct,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -22,12 +22,14 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
|
||||||
let attrs = &task.attrs;
|
let attrs = &task.attrs;
|
||||||
let entry_stmts = interrupt_entry(app, analysis);
|
let entry_stmts = interrupt_entry(app, analysis);
|
||||||
let exit_stmts = interrupt_exit(app, analysis);
|
let exit_stmts = interrupt_exit(app, analysis);
|
||||||
|
let config = handler_config(app, analysis, symbol.clone());
|
||||||
|
|
||||||
mod_app.push(quote!(
|
mod_app.push(quote!(
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
#(#cfgs)*
|
#(#cfgs)*
|
||||||
|
#(#config)*
|
||||||
unsafe fn #symbol() {
|
unsafe fn #symbol() {
|
||||||
#(#entry_stmts)*
|
#(#entry_stmts)*
|
||||||
|
|
||||||
|
|
|
@ -3,13 +3,11 @@ use core::sync::atomic::{AtomicUsize, Ordering};
|
||||||
use proc_macro2::{Span, TokenStream as TokenStream2};
|
use proc_macro2::{Span, TokenStream as TokenStream2};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::{Ident, PatType};
|
use syn::{Ident, PatType};
|
||||||
|
//hook the target specific interrupt_ident function
|
||||||
|
pub use super::bindings::interrupt_ident;
|
||||||
|
|
||||||
const RTIC_INTERNAL: &str = "__rtic_internal";
|
const RTIC_INTERNAL: &str = "__rtic_internal";
|
||||||
|
|
||||||
pub fn interrupt_ident() -> Ident {
|
|
||||||
let span = Span::call_site();
|
|
||||||
Ident::new("interrupt", span)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Mark a name as internal
|
/// Mark a name as internal
|
||||||
pub fn mark_internal_name(name: &str) -> Ident {
|
pub fn mark_internal_name(name: &str) -> Ident {
|
||||||
|
|
|
@ -13,7 +13,8 @@ macro_rules! with_backend {
|
||||||
#[cfg(any(
|
#[cfg(any(
|
||||||
feature = "cortex-m-source-masking",
|
feature = "cortex-m-source-masking",
|
||||||
feature = "cortex-m-basepri",
|
feature = "cortex-m-basepri",
|
||||||
feature = "test-template"
|
feature = "test-template",
|
||||||
|
feature = "riscv-esp32c3"
|
||||||
))]
|
))]
|
||||||
$($tokens)*
|
$($tokens)*
|
||||||
};
|
};
|
||||||
|
@ -107,6 +108,7 @@ with_backend! {
|
||||||
#[cfg(not(any(
|
#[cfg(not(any(
|
||||||
feature = "cortex-m-source-masking",
|
feature = "cortex-m-source-masking",
|
||||||
feature = "cortex-m-basepri",
|
feature = "cortex-m-basepri",
|
||||||
feature = "test-template"
|
feature = "test-template",
|
||||||
|
feature = "riscv-esp32c3"
|
||||||
)))]
|
)))]
|
||||||
compile_error!("Cannot compile. No backend feature selected.");
|
compile_error!("Cannot compile. No backend feature selected.");
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
All notable changes to this project will be documented in this file.
|
All notable changes to this project will be documented in this file.
|
||||||
This project adheres to [Semantic Versioning](http://semver.org/).
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
|
|
||||||
For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
For each category, _Added_, _Changed_, _Fixed_ add new entries at the top!
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
@ -13,6 +13,10 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
## [v1.0.3]
|
||||||
|
|
||||||
|
- `portable-atomic` used as a drop in replacement for `core::sync::atomic` in code and macros. `portable-atomic` imported with `default-features = false`, as we do not require CAS.
|
||||||
|
|
||||||
## [v1.0.2] - 2023-08-29
|
## [v1.0.2] - 2023-08-29
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
@ -25,6 +29,6 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
|
|
||||||
- `make_channel` could be UB
|
- `make_channel` could be UB
|
||||||
|
|
||||||
## [v1.0.0] - 2023-05-31 - yanked
|
## [v1.0.0] - 2023-05-31 - yanked
|
||||||
|
|
||||||
- Initial release
|
- Initial release
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "rtic-sync"
|
name = "rtic-sync"
|
||||||
version = "1.0.2"
|
version = "1.0.3"
|
||||||
|
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = [
|
authors = [
|
||||||
|
@ -20,6 +20,7 @@ license = "MIT OR Apache-2.0"
|
||||||
heapless = "0.7"
|
heapless = "0.7"
|
||||||
critical-section = "1"
|
critical-section = "1"
|
||||||
rtic-common = { version = "1.0.0", path = "../rtic-common" }
|
rtic-common = { version = "1.0.0", path = "../rtic-common" }
|
||||||
|
portable-atomic = { version = "1", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tokio = { version = "1", features = ["rt", "macros", "time"] }
|
tokio = { version = "1", features = ["rt", "macros", "time"] }
|
||||||
|
|
|
@ -27,8 +27,8 @@ use core::cell::UnsafeCell;
|
||||||
use core::future::poll_fn;
|
use core::future::poll_fn;
|
||||||
use core::ops::{Deref, DerefMut};
|
use core::ops::{Deref, DerefMut};
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use core::sync::atomic::{fence, AtomicBool, Ordering};
|
|
||||||
use core::task::{Poll, Waker};
|
use core::task::{Poll, Waker};
|
||||||
|
use portable_atomic::{fence, AtomicBool, Ordering};
|
||||||
|
|
||||||
use rtic_common::dropper::OnDrop;
|
use rtic_common::dropper::OnDrop;
|
||||||
use rtic_common::wait_queue::{Link, WaitQueue};
|
use rtic_common::wait_queue::{Link, WaitQueue};
|
||||||
|
|
|
@ -108,7 +108,7 @@ macro_rules! make_channel {
|
||||||
static mut CHANNEL: $crate::channel::Channel<$type, $size> =
|
static mut CHANNEL: $crate::channel::Channel<$type, $size> =
|
||||||
$crate::channel::Channel::new();
|
$crate::channel::Channel::new();
|
||||||
|
|
||||||
static CHECK: ::core::sync::atomic::AtomicU8 = ::core::sync::atomic::AtomicU8::new(0);
|
static CHECK: $crate::portable_atomic::AtomicU8 = $crate::portable_atomic::AtomicU8::new(0);
|
||||||
|
|
||||||
$crate::channel::critical_section::with(|_| {
|
$crate::channel::critical_section::with(|_| {
|
||||||
if CHECK.load(::core::sync::atomic::Ordering::Relaxed) != 0 {
|
if CHECK.load(::core::sync::atomic::Ordering::Relaxed) != 0 {
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
pub mod arbiter;
|
pub mod arbiter;
|
||||||
pub mod channel;
|
pub mod channel;
|
||||||
|
pub use portable_atomic;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -8,6 +8,7 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
- Unstable support for ESP32-C3
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,8 @@ features = ["rtic-macros/test-template"]
|
||||||
name = "rtic"
|
name = "rtic"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
esp32c3 = { version = "0.17.0", optional = true}
|
||||||
|
riscv = {version = "0.10.1", optional = true}
|
||||||
cortex-m = { version = "0.7.0", optional = true }
|
cortex-m = { version = "0.7.0", optional = true }
|
||||||
bare-metal = "1.0.0"
|
bare-metal = "1.0.0"
|
||||||
#portable-atomic = { version = "0.3.19" }
|
#portable-atomic = { version = "0.3.19" }
|
||||||
|
@ -62,14 +64,13 @@ trybuild = "1"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
|
|
||||||
thumbv6-backend = ["cortex-m", "rtic-macros/cortex-m-source-masking"]
|
thumbv6-backend = ["cortex-m", "rtic-macros/cortex-m-source-masking"]
|
||||||
thumbv7-backend = ["cortex-m", "rtic-macros/cortex-m-basepri"]
|
thumbv7-backend = ["cortex-m", "rtic-macros/cortex-m-basepri"]
|
||||||
thumbv8base-backend = ["cortex-m", "rtic-macros/cortex-m-source-masking"]
|
thumbv8base-backend = ["cortex-m", "rtic-macros/cortex-m-source-masking"]
|
||||||
thumbv8main-backend = ["cortex-m", "rtic-macros/cortex-m-basepri"]
|
thumbv8main-backend = ["cortex-m", "rtic-macros/cortex-m-basepri"]
|
||||||
# riscv-clic-backend = ["rtic-macros/riscv-clic"]
|
# riscv-clic-backend = ["rtic-macros/riscv-clic"]
|
||||||
# riscv-ch32-backend = ["rtic-macros/riscv-ch32"]
|
# riscv-ch32-backend = ["rtic-macros/riscv-ch32"]
|
||||||
# riscv-esp32c3-backend = ["rtic-macros/riscv-esp32c3"]
|
riscv-esp32c3-backend = ["esp32c3", "riscv", "rtic-macros/riscv-esp32c3"]
|
||||||
|
|
||||||
# needed for testing
|
# needed for testing
|
||||||
rtic-uitestv7 = ["thumbv7-backend"]
|
rtic-uitestv7 = ["thumbv7-backend"]
|
||||||
|
|
|
@ -11,8 +11,12 @@ fn main() {
|
||||||
println!("cargo:rustc-cfg=feature=\"cortex-m-basepri\"");
|
println!("cargo:rustc-cfg=feature=\"cortex-m-basepri\"");
|
||||||
} else if target.starts_with("thumbv6m") | target.starts_with("thumbv8m.base") {
|
} else if target.starts_with("thumbv6m") | target.starts_with("thumbv8m.base") {
|
||||||
println!("cargo:rustc-cfg=feature=\"cortex-m-source-masking\"");
|
println!("cargo:rustc-cfg=feature=\"cortex-m-source-masking\"");
|
||||||
|
//this should not be this general
|
||||||
|
//riscv processors differ in interrupt implementation
|
||||||
|
//even within the same target
|
||||||
|
//need some other way to discern
|
||||||
} else if target.starts_with("riscv32i") {
|
} else if target.starts_with("riscv32i") {
|
||||||
panic!("No RISC-V support yet.");
|
println!("cargo:rustc-cfg=feature=\"riscv-esp32c3\"");
|
||||||
|
|
||||||
// TODO: Add feature here for risc-v targets
|
// TODO: Add feature here for risc-v targets
|
||||||
// println!("cargo:rustc-cfg=feature=\"riscv\"");
|
// println!("cargo:rustc-cfg=feature=\"riscv\"");
|
||||||
|
|
|
@ -4,56 +4,38 @@ pub use atomic_polyfill as atomic;
|
||||||
|
|
||||||
pub mod executor;
|
pub mod executor;
|
||||||
|
|
||||||
#[cfg(all(
|
// Cortex-M target (any)
|
||||||
feature = "cortex-m-basepri",
|
#[cfg(feature = "cortex-m")]
|
||||||
not(any(feature = "thumbv7-backend", feature = "thumbv8main-backend"))
|
pub use cortex_common::*;
|
||||||
))]
|
|
||||||
compile_error!(
|
|
||||||
"Building for Cortex-M with basepri, but 'thumbv7-backend' or 'thumbv8main-backend' backend not selected"
|
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(all(
|
#[cfg(feature = "cortex-m")]
|
||||||
feature = "cortex-m-source-masking",
|
mod cortex_common;
|
||||||
not(any(feature = "thumbv6-backend", feature = "thumbv8base-backend"))
|
|
||||||
))]
|
// Cortex-M target with basepri support
|
||||||
compile_error!(
|
#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))]
|
||||||
"Building for Cortex-M with source masking, but 'thumbv6-backend' or 'thumbv8base-backend' backend not selected"
|
mod cortex_basepri;
|
||||||
);
|
|
||||||
|
|
||||||
#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))]
|
#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))]
|
||||||
pub use cortex_basepri::*;
|
pub use cortex_basepri::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "cortex-m-basepri", feature = "rtic-uitestv7"))]
|
// Cortex-M target with source mask support
|
||||||
mod cortex_basepri;
|
#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))]
|
||||||
|
mod cortex_source_mask;
|
||||||
|
|
||||||
#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))]
|
#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))]
|
||||||
pub use cortex_source_mask::*;
|
pub use cortex_source_mask::*;
|
||||||
|
|
||||||
#[cfg(any(feature = "cortex-m-source-masking", feature = "rtic-uitestv6"))]
|
// RISC-V target (any)
|
||||||
mod cortex_source_mask;
|
#[cfg(feature = "riscv")]
|
||||||
|
pub use riscv_common::*;
|
||||||
|
|
||||||
#[cfg(feature = "cortex-m")]
|
#[cfg(feature = "riscv")]
|
||||||
pub use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
|
mod riscv_common;
|
||||||
|
|
||||||
/// Sets the given `interrupt` as pending
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
///
|
mod riscv_esp32c3;
|
||||||
/// This is a convenience function around
|
#[cfg(feature = "riscv-esp32c3")]
|
||||||
/// [`NVIC::pend`](../cortex_m/peripheral/struct.NVIC.html#method.pend)
|
pub use riscv_esp32c3::*;
|
||||||
#[cfg(feature = "cortex-m")]
|
|
||||||
pub fn pend<I>(interrupt: I)
|
|
||||||
where
|
|
||||||
I: InterruptNumber,
|
|
||||||
{
|
|
||||||
NVIC::pend(interrupt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Priority conversion, takes logical priorities 1..=N and converts it to NVIC priority.
|
|
||||||
#[cfg(feature = "cortex-m")]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn cortex_logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
|
|
||||||
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn assert_send<T>()
|
pub fn assert_send<T>()
|
||||||
|
|
|
@ -8,6 +8,11 @@ pub use cortex_m::{
|
||||||
Peripherals,
|
Peripherals,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "thumbv7-backend", feature = "thumbv8main-backend")))]
|
||||||
|
compile_error!(
|
||||||
|
"Building for Cortex-M with basepri, but 'thumbv7-backend' or 'thumbv8main-backend' backend not selected"
|
||||||
|
);
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn run<F>(priority: u8, f: F)
|
pub fn run<F>(priority: u8, f: F)
|
||||||
where
|
where
|
||||||
|
|
18
rtic/src/export/cortex_common.rs
Normal file
18
rtic/src/export/cortex_common.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
pub use cortex_m::{interrupt::InterruptNumber, peripheral::NVIC};
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn cortex_logical2hw(logical: u8, nvic_prio_bits: u8) -> u8 {
|
||||||
|
((1 << nvic_prio_bits) - logical) << (8 - nvic_prio_bits)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the given `interrupt` as pending
|
||||||
|
///
|
||||||
|
/// This is a convenience function around
|
||||||
|
/// [`NVIC::pend`](../cortex_m/peripheral/struct.NVIC.html#method.pend)
|
||||||
|
pub fn pend<I>(interrupt: I)
|
||||||
|
where
|
||||||
|
I: InterruptNumber,
|
||||||
|
{
|
||||||
|
NVIC::pend(interrupt);
|
||||||
|
}
|
|
@ -6,6 +6,11 @@ pub use cortex_m::{
|
||||||
Peripherals,
|
Peripherals,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(any(feature = "thumbv6-backend", feature = "thumbv8base-backend")))]
|
||||||
|
compile_error!(
|
||||||
|
"Building for Cortex-M with source masking, but 'thumbv6-backend' or 'thumbv8base-backend' backend not selected"
|
||||||
|
);
|
||||||
|
|
||||||
/// Mask is used to store interrupt masks on systems without a BASEPRI register (M0, M0+, M23).
|
/// Mask is used to store interrupt masks on systems without a BASEPRI register (M0, M0+, M23).
|
||||||
/// It needs to be large enough to cover all the relevant interrupts in use.
|
/// It needs to be large enough to cover all the relevant interrupts in use.
|
||||||
/// For M0/M0+ there are only 32 interrupts so we only need one u32 value.
|
/// For M0/M0+ there are only 32 interrupts so we only need one u32 value.
|
||||||
|
|
2
rtic/src/export/riscv_common.rs
Normal file
2
rtic/src/export/riscv_common.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
/// GENERIC RE-EXPORTS: needed for all RTIC backends
|
||||||
|
pub use riscv::interrupt;
|
164
rtic/src/export/riscv_esp32c3.rs
Normal file
164
rtic/src/export/riscv_esp32c3.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
use esp32c3::INTERRUPT_CORE0; //priority threshold control
|
||||||
|
pub use esp32c3::{Interrupt, Peripherals};
|
||||||
|
pub use riscv::{interrupt, register::mcause}; //low level interrupt enable/disable
|
||||||
|
|
||||||
|
#[cfg(all(feature = "riscv-esp32c3", not(feature = "riscv-esp32c3-backend")))]
|
||||||
|
compile_error!("Building for the esp32c3, but 'riscv-esp32c3-backend not selected'");
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn run<F>(priority: u8, f: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(),
|
||||||
|
{
|
||||||
|
if priority == 1 {
|
||||||
|
//if priority is 1, priority thresh should be 1
|
||||||
|
f();
|
||||||
|
unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.write(|w| w.cpu_int_thresh().bits(1));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//read current thresh
|
||||||
|
let initial = unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.read()
|
||||||
|
.cpu_int_thresh()
|
||||||
|
.bits()
|
||||||
|
};
|
||||||
|
f();
|
||||||
|
//write back old thresh
|
||||||
|
unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.write(|w| w.cpu_int_thresh().bits(initial));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lock implementation using threshold and global Critical Section (CS)
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The system ceiling is raised from current to ceiling
|
||||||
|
/// by either
|
||||||
|
/// - raising the threshold to the ceiling value, or
|
||||||
|
/// - disable all interrupts in case we want to
|
||||||
|
/// mask interrupts with maximum priority
|
||||||
|
///
|
||||||
|
/// Dereferencing a raw pointer inside CS
|
||||||
|
///
|
||||||
|
/// The priority.set/priority.get can safely be outside the CS
|
||||||
|
/// as being a context local cell (not affected by preemptions).
|
||||||
|
/// It is merely used in order to omit masking in case current
|
||||||
|
/// priority is current priority >= ceiling.
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn lock<T, R>(ptr: *mut T, ceiling: u8, f: impl FnOnce(&mut T) -> R) -> R {
|
||||||
|
if ceiling == (15) {
|
||||||
|
//turn off interrupts completely, were at max prio
|
||||||
|
let r = critical_section::with(|_| f(&mut *ptr));
|
||||||
|
r
|
||||||
|
} else {
|
||||||
|
let current = unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.read()
|
||||||
|
.cpu_int_thresh()
|
||||||
|
.bits()
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.write(|w| w.cpu_int_thresh().bits(ceiling + 1))
|
||||||
|
} //esp32c3 lets interrupts with prio equal to threshold through so we up it by one
|
||||||
|
let r = f(&mut *ptr);
|
||||||
|
unsafe {
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_thresh
|
||||||
|
.write(|w| w.cpu_int_thresh().bits(current))
|
||||||
|
}
|
||||||
|
r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the given software interrupt as pending
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn pend(int: Interrupt) {
|
||||||
|
unsafe {
|
||||||
|
let peripherals = Peripherals::steal();
|
||||||
|
match int {
|
||||||
|
Interrupt::FROM_CPU_INTR0 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_0
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_0().bit(true)),
|
||||||
|
Interrupt::FROM_CPU_INTR1 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_1
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_1().bit(true)),
|
||||||
|
Interrupt::FROM_CPU_INTR2 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_2
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_2().bit(true)),
|
||||||
|
Interrupt::FROM_CPU_INTR3 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_3
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_3().bit(true)),
|
||||||
|
_ => panic!("Unsupported software interrupt"), //should never happen, checked at compile time
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets the given software interrupt as not pending
|
||||||
|
pub fn unpend(int: Interrupt) {
|
||||||
|
unsafe {
|
||||||
|
let peripherals = Peripherals::steal();
|
||||||
|
match int {
|
||||||
|
Interrupt::FROM_CPU_INTR0 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_0
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_0().bit(false)),
|
||||||
|
Interrupt::FROM_CPU_INTR1 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_1
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_1().bit(false)),
|
||||||
|
Interrupt::FROM_CPU_INTR2 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_2
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_2().bit(false)),
|
||||||
|
Interrupt::FROM_CPU_INTR3 => peripherals
|
||||||
|
.SYSTEM
|
||||||
|
.cpu_intr_from_cpu_3
|
||||||
|
.write(|w| w.cpu_intr_from_cpu_3().bit(false)),
|
||||||
|
_ => panic!("Unsupported software interrupt"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn enable(int: Interrupt, prio: u8, cpu_int_id: u8) {
|
||||||
|
const INTERRUPT_MAP_BASE: u32 = 0x600c2000; //this isn't exposed properly in the PAC,
|
||||||
|
//should maybe figure out a workaround that
|
||||||
|
//doesnt involve raw pointers.
|
||||||
|
//Again, this is how they do it in the HAL
|
||||||
|
//but i'm really not a fan.
|
||||||
|
let interrupt_number = int as isize;
|
||||||
|
let cpu_interrupt_number = cpu_int_id as isize;
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
let intr_map_base = INTERRUPT_MAP_BASE as *mut u32;
|
||||||
|
intr_map_base
|
||||||
|
.offset(interrupt_number)
|
||||||
|
.write_volatile(cpu_interrupt_number as u32);
|
||||||
|
//map peripheral interrupt to CPU interrupt
|
||||||
|
(*INTERRUPT_CORE0::ptr())
|
||||||
|
.cpu_int_enable
|
||||||
|
.modify(|r, w| w.bits((1 << cpu_interrupt_number) | r.bits())); //enable the CPU interupt.
|
||||||
|
let intr = INTERRUPT_CORE0::ptr();
|
||||||
|
let intr_prio_base = (*intr).cpu_int_pri_0.as_ptr();
|
||||||
|
|
||||||
|
intr_prio_base
|
||||||
|
.offset(cpu_interrupt_number)
|
||||||
|
.write_volatile(prio as u32);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue