diff --git a/Cargo.toml b/Cargo.toml index b2d2674..5061f46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] authors = ["LongHairedHacker "] -name = "wspr-beacon" +name = "stm32-pll-ssb" edition = "2018" version = "0.1.0" @@ -11,11 +11,12 @@ cortex-m-rtic = "1.1.3" defmt = "0.3.2" defmt-rtt = "0.3.2" panic-probe = { version = "0.3.0", features = ["print-defmt"] } -stm32f1xx-hal = { version = "0.9.0", features = ["stm32f103", "rt"] } +stm32f1xx-hal = { version = "0.9.0", features = ["stm32f103", "rt", "medium"] } embedded-hal = {version = "0.2.3"} nb = "1.0.0" arrayvec = {version = "0.7.0", default-features = false} systick-monotonic = "1.0.0" +num-traits = { version = "0.2", default-features = false, features = ["libm"] } [features] diff --git a/src/main.rs b/src/main.rs index 69200f3..c598944 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,29 +16,28 @@ use rtic::app; mod si5153; -#[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [TIM2])] +#[app(device = stm32f1xx_hal::pac, peripherals = true, dispatchers = [SPI3])] mod app { - use core::num::dec2flt::float; - use stm32f1xx_hal::{ adc, gpio::{ self, gpioa, gpiob, gpioc, Alternate, Analog, Floating, Input, OpenDrain, Output, - PushPull, CRL, + PushPull, CRH, CRL, }, i2c, i2c::BlockingI2c, - pac::{ADC1, I2C1}, + pac::{ADC1, I2C1, TIM4}, prelude::*, serial::{self, Config, Serial}, stm32, - timer::{self, Event}, + timer::{self, Channel, Event, Tim3NoRemap, Tim4NoRemap}, }; use systick_monotonic::Systick; use arrayvec::ArrayString; + use num_traits::float::Float; use crate::si5153; @@ -50,8 +49,15 @@ mod app { ), >; + type AudioPwm = timer::PwmHz< + TIM4, + Tim4NoRemap, + timer::Ch<2>, + gpio::Pin, CRH, 'B', 8>, + >; + #[monotonic(binds = SysTick, default = true)] - type MonoTimer = Systick<1_000_000>; + type MonoTimer = Systick<1_000>; #[shared] struct Shared {} @@ -61,8 +67,13 @@ mod app { pll: si5153::Si5153, i2c: AppI2C1, board_led: gpioc::PC13>, + rx_en: gpioa::PA7>, adc1: adc::Adc, mic_in: gpio::Pin, + i_in: gpio::Pin, + q_in: gpio::Pin, + phase: f32, + audio_pwm: AudioPwm, } #[init] @@ -111,16 +122,50 @@ mod app { let mut pll = si5153::Si5153::new(&i2c); pll.init(&mut i2c, 25000000, 800000000, 800000000); pll.set_ms_source(&mut i2c, si5153::Multisynth::MS0, si5153::PLL::A); + pll.set_ms_source(&mut i2c, si5153::Multisynth::MS1, si5153::PLL::A); + pll.set_ms_source(&mut i2c, si5153::Multisynth::MS2, si5153::PLL::B); + + pll.set_ms_freq(&mut i2c, si5153::Multisynth::MS0, 8_000_000); + pll.set_ms_phase(&mut i2c, si5153::Multisynth::MS0, 100); + pll.enable_ms_output(&mut i2c, si5153::Multisynth::MS0); + + pll.set_ms_freq(&mut i2c, si5153::Multisynth::MS1, 8_000_000); + pll.set_ms_phase(&mut i2c, si5153::Multisynth::MS1, 0); + pll.enable_ms_output(&mut i2c, si5153::Multisynth::MS1); + + pll.pll_reset(&mut i2c); let adc1 = adc::Adc::adc1(cx.device.ADC1, clocks); let mic_in = gpioa.pa4.into_analog(&mut gpioa.crl); - let mut pwm = - cx.device - .TIM2 - .pwm_hz::(pins, &mut afio.mapr, 4800.Hz(), &clocks); + let i_in = gpioa.pa1.into_analog(&mut gpioa.crl); + let q_in = gpioa.pa0.into_analog(&mut gpioa.crl); - transmit::spawn().unwrap(); + let audio_out = gpiob.pb8.into_alternate_push_pull(&mut gpiob.crh); + let mut audio_pwm = cx.device.TIM4.pwm_hz::( + audio_out, + &mut afio.mapr, + 4800.Hz(), + &clocks, + ); + audio_pwm.enable(Channel::C3); + audio_pwm.set_duty(Channel::C3, 0u16); + + let mut rx_en = gpioa.pa7.into_push_pull_output(&mut gpioa.crl); + rx_en.set_high(); + + let mut bias_pin = gpioa.pa6.into_alternate_push_pull(&mut gpioa.crl); + let mut bias_pwm = cx.device.TIM3.pwm_hz::( + bias_pin, + &mut afio.mapr, + 4800.Hz(), + &clocks, + ); + + let mut timer = timer::Timer2::new(cx.device.TIM2, &clocks).counter_hz(); + timer.start(4800.Hz()).unwrap(); + // Generate an interrupt when the timer expires + timer.listen(Event::Update); ( Shared {}, @@ -128,21 +173,35 @@ mod app { i2c, pll, board_led, + rx_en, adc1, mic_in, + i_in, + q_in, + phase: 0.0, + audio_pwm, }, init::Monotonics(mono), ) } - #[task(local=[pll, i2c, adc1, mic_in])] + #[task(binds=TIM2, local=[pll, i2c, adc1, mic_in, i_in, q_in, audio_pwm, phase, board_led])] fn transmit(mut ctx: transmit::Context) { - let mut adc = ctx.local.adc1; - let mut mic_in = ctx.local.mic_in; + *ctx.local.phase += core::f32::consts::PI * 2.0 * 1000.0 / 4800.0; + if *ctx.local.phase > 2.0 * core::f32::consts::PI { + *ctx.local.phase -= core::f32::consts::PI; + ctx.local.board_led.toggle(); + } - let data: u16 = adc.read(&mut *mic_in).unwrap(); - let sample = (data as f32 / u16::MAX as f32); + //defmt::debug!("Phase: {}", ctx.local.phase); - transmit::spawn_after(208.micros().into()).unwrap(); + let max_duty = if ctx.local.audio_pwm.get_max_duty() != 0 { + ctx.local.audio_pwm.get_max_duty() as f32 + } else { + 2.0.powi(16) + }; + + let sample = (ctx.local.phase.sin() + 0.5) * max_duty; + ctx.local.audio_pwm.set_duty(Channel::C3, sample as u16); } } diff --git a/src/si5153.rs b/src/si5153.rs index b077da2..5a98dd3 100644 --- a/src/si5153.rs +++ b/src/si5153.rs @@ -31,6 +31,7 @@ pub enum Multisynth { const MS_BASE_ADDR: [u8; 3] = [42, 50, 58]; const MS_CTRL_ADDR: [u8; 3] = [16, 17, 18]; +const CLK_PHOFF_ADDR: [u8; 3] = [165, 166, 167]; impl Multisynth { fn base_address(&self) -> u8 { @@ -40,6 +41,11 @@ impl Multisynth { fn ctrl_address(&self) -> u8 { return MS_CTRL_ADDR[*self as usize]; } + + fn phoff_address(&self) -> u8 { + defmt::debug!("Adress: {}", CLK_PHOFF_ADDR[*self as usize]); + return CLK_PHOFF_ADDR[*self as usize]; + } } pub struct PllParams { @@ -77,11 +83,10 @@ where self.write_byte_reg(i2c, CLK_ENABLE_CONTROL, self.outputs); // Disable all outputs self.write_byte_reg(i2c, XTAL_LOAD_CAP, 0xD2); //crystal load capacitor = 10pF - self.write_byte_reg(i2c, PLL_RESET, 0xA0); // Reset both PLLs - for ms in [Multisynth::MS0, Multisynth::MS1, Multisynth::MS2].iter() { self.ms_srcs[*ms as usize] = PLL::A; self.write_byte_reg(i2c, ms.ctrl_address(), 0x0F); // MSi as Source, PLLA to MSi, 8 mA output + self.write_byte_reg(i2c, ms.phoff_address(), 0); // Phase offset to 0. } for pll in [PLL::A, PLL::B].iter() { @@ -101,6 +106,8 @@ where self.write_params(i2c, pll.base_address(), ¶ms) } + + self.write_byte_reg(i2c, PLL_RESET, 0xA0); // Reset both PLLs } pub fn enable_ms_output(&mut self, i2c: &mut I2C, synth: Multisynth) { @@ -143,6 +150,14 @@ where self.write_params(i2c, synth.base_address(), ¶ms) } + pub fn set_ms_phase(&mut self, i2c: &mut I2C, synth: Multisynth, phase: u8) { + self.write_byte_reg(i2c, synth.phoff_address(), phase); + } + + pub fn pll_reset(&mut self, i2c: &mut I2C) { + self.write_byte_reg(i2c, PLL_RESET, 0xA0); + } + fn write_byte_reg(&self, i2c: &mut I2C, reg_addr: u8, data: u8) { let res = i2c.write(I2C_ADDR, &[reg_addr, data]); if res.is_err() {