Add PTC support for SAMD11 and SAMD21
I went to rewrite some firmware for a little Trinket M0 device I got recently when I noticed that the Adafruit FreeTouch library it depended on uses the board's PTC capabilities, which I was unable to find any documentation or information on in embedded-hal, atsamd-hal, etc. So I took a look into the SVD file for the board (specifically ATSAMD21E18) and found that PTC information was missing from it completely. I also went to Microchip's website and got the most up-to-date SVD files I could, which similarly were missing them. That being the case, I wrote in that information as best I could based on the SAMD21{E,G,J} datasheet and the FreeTouch repository, specifically relying heavily on adafruit_ptc.c and samd21_ptc_component.h. I did take some liberties when translating the contents of samd21_ptc_component.h into the SVD file based on the contents of the rest of the file (especially the ADC peripheral section). It's also the first time I've ever done any work with SVD files. I mention this as a sort of warning in case what I made is just horrifically bad, since I don't know what's good yet.
I've only implemented PTC for SAMD21E so far, though it should be relatively simple to add it to the G and J variants as well by copying the PTC peripheral and generic clock section ID enumerated value to the SVD files for those chips, and adding the correct pin mappings according to the datasheet linked to earlier (found in table 6.1). A little bit more work needs to be done to handle the X signal lines for use in mutual-capacitance PTC, though I think that could be done by just treating Y lines as channels [0, 16) and X lines as channels [16, 32), doing a check for the channel ID being greater than 15, and subtracting 16 from the ID and using that to enable an X line. Maybe that'll be my next commit. But as of now, self-capacitance PTC should be working.
Last thing of note, then: I currently am unable to verify whether this works on hardware. While having this implementation is nice, it's just the boilerplate necessary to create an implementation of FreeTouch, which I can then use to verify functionality. So what I'm PRing with now is a, "Hey, I did this thing that smells about right," sort of deal.
That should be the G and J flavours covered, I think. I can now let myself move on to making other things so I can test it on hardware.
I'm not sure if we had a special workflow/script for applying patches to the SVDs (instead of just adding things in-place). @sajattack do you remember?
Xslt scripts
https://github.com/atsamd-rs/atsamd/blob/d24c3c5bc6b1b8118ef8884cadc627fea5912afa/update.sh#L18 https://github.com/atsamd-rs/atsamd/tree/master/svd/devices
That's what I ran to create the new files in pac/ . Provided I patched the SVD files correctly, have I added the peripheral correctly?
Sorry I have no experience with the PAC / patching / SVD side of the project - I'll leave that bit to @sajattack
Instead of patching the svd manually, you need to write an xslt patch.
Something like this, then?
Something like that :sweat_smile: I've never actually done this myself. We might want someone more familiar with xslt on this review.
@AuroransSolis do you need some help testing this on hardware before we merge it?
I would very much appreciate that, yes. I'm attempting to test it myself through a reimplementation of some firmware for a little device based on the Trinket M0 (ATSAMD21E18A) that I got recently, but I'm a little stuck on a few things needed to complete it (namely interaction with NVMCTRL to store device settings - may end up making another PR for implementing that sometime soon) and it may take me a while to get through that what with being in school currently and all.
The thing I'm most unsure about is how to use the PTC peripheral in mutual capacitance mode (having some X and Y lines enabled) as opposed to self-capacitance mode (having only Y lines enabled, which what FreeTouch and LibrePTC use as far as I'm aware), and whether I've implemented that correctly. Probably the best way to test it would be to use Atmel's QTouch library and compare readings with what my PTC implementation produces. I don't think I'm personally acquainted well enough with embedded development to do that myself, so help in that regard would be appreciated.
I was mainly just volunteering to test a build or something on my Adafruit Circuit Playground Express. I'm not sure if I can help with the comparison to the atmel library.
Ah, well, I guess that Adafruit's FreeTouch or LibrePTC could also work for testing purposes, since there's a few projects out there that depend on those and they seem to work well enough. Just make sure that they're configured the same way and see if they produce the same measurements. I wrote a FreeTouch implementation based on my fork of this repo if you'd like to use that, and it can be found here.
Also, I ended up finding datasheets relevant to the other chips that atsamd-hal targets - and it turns out that all of them support PTC. If you'd like, I can make patches for all of those and add device-/device family-specific implementations in hal/common as necessary. If you'd like that, would you prefer that I add that to this PR or make a new one extending it to the other MCUs?
Ah, screw it, I'm going to broaden the scope of this PR to bring PTC to all the devices targeted by this crate. Not sure how to do testing for all of them, but oh well.
Wow, okay, so the SAM{D51,E5{1,3,4}} chips are really something else. I'm going to have to make an entirely separate PTC patch for them. And since I don't have anything to reference for them, I just wanna put out a heads-up that it's going to be extra unverified (compared the the mostly unverified patch I created for SAMD{1,2}1). Unless someone happens to have a board with one of those chips and would be able to run an example I'll come up with Eventually™ after I make the new patch.
Finally back and working on this! Huzzah! Down to brass tacks: I think I'm going to reduce scope back to what I've got done already (SAMD11 and SAMD21). I'll open another pull request later for SAMD51 and SAME51, since there's a number of challenges to address there that I'm not currently sure how to handle. For instance, when activating PTC, the PTC module takes sole ownership of ADC0. I think I can handle this by requiring instantiation of PTC to be given ADC0, but then I need to give that back at some point as well (I think?). There's other things as well that are wildly different from the two chip families I've already implemented support for which I think are out of scope for this PR. I'm also just thoroughly confused by the SAMD51/SAME51 datasheet for the time being, so I'll need a lot more time to read through that properly to create a (hopefully correct) implementation of PTC for them. And with the commit that should be appearing soon, I'll mark this as ready for review.
Wow, I really did just completely flub that commit message. Nice work, me. Anywho, I think that it should pass the checks now, since all the boards compile fine on my machine.
@AuroransSolis, can you please rebase to master? Thanks!
Sure thing, gimme a bit to work on it and I'll do that.
Sure thing, gimme a bit to work on it and I'll do that.
I guess I should have asked if this is ready to go first :)
How do you mean? In the sense of, "Does the PTC functionality actually work?" ready, or something else? If that, I haven't yet had the time to finish my project that makes use of PTC, so I'm not sure if it works. I did my best just to copy the routines in Adafruit's FreeTouch library.
Okay, hopefully that's the rebase done. Also before you allow any other workflow runs, lemme do them on my desktop so I don't have to pester anyone if it fails. I'll also work on finishing up my project using PTC to ensure that it works.
Edit: Everything built fine, now I just gotta make sure it works :^)
Cool, thanks @AuroransSolis! I was really just asking if you thought this was ready to be merged. We'll wait for your hardware tests though.
I'm reading all zeros in my test code: https://gist.github.com/56be1efb5ceaca53e0afbd74e0ee1e53
Did some more troubleshooting. Adafruit_FreeTouch will wait for CONVERT to become zero before reading RESULT. However, it seems like this never happens here...
Here's the full branch I've been working on: https://github.com/leo60228/atsamd/tree/ptc
I wrote some C code using the registers directly, which works: https://gist.github.com/87f62716dae3b266de322446958d01df However, a literal Rust port encounters the same issue as the HAL, where CONVERT never becomes 0...: https://gist.github.com/5d61e6dc04eb00745003be0b039c8106
I'm not entirely sure what I did, but my code works now.
I've updated the HAL code to at least partially work on my branch. However, the readings are incorrect, with every few readings being 0. It seems like Adafruit_FreeTouch did the register writes in the order it did for a reason...
@AuroransSolis , will you incorporate @leo60228 's changes? Let us know when this works on HW and is ready to review