Skip to content

Commit

Permalink
esp32c3 support
Browse files Browse the repository at this point in the history
  • Loading branch information
onsdagens authored and korken89 committed Sep 27, 2023
1 parent 3b8d787 commit 2b2208e
Show file tree
Hide file tree
Showing 27 changed files with 524 additions and 59 deletions.
4 changes: 4 additions & 0 deletions rtic-common/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,8 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!

### 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
3 changes: 2 additions & 1 deletion rtic-common/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rtic-common"
version = "1.0.0"
version = "1.0.1"

edition = "2021"
authors = [
Expand All @@ -18,6 +18,7 @@ license = "MIT OR Apache-2.0"

[dependencies]
critical-section = "1"
portable-atomic = { version = "1", default-features = false }

[features]
default = []
Expand Down
2 changes: 1 addition & 1 deletion rtic-common/src/wait_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
use core::marker::PhantomPinned;
use core::pin::Pin;
use core::ptr::null_mut;
use core::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
use core::task::Waker;
use critical_section as cs;
use portable_atomic::{AtomicBool, AtomicPtr, Ordering};

/// A helper definition of a wait queue.
pub type WaitQueue = DoublyLinkedList<Waker>;
Expand Down
4 changes: 4 additions & 0 deletions rtic-macros/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!

## [Unreleased]

### Added

- Unstable ESP32-C3 support.

## [v2.0.1] - 2023-07-25

### Added
Expand Down
2 changes: 2 additions & 0 deletions rtic-macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,11 @@ default = []
# list of supported codegen backends
cortex-m-source-masking = []
cortex-m-basepri = []
riscv-esp32c3 = []
# riscv-clic = []
# riscv-ch32 = []


# backend API test
test-template = []

Expand Down
7 changes: 5 additions & 2 deletions rtic-macros/src/codegen/async_dispatchers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use crate::syntax::ast::App;
use crate::{
analyze::Analysis,
codegen::{
bindings::{interrupt_entry, interrupt_exit},
bindings::{async_entry, interrupt_entry, interrupt_exit, handler_config},
util,
},
};
Expand Down Expand Up @@ -67,14 +67,17 @@ pub fn codegen(app: &App, analysis: &Analysis) -> TokenStream2 {
let attribute = &interrupts.get(&level).expect("UNREACHABLE").1.attrs;
let entry_stmts = interrupt_entry(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!(
#[allow(non_snake_case)]
#[doc = #doc]
#[no_mangle]
#(#attribute)*
#(#config)*
unsafe fn #dispatcher_name() {
#(#entry_stmts)*
#(#async_entry_stmts)*

/// The priority of this interrupt handler
const PRIORITY: u8 = #level;
Expand Down
14 changes: 14 additions & 0 deletions rtic-macros/src/codegen/bindings.rs
Original file line number Diff line number Diff line change
@@ -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"))]
pub use cortex::*;

Expand All @@ -9,3 +17,9 @@ mod cortex;

#[cfg(feature = "test-template")]
mod template;

#[cfg(feature = "riscv-esp32c3")]
pub use esp32c3::*;

#[cfg(feature = "riscv-esp32c3")]
mod esp32c3;
21 changes: 20 additions & 1 deletion rtic-macros/src/codegen/bindings/cortex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
codegen::util,
syntax::{analyze::Analysis as SyntaxAnalysis, ast::App},
};
use proc_macro2::TokenStream as TokenStream2;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::quote;
use std::collections::HashSet;
use syn::{parse, Attribute, Ident};
Expand All @@ -29,6 +29,10 @@ fn is_exception(name: &Ident) -> bool {
| "SysTick"
)
}
pub fn interrupt_ident() -> Ident {
let span = Span::call_site();
Ident::new("interrupt", span)
}

#[cfg(feature = "cortex-m-source-masking")]
mod source_masking {
Expand Down Expand Up @@ -323,6 +327,14 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea
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> {
let max = if let Some(max) = analysis.max_async_prio {
quote!(#max)
Expand All @@ -338,3 +350,10 @@ pub fn async_prio_limit(app: &App, analysis: &CodegenAnalysis) -> Vec<TokenStrea
static RTIC_ASYNC_MAX_LOGICAL_PRIO: u8 = #max;
)]
}
pub fn handler_config(
_app: &App,
_analysis: &CodegenAnalysis,
_dispatcher_name: Ident,
) -> Vec<TokenStream2> {
vec![]
}
213 changes: 213 additions & 0 deletions rtic-macros/src/codegen/bindings/esp32c3.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
17 changes: 16 additions & 1 deletion rtic-macros/src/codegen/bindings/template.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,21 @@ pub fn interrupt_exit(_app: &App, _analysis: &CodegenAnalysis) -> Vec<TokenStrea
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![]
}
Loading

0 comments on commit 2b2208e

Please sign in to comment.