-
Notifications
You must be signed in to change notification settings - Fork 30
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
Add tempmon abstruction #115
Conversation
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.
Thank you for contributing!
I think in general the idea is really nice, and the API seems reasonable. A few things though..
The usage of floats in the API is, in my opinion, is less than ideal. It's ok if you have a few helper functions alongside this as const fn's if you like, but float as a whole tend to be troublesome. Yes this micro has a fpu so perhaps its less of an issue, but generally speaking, on a microcontroller and it's SDK you aren't likely going to see floats in use.
Does it make sense as well to make the powered state of this peripheral part of its type state to help the programmer ensure the peripheral is in the desired state at various code points where it might be used?
Consider someone calls get_temp(), or measure_temp on an unpowered tempmon, what happens if its off?
Actually, I will add a power_on check and as you mention and I turn the values into a Result. One additional question:Should I change the messure_temp() into non-blocking and return |
Seems reasonable, a Result return here makes sense as it is fallible if the device isn't on. Perhaps using nb here would be nice, I haven't used it in an async way myself though so I can't comment one way or the other here |
ich changed the math to °mC and adopted the docs to that. In addition, I implemented an error handling to deal with the power_down state. The temp_mon.measure_temp() is now compatible to I also ran |
@mciantyre, I created an example app to test this code, should I add it to teensy4-rs/examples? |
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.
Thanks for the new peripheral. A few questions and observations from my first review.
I created an example app to test this code, should I add it to teensy4-rs/examples?
Happy to maintain it there. Thanks!
imxrt-hal/src/tempmon.rs
Outdated
ral::write_reg!( | ||
ral::tempmon, | ||
self.base, | ||
TEMPSENSE0, | ||
MEASURE_TEMP: 1 | ||
); |
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.
This write_reg!
sets the MEASURE_TEMP
bit high, and sets all other register bits to zero. We're similarly using write_reg!
throughout this implementation to change one field in a register. Is this causing any issues in practice?
Would modify_reg
, which preserves the unspecified fields, be more appropriate? Or, could we use the various *_SET
, *_CLR
, and *_TOGGLE
registers with write_reg!
to achieve our goals? It might be better to write this 1 to TEMPSENSE0_SET
, since the hardware will preserve the other bits. (I'd recommend using the set/clear/toggle registers when possible. We could then discuss &mut self
vs &self
receivers for these methods.)
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.
I changed it, please let me know if this is how it should be. I didn't find an example.
I think it should be &mut self.
Otherwise, somebody could change the behavior of the tempmon without having a mutable reference.
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.
I changed it, please let me know if this is how it should be. I didn't find an example
Found it, modify_reg!()
is what I was looking for
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.
Were there issues using the *_SET
and *_CLR
register variants? I noticed a commit that added them, then another commit to prefer modify_reg!
.
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.
I just changed it, because I didn't really understand how it works. but using *_SET
and *_CLR
feels much faster!
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.
Ahh I'm sorry I wasn't clear. The latest commit shows you're using these registers pefectly. Thanks for taking another look!
Quick summary for future PR readers:
- All high bits written to a
*_SET
register will set the corresponding in the normal register - All high bits written to a
*_CLR
register will clear the corresponding bits in the normal register - All high bits written to a
*_TOG
register will toggle the corresponding bits in the normal register
Note that we're always writing high bits, even if the end result is to produce low bits in the register.
Section 1.5.2 of the 1060 reference manual provides more discussion about these special registers. In particular,
[...] it is more efficient to simply set or clear the target bit [...]. A simple set or clear operation is also atomic, while a CS [clear then set] operation is not.
I see your point about taking &mut self
, since this operation changes the peripheral's state. But on the other hand, just as we can safely modify an atomic behind a shared reference &self
, we might be able to safely start, stop, power up, and power down the tempmon peripheral behind a &self
when using these special registers. (Let's not change anything in this PR, since I'm still looking for feedback on this idea.)
imxrt-hal/src/tempmon.rs
Outdated
// this could be triggered again without any effect | ||
Err(nb::Error::WouldBlock) | ||
} else { | ||
self.measurement_active = false; |
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.
Is it important to maintain this state in RAM? This seems like information we already have in the MEASURE_TEMP
field. Instead of setting this bool to false
, we could set MEASURE_TEMP = 0
.
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.
I thought about that as well, but there is an edge-case.
The Chip sets MEASURE_TEMP to 0 as soon he finished the measurement in single-shot mode.
If MEASURE_TEMP is 0 again, I would start the next measurement and never reach the TEMP_CNT
section
I'm sorry, but I didn't find a better solution. This is really not a nice solution :-(
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.
Thanks for clarifying. I read that FINISHED
clears, but I didn't read that the hardware could also clear MEASURE_TEMP
. If that't the case, this seems perfect.
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.
believe it or not, I double-checked it and I didn't know why I assumed this behavior.
Probably I expected this that way because I start the next measurement with a 1.
I learned a lot about memory-mapping and how it works. Thanks for your patience :-)
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.
No problem! Thanks for double checking, and for updating the approach. It wouldn't have surprised me if the behavior was undocumented / missing in the reference manual 😛.
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.
I believe all the vital changes have been made, some wording could be improved in some comments such as describing parameters and returns, especially units involved when they aren't clear.
imxrt-hal/src/tempmon.rs
Outdated
// this could be triggered again without any effect | ||
Err(nb::Error::WouldBlock) | ||
} else { | ||
self.measurement_active = false; |
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.
Thanks for clarifying. I read that FINISHED
clears, but I didn't read that the hardware could also clear MEASURE_TEMP
. If that't the case, this seems perfect.
imxrt-hal/src/tempmon.rs
Outdated
ral::write_reg!( | ||
ral::tempmon, | ||
self.base, | ||
TEMPSENSE0, | ||
MEASURE_TEMP: 1 | ||
); |
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.
Were there issues using the *_SET
and *_CLR
register variants? I noticed a commit that added them, then another commit to prefer modify_reg!
.
Thanks for all your patience! I learned a lot about the RAL layer and many other things. I think this is it now 🎉 |
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.
Looks awesome. Thank you for working through this!
OK with me to merge. Leaving this open in case @teburd wants any other documentation updates. Otherwise, I'll merge and forward port to the main branch sometime next / the following weekend.
We can use #116 to discuss how we want to release this feature.
imxrt-hal/src/tempmon.rs
Outdated
ral::write_reg!( | ||
ral::tempmon, | ||
self.base, | ||
TEMPSENSE0, | ||
MEASURE_TEMP: 1 | ||
); |
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.
Ahh I'm sorry I wasn't clear. The latest commit shows you're using these registers pefectly. Thanks for taking another look!
Quick summary for future PR readers:
- All high bits written to a
*_SET
register will set the corresponding in the normal register - All high bits written to a
*_CLR
register will clear the corresponding bits in the normal register - All high bits written to a
*_TOG
register will toggle the corresponding bits in the normal register
Note that we're always writing high bits, even if the end result is to produce low bits in the register.
Section 1.5.2 of the 1060 reference manual provides more discussion about these special registers. In particular,
[...] it is more efficient to simply set or clear the target bit [...]. A simple set or clear operation is also atomic, while a CS [clear then set] operation is not.
I see your point about taking &mut self
, since this operation changes the peripheral's state. But on the other hand, just as we can safely modify an atomic behind a shared reference &self
, we might be able to safely start, stop, power up, and power down the tempmon peripheral behind a &self
when using these special registers. (Let's not change anything in this PR, since I'm still looking for feedback on this idea.)
imxrt-hal/src/tempmon.rs
Outdated
// this could be triggered again without any effect | ||
Err(nb::Error::WouldBlock) | ||
} else { | ||
self.measurement_active = false; |
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.
No problem! Thanks for double checking, and for updating the approach. It wouldn't have surprised me if the behavior was undocumented / missing in the reference manual 😛.
Noted the places where I saw units for parameters and returns might be useful, I believe its mC -> C and vice versa, but would be nice to have it noted there. |
I got a little bit side trapped by the Temperature Monitor (TEMPMON)
I thought it is barely simple and a great start in getting my hands dirty with the
imxrt-ral
ecosystem.The interrupts are not really handy.
Open to discuss
I played around with the UX a little bit and finally, it is OK.
In my test app, I implemented a static alarm flag to note, when I have to enable the interrupts again.
Another method would be, to stop the measurement process, but as soon you read the temperature, the interrupt is triggered again.
If anybody has a great idea on how to improve it, please let me know 😃