-
Notifications
You must be signed in to change notification settings - Fork 200
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 SAMD20J18A support #555
base: master
Are you sure you want to change the base?
Conversation
optional = true | ||
|
||
[dependencies.atsamd-hal] | ||
path = "../../hal" |
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 think we'll want this to be a tier two board, so no path dependency
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 I remove the path dependency, it will use the published crate which does not contains the current updates, how should I replace it?
Btw why does including this path makes it a Tier 1 dependency?
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.
ah, good point... I think we'll need to leave it as a path dependency for now since it's new.
Tier one BSPs use path dependencies on the HAL, which means for any HAL change affecting BSPs, all Tier one BSPs must be upgraded in the same PR for CI to pass. Tier two BSPs only rely on released versions of the HAL/PACs, so they can be locked to an older version and updated if someone is interested in doing so. This lowers the burden on maintainers as well as folks looking to change the HAL. See the README for more details.
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.
Ok, I understand now. Maybe we can remove the board implementation from this PR, and I open a new PR with it after this one is merged? (If yes, I would probably keep it until the end of the PR for practical reasons and remove it at the end :))
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.
FWIW, to facilitate development, one option is to use a patch in Cargo.toml . The idea would be to PR the changes that you want to eventually be published, but don't include the patch section which just refers to your local copy of atsamd-rs instead of the one on crates.io .
That said, it probably still makes sense to publish the PAC and HAL changes, before a separate PR to add the new boards.
name: pb31, | ||
aliases: { AlternateB: Sercom5Pad1SpiSS } | ||
}, | ||
); |
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.
It would be nice to have some of the other BSP helper functions, like SPI/I2C/UART.
hal/src/thumbv6m/clock.rs
Outdated
@@ -180,23 +180,35 @@ impl GenericClockController { | |||
} | |||
|
|||
// Feed 32khz into the DFLL48 | |||
state.enable_clock_generator(DFLL48, GCLK1); | |||
#[cfg(not(feature = "samd20"))] | |||
state.enable_clock_generator(ClockId::DFLL48, GCLK1); |
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 DFLL48
here but DFLL48M in
state.set_gclk_divider_and_source`?
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 svd file defines it that way. Maybe I can try adding a replacement rule in the xslt, I'll check that
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 made a replacement in the xslt so the naming is now identical :)
#[cfg(feature = "samd20")] | ||
while sercom.spi().status.read().syncbusy().bit_is_set() | ||
|| sercom.spi().ctrla.read().swrst().bit_is_set() | ||
{} |
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.
same syncbusy peripheral comment
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 think you missed SPI in your reg sync cleanup
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, sorry I just pushed my work of tonight and I will continue tomorrow, there are still a few things I need to clean :)
I'm not that familiar with SAMD20. But I think it's mostly SAMD21 without USB. So it's probably useful to have a common feature for them ( |
71800b2
to
74bf234
Compare
Yes, good idea! I'll try to make a |
74bf234
to
da90c84
Compare
85b143b
to
7c3958b
Compare
7c3958b
to
b76a5a5
Compare
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.
Looking better! the samd2x
feature helps a lot I think
|
||
[target.thumbv6m-none-eabi] | ||
runner = 'arm-none-eabi-gdb -q -x openocd.gdb' | ||
#runner = 'probe-run --chip ATSAMD21G18A' |
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: even this is commented out, it's the wrong chip name
optional = true | ||
|
||
[dependencies.atsamd-hal] | ||
path = "../../hal" |
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.
ah, good point... I think we'll need to leave it as a path dependency for now since it's new.
Tier one BSPs use path dependencies on the HAL, which means for any HAL change affecting BSPs, all Tier one BSPs must be upgraded in the same PR for CI to pass. Tier two BSPs only rely on released versions of the HAL/PACs, so they can be locked to an older version and updated if someone is interested in doing so. This lowers the burden on maintainers as well as folks looking to change the HAL. See the README for more details.
(PA28, Pa28), | ||
(PA30, Pa30), | ||
(PA31, Pa31), | ||
#[cfg(any(feature = "min-samd21j", feature = "min-samd51j"))] | ||
#[cfg(any(feature = "min-samd2x", feature = "min-samd51g"))] |
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.
Are you sure about all of these samd51j
-> samd51g
changes?
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 don't think these changes are correct. I was pretty confident about these attributes when I wrote the module.
@@ -40,6 +40,14 @@ pub mod uart; | |||
#[cfg(feature = "dma")] | |||
pub mod dma; | |||
|
|||
/// Register synchronization flags | |||
pub enum reg_sync { |
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 think enums are usually camel case RegSync
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 would like to look at this and verify it's the best approach to integrating with the rest of the sercom
code.
#[cfg(feature = "samd20")] | ||
return !self.spi().status.read().syncbusy().bit_is_set(); | ||
#[cfg(not(feature = "samd20"))] | ||
!self.spi().syncbusy.read().enable().bit_is_set() |
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: I'd prefer either both using return
or both not just for consistency
@@ -19,6 +19,12 @@ const BUS_STATE_BUSY: u8 = 3; | |||
const MASTER_ACT_READ: u8 = 2; | |||
const MASTER_ACT_STOP: u8 = 3; | |||
|
|||
enum i2c_reg_sync { |
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.
same camel case comment here
|
||
/// Wait for the registers synchronization | ||
#[inline] | ||
fn is_register_synced(&mut self, synced_reg: i2c_reg_sync) -> bool { |
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.
not sure &mut self
is needed for just a 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.
Same suggestion as for the SPI and UART modules: consider using the approach that doesn't require maintaining a bespoke enum.
#[cfg(feature = "samd20")] | ||
while sercom.spi().status.read().syncbusy().bit_is_set() | ||
|| sercom.spi().ctrla.read().swrst().bit_is_set() | ||
{} |
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 think you missed SPI in your reg sync cleanup
|
||
// 16x oversample fractional | ||
#[cfg(not(feature = "samd20"))] | ||
w.sampr().bits(0x00); |
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.
does SAMD20 not have oversampling setting? If it does and it's just different, make sure to still set it
pad_alias!(Sercom2, Sercom3); | ||
#[cfg(any(feature = "min-samd21g", feature = "min-samd51g"))] | ||
#[cfg(any(feature = "min-samd2x", feature = "min-samd51g"))] |
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.
What's the difference between min-samd2x
and samd2x
? That seems redundant. min-samd21g
is intended to exclude samd21e
.
/// Wait for the registers synchronization | ||
#[inline] | ||
fn is_register_synced(&mut self, synced_reg: reg_sync) -> bool { | ||
#[cfg(feature = "samd20")] | ||
return !self.spi().status.read().syncbusy().bit_is_set(); | ||
#[cfg(not(feature = "samd20"))] | ||
match synced_reg { | ||
reg_sync::CtrlB => !self.spi().syncbusy.read().ctrlb().bit_is_set(), | ||
reg_sync::Length => !self.spi().syncbusy.read().length().bit_is_set(), | ||
reg_sync::Enable => !self.spi().syncbusy.read().enable().bit_is_set(), | ||
reg_sync::SwRst => !self.spi().syncbusy.read().swrst().bit_is_set(), | ||
} | ||
} | ||
|
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 would like to look through the SAMD20 datasheet myself before we move forward with this.
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 would like to propose an alternate approach. Instead of declaring a function that takes an enum, we could do something like:
#[cfg(not(feature = "samd20"))]
#[inline]
fn sync_ctrlb(&self) {
while self.spi().syncbusy.read().ctrlb().bit_is_set() {}
}
#[cfg(feature = "samd20")]
#[inline]
fn sync_ctrlb(&self) {
while self.spi().status.read().syncbusy().bit_is_set() {}
}
This has the advantage of not having any overhead of passing enums around, and reduces chances of making mistakes. At any rate, a shared reference to self
is sufficient.
Also, SYNCBUSY.LENGTH
seems to be exclusive to SAMx5x targets.
#[cfg(feature = "samd20")] | ||
w.txpo().bit(txpo != 0); | ||
#[cfg(not(feature = "samd20"))] | ||
w.txpo().bits(txpo); | ||
w.rxpo().bits(rxpo) |
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 review the differences in SERCOM carefully. @jbeaurivage, have you looked at this yet?
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 haven't yet, but I'd definitely like to comb through this finely with the datasheet next to me. Annoyingly enough, it seems the SAMD20 isn't exactly 'just a SAMD21 minus the USB'.
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.
@didjcodt, can you please explain what's the reasoning here? This kind of thing should probably be handled at the impl_rxpotxpo
level rather than inside the functions.
#[cfg(any(feature = "samd11", feature = "samd21"))] | ||
#[cfg(any(feature = "samd11", feature = "samd2x"))] |
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.
Please revert this change
//! SAMD11/SAMD21, the CHID register must be written with the correct channel ID | ||
//! before accessing the channel specific registers. There is a provided | ||
//! `with_chid` method that takes a closure with the register read/write proxies | ||
//! to ensure any read/write to these registers are done in an interrupt-safe | ||
//! way. For SAMD51+, `with_chid` returns the register block which contains the | ||
//! registers owned by a specific channel. | ||
//! SAMD11/SAMD20/SAMD21, the CHID register must be written with the correct | ||
//! channel ID before accessing the channel specific registers. There is a | ||
//! provided `with_chid` method that takes a closure with the register | ||
//! read/write proxies to ensure any read/write to these registers are done in | ||
//! an interrupt-safe way. For SAMD51+, `with_chid` returns the register block | ||
//! which contains the registers owned by a specific channel. |
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.
Please remove SAMD20 from this comment
#[cfg(any(feature = "samd11", feature = "samd21"))] | ||
#[cfg(not(feature = "min-samd51g"))] |
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.
Please revert this change
#[cfg(any(feature = "samd11", feature = "samd21"))] | ||
#[cfg(not(feature = "min-samd51g"))] |
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.
Please revert this change
not(any(feature = "samd11", feature = "samd21")), | ||
feature = "min-samd51g", |
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 would remove all changes to the dmac
module, because the SAMD20 chips do not have a DMAC
peripheral on board. Could you please feature-gate the dmac
module to exclude SAMD20?
#[cfg(feature = "samd21")] | ||
use crate::pac::{TC3, TC4, TC5, TCC1, TCC2}; | ||
#[cfg(feature = "samd21j")] | ||
#[cfg(feature = "samd2x")] |
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.
Does this mean that SAMD20s don't have TC1 and TC2?
|
||
/// Wait for the registers synchronization | ||
#[inline] | ||
fn is_register_synced(&mut self, synced_reg: i2c_reg_sync) -> bool { |
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.
Same suggestion as for the SPI and UART modules: consider using the approach that doesn't require maintaining a bespoke enum.
#[cfg(feature = "samd20")] | ||
self.i2cm() | ||
.addr | ||
.write(|w| w.addr().bits(addr)); | ||
#[cfg(not(feature = "samd20"))] |
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 is this different?
|
||
#[cfg(feature = "samd20")] | ||
if status.lowtout().bit_is_set() { | ||
return Err(I2CError::Timeout); | ||
} | ||
#[cfg(not(feature = "samd20"))] | ||
if status.lowtout().bit_is_set() || status.sexttout().bit_is_set() | ||
|| status.mexttout().bit_is_set() | ||
{ |
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 might want to break this up into separate SAMD20/non-SAMD20 functions to avoid so many #[cfg]
s, or at least into config blocks.
#[cfg(feature = "min-samd21g")] | ||
#[cfg(feature = "min-samd2x")] |
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.
min-samd21g
-> min-samd2x
Summary
This Pull Request integrates the SAMD20J18A microcontroller:
This is only a proof of concept, not all features have been tested in real life even though everything compiles fine :)
Checklist
CHANGELOG.md
for the BSP or HAL updatedIf Adding a new Board
crates.json