2020-04-20 05:05 PM
I am currently working on a Rust implementation of a STM32f3 Discovery Board hal. As mentioned in the documentation, I am doing the following:
Before setting the WUTE bit, I also set the WUTIE bit. My ultimate goal is the trigger a 1 second periodic interrupt using the RTC. The moment I set the WUTE bit, I see all of the bits that I have just set in the RTC_CR register go low, while the RTC_WUTE bit remaining high. Is this normal? I tried testing out the code to see if the interrupts are active, to no avail.
2020-04-20 10:50 PM
At this point I normally would say "post code" but since
> Rust ... HAL
doesn't sound familiar... post instructions (disasm) leading to the described result.
JW
2020-04-22 10:12 AM
Hello @Community member ,
I am currently not at home, but I will give you the instructions as soon as I am able! I happen to have screenshots of the registers before and after. For now, I hope this paints a better picture.
BEFORE (I select LSI as clock source):
AFTER ( after setting WUTE, WCKSEL is set back to 0b000 for some reason):
Moreover, when I set WUTIE to allow for the hardware interrupt, it then clears the WUTE bit:
This is the behavior that I was asking about. Is it normal for the signals to be cleared like that?
I'll go ahead and paste the snippet of Rust code, in the event that it aids in understanding.
self.modify(|regs| {
regs.wutr.write(|w| unsafe { w.wut().bits(0x0001) });
regs.cr.write(|w| unsafe { w.wcksel().bits(clocksrc) });
regs.cr.write( |w| w.wute().set_bit() );
regs.cr.write(|w| w.wutie().set_bit() );
});
2020-04-23 12:23 PM
Hello @Community member ,
I've attached the complete disassembly output (output.txt) describing what is going on leading up to the register changes. Below is the code in Rust for reference:
fn modify<F>(&mut self, mut closure: F)
where
F: FnMut(&mut RTC) -> (), {
// Disable write protection
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
// Enter init mode
let isr = self.regs.isr.read();
if isr.initf().bit_is_clear() {
self.regs.isr.write(|w| w.init().set_bit());
while self.regs.isr.read().initf().bit_is_clear() {}
}
// Invoke closure
closure(&mut self.regs);
// Exit init mode
self.regs.isr.write(|w| w.init().clear_bit());
// wait for last write to be done
while !self.regs.isr.read().initf().bit_is_clear() {};
//Locks write protect
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
The closure on line 14 is kind of like a lambda function. It is executing the code snippet that I posted on the previous post:
self.modify(|regs| {
regs.wutr.write(|w| unsafe { w.wut().bits(0x0001) });
regs.cr.write(|w| unsafe { w.wcksel().bits(clocksrc) });
regs.cr.write( |w| w.wute().set_bit() );
regs.cr.write(|w| w.wutie().set_bit() );
});
This is represented by this part of the assembly (taken from output.txt):
~"156\t // Invoke closure\n"
~"157\t closure(&mut self.regs);\n"
~"=> 0x08001eca <+376>:\tldr\tr0, [sp, #52]\t; 0x34\n"
~" 0x08001ecc <+378>:\tstr\tr0, [sp, #84]\t; 0x54\n"
~" 0x08001ece <+380>:\tldr\tr1, [sp, #84]\t; 0x54\n"
~" 0x08001ed0 <+382>:\tadd\tr0, sp, #56\t; 0x38\n"
~" 0x08001ed2 <+384>:\tbl\t0x800178a <stm32f3xx_hal::rtc::Rtc::enable_wut::{{closure}}>\n"
~" 0x08001ed6 <+388>:\tb.n\t0x8001ed8 <stm32f3xx_hal::rtc::Rtc::modify+390>\n"
~" 0x08001ed8 <+390>:\tldr\tr0, [sp, #52]\t; 0x34\n"
~" 0x08001eda <+392>:\tstr\tr0, [sp, #284]\t; 0x11c\n"
~"\n"
I have extremely limited experience with reading assembly code. Please let me know if I can provide more useful information!
-Best
Scott
2020-04-23 12:25 PM
Hello @waclawek.jan (Community Member) ,
I've attached the complete disassembly output (output.txt) describing what is going on leading up to the register changes. Below is the code in Rust for reference:
fn modify<F>(&mut self, mut closure: F)
where
F: FnMut(&mut RTC) -> (), {
// Disable write protection
self.regs.wpr.write(|w| unsafe { w.bits(0xCA) });
self.regs.wpr.write(|w| unsafe { w.bits(0x53) });
// Enter init mode
let isr = self.regs.isr.read();
if isr.initf().bit_is_clear() {
self.regs.isr.write(|w| w.init().set_bit());
while self.regs.isr.read().initf().bit_is_clear() {}
}
// Invoke closure
closure(&mut self.regs);
// Exit init mode
self.regs.isr.write(|w| w.init().clear_bit());
// wait for last write to be done
while !self.regs.isr.read().initf().bit_is_clear() {};
//Locks write protect
self.regs.wpr.write(|w| unsafe { w.bits(0xFF) });
}
The closure on line 14 is kind of like a lambda function. It is executing the code snippet that I posted on the previous post:
self.modify(|regs| {
regs.wutr.write(|w| unsafe { w.wut().bits(0x0001) });
regs.cr.write(|w| unsafe { w.wcksel().bits(clocksrc) });
regs.cr.write( |w| w.wute().set_bit() );
regs.cr.write(|w| w.wutie().set_bit() );
});
This is represented by this part of the assembly (taken from output.txt):
~"156\t // Invoke closure\n"
~"157\t closure(&mut self.regs);\n"
~"=> 0x08001eca <+376>:\tldr\tr0, [sp, #52]\t; 0x34\n"
~" 0x08001ecc <+378>:\tstr\tr0, [sp, #84]\t; 0x54\n"
~" 0x08001ece <+380>:\tldr\tr1, [sp, #84]\t; 0x54\n"
~" 0x08001ed0 <+382>:\tadd\tr0, sp, #56\t; 0x38\n"
~" 0x08001ed2 <+384>:\tbl\t0x800178a <stm32f3xx_hal::rtc::Rtc::enable_wut::{{closure}}>\n"
~" 0x08001ed6 <+388>:\tb.n\t0x8001ed8 <stm32f3xx_hal::rtc::Rtc::modify+390>\n"
~" 0x08001ed8 <+390>:\tldr\tr0, [sp, #52]\t; 0x34\n"
~" 0x08001eda <+392>:\tstr\tr0, [sp, #284]\t; 0x11c\n"
~"\n"
I have extremely limited experience with reading assembly code. Please let me know if I can provide more useful information!
-Best
Scott
2020-04-23 02:53 PM
156 // Invoke closure
157 closure(&mut self.regs);
=> 0x08001eca <+376>: ldr r0, [sp, #52] ; 0x34
0x08001ecc <+378>: str r0, [sp, #84] ; 0x54
0x08001ece <+380>: ldr r1, [sp, #84] ; 0x54
0x08001ed0 <+382>: add r0, sp, #56 ; 0x38
0x08001ed2 <+384>: bl 0x800178a <stm32f3xx_hal::rtc::Rtc::enable_wut::{{closure}}>
0x08001ed6 <+388>: b.n 0x8001ed8 <stm32f3xx_hal::rtc::Rtc::modify+390>
0x08001ed8 <+390>: ldr r0, [sp, #52] ; 0x34
0x08001eda <+392>: str r0, [sp, #284] ; 0x11c
This does not do much - just pulls some parameters from stack and calls the routine at 0x800178a. That routine presumably does the bulk of the job.
[EDIT] I've just noticed output.txt... okay that would take some time to go through... [/EDIT]
[EDIT2] From what I understand, the code in output.txt does mostly nothing just prepares constants (0x40002824 and 0x4000280C which are RTC_WPR and RTC_ISR, repsectively) onto stack, in several instances; in an incredibly convoluted and inefficient way. Then the call commented above is made which presumably does the "real thing".
Try to single-step the code in disasm view (i.e. instruction-by-instruction) and observe, where and how the RTC registers are written - it's pretty simple to spot when viewed real-time in debugger. It is a STR instruction, where the first parameter is the register which contains the value to be writeen, and the second (in brackets) is the register which contains the target address, sometimes together with a constant offset.
Or, try to describe, what your code is supposed to do, step-by-step, in a common procedural language, e.g. C, or as narrative.
JW