Skip to content

Supporting adafruit ATSAMD21 based boards #61

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

Closed
4 tasks
wez opened this issue Mar 12, 2018 · 9 comments
Closed
4 tasks

Supporting adafruit ATSAMD21 based boards #61

wez opened this issue Mar 12, 2018 · 9 comments
Labels
feb-2019-cleanup These issues are proposed to be closed, as part of a cleanup of issues in February 2019

Comments

@wez
Copy link

wez commented Mar 12, 2018

I hack on keyboard hardware and firmware in my spare time, and I do it in bursts. I've previously worked with the nrf52 boards from adafruit and have made contact with @jamesmunns on that front.

I have a few adafruit boards that I'd love to use with rust and I'm willing to help move the ball forwards, but I'm not super sure what to do, in which order, and I'm not sure what the current best practices are.

I'm going to list my assumptions below, can you correct me and/or point me in the right direction?
I suspect some of this aligns with the weekly driver initiative, but some of these are lower level board support things.

Available M0 hardware

I have these boards floating around; they're all based on the ATSAMD21:

I'm looking at targeting the Feather M0 express for a future build, but want to make some progress on the rust side first. Ultimately, I'd like to get pure rust USB peripheral support working on one of these things. I have a couple of cheap SWD debugging adapters.

Game plan

  • apply svd2rust to svd files from http://packs.download.atmel.com/ to generate the low level board support files
  • Publish a crate named something like atsamd21_svd for this
  • Write the human-curated board support crate(s) for these. Should these get published in an adafruit m0 crate? Guidance on structure and naming appreciated! Are there canonical examples of these?
  • Quickstart crate specifically for the adafruit boards? Not sure if this is needed or if the existing cortex-m-quickstart is sufficient. Is there an alternative approach that should be taken? Does
    One step setup #43 make some of this obsolete?

Does that sound like the right plan? What am I missing? Are there folks interested in reviewing/providing feedback on these steps?

Thanks!

@wez wez mentioned this issue Mar 12, 2018
@kevinmehall
Copy link

I'm interested in this as well, and would have published said atsamd21_svd crate already if it were that simple, but svd2rust can't handle a few of the features that Atmel uses in their SVDs. I've been meaning to put some time into fixing this, but haven't gotten very far yet.

The biggest missing svd2rust feature, register clusters, just landed (rust-embedded/svd2rust#107), but I haven't had a chance to test it yet. The timers, RTC, SERCOM, and USB peripherals have their entire interface within SVD <cluster> elements, which were previously ignored.

Remaining missing features that I know of: (updated from my comment here)

  • derivedFrom on registers (blocked on Implement derivedFrom on cluster/register/field/enumeratedvalues element svd#21) -- this is the cause of some of the "overlaps with another register" warnings, because the register width defaults to 32bit when a register is derived from another 8 bit register and this attribute is ignored.

  • overlapping registers ("overloaded" registers svd2rust#16) -- the rest of the "overlaps with another register" is when there are legitimately two registers at the same address. They use this when the field layout of the register depends on the configuration. Some of them, like the count_dith4 are pretty useless though, as it's just changing the number of valid bits in the count field depending on the dithering setting.

@therealprof
Copy link
Contributor

What @kevinmehall said. I've written code for the ATSAMD20 a while ago (https://github.com/therealprof/atsamd20e15a) to support https://github.com/LuckyResistor/SnowFlakeProject so I might be able to help out with a few bits and pieces. However that MCU is so quirky, the documentation incomplete and utter crap and the a community pretty much non-existent so I don't want to sink a lot of time there...

@wez
Copy link
Author

wez commented Mar 12, 2018

@kevinmehall ah, interesting. I skimmed those two outstanding issues; do you have a sense of how complicated they'd be to resolve? Does it require deep-diving into the svd spec and rewriting the parser/code generator for svd? I'm hesitant to dive in there because I saw commentary on #46 that suggested that that code was really in need of love to make it easier to maintain.

Alternatively, can we squeak by without those by making some tweaks to the SVD? Obviously not a long term strategy; just trying to get a sense of how much ocean boiling is needed to get things going :-)

@wez
Copy link
Author

wez commented Mar 13, 2018

FWIW, I just ran svd2rust; rust-embedded/svd2rust#191 is the only hard error I get with svd2rust master at the moment. There are also warnings about overlapping registers for pmux and pincfg.

@tannewt
Copy link

tannewt commented Mar 13, 2018

I work for Adafruit on CircuitPython and would love to see Rust support. I work with the SAMD21 and SAMD51 day-to-day and would be happy to answer any questions. It'd be awesome to produce UF2 files for easy loading with our bootloader.

Also, if anyone needs hardware, let me know ([email protected]) and I'll see what I can do (no promises). The Metro is usually the easiest to develop on because it has an SWD header.

As far as board definitions go, our equivalent in CircuitPython lives here: https://github.com/adafruit/circuitpython/tree/master/ports/atmel-samd/boards

@wez
Copy link
Author

wez commented Mar 15, 2018

https://github.com/wez/svd2rust/tree/derivedFrom and https://github.com/wez/svd/tree/altreg are the current state of my svd changes (including @nsabovic's rust-embedded/svd2rust#190).

With that build I can generate the atsamd21 svd with no warnings, with unions for the overlapping portions and with PMUX1_%s correctly derived. I need to try to use the results in some real code and run it on one of these boards, and do some more rigorous regression testing, but I think we're a bit closer to something real now!

@wez
Copy link
Author

wez commented Mar 16, 2018

I've created https://github.com/wez/atsamd21-rs to hold the svd2rust generated bits as well as the hal bits that I'm going to be looking at this weekend. It requires the changes that I've submitted as PRs to svd2rust to generate the underlying peripheral access crate(s). I've included just the ATSAMD21G18A for now as that matches the hardware I'm going to test with.

I'm not sure if the current structure is or should be the final structure; there are a number of board variants and it would be nice to do something to automatically extract the common parts. I'm going to ignore that aspect for now and focus instead on the basic hal for the board I have.

wez added a commit to wez/awesome-embedded-rust that referenced this issue Apr 21, 2018
These both live in the same repo, so I'm not sure if you'd prefer to break this out and link to the subdirs in that repo or just keep this one entry.

rust-embedded/wg#61 is the issue I opened with some background on this.
bors bot added a commit to rust-embedded/svd2rust that referenced this issue May 8, 2018
192: Emit unions for overlapping/overloaded registers r=Emilgardis a=wez

I want to get a complete working build for ATSAMD21 (rust-embedded/wg#61) so I'm taking a stab at that.

* Introduced a `FieldRegion` helper to reason about overlapping regions
* If overlaps are detected, a `union` container is emitted
* If the only item in a `RegisterBlock` is a union, that `RegisterBlock` is emitted as a union
* Otherwise: we generate a name for the union field by taking the longest common prefix of the union's alternates, or just pick an artificial name like `u1` if there was no common prefix.
* If the starting address offset of elements in a union are not all the same, we don't have a way to emit padding for them today.  We will emit a warning (and bad code) in that case (example below).  The one example of this I see in ATSAMD21 is due to missing `derivedFrom` support for registers; we're currently generating bad code for these anyway.  I have resolved in another branch that I'll turn into a PR once this one is landed.

```
WARNING: field Some(Ident("pmux1_1")) has different offset 177 than its union container 176
WARNING: field Some(Ident("pmux1_2")) has different offset 178 than its union container 176
```

Examples:

```
#[doc = "Real-Time Counter"]
pub mod rtc {
    #[doc = r" Register block"]
    #[repr(C)]
    pub union RegisterBlock {
        #[doc = "0x00 - Clock/Calendar with Alarm"]
        pub mode2: MODE2,
        #[doc = "0x00 - 16-bit Counter with Two 16-bit Compares"]
        pub mode1: MODE1,
        #[doc = "0x00 - 32-bit Counter with Single 32-bit Compare"]
        pub mode0: MODE0,
    }
```

```
    #[doc = r" Register block"]
    #[repr(C)]
    pub struct USART {
        #[doc = "0x00 - USART Control A"]
        pub ctrla: self::usart::CTRLA,
        #[doc = "0x04 - USART Control B"]
        pub ctrlb: self::usart::CTRLB,
        _reserved2: [u8; 4usize],
        #[doc = "USART Baud Rate"]
        pub baud: baud_union,
      ...
    }
    #[doc = "USART Baud Rate"]
    #[repr(C)]
    pub union baud_union {
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_usartfp_mode: self::usart::BAUD_USARTFP_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_fracfp_mode: self::usart::BAUD_FRACFP_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_frac_mode: self::usart::BAUD_FRAC_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud: self::usart::BAUD,
    }
```

Refs: #191 
#16



Co-authored-by: Wez Furlong <[email protected]>
Co-authored-by: Emil Gardström <[email protected]>
bors bot added a commit to rust-embedded/svd2rust that referenced this issue May 8, 2018
192: Emit unions for overlapping/overloaded registers r=Emilgardis a=wez

I want to get a complete working build for ATSAMD21 (rust-embedded/wg#61) so I'm taking a stab at that.

* Introduced a `FieldRegion` helper to reason about overlapping regions
* If overlaps are detected, a `union` container is emitted
* If the only item in a `RegisterBlock` is a union, that `RegisterBlock` is emitted as a union
* Otherwise: we generate a name for the union field by either taking the shortest common prefix of the union's alternates or the shortest register name (depending on type name conflicts). If that doesn't work just pick an artificial name like `u1`.
* If the starting address offset of elements in a union are not all the same, we don't have a way to emit padding for them today.  We will emit a warning (and bad code) in that case (example below).  The one example of this I see in ATSAMD21 is due to missing `derivedFrom` support for registers; we're currently generating bad code for these anyway.  I have resolved in another branch that I'll turn into a PR once this one is landed.

```
WARNING: field Some(Ident("pmux1_1")) has different offset 177 than its union container 176
WARNING: field Some(Ident("pmux1_2")) has different offset 178 than its union container 176
```

Examples:

```
#[doc = "Real-Time Counter"]
pub mod rtc {
    #[doc = r" Register block"]
    #[repr(C)]
    pub union RegisterBlock {
        #[doc = "0x00 - Clock/Calendar with Alarm"]
        pub mode2: MODE2,
        #[doc = "0x00 - 16-bit Counter with Two 16-bit Compares"]
        pub mode1: MODE1,
        #[doc = "0x00 - 32-bit Counter with Single 32-bit Compare"]
        pub mode0: MODE0,
    }
```

```
    #[doc = r" Register block"]
    #[repr(C)]
    pub struct USART {
        #[doc = "0x00 - USART Control A"]
        pub ctrla: self::usart::CTRLA,
        #[doc = "0x04 - USART Control B"]
        pub ctrlb: self::usart::CTRLB,
        _reserved2: [u8; 4usize],
        #[doc = "USART Baud Rate"]
        pub baud: baud_union,
      ...
    }
    #[doc = "USART Baud Rate"]
    #[repr(C)]
    pub union baud_union {
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_usartfp_mode: self::usart::BAUD_USARTFP_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_fracfp_mode: self::usart::BAUD_FRACFP_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud_frac_mode: self::usart::BAUD_FRAC_MODE,
        #[doc = "0x0c - USART Baud Rate"]
        pub baud: self::usart::BAUD,
    }
```

Refs: #191 
#16



Co-authored-by: Wez Furlong <[email protected]>
Co-authored-by: Emil Gardström <[email protected]>
@jamesmunns
Copy link
Member

Hey @wez, are you okay if we close this issue?

@jamesmunns jamesmunns added the feb-2019-cleanup These issues are proposed to be closed, as part of a cleanup of issues in February 2019 label Feb 4, 2019
@wez
Copy link
Author

wez commented Feb 4, 2019

Yep, fine by me!

@wez wez closed this as completed Feb 4, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feb-2019-cleanup These issues are proposed to be closed, as part of a cleanup of issues in February 2019
Projects
None yet
Development

No branches or pull requests

5 participants