Embassy Time inaccurate exception

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let mut read_buffer = unsafe { &mut DMA_BUF[..] };

    let mut config = Config::default();

    {
        use embassy_stm32::rcc::*;
        // config.rcc.hse = Some(
        //     Hse{
        //         freq:Hertz::mhz(8),
        //         mode:HseMode::Bypass
        //     }
        // );
        config.rcc.mux.adcsel = mux::Adcsel::SYS;
    }

    let p = embassy_stm32::init(config);




    info!("Hello World!");

    let mut adc = Adc::new(p.ADC1);

    let mut dma = p.DMA1_CH1;
    let mut vrefint_channel: AnyAdcChannel<embassy_stm32::peripherals::ADC1>  = adc.enable_vrefint().degrade_adc();
    let mut pa0 = p.PA0.degrade_adc();

    let pc7 = p.PC7;
    let mut led1 = Output::new(pc7, Level::Low, Speed::Low);

    let sampling_interval = Duration::from_micros(156); // 156.25微秒
    let samples_per_cycle = 10; // 每个周期128个点
    let cycles = 5; // 5个周期

    loop {
        // for i in 0..samples_per_cycle {
            // adc.read(
            //     &mut dma,
            //     [
            //         (&mut vrefint_channel, SampleTime::CYCLES47_5),
            //         (&mut pa0, SampleTime::CYCLES12_5),
            //     ]
            //         .into_iter(),
            //     &mut read_buffer,
            // )
            //     .await;

            led1.toggle();
            Timer::after(Duration::from_micros(100)).await

        // }

        // 每个

        // Timer::after_secs(1).await;
    }
}

The code in the program uses 100 microseconds as the stop time, but it is observed to be 200 microseconds from the oscilloscope. How should this be adjusted?

Are you measuring the full period, or the pulse width? The code is delaying for 100 μs for each pulse, resulting in a 200 μs period. In other words, it creates a square wave with a 50% duty cycle, where the duty cycle is 100 μs.

full period, I am high for 200 microseconds

#![allow(warnings)]
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![feature(impl_trait_in_assoc_type)]


use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, AdcChannel as _, AnyAdcChannel, SampleTime};
use embassy_stm32::Config;
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::time::Hertz;
use embassy_time::{Duration, Timer};
use {defmt_rtt as _, panic_probe as _};

static mut DMA_BUF: [u16; 2] = [0; 2];

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let mut read_buffer = unsafe { &mut DMA_BUF[..] };

    let mut config = Config::default();

    {
        use embassy_stm32::rcc::*;

        config.rcc.mux.adcsel = mux::Adcsel::SYS;
    }

    let p = embassy_stm32::init(config);
    let pc7 = p.PC7;

    let mut led1 = Output::new(pc7, Level::Low, Speed::Low);

    info!("Hello World!");

    let mut adc = Adc::new(p.ADC1);

    let mut dma = p.DMA1_CH1;
    let mut vrefint_channel: AnyAdcChannel<embassy_stm32::peripherals::ADC1>  = adc.enable_vrefint().degrade_adc();
    let mut pa0 = p.PA0.degrade_adc();



    loop {

        led1.toggle();
        Timer::after(Duration::from_micros(100)).await

    }
}

@parasyte

At 500 μs per division, the period does appear to take longer than expected. If you've ruled out measurement error, then I would begin to consider some other possible explanations:

  • Make sure you are running --release builds on the device (I'm not sure if non-optimized debug builds can even be compiled on your target, some embedded targets don't work right unless built with --release).
  • embassy-time is pretty configurable, defaulting to a 1MHz tick rate. Have you changed it to anything that might affect timer precision?
  • embassy-stm32 has some feature flags for configuring the time driver, which might also be relevant: embassy/embassy-stm32 at embassy-stm32-v0.2.0 · embassy-rs/embassy.

Not sure what else to suggest at this time.

My startup command:

cargo run --release | tee log-10x3a-99.txt    

I don't know how to modify this 1MHz

#![allow(warnings)]
#![no_std]
#![no_main]
#![feature(type_alias_impl_trait)]
#![feature(impl_trait_in_assoc_type)]

use defmt::*;
use embassy_executor::Spawner;
use embassy_stm32::adc::{Adc, AdcChannel as _, AnyAdcChannel, SampleTime};
use embassy_stm32::gpio::{Level, Output, Speed};
use embassy_stm32::rcc::mux::Adcsel;
use embassy_stm32::time::Hertz;
use embassy_stm32::Config;
use embassy_time::{Duration, Ticker, Timer};
use stm32_metapac::Interrupt::RCC;
use {defmt_rtt as _, panic_probe as _};
static mut DMA_BUF: [u16; 2] = [0; 2];

#[embassy_executor::main]
async fn main(_spawner: Spawner) {
    let mut read_buffer = unsafe { &mut DMA_BUF[..] };

    let mut config = Config::default();
    config.rcc.hsi = true;
    config.rcc.mux.adcsel = Adcsel::SYS;

    let p = embassy_stm32::init(config);
    let pc7 = p.PC7;

    let mut ticker = Ticker::every(Duration::from_micros(100));

    let mut led1 = Output::new(pc7, Level::Low, Speed::Low);

    info!("Hello World!");

    let mut adc = Adc::new(p.ADC1);
    let mut dma = p.DMA1_CH1;
    let mut vrefint_channel: AnyAdcChannel<embassy_stm32::peripherals::ADC1> =
        adc.enable_vrefint().degrade_adc();
    let mut pa0 = p.PA0.degrade_adc();
    let samples_per_cycle = 10; // 每个周期128个点

    let cycles = 5; // 5个周期

    loop {
        led1.toggle();
        // ticker.next().await;
        info!("toggle");

        Timer::after_micros(70).await;

        // for cycle in 0..cycles {
        //     for i in 0..samples_per_cycle {
        //         adc.read(
        //             &mut dma,
        //             [
        //                 (&mut vrefint_channel, SampleTime::CYCLES47_5),
        //                 (&mut pa0, SampleTime::CYCLES12_5),
        //             ]
        //                 .into_iter(),
        //             &mut read_buffer,
        //         )
        //             .await;
        //
        //         led1.toggle();
        //         ticker.next().await;
        //     }
        //
        //     info!("Cycle {} completed", cycle + 1);
        // }
    }
}

Is it related to the CPU frequency?

I want to check the CPU frequency but don't know how to check it, and I also can't directly view the logs related to RCC.

I'm going to second the suggestion to open the source code of embassy-time (cargo-crev), see where it's getting its clock from, and compare that against the datasheet for your microcontroller.

This plan is not very convenient in practice, and many imported files cannot be found. case: