Skip to content
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

Using ADC with clocking v2 API #796

Open
rnd-ash opened this issue Dec 3, 2024 · 7 comments
Open

Using ADC with clocking v2 API #796

rnd-ash opened this issue Dec 3, 2024 · 7 comments

Comments

@rnd-ash
Copy link
Contributor

rnd-ash commented Dec 3, 2024

I'm trying to use the ADC with the clocking v2 API, and have found that these 2 are incompatible with one another. The ADC API does not allow you to manually provide the clocks, instead, you have to provide the GenericClockController, which in doing so would break compatibility with MCAN since that uses the V2 API.

How would it be possible to work around this limitation? - I might have a go myself at migrating the ADC layer to V2 if this is not already in the works.

@bradleyharden
Copy link
Contributor

@rnd-ash, I would have to refresh my memory of clock::v2 to think about how you could work around the limitation. But if you want to try building an adc::v2, I don't believe anyone else is working on it. A lot of the clock::v2 stuff stalled pending a port for thumbv6 chips. I had implemented part of it, but I had to stop and haven't had time to pick it up again.

@rnd-ash
Copy link
Contributor Author

rnd-ash commented Dec 8, 2024

Looking at the ADC setup code, it seems fairly simple to use V2. But the user would have to provide an enabled ADC clock rather than the current method where the ADC initialization code sets up the clock itself.

Also, whilst I'm at it, I'll see if I can modify the constructor such that you can specify the SPS rate of the ADC.

@jbeaurivage
Copy link
Contributor

@rnd-ash, how would you feel about going a step further and making this a full refresh of the adc module? It's definitely in need of one. What I'm thinking should be included:

  • clock::v2 integration - unfortunately, only for thumbv7 targets for now
  • Ideally, a typelevel API with channel splitting, like in eic or dmac, instead of the current macro-heavy implementation
  • async support
  • DMA support

Let me know if you'd be willing to contribute to the effort. I'm certainly available to help and support as needed.

@rnd-ash
Copy link
Contributor Author

rnd-ash commented Dec 9, 2024

I don't think I'll have time to do all this, not to mention, at the moment, I'm using @kyp44 RTIC 2.0 branch.

I will see if today I can come up with a newer working ADC concept code (With clocking V2), but ill only be able to test it on the 1 board I have (Its my own BSP - Microchip Curiosity nano SAME51J20A). For now, I think i'll just get clock::v2 integration working, and maybe async so it can be used with RTIC 2, but I don't think DMA will be something Ill work on quite yet.

Ill see what i come up with today.

@jbeaurivage
Copy link
Contributor

jbeaurivage commented Dec 9, 2024

No worries, I can pick up where you leave off. Since the effort will likely be done in multiple PRs, I'll create a new feat/adc-v2 branch in which to merge them.

@kyp44
Copy link
Contributor

kyp44 commented Dec 9, 2024

Just to chime in, I am interested in async ADC, specifically async awaiting using the window monitor interrupt. My use case is the PyGamer joystick, which uses two ADC channels, one for each axis IIRC.

Once I finally wrap up the RTIC RTC monotonics and get them into rtic-mononotonics I was thinking of trying to tackle ADC async myself, using the other async-enabled peripherals as a API design guide. Using the v2 clock API would be great too as I'd like to migrate to that if I am able to.

TLDR: I am interested in helping out with async and/or clock v2 ADC sometime in the near future.

@rnd-ash
Copy link
Contributor Author

rnd-ash commented Dec 10, 2024

I had a small crack at it last night, The bare minimum to get ADC working with the V2 clock API is as so:

pub struct Adc0<PS: PclkSourceId> {
    pclk: Pclk<v2::types::Adc0, PS>,
    adc: pac::Adc0,
}

impl<PS: PclkSourceId> Adc0<PS> {
    pub fn new(mclk: &mut Mclk, adc0: pac::Adc0, pclk: Pclk<v2::types::Adc0, PS>) -> Self {
        let freq = pclk.freq().to_Hz();
        // TODO Original comment is 'set to 1/(1/(48000000/32) * 6) = 250000 SPS'
        // Given that pclk can be anything here, how can we try and set a target SPS dynamically
        //
        mclk.apbdmask().modify(|_, w| w.adc0_().set_bit());

        adc0.ctrla().modify(|_, w| w.prescaler().div32());
        adc0.ctrlb().modify(|_, w| w.ressel()._12bit());

        while adc0.syncbusy().read().ctrlb().bit_is_set() {}
        adc0.sampctrl().modify(|_, w| unsafe {w.samplen().bits(5)}); // sample length
        while adc0.syncbusy().read().sampctrl().bit_is_set() {}
        adc0.inputctrl().modify(|_, w| w.muxneg().gnd()); // No negative input (internal gnd)
        while adc0.syncbusy().read().inputctrl().bit_is_set() {}

        adc0.calib().write(|w| unsafe {
            w.biascomp().bits(calibration::adc0_biascomp_scale_cal());
            w.biasrefbuf().bits(calibration::adc0_biasref_scale_cal());
            w.biasr2r().bits(calibration::adc0_biasr2r_scale_cal())
        });

        Self {
            pclk,
            adc: adc0,
        }
    }

Compared to the constructor for the existing ADC, the changes are minimal

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants