embassy-rs / embassy

Modern embedded framework, using Rust and async.
https://embassy.dev
Apache License 2.0
5.57k stars 774 forks source link

Unwrap of None when in Sdmmc::init_card #2642

Closed nbc12 closed 8 months ago

nbc12 commented 8 months ago

I'm trying to use a SDMMC card on my stm32f401rc, but when I run init_card, I get this over defmt:

0.000915 ERROR panicked at 'unwrap failed: crate :: rcc :: get_freqs().pll1_q'
error: `Unwrap of a None option value`
└─ embassy_stm32::sdmmc::{impl#40}::kernel_clk::{closure#0} @ C:\Users\User\.cargo\registry\src\index.crates.io-6f17d22bba15001f\embassy-stm32-0.1.0\src\fmt.rs:179  
0.001495 ERROR panicked at C:\Users\User\.cargo\registry\src\index.crates.io-6f17d22bba15001f\defmt-0.3.6\src\lib.rs:368:5:
explicit panic
└─ panic_probe::print_defmt::print @ C:\Users\User\.cargo\registry\src\index.crates.io-6f17d22bba15001f\panic-probe-0.3.1\src\lib.rs:104

I think Sdmmc::init_card unwraps a None. I think I've tracked it to the kernel_clk macro in embassy-stm32::sdmmc, but IDK what else to do with it.

My SDMMC IC is a MKDV2GCL-NE, the datasheet is here. The datasheet says D3 has to be driven high in order for it to go into SD mode. ~Does it have something to do with that?~ Edit: Nevermind, I did p.PC11.set_high() before creating the sdmmc object, and nothing chnaged.

Anyway, here's a minimal example.

use embassy_stm32::{sdmmc::{self, Sdmmc}, time::khz, Config};
use embassy_executor::Spawner;
use {defmt_rtt as _, panic_probe as _};

use embassy_stm32::{
    bind_interrupts, peripherals::SDIO,
};
bind_interrupts!(pub struct Irqs {
    SDIO => sdmmc::InterruptHandler<SDIO>;
});

#[embassy_executor::main]
async fn main(spawner: Spawner) {
    let p = embassy_stm32::init(Config::default());

    let mut sdmmc = Sdmmc::new_4bit(
        p.SDIO,
        Irqs,
        p.DMA2_CH3,
        p.PC12, // clk
        p.PD2, // cmd
        p.PC8, // d0
        p.PC9, // d1
        p.PC10, // d2
        p.PC11, // d3
        sdmmc::Config::default(),
    );

    let result = sdmmc.init_card(khz(400)).await;
}

Note that I don't even do anything with the Result, it unwraps in the call stack of init_card somewhere.

Here is the dependencies section of Cargo.toml

embassy-stm32 = { version = "0.1", features = [ "defmt", "stm32f401rc", "unstable-pac", "memory-x", "time-driver-any", "exti", "time" ] }
embassy-sync = { version = "*", features = [ "defmt" ] }
embassy-executor = { version = "0.5", features = [ "nightly", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers" ] }
embassy-time = { version = "0.3", features = [ "defmt", "defmt-timestamp-uptime", "tick-hz-32_768" ] }

panic-probe = { version = "0.3", features = ["print-defmt"] }

defmt = "0.3"
defmt-rtt = "0.4"

cortex-m = { version = "0.7.7", features = ["inline-asm", "critical-section-single-core"] }
cortex-m-rt = "0.7.3"

I'm on nightly-x86_64-pc-windows-msvc, rustc 1.78.0-nightly (3246e7951 2024-02-19)

Thanks for all the hard work, I'm really enjoying using embassy!

nbc12 commented 8 months ago

Nevermind, this fixed it. Just have to set the config like is done in the examples.

let mut config = Config::default();
{
    use embassy_stm32::rcc::*;
    config.rcc.hse = Some(Hse {
        freq: Hertz(8_000_000),
        mode: HseMode::Bypass,
    });
    config.rcc.pll_src = PllSource::HSE;
    config.rcc.pll = Some(Pll {
        prediv: PllPreDiv::DIV4,
        mul: PllMul::MUL168,
        divp: Some(PllPDiv::DIV2), // 8mhz / 4 * 168 / 2 = 168Mhz.
        divq: Some(PllQDiv::DIV7), // 8mhz / 4 * 168 / 7 = 48Mhz.
        divr: None,
    });
    config.rcc.ahb_pre = AHBPrescaler::DIV1;
    config.rcc.apb1_pre = APBPrescaler::DIV4;
    config.rcc.apb2_pre = APBPrescaler::DIV2;
    config.rcc.sys = Sysclk::PLL1_P;
}
let p = embassy_stm32::init(config);