imxrt-rs/imxrt-hal

what is the proper way to configure and use the gpt2 peripheral?

mutantbob opened this issue · 3 comments

I am using gpt1 to blink an LED. I want to use gpt2 to toggle the virtual shift modifier on my USB keyboard experiment. I have the following code (derived from https://github.com/imxrt-rs/imxrt-usbd/blob/master/examples/teensy4/src/support.rs)

pub fn rig_timer<'a>(
    duration: Duration,
    dcdc: &mut DCDC,
    gpt1: Unclocked,
    ccm_pll1: &mut imxrt_hal::ccm::PLL1,
    ccm_handle: &'a mut imxrt_hal::ccm::Handle,
    ccm_perclk: imxrt_hal::ccm::perclk::Multiplexer,
) -> (GPT, imxrt_hal::ccm::perclk::Configured<'a>) {
    let (_frequency, ipg_hz) = ccm_pll1.set_arm_clock(hal::ccm::PLL1::ARM_HZ, ccm_handle, dcdc);
    let mut cfg = ccm_perclk.configure(
        ccm_handle,
        hal::ccm::perclk::PODF::DIVIDE_3,
        hal::ccm::perclk::CLKSEL::IPG(ipg_hz),
    );
    let gpt1 = rig_timer_2(duration, gpt1, &mut cfg);

    (gpt1, cfg)
}

pub fn rig_timer_2(duration: Duration, gpt: Unclocked, cfg: &mut Configured<'_>) -> GPT {
    let mut gpt = gpt.clock(cfg);
    gpt.set_wait_mode_enable(true);
    gpt.set_mode(hal::gpt::Mode::Reset);

    let gpt_ocr: hal::gpt::OutputCompareRegister = hal::gpt::OutputCompareRegister::One;
    gpt.set_output_compare_duration(gpt_ocr, duration);
    gpt
}

and I use it later


        let (gpt1, mut clock_config) = support::rig_timer(
            duration,
            &mut dcdc,
            gpt1,
            &mut ccm.pll1,
            &mut ccm.handle,
            ccm.perclk,
        );

        let gpt2 = support::rig_timer_2(
            core::time::Duration::from_millis(200),
            gpt2,
            &mut clock_config,
        );

but it appears that only gpt1 is usable with the idiom (also from support.rs)

pub fn time_elapse(gpt: &mut hal::gpt::GPT, func: impl FnOnce()) {
    let mut status = gpt.output_compare_status(GPT_OCR);
    if status.is_set() {
        status.clear();
        func();
    }
}

If I use gpt2, I never observe status.is_set() being true.

I flipped things so that gpt2 controls the LED and gpt1 controls the virtual shift key, and then the shift key flips like I want, but the LED never toggles, so I am reasonably confident the problem is with gpt2 (probably my configuration of gpt2).

What am I overlooking? What should I change to make gpt2 work the way I think it should?

Sorry for the trouble. Nothing seems wrong with your routines. The one thing I don't explicitly see in these snippets is calls to set_enable(true). That call must be happening for GPT1, or it wouldn't work. Is a similar call also happening for GPT2?

As a small sanity check, I

Your initial instinct was correct. I was missing gpt2.set_enable(true).

I wonder if this means that there should be separate types for the object before and after set_enable. If there are multiple methods that only make sense to call after set_enable, this might be worth investigating (although the API change would be inconvenient to all downstream projects).

This is precisely the use case for a type state, but at some point the type states become burdensome to manage. It's a tradeoff as always.