-
-
Notifications
You must be signed in to change notification settings - Fork 11
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
HAL: Add PMC, EFC configuration APIs #16
Conversation
So far |
Depends on #15. |
You might want to also take jamesmunns/same70-experiments@58a3c34, which fixed a couple things I found through testing. |
Sourced from [0]; /vendor/asamx7x-hal. [0] jamesmunns/same70-experiments@58a3c34
Amended, thanks. |
@@ -145,3 +145,7 @@ pub use atsamv71q21b as target_device; | |||
pub mod serial; | |||
#[cfg(feature = "rev-b")] | |||
pub mod watchdog; | |||
#[cfg(feature = "rev-b")] |
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.
If you haven't seen the cfg-if
crate, it's pretty handy for avoiding wordy cfgs like this.
Thanks @jamesmunns for the hint. From what I remember all MCUs in this series share peripherals implementations, only register allocation and number of instances varies. Thanks @tmplt for bringing this in. I'll review over the weekend. |
More features will be added in future commits that require explicit configuration. Moved to build.rs to remove noise from HAL implementation.
I have briefly looked over the current PMC API and considered some changes, inspired by the in-progress Here's is a draft of such an API application (not finalized): let pmc = pmc::new(device.PMC);
// fundamental clock configuration (HCLK, FCLK, MCK)
let mainck = pmc.get_mainck(MainClkConfig::Internal(12.to_Hz()))?;
let plla = pmc.get_plla(PllaConfig { source: mainck, div: 1, mult: 4 })?;
let (hclk, mck) = pmc.get_clocks(ClocksConfig { source: plla, pres: ClocksPrescaler::Pres4, div: MckDiv::Pres1 });
// peripheral clock configuration
let pck4 = pmc.get_peripheral(4, PeriphClkConfig { source: plla, pres: 1 })?; |
device-selected is a meta-feature that is not described in §2.
This change supports the theoretical case of non-constant VDDIO (for E70/S70). An enum is also a much stronger association, rather than an environmental variable (feature).
That is, so the crate does not build if only device-selected is enabled.
We will be utilizing this information later down the line, for example when configuring peripheral baud rates.
UPLLCKDIV is derived from UPLLCK by either /1 or /2. Only the divider is forwarded to HCLK and PCK, as per §31.3.
Some clocks will emit MHz (UPLLCK, MAINCK) while others will emit Hz (PLLA - depending on dev/mult, and SLCK).
This will later be moved into a proper examples/*.rs when a GPIO API is available.
This is now ready for review. The documented example (which is a copy of the added The module can probably be improved by some macro application, but I cannot prioritize that at the moment. More safety can also be added, such as ensuring that a clock that is in used it not turned off, but that too must wait for my part. |
I must have spoken too soon: |
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 good in overall, but I have a few suggestions if you don't mind.
} | ||
|
||
impl PeripheralIdentifier { | ||
pub fn supports_pmc_clocking(&self) -> Result<(), ()> { |
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.
Why Result<>
and why not const?
[[package]] | ||
name = "fugit" | ||
version = "0.3.5" | ||
source = "registry+https://github.com/rust-lang/crates.io-index" | ||
checksum = "f6d8595783d5ca52f0e9830036b3d24f359fae0fcc6bb5fde41f2dd82997cb58" | ||
dependencies = [ | ||
"gcd", | ||
] | ||
|
||
[[package]] | ||
name = "gcd" | ||
version = "2.1.0" | ||
source = "registry+https://github.com/rust-lang/crates.io-index" | ||
checksum = "f37978dab2ca789938a83b2f8bc1ef32db6633af9051a6cd409eff72cbaaa79a" | ||
dependencies = [ | ||
"paste", |
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 always thought the rule in Rust world is not to commit Cargo.lock
for library crates.
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.
Somehow slipped through; I'll remove it.
# Refer to §2 in the data sheet. | ||
## Refer to §2. |
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.
? Why refer doubled here?
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.
Good catch.
// Configure the clock hierarchy | ||
{ | ||
use hal::pmc::{ | ||
HostClockConfig, MainCkSource, MckDivider, MckPrescaler, Megahertz, PckId, | ||
PllaConfig, Pmc, UpllDivider, | ||
}; | ||
|
||
let mut pmc = Pmc::new(ctx.device.PMC); | ||
let mainck = pmc | ||
.get_mainck(MainCkSource::ExternalBypass(Megahertz::from_raw(12))) | ||
.unwrap(); | ||
let _plla = pmc | ||
.get_pllack(PllaConfig { div: 1, mult: 8 }, &mainck) | ||
.unwrap(); | ||
let _hclk = pmc | ||
.get_hclk( | ||
HostClockConfig { | ||
pres: MckPrescaler::CLK_1, | ||
div: MckDivider::EQ_PCK, | ||
}, | ||
&mainck, | ||
&mut efc, | ||
) | ||
.unwrap(); | ||
|
||
let upllck = pmc.get_upllck(&mainck, &mut ctx.device.UTMI).unwrap(); | ||
let upllckdiv = pmc.get_upllckdiv(&upllck, UpllDivider::Div2); | ||
let _pck2 = pmc.get_pck(&upllckdiv, 100 - 1, PckId::Pck2); // @ 2.4MHz | ||
} |
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.
Wouldn't be more readable if these are separate functions?
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'm not sure what you mean. What functions here could be further separated?
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.
The whole function is long but seems to have clear separation into stages. To improve readability they could be shorter private functions with descriptive names.
pub enum VddioLevel { | ||
/// VDDIO = 3.3V, typical | ||
V3, | ||
/// VDDIO = 1.7V, minimal | ||
V1, | ||
} |
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.
Wouldn't V3v3
and V1v7
more accurate in places where code is read?
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.
Good idea; those are much better names.
pub fn calculate(freq: Megahertz, vddio: &VddioLevel) -> Result<Self, PmcError> { | ||
#[cfg(any(feature = "v70", feature = "v71"))] | ||
if vddio == &VddioLevel::V1 { | ||
// V70/V71 must be driven with VDDIO = 3.3V, typical | ||
return Err(PmcError::InvalidConfiguration); | ||
} | ||
|
||
Self::fws_from_freq(freq, vddio) | ||
} |
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.
Shouldn't we prevent the invalid configuration at compile time?
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.
We should. I had not played around with the type system before I began work on #18. I'll review this module and see what can be made static.
// TODO hande note for MOSCRCF unhandled (p. 276; | ||
// first table, second row) |
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.
Can I suggest one of commercial practices that I like? Turn each TODO into an issue, then point the issue ID with the comment like: // TODO #333: Handle note for MOSCRF
- I've learnt TODO comments quickly gets neglected and later in time confuse other contributors. With issue in place there's more urge to actually do the stuff.
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.
Yep, let's do that.
}); | ||
while self.pmc.pmc_sr.read().moscsels().bit_is_clear() {} | ||
|
||
// TODO check MAINCK frequency (§31.17; step 5). |
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.
Ditto.
/// This method corresponds to Step 6 of 31.17 Recommended Programming Sequence. | ||
pub fn get_pllack<SRC: PllaSource>( |
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.
Would be nice to equip docs of these API functions with some 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.
Do you mean an example for each get_
-function?
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.
Yes.
if div == 0 || div > 127 { | ||
return Err(PmcError::InvalidConfiguration); | ||
} | ||
// TODO: Ensure valid requested output frequency. |
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.
Ditto.
Thanks for the review, @michalfita. I am busy with internal development of this HAL at the moment, but aim to continue the upstreaming process here when time is available. It can take a while until then. |
You @martinmortsell and @jamesmunns are probably only users of this work ATM, so it's fine. However, it would be nice to release it at some point. |
Branch is now deprecated. Closing. Refer to #24. |
Before this commit other pin bits were not preserved. Closes atsams-rs#16.
hal/pio: correctly modify ABCD registers on Pin::into_peripheral Closes atsams-rs#16 See merge request embedded-rust/atsamx7x-hal!5
Based upon @jamesmunns work, described in #14, but heavily refactored.
Closes #5.