#![no_std] #![no_main] use core::u16::MIN; use cortex_m::singleton; use defmt::info; use defmt::{println, write}; use defmt_rtt as _; use embedded_hal::pwm::SetDutyCycle; use panic_probe as _; // Alias for our HAL crate use rp2040_hal as hal; // A shorter alias for the Peripheral Access Crate, which provides low-level // register access use hal::fugit::RateExtU32; use hal::pac; // Some traits we need use embedded_hal::digital::OutputPin; use embedded_hal::digital::{InputPin, StatefulOutputPin}; /// 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. #[unsafe(link_section = ".boot_loader")] #[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; // below this we won't be able to turn on the transistor (0.6v) const MIN_DUTY: u16 = 12000; #[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(); let mut delay = cortex_m::delay::Delay::new(core.SYST, 133_000_000u32); // 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, ); let mut adc = hal::Adc::new(pac.ADC, &mut pac.RESETS); let mut adc_pin = hal::adc::AdcPin::new(pins.gpio26.into_floating_input()).unwrap(); let mut adc_fifo = adc .build_fifo() .clock_divider(0xFFFF, 0xFF) .set_channel(&mut adc_pin) .start(); let mut pwm_slices = hal::pwm::Slices::new(pac.PWM, &mut pac.RESETS); let pwm = &mut pwm_slices.pwm2; pwm.set_div_int(125); pwm.set_ph_correct(); pwm.enable(); let pwm_channel = &mut pwm.channel_a; pwm_channel.output_to(pins.gpio20); // let mut led_pin = pins.gpio25.into_push_pull_output(); let mut duty = MIN_DUTY; let mut power = 0; let mut tick = 0u16; loop { pwm_channel.set_duty_cycle(duty); duty = duty.saturating_add(2000); delay.delay_ms(10); if adc_fifo.len() > 7 { let mut samps = [0u16; 8]; for i in 0..8 { samps[i] = adc_fifo.read(); } let avg = avg_fifo(&samps, false); let voltage = (avg * 3300) / 4095; let new_power = (voltage * (duty - MIN_DUTY) as u32) / 0xFFF; if tick % 10 == 0 { info!("{} duty, {}mV, {} power", duty, voltage, new_power); } tick = tick.wrapping_add(1); if new_power < power { duty = MIN_DUTY.max(duty - 3000); } power = new_power; } } } fn avg_fifo(samps: &[u16], log_all: bool) -> u32 { let mut avg = 0u32; if log_all { info!("{}", samps); } samps.iter().for_each(|n| { avg += *n as u32; }); avg / (samps.len() as u32) }