Compare commits
5 Commits
befa56df5c
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bad1b474f | ||
|
|
9e862774cb | ||
|
|
e06f84df2f | ||
|
|
85a8c6b164 | ||
|
|
7a41405a71 |
@@ -28,11 +28,11 @@ rustflags = [
|
|||||||
|
|
||||||
# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB
|
# This runner will make a UF2 file and then copy it to a mounted RP2040 in USB
|
||||||
# Bootloader mode:
|
# Bootloader mode:
|
||||||
runner = "elf2uf2-rs -d"
|
# runner = "elf2uf2-rs -d"
|
||||||
|
|
||||||
# This runner will find a supported SWD debug probe and flash your RP2040 over
|
# This runner will find a supported SWD debug probe and flash your RP2040 over
|
||||||
# SWD:
|
# SWD:
|
||||||
# runner = "probe-rs run --chip RP2040 --protocol swd"
|
runner = "probe-rs run --chip RP2040 --protocol swd --speed 150"
|
||||||
|
|
||||||
[env]
|
[env]
|
||||||
DEFMT_RTT_BUFFER_SIZE = { value = "4096", force = true }
|
DEFMT_RTT_BUFFER_SIZE = { value = "4096", force = true }
|
||||||
|
|||||||
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -586,9 +586,9 @@ checksum = "e87a2ed6b42ec5e28cc3b94c09982969e9227600b2e3dcbc1db927a84c06bd69"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.22"
|
version = "1.0.23"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
checksum = "537dd038a89878be9b64dd4bd1b260315c1bb94f4d784956b81e27a088d9a09e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "usb-device"
|
name = "usb-device"
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ edition = "2024"
|
|||||||
cortex-m = { version = "0.7.7", features = [ "critical-section-single-core" ] }
|
cortex-m = { version = "0.7.7", features = [ "critical-section-single-core" ] }
|
||||||
cortex-m-rt = "0.7.5"
|
cortex-m-rt = "0.7.5"
|
||||||
defmt = "1.0.1"
|
defmt = "1.0.1"
|
||||||
defmt-rtt = "1.0.0"
|
defmt-rtt = "1.1.0"
|
||||||
embedded-hal = "1.0.0"
|
embedded-hal = "1.0.0"
|
||||||
panic-probe = { version = "1.0.0", features = [ "print-rtt" ]}
|
panic-probe = { version = "1.0.0", features = [ "print-rtt" ]}
|
||||||
rp2040-boot2 = "0.3.0"
|
rp2040-boot2 = "0.3.0"
|
||||||
|
|||||||
166
src/main.rs
166
src/main.rs
@@ -2,33 +2,31 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
use cortex_m::prelude::_embedded_hal_PwmPin;
|
use cortex_m::prelude::_embedded_hal_PwmPin;
|
||||||
use defmt::info;
|
|
||||||
use defmt::{println, write};
|
|
||||||
|
|
||||||
|
use defmt::info;
|
||||||
|
use defmt::println;
|
||||||
use defmt_rtt as _;
|
use defmt_rtt as _;
|
||||||
use panic_probe as _;
|
use panic_probe as _;
|
||||||
|
|
||||||
|
use rp2040_hal::pll::PLLConfig;
|
||||||
|
use rp2040_hal::pll::common_configs::PLL_USB_48MHZ;
|
||||||
// Alias for our HAL crate
|
// Alias for our HAL crate
|
||||||
use rp2040_hal as hal;
|
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::fugit::RateExtU32;
|
||||||
use hal::pac;
|
use hal::pac;
|
||||||
|
|
||||||
// Some traits we need
|
use embedded_hal::digital::InputPin;
|
||||||
use embedded_hal::digital::OutputPin;
|
use embedded_hal::digital::OutputPin;
|
||||||
use embedded_hal::digital::{InputPin, StatefulOutputPin};
|
|
||||||
use sh1106_pico_rs::graphics::GraphicsBuf;
|
use sh1106_pico_rs::graphics::GraphicsBuf;
|
||||||
use sh1106_pico_rs::sh1106::SH1106Dev;
|
use sh1106_pico_rs::sh1106::SH1106Dev;
|
||||||
|
|
||||||
/// The linker will place this boot block at the start of our program image. We
|
/// NB if OVERCLOCKING
|
||||||
/// need this to help the ROM bootloader get our code up and running.
|
/// you MUST use a BOOT_LOADER which can tolerate the OC
|
||||||
/// Note: This boot block is not necessary when using a rp-hal based BSP
|
/// the GENERIC_03H one cannot (unsure why) but W25Q080 has been solid for me
|
||||||
/// as the BSPs already perform this step.
|
|
||||||
#[unsafe(link_section = ".boot_loader")]
|
#[unsafe(link_section = ".boot_loader")]
|
||||||
#[used]
|
#[used]
|
||||||
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_GENERIC_03H;
|
pub static BOOT2: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080;
|
||||||
|
|
||||||
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
|
/// External high-speed crystal on the Raspberry Pi Pico board is 12 MHz. Adjust
|
||||||
/// if your board has a different frequency
|
/// if your board has a different frequency
|
||||||
@@ -41,21 +39,51 @@ fn main() -> ! {
|
|||||||
let core = pac::CorePeripherals::take().unwrap();
|
let core = pac::CorePeripherals::take().unwrap();
|
||||||
|
|
||||||
// Set up the watchdog driver - needed by the clock setup code
|
// Set up the watchdog driver - needed by the clock setup code
|
||||||
let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
|
// let mut watchdog = hal::Watchdog::new(pac.WATCHDOG);
|
||||||
|
|
||||||
|
hal::vreg::set_voltage(
|
||||||
|
&mut pac.VREG_AND_CHIP_RESET,
|
||||||
|
pac::vreg_and_chip_reset::vreg::VSEL_A::VOLTAGE1_30,
|
||||||
|
);
|
||||||
|
// settle
|
||||||
|
// cortex_m::asm::delay(3_000_000);
|
||||||
|
|
||||||
|
let xosc = hal::xosc::setup_xosc_blocking_custom_delay(pac.XOSC, XTAL_FREQ_HZ.Hz(), 128)
|
||||||
|
.map_err(|_x| false)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// watchdog.enable_tick_generation((XTAL_FREQ_HZ / 1_000_000) as u8);
|
||||||
|
|
||||||
// Configure the clocks
|
// Configure the clocks
|
||||||
let clocks = hal::clocks::init_clocks_and_plls(
|
let mut clocks = hal::clocks::ClocksManager::new(pac.CLOCKS);
|
||||||
XTAL_FREQ_HZ,
|
|
||||||
pac.XOSC,
|
let pll_usb = rp2040_hal::pll::setup_pll_blocking(
|
||||||
pac.CLOCKS,
|
|
||||||
pac.PLL_SYS,
|
|
||||||
pac.PLL_USB,
|
pac.PLL_USB,
|
||||||
|
xosc.operating_frequency(),
|
||||||
|
PLL_USB_48MHZ,
|
||||||
|
&mut clocks,
|
||||||
&mut pac.RESETS,
|
&mut pac.RESETS,
|
||||||
&mut watchdog,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let mut delay = cortex_m::delay::Delay::new(core.SYST, 133_000_000u32);
|
let pll_sys = hal::pll::setup_pll_blocking(
|
||||||
|
pac.PLL_SYS,
|
||||||
|
xosc.operating_frequency(),
|
||||||
|
PLLConfig {
|
||||||
|
vco_freq: 1500.MHz(),
|
||||||
|
refdiv: 1,
|
||||||
|
post_div1: 5,
|
||||||
|
post_div2: 1,
|
||||||
|
},
|
||||||
|
&mut clocks,
|
||||||
|
&mut pac.RESETS,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
clocks.init_default(&xosc, &pll_sys, &pll_usb).unwrap();
|
||||||
|
|
||||||
|
// let mut delay = cortex_m::delay::Delay::new(core.SYST, 200_000_000);
|
||||||
|
|
||||||
// The single-cycle I/O block controls our GPIO pins
|
// The single-cycle I/O block controls our GPIO pins
|
||||||
let sio = hal::Sio::new(pac.SIO);
|
let sio = hal::Sio::new(pac.SIO);
|
||||||
|
|
||||||
@@ -67,14 +95,6 @@ fn main() -> ! {
|
|||||||
&mut pac.RESETS,
|
&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()
|
|
||||||
.set_channel(&mut adc_pin)
|
|
||||||
.clock_divider(47999, 0)
|
|
||||||
.start_paused();
|
|
||||||
|
|
||||||
let mut led_pin = pins.gpio25.into_push_pull_output();
|
let mut led_pin = pins.gpio25.into_push_pull_output();
|
||||||
led_pin.set_high();
|
led_pin.set_high();
|
||||||
|
|
||||||
@@ -83,11 +103,15 @@ fn main() -> ! {
|
|||||||
|
|
||||||
// Configure PWM0
|
// Configure PWM0
|
||||||
let pwm0 = &mut pwm_slices.pwm0;
|
let pwm0 = &mut pwm_slices.pwm0;
|
||||||
pwm0.set_ph_correct();
|
pwm0.clr_ph_correct();
|
||||||
|
pwm0.set_div_int(1);
|
||||||
pwm0.set_div_frac(0);
|
pwm0.set_div_frac(0);
|
||||||
pwm0.disable();
|
pwm0.clear_interrupt();
|
||||||
|
pwm0.enable();
|
||||||
|
|
||||||
pwm0.channel_a.output_to(pins.gpio16);
|
let mut pwm_pin = pins.gpio16;
|
||||||
|
pwm_pin.set_drive_strength(rp2040_hal::gpio::OutputDriveStrength::TwelveMilliAmps);
|
||||||
|
pwm0.channel_a.output_to(pwm_pin);
|
||||||
|
|
||||||
let mut on_off_input = pins.gpio15.into_pull_up_input();
|
let mut on_off_input = pins.gpio15.into_pull_up_input();
|
||||||
|
|
||||||
@@ -99,13 +123,12 @@ fn main() -> ! {
|
|||||||
|
|
||||||
let mut broadcast_on = false;
|
let mut broadcast_on = false;
|
||||||
|
|
||||||
let mut current_tune = 108;
|
let mut current_tune = 10;
|
||||||
|
|
||||||
const MAX_TUNE: u16 = 350u16;
|
const MAX_TUNE: u16 = 350u16;
|
||||||
const MIN_TUNE: u16 = 4u16;
|
const MIN_TUNE: u16 = 4u16;
|
||||||
|
|
||||||
pwm0.set_top(current_tune);
|
set_tune(current_tune, pwm0);
|
||||||
pwm0.channel_a.set_duty(current_tune / 2);
|
|
||||||
|
|
||||||
// Create the I²C drive
|
// Create the I²C drive
|
||||||
let mut i2c = hal::I2C::i2c0(
|
let mut i2c = hal::I2C::i2c0(
|
||||||
@@ -117,30 +140,41 @@ fn main() -> ! {
|
|||||||
&clocks.system_clock,
|
&clocks.system_clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let mut delay = cortex_m::delay::Delay::new(core.SYST, 200_000);
|
||||||
|
|
||||||
let mut sh1106_dev = SH1106Dev::new(&mut delay, &mut i2c);
|
let mut sh1106_dev = SH1106Dev::new(&mut delay, &mut i2c);
|
||||||
sh1106_dev.set_vertical_flip(&mut i2c, true);
|
sh1106_dev.set_vertical_flip(&mut i2c, true);
|
||||||
let sh1106_dev = sh1106_dev;
|
let sh1106_dev = sh1106_dev;
|
||||||
let mut gfx_buf = GraphicsBuf::new();
|
let mut gfx_buf = GraphicsBuf::new();
|
||||||
|
|
||||||
let mut last_gfx_update = 0u32;
|
let mut last_gfx_update = 0u32;
|
||||||
|
|
||||||
// Infinite loop, fading LED up and down
|
|
||||||
loop {
|
loop {
|
||||||
tick = tick.saturating_add(1);
|
tick = tick.wrapping_add(1);
|
||||||
|
|
||||||
if tick.wrapping_sub(last_gfx_update) > 1_000_000 {
|
if tick.wrapping_sub(last_gfx_update) > 500_000 {
|
||||||
gfx_buf.clear();
|
gfx_buf.clear();
|
||||||
gfx_buf.draw_string(20, 20, "Hello Radio!");
|
gfx_buf.draw_string(20, 14, "Hello Radio!");
|
||||||
|
|
||||||
let tuned_freq = 125_000u32 / (current_tune * 2) as u32;
|
let tuned_freq = 300_000 / (current_tune as u32);
|
||||||
let mut tune_str_buf = [0u8; 4];
|
let mut tune_str_buf = [0u8; 5];
|
||||||
u16_into_str(tuned_freq as u16, &mut tune_str_buf);
|
let len = u32_into_str(tuned_freq, &mut tune_str_buf);
|
||||||
let tune_str = str::from_utf8(&tune_str_buf).unwrap();
|
let tune_str = str::from_utf8(&tune_str_buf[tune_str_buf.len() - len..]).unwrap();
|
||||||
info!("{}, {}", tune_str, tune_str.len());
|
// info!("val {}, len {}", tuned_freq, len);
|
||||||
gfx_buf.draw_string(20, 34, tune_str);
|
// info!("{}, {}", tune_str, tune_str.len());
|
||||||
|
gfx_buf.draw_string(20, 28, tune_str);
|
||||||
|
gfx_buf.sprites[0].y = match gfx_buf.sprites[0].y {
|
||||||
|
32 => 33,
|
||||||
|
_ => 32,
|
||||||
|
};
|
||||||
|
|
||||||
|
let len = u32_into_str(current_tune as u32, &mut tune_str_buf);
|
||||||
|
let tune_str = str::from_utf8(&tune_str_buf[tune_str_buf.len() - len..]).unwrap();
|
||||||
|
// info!("len {}", len);
|
||||||
|
|
||||||
|
gfx_buf.draw_string(64, 28, tune_str);
|
||||||
|
|
||||||
match broadcast_on {
|
match broadcast_on {
|
||||||
true => gfx_buf.draw_string(20, 48, "ON THE AIR"),
|
true => gfx_buf.draw_string(20, 42, "ON THE AIR"),
|
||||||
false => gfx_buf.draw_string(20, 48, "Offline"),
|
false => gfx_buf.draw_string(20, 48, "Offline"),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +188,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if on_off_input.is_low().unwrap() {
|
if on_off_input.is_low().unwrap() {
|
||||||
|
info!("Broadcast toggle");
|
||||||
last_input = tick;
|
last_input = tick;
|
||||||
broadcast_on = !broadcast_on;
|
broadcast_on = !broadcast_on;
|
||||||
|
|
||||||
@@ -165,26 +200,47 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if tune_up_input.is_low().unwrap() {
|
if tune_up_input.is_low().unwrap() {
|
||||||
|
info!("Tune DOWN");
|
||||||
last_input = tick;
|
last_input = tick;
|
||||||
current_tune = MAX_TUNE.min(current_tune + 2);
|
current_tune = MAX_TUNE.min(current_tune + 2);
|
||||||
pwm0.set_top(current_tune);
|
set_tune(current_tune, pwm0);
|
||||||
pwm0.channel_a.set_duty(current_tune / 2);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if tune_dn_input.is_low().unwrap() {
|
if tune_dn_input.is_low().unwrap() {
|
||||||
|
info!("Tune UP");
|
||||||
last_input = tick;
|
last_input = tick;
|
||||||
current_tune = MIN_TUNE.max(current_tune - 2);
|
current_tune = MIN_TUNE.max(current_tune - 2);
|
||||||
pwm0.set_top(current_tune);
|
set_tune(current_tune, pwm0);
|
||||||
pwm0.channel_a.set_duty(current_tune / 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn u16_into_str(mut value: u16, str_buf: &mut [u8; 4]) {
|
fn set_tune(
|
||||||
for i in 0..4 {
|
tune: u16,
|
||||||
str_buf[3 - i] = b'0' + (value % 10) as u8;
|
pwm: &mut rp2040_hal::pwm::Slice<rp2040_hal::pwm::Pwm0, rp2040_hal::pwm::FreeRunning>,
|
||||||
value /= 10;
|
) {
|
||||||
}
|
pwm.set_top(tune - 1);
|
||||||
info!("utf8 buf {}", str_buf);
|
pwm.channel_a.set_duty(tune / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the length of the final str removing leading zeroes
|
||||||
|
fn u32_into_str(mut value: u32, str_buf: &mut [u8]) -> usize {
|
||||||
|
let mut len = str_buf.len();
|
||||||
|
|
||||||
|
// info!("val {}", value);
|
||||||
|
for i in 0..len {
|
||||||
|
// info!("val {}, i {}, digit {}", value, i, value % 10);
|
||||||
|
str_buf[len - i - 1] = b'0' + (value % 10) as u8;
|
||||||
|
value /= 10;
|
||||||
|
|
||||||
|
if value <= 0 {
|
||||||
|
// info!("Ran out of digits at {}", i);
|
||||||
|
len = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// info!("utf8 buf {}, len {}", str_buf, len);
|
||||||
|
|
||||||
|
len
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user