PWM setup works

SI5351 works, but is unreliable
This commit is contained in:
Sebastian 2022-12-29 14:04:41 +01:00
parent 507bd0dfef
commit 0c5614e38e
3 changed files with 97 additions and 22 deletions

View File

@ -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]

View File

@ -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);
}
}

View File

@ -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(), &params)
}
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(), &params)
}
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() {