parent
507bd0dfef
commit
0c5614e38e
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
authors = ["LongHairedHacker <sebastian@sebastians-site.de>"]
|
||||
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]
|
||||
|
|
95
src/main.rs
95
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<Alternate<gpio::PushPull>, 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<AppI2C1>,
|
||||
i2c: AppI2C1,
|
||||
board_led: gpioc::PC13<Output<PushPull>>,
|
||||
rx_en: gpioa::PA7<Output<PushPull>>,
|
||||
adc1: adc::Adc<ADC1>,
|
||||
mic_in: gpio::Pin<Analog, CRL, 'A', 4>,
|
||||
i_in: gpio::Pin<Analog, CRL, 'A', 1>,
|
||||
q_in: gpio::Pin<Analog, CRL, 'A', 0>,
|
||||
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::<Tim3NoRemap, _, _>(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::<Tim4NoRemap, _, _>(
|
||||
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::<Tim3NoRemap, _, _>(
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
Loading…
Reference in New Issue