mciantyre / teensy4-rs

Rust support for the Teensy 4
Apache License 2.0
271 stars 31 forks source link

Must power cycle to get LED working when flashing via JTAG #129

Closed cstrahan closed 1 year ago

cstrahan commented 1 year ago

Describe the bug

When I flash one of the LED blinky examples to my Teensy 4.1 or MicroMod over JTAG, the LED only starts blinking after power cycling.

The following program uses defmt_rtt to log messages via RTT, which I successfully receive (using cargo embed):

#![no_std]
#![no_main]

use bsp::board;
use teensy4_bsp as bsp;
use teensy4_panic as _;

use defmt_rtt as _;

use bsp::hal::gpt::ClockSource;
use bsp::hal::timer::Blocking;

const DELAY_MS: u32 = 500;

const GPT1_FREQUENCY: u32 = 1_000;
const GPT1_CLOCK_SOURCE: ClockSource = ClockSource::HighFrequencyReferenceClock;
const GPT1_DIVIDER: u32 = board::PERCLK_FREQUENCY / GPT1_FREQUENCY;

#[bsp::rt::entry]
fn main() -> ! {
    let instances = board::instances();

    let board::Resources {
        mut pins,
        mut gpt1,
        mut gpio2,
        ..
    } = board::t41(instances);

    let led = board::led(&mut gpio2, pins.p13);

    gpt1.disable();
    gpt1.set_divider(GPT1_DIVIDER);
    gpt1.set_clock_source(GPT1_CLOCK_SOURCE);

    let mut delay = Blocking::<_, GPT1_FREQUENCY>::from_gpt(gpt1);

    let mut counter: u32 = 0;
    loop {
        led.toggle();
        defmt::info!("This is a test! {}", counter);
        delay.block_ms(DELAY_MS);
        counter = counter.wrapping_add(1);
    }
}

But the LED doesn't blink until I power cycle the Teensy. I'm guessing some sort of board initialization issue? :thinking:

To Reproduce

Kinda hard to repro without a modded Teensy :)

Expected behavior

LED blinky example should result in blinky LED.

Additional context

N/A

cstrahan commented 1 year ago

Hm... I think this was/is only manifesting when the previous thing flashed to Teensy was a program built with the official Teensy Arduino core. After flashing and then cutting power, subsequent flashes seem to work fine. And a quick sanity checking that I can set the other pins works just fine.

Kind of curious, but I guess I'll close this for now.

mciantyre commented 1 year ago

Good find. Here's what I guess is happening, with some context:

If a program built from the official SDK were flashed, those IOMUXC_GPR registers are set. After programming with JTAG, they're likely still set until an appropriate reset can clear those IOMUXC_GPR register values. A power cycle must be one of those reset events.

If this is correct, something like this code (near the top of board::prepare_resources) might resolve the issue.

    ral::write_reg!(ral::iomuxc_gpr, instances.IOMUXC_GPR, GPR26, 0);
    ral::write_reg!(ral::iomuxc_gpr, instances.IOMUXC_GPR, GPR27, 0);
    ral::write_reg!(ral::iomuxc_gpr, instances.IOMUXC_GPR, GPR28, 0);
    ral::write_reg!(ral::iomuxc_gpr, instances.IOMUXC_GPR, GPR29, 0);

I expect the HalfKay bootloader handles this nuance for the majority of Teensy 4 users 😛 but it's been a while since I've tried the official SDK, so I should double-check this. And this might not hold anymore if the MicroMod has JTAG / SWD debug capabilities.