Skip to content

Unable to output accurate frequency for Raspberry Rp2040 platform #3

@sndnvaps

Description

@sndnvaps

there is my code

Cargo.toml

[package]
name = "pico_ad9834_dds"
version = "0.1.0"
edition = "2021"
authors = ["Samuel Freeman <admin@sndnvaps.com>"]
license = "MIT/Apache-2.0"
categories = ["no-std", "embedded"]

[dependencies]
critical-section = "1.2.0"
rp-pico = "0.9.0"
rp2040-hal = "0.10.2"
rp2040-boot2 ="0.3"
embedded-hal = "1.0.0"
embedded-hal-bus = "0.3.0"
cortex-m = "0.7"
cortex-m-rt = "0.7"
panic-halt = "1.0.0"
defmt = "1.0.1"

ad983x = "1.0.0"

main.rs

#![no_std]
#![no_main]

use ad983x::{Ad983x, FrequencyRegister, OutputWaveform};

// Ensure we halt the program on panic (if we don't mention this crate it won't
// be linked)
use panic_halt as _;

// Alias for our HAL crate
use embedded_hal_bus::spi::ExclusiveDevice;
use rp2040_hal as hal;
// Some traits we need
use hal::clocks::Clock;
use hal::fugit::RateExtU32;
// A shorter alias for the Peripheral Access Crate, which provides low-level
// register access

use embedded_hal::digital::OutputPin;

use core::cell::RefCell;
use core::sync::atomic::{AtomicBool, Ordering};
use critical_section::Mutex;
use hal::gpio::Interrupt::EdgeLow;
use hal::{
    gpio::{self, Interrupt},
    pac::{self, interrupt},
};

/// The linker will place this boot block at the start of our program image. We
/// need this to help the ROM bootloader get our code up and running.
/// Note: This boot block is not necessary when using a rp-hal based BSP
/// as the BSPs already perform this step.
#[link_section = ".boot2"]
#[used]
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;

/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
/// if your board has a different frequency
const XTAL_FREQ_HZ: u32 = 12_000_000u32;

//初始化pwm_enabled状态为false,开机的时候不输出信号
//需要按下usr_btn后,才输出pwm信号,再次按下usr_btn暂停pwm信号输出
static PWM_ENABLED: AtomicBool = AtomicBool::new(false);

/// This pin will be our interrupt source.
/// It will trigger an interrupt if pulled to ground (via a switch or jumper wire)
/// usr btn defind as gpio24
type ButtonPin = gpio::Pin<gpio::bank0::Gpio24, gpio::FunctionSioInput, gpio::PullUp>;
/// This how we transfer our Led and Button pins into the Interrupt Handler.
/// We'll have the option hold both using the LedAndButton type.
/// This will make it a bit easier to unpack them later.
static GLOBAL_PINS: Mutex<RefCell<Option<ButtonPin>>> = Mutex::new(RefCell::new(None));

/// Entry point to our bare-metal application.
///
/// The `#[rp2040_hal::entry]` macro ensures the Cortex-M start-up code calls this function
/// as soon as all global variables and the spinlock are initialised.
///
/// The function configures the RP2040 peripherals, then performs some example
/// SPI transactions, then goes to sleep.
#[rp2040_hal::entry]
fn main() -> ! {
    // Grab our singleton objects
    let mut pac = pac::Peripherals::take().unwrap();
    // let core = pac::CorePeripherals::take().unwrap();
    // Set up the watchdog driver - needed by the clock setup code
    let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);

    // Configure the clocks
    let clocks = hal::clocks::init_clocks_and_plls(
        XTAL_FREQ_HZ,
        pac.XOSC,
        pac.CLOCKS,
        pac.PLL_SYS,
        pac.PLL_USB,
        &mut pac.RESETS,
        &mut watchdog,
    )
    .unwrap();

    // The delay object lets us wait for specified amounts of time (in
    // milliseconds)
    let delay = hal::Timer::new(pac.TIMER, &mut pac.RESETS, &clocks);

    // The single-cycle I/O block controls our GPIO pins
    let sio = hal::Sio::new(pac.SIO);

    // Set the pins to their default state
    let pins = hal::gpio::Pins::new(
        pac.IO_BANK0,
        pac.PADS_BANK0,
        sio.gpio_bank0,
        &mut pac.RESETS,
    );

    //led is in gpio25
    let mut led_pin = pins.gpio25.into_push_pull_output();

    // 配置GPIO按钮并启用中断
    let button_pin = pins.gpio24.reconfigure();
    button_pin.set_interrupt_enabled(Interrupt::EdgeLow, true);

    // Give away our pins by moving them into the `GLOBAL_PINS` variable.
    // We won't need to access them in the main thread again
    critical_section::with(|cs| {
        GLOBAL_PINS.borrow(cs).replace(Some(button_pin));
    });
    unsafe {
        cortex_m::peripheral::NVIC::unmask(pac::Interrupt::IO_IRQ_BANK0);
    }

    //set spi_bus cs
    let ad9834_fsync = pins.gpio8.into_function::<hal::gpio::FunctionSioOutput>(); // FSYNC -> CS -> AD9834 DDS模块上面的FS引脚,又为spi_bus的片选引脚(CS)

    // Set up our SPI pins so they can be used by the SPI driver
    let spi_mosi = pins.gpio7.into_function::<hal::gpio::FunctionSpi>(); //spi0 TX -> ad9834 dds模块上面的SDA引脚

    //此引脚不接
    let spi_miso = pins.gpio4.into_function::<hal::gpio::FunctionSpi>(); //spio RX ->ad9834 dds模块上不接此引脚

    let spi_sclk = pins.gpio6.into_function::<hal::gpio::FunctionSpi>(); //spio sck -> ad9834 dds模块上面的sck引脚
    let spi_bus = hal::spi::Spi::<_, _, _, 8>::new(pac.SPI0, (spi_mosi, spi_miso, spi_sclk));

    // Exchange the uninitialised SPI driver for an initialised one
    let spi_bus = spi_bus.init(
        &mut pac.RESETS,
        clocks.peripheral_clock.freq(),
        16.MHz(),
        embedded_hal::spi::MODE_0,
    );

    let dev = ExclusiveDevice::new(spi_bus, ad9834_fsync, delay).unwrap();

    let mut dds = Ad983x::new_ad9834(dev);

    dds.reset().unwrap(); // reset is necessary before operation
                          //FreqReg = (Fout * 1*pow(2,28))/F_mclk
                          //当输出频率为Fout=440Hz,F_mclk= 25MHz,FreqReg= 4724
                          /*
                          dds.set_frequency(FrequencyRegister::F0, 4724).unwrap();
                          dds.set_output_waveform(OutputWaveform::Sinusoidal).unwrap(); //output sine_wave
                          dds.enable().unwrap();
                          */
    // Given a 25 MHz clock, this now outputs a sine wave
    // with a frequency of 440 Hz, which is a standard
    // A4 tone.
    //let mclk_hz = 75_000_000.0;
    //let frequency_hz = 50.0;
    //let synth_value = frequency_hz * f64::from(1 << 28) / mclk_hz; // -> synth_value = 178.96取整数为179
    dds.reset().unwrap();
    //dds.enable().unwrap();
   
    dds.set_output_waveform(OutputWaveform::Triangle).unwrap(); //output sine_wave
    dds.set_frequency(FrequencyRegister::F1, 4724)
        .unwrap();

    //dds.set_frequency_lsb(FrequencyRegister::F1,0x00B3).unwrap();
    //dds.set_frequency_msb(FrequencyRegister::F1, 0x0000).unwrap();
    dds.select_frequency(FrequencyRegister::F1).unwrap();
    //dds.enable().unwrap();
    //cortex_m::asm::wfi();
    loop {
        if PWM_ENABLED.load(Ordering::Relaxed) {
            led_pin.set_high().unwrap();
            //dds.reset().unwrap();
            //dds.set_frequency_lsb(FrequencyRegister::F1,0x00B3).unwrap();
            //dds.set_frequency_msb(FrequencyRegister::F1, 0x0000).unwrap();
            dds.enable().unwrap();
            //dds.select_frequency(FrequencyRegister::F1).unwrap();

            //cortex_m::asm::wfi();
        } else {
            led_pin.set_low().unwrap();
            dds.reset().unwrap();
        }
    }
}

// End of file

#[allow(static_mut_refs)] // See https://github.com/rust-embedded/cortex-m/pull/561
#[interrupt]
fn IO_IRQ_BANK0() {
    static mut BTN_IRQ: Option<ButtonPin> = None;
    if BTN_IRQ.is_none() {
        critical_section::with(|cs| {
            *BTN_IRQ = GLOBAL_PINS.borrow(cs).take();
        });
    }

    if let Some(gpios) = BTN_IRQ {
        let btn = gpios;
        if btn.interrupt_status(EdgeLow) {
            // 切换PWM使能状态
            let current_state = PWM_ENABLED.load(Ordering::Relaxed);
            PWM_ENABLED.store(!current_state, Ordering::Relaxed);

            // Our interrupt doesn't clear itself.
            // Do that now so we don't immediately jump back to this interrupt handler.
            btn.clear_interrupt(EdgeLow);
            // 简单防抖延迟
            cortex_m::asm::delay(50_000);
        }
    }
}

it only get the 880KHz ,cannt got 440Hz

my ad9834 board pic

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions