-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
app! macro take 2 #34
Conversation
macros/src/syntax/parse.rs
Outdated
pieces.push(tt); | ||
} | ||
} else { | ||
panic!("expected type, found EOM"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: maybe expand EOM
to end of macro
? It took me a few moments to recognize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will do
interrupts.push(quote! { | ||
let prio_bits = #device::NVIC_PRIO_BITS; | ||
let hw = ((1 << prio_bits) - #priority) << (8 - prio_bits); | ||
nvic.set_priority(#device::Interrupt::#name, hw); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: could this be extracted as another function on NVIC
? Seems useful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you mean adding a set_logical_priority
to NVIC or adding a logical2hw
function to map a logical priority to a "hardware" value that can be directly written to an NVIC register?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
former
Outstanding work @japaric! You've addressed nearly every concern of mine, except:
|
@whitequark Thanks
I was thinking about this and it would be easy to change the implementation such that init has access to all the resources declared in other tasks. The issue I see with this approach is that init is likely going to require more resources, specially peripherals (e.g. RCC), than what the other tasks use so you would still need to list more resources in The problem with giving init access to all the peripherals is that there's no such list that the |
the last commit removes init.resources from rtfm! and makes idle.local optional. The change depends on rust-embedded/svd2rust#123 Diff of the example shown below: --- a/0-example.rs 2017-07-06 17:54:13.908406632 -0500
+++ b/0-example.rs 2017-07-06 17:55:23.428268225 -0500
@@ -42,25 +41,23 @@
init: {
path: init,
- resources: [AFIO, GPIOA, GPIOC, TIM2, RCC, USART1],
},
idle: {
- local: {},
path: idle,
resources: [DWT, SLEEP_CYCLES],
},
}
-fn init(r: init::Resources) {
- let timer = Timer(r.TIM2);
- let serial = Serial(r.USART1);
+fn init(p: init::Peripherals, _: init::Resources) {
+ let timer = Timer(p.TIM2);
+ let serial = Serial(p.USART1);
- led::init(r.GPIOC, r.RCC);
+ led::init(p.GPIOC, p.RCC);
- serial.init(BAUD_RATE.invert(), r.AFIO, None, r.GPIOA, r.RCC);
+ serial.init(BAUD_RATE.invert(), p.AFIO, None, p.GPIOA, p.RCC);
- timer.init(FREQUENCY.invert(), r.RCC);
+ timer.init(FREQUENCY.invert(), p.RCC);
timer.resume();
}
@@ -122,4 +119,4 @@
let byte = serial.read().unwrap();
serial.write(byte).unwrap();
-}
\ No newline at end of file
+} |
- allow trailing commas in list of resources - make task.resources optional - add rtfm::set_pending function which can be used to force an interrupt into the pending state. This is a replacement of the old rtfm::request. rtfm::set_pending takes the Interrupt enum provided by the device crate as argument. (The old rtfm::request took a task function as argument) - the user may want to use types they imported into the root of the crate. These types are not available in e.g. `mod idle` so `idle::Resources` *can't* be defined in that module. To workaround this problem `idle::Resources` will be defined in the root, with some other name, and then be re-exported in the `idle` module. - remove the "a resource only used by one task should be local data" check. In some cases you do want a resource owned by a single task instead of local data since `init` can access resources but not a task local data.
I have ported two non trivial applications to the latest rtfm! version from cortex-m-rtfm v0.1.1. I'm quite happy with the result. The Cells and RefCells are gone; the task code is shorter, mainly because no |
nice! |
I have now ported all the examples in the blue-pill crate to this macro (japaric/stm32f103xx-hal#19). The result in a reduction in LoC of about 30% in average. In another news this has already broke due to a change in rustc:
|
@japaric Why are you using proc macro internals? |
@whitequark I thought that functionlike! proc macros weren't implemented given the existence of proc-macro-hack and the lack of documentation about macros 2.0 so I was using a compiler plugin. But I figured out how to use |
Some changes:
app! {
device: blue_pill::stm32f103xx,
tasks: {
SYS_TICK: {
priority: 1,
resources: { SYST }, // <- wrong delimiter
},
},
}
I believe this is good as the error messages can get without proper span information. |
This is amazing work. |
💔 Test failed - status-travis |
and move the logic that differentiates interrupts from exceptions from the crate to the procedural macro logic
@homunkulus try |
@homunkulus r+ |
📌 Commit 3d2be6d has been approved by |
@homunkulus r+ |
📌 Commit 697c2d6 has been approved by |
@homunkulus r+ |
📌 Commit 2d80f36 has been approved by |
☀️ Test successful - status-travis |
34: [RFC] Mod instead of const r=korken89 a=AfoHT Link to [rendered RFC](https://github.com/AfoHT/rfcs/blob/mod_const/text/0000-use-mod-over-const.md) Implemented and ran the test suites and examples, noticed no side-effecs. https://github.com/AfoHT/rtfm-syntax/tree/mod_const https://github.com/AfoHT/cortex-m-rtfm/tree/mod_const Co-authored-by: Henrik Tjäder <henrik@tjaders.com>
This is one possible solution to the stack overflow problem described in rtic-rs#34. This approach uses a linker wrapper, called [swap-ld], to generate the desired memory layout. See rtic-rs#34 for a description of the desired memory layout and rtic-rs#41 for a description of how `swap-ld` works. The observable effects of this change in cortex-m programs are: - the `_sbss` symbol is now override-able. - there is now a `.stack` linker section that denotes the span of the call stack. `.stack` won't be loaded into the program; it just exists for informative purposes (`swap-ld` uses this information). Given the following program: ``` rust fn main() { static mut X: u32 = 0; static mut Y: u32 = 1; loop { unsafe { ptr::write_volatile(&mut X, X + 1); ptr::write_volatile(&mut Y, Y + 1); } } } ``` If you link this program using the `arm-none-eabi-ld` linker, which is the cortex-m-quickstart default, you'll get the following memory layout: ``` console $ console section size addr .vector_table 0x130 0x8000000 .text 0x94 0x8000130 .rodata 0x0 0x80001c4 .stack 0x5000 0x20000000 .bss 0x4 0x20000000 .data 0x4 0x20000004 ``` Note how the space reserved for the stack (depicted by the `.stack` linker section) overlaps with the space where .bss and .data reside. If you, instead, link this program using `swap-ld` you'll get the following memory layout: ``` console $ arm-none-eabi-size -Ax app section size addr .vector_table 0x130 0x8000000 .text 0x94 0x8000130 .rodata 0x0 0x80001c4 .stack 0x4ff8 0x20000000 .bss 0x4 0x20004ff8 .data 0x4 0x20004ffc ``` Note that no overlap exists in this case and that the call stack size has reduced to accommodate the .bss and .data sections. Unlike rtic-rs#41 the addresses of static variables is now correct: ``` console $ arm-none-eabi-objdump -CD app Disassembly of section .vector_table: 08000000 <_svector_table>: 8000000: 20004ff8 strdcs r4, [r0], -r8 ; initial Stack Pointer 08000004 <cortex_m_rt::RESET_VECTOR>: 8000004: 08000131 stmdaeq r0, {r0, r4, r5, r8} 08000008 <EXCEPTIONS>: 8000008: 080001bd stmdaeq r0, {r0, r2, r3, r4, r5, r7, r8} (..) Disassembly of section .stack: 20000000 <.stack>: ... Disassembly of section .bss: 20004ff8 <cortex_m_quickstart::main::X>: 20004ff8: 00000000 andeq r0, r0, r0 Disassembly of section .data: 20004ffc <_sdata>: 20004ffc: 00000001 andeq r0, r0, r1 ``` closes rtic-rs#34 [swap-ld]: https://github.com/japaric/swap-ld
Update
More ports from RTFM v1 to this macro:
Full example
^ This is semantically the same example presented in #31, but with this new
macro 33% less code is required.
Next iteration of the rtfm! macro presented in #31. The most notable change wrt
the previous version is that the macro has become a
compiler pluginprocedural macro.Pros
Automatic ceiling derivation. The ceiling will be computed from the
information about which tasks use which resources.
Simpler task and resource specification. There's no split between interrupts
used as tasks and exceptions used as tasks; there's only tasks now. Likewise
there's no distinction between peripherals used as resources and data
resources; there's only resources now.
More flexible syntax. The fields can be shuffled around without breaking the
parser.
Simpler signatures as there's no
Peripherals
/Resources
split.Adaptive signatures. The signature of idle will be
fn() -> !
if it makes nouses of resources and has no local data, but it will change to
fn(idle::Local)
if local data is used, etc.Less claims. Full access to resources is given to tasks whose priority matches
the resource ceiling.
More control over error messages related to the parsing and expansion of
rtfm!
.Cons
rtfm!
is now a compiler plugin. This makes the chance of it breaking acrossnightly updates greater than zero. However, I've implemented the compiler plugin
on top of token streams so we should be safe from compiler changes related to
the language syntax and parser. Once function style macros becomes available via
the more stable proc-macros feature it should be straightforward to move to it.
And yes, I tried proc-macro-hack which allows function style proc macros on
top of custom derive proc macros but it doesn't work for no-std / cross
compilation because the hack requires a proc-macro crate compiled for the target
(which is not possible for thumb because proc-macro contains
String
s).Other changes
I realized that the change to scope based safety fixes Interoperation with cortex_m::peripheral::Peripheral.borrow is unsound #13 so I've added a
borrow
/borrow_mut
method to resources to get direct access to themwithin a global critical section.
Given that we pretty much generate the implementation of the claim methods in
the application crate I have changed things such that (NVIC) PRIORITY_BITS is
no longer in the cortex-m-rtfm, but rather it's expected to be provided by the
device crate. This way we don't need a bunch of P{2,3,..} Cargo features in
the cortex-m-rtfm crate. OTOH, device generated crates now must provide a
NVIC_PRIO_BITS
constant that provides this information. SVD files containthis information in the form of the optional
<nvicPrioBits>
field.svd2rust will be taught to generate the
NVIC_PRIO_BITS
constant.into a
task!
macro. This macro doesn't have to be in the root of the crate.cc @whitequark