-
Notifications
You must be signed in to change notification settings - Fork 5
Clearing CPUOFF at end of interrupt #20
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
Comments
The Low Power Modes are something I'm not very familiar w/ in terms of LLVM and Rust. I vaguely remember talking about implementing it a few years ago and concluding that the TI-provided LPM builtins cannot be implemented in terms of inline-assembly, precisely because of the stack pointer shenanigans you mention. I.e. it requires compiler support to know where the stack pointer to be modified is at the point you want to exit LPM, and LLVM doesn't have this support. Your idea seems like a viable workaround that I never considered :). I would have to think about this tho, and my bandwidth is stretched thin as it is right now. But I'm not against the idea in principle as long as it's a default-off feature. I'm worried about this line in the inline assembly rules:
cc: @Amanieu Does this also mean "You cannot assume that an Cool that you're doing an MSP430 port of Embassy... saves me the trouble :P. |
Using a naked function is the only way to make this work. Note that nightly isn't required, you can use |
Using a naked function will incur significant overhead for simple handlers. You will have to push all the caller saved registers on stack before invoking the inner handler. (On Cortex-M the hardware does it automatically, but not on MSP430). That's why MSP430 uses the "msp430-interrupt" calling convention instead of naked functions to avoid this. In C++ land on GCC, people use built-in function On LLVM, we can use the #![feature(link_llvm_intrinsics)]
extern {
#[link_name="llvm.frameaddress"]
fn frameaddress(frame: i32) -> * mut i16;
}
pub unsafe extern "msp430-interrupt" fn interrupt_handler() {
// Do stuff
// ...
unsafe {
*frameaddress(0).offset(1) |= 16;
}
} It should be easy to modify msp430-rt macros to emit this sequence if needed. |
My idea was to make both the outer function and inner function use That said, looks like |
@cr1901 Ah, I see. That would be a good workaround. Just calling them directly doesn't work but with inline assembly and naked function it's possible. The overhead is only a jump instruction. |
This was my plan, but now that I know it is possible to directly access the SR I might attempt that method. As mentioned above that probably wont be stabilized though, so if the maintainers wish to avoid the use of that feature then I'll use the inner function with the extra jump and return overhead. I will leave a comment when I begin working on this, but right now I am busy with other things. |
While it's on my mind... a theoretical workaround is to put However, I don't have plans to pursue this right now and would greatly prefer the trampoline method for now. Changing to the frame-address method in the future would be an implementation detail/semver-compat release. |
I currently have a branch of embassy that I am using successfully for an MSP430i2041-based project over here: https://github.com/vadixidav/embassy/tree/msp430. This issue is related to the note I left in this commit: vadixidav/embassy@2a43df7.
Essentially, I would like for embassy to put the CPU to sleep when not in use. This would normally mean executing the following:
However, I am unable to do this because, at the end of my interrupts, the compiler generated several pop instructions that pop registers from the stack. This is a perfectly reasonable and valid thing for it to do. The problem is that this prevents me from using the
bic
instruction to clear the CPUOFF bit in the SR before the generatedreti instruction
. What I really want to do is perform abic
instruction immediately before thereti
instruction at the end of the interrupt. Then I could guarantee that the SR is on the top of the stack and clear the CPUOFF bit. The only way I can see to achieve this (though my imagination only goes so far) without making too significant of changes to Rust's msp430 support would be to ensure that the outermost stack frame doesn't need to push any registers sobic #16, @R1
will do what I want.This is where
msp430-rt
comes in. I believe that theinterrupt
macro (#[interrupt]
) should automatically do the following:call
instruction (this forces the inner function to clean up its stack before returning)asm!("bic #16, @R1");
after thecall
instructionThis would unconditionally wake the CPU back up after an interrupt.
I don't think this is perfectly ideal, but I believe that it would be better to unconditionally assume the CPU should be waken up after an interrupt than to wait until there is a proper solution that allows the user to specify if they would like to wake the CPU back up or not. Later we could add an inner inner function that returns a bool indicating if it should wake up or not and then set a static variable.
This very basic functionality I am suggesting could be added as a feature flag like
wake-after-interrupt
for people who are usingmsp430-rt
with embassy. Any alternatives to solve this problem are welcome. The MSP430 toolchain has a built-in that allows you to set flags in the SP for the function that was interrupted that can only be executed in the outermost stack frame of the interrupt, but I don't think we can reasonably implement this without adding special features to Rust that probably aren't worth the effort at this stage.The text was updated successfully, but these errors were encountered: