Moved UI code to its own file
This commit is contained in:
parent
a63f187211
commit
2dc4af2145
168
src/main.rs
168
src/main.rs
|
@ -17,6 +17,7 @@ use rtic::app;
|
|||
|
||||
mod filters;
|
||||
mod si5153;
|
||||
mod ui;
|
||||
|
||||
#[app(device = stm32f4xx_hal::pac, peripherals = true, dispatchers = [SPI3])]
|
||||
mod app {
|
||||
|
@ -38,7 +39,7 @@ mod app {
|
|||
},
|
||||
gpio::{self, gpioa, gpioc, Analog, Output, PushPull},
|
||||
i2c::{self, I2c},
|
||||
pac::{ADC1, DMA1, DMA2, I2C1, SPI1, TIM2, TIM4},
|
||||
pac::{ADC1, DMA1, DMA2, I2C1, SPI1, SYST, TIM2, TIM4},
|
||||
prelude::*,
|
||||
qei,
|
||||
spi::{self, Spi},
|
||||
|
@ -54,6 +55,7 @@ mod app {
|
|||
|
||||
use crate::filters;
|
||||
use crate::si5153;
|
||||
use crate::ui::UI;
|
||||
|
||||
use embedded_graphics::mono_font::MonoTextStyle;
|
||||
use embedded_graphics::pixelcolor::Rgb565;
|
||||
|
@ -95,17 +97,7 @@ mod app {
|
|||
>,
|
||||
audio_max_duty: u16,
|
||||
|
||||
disp_led: gpioa::PA10<Output<PushPull>>,
|
||||
disp_cs: gpioa::PA15<Output<PushPull>>,
|
||||
disp: ST7735<Spi<SPI1>, gpio::Pin<'A', 12, Output>, gpio::Pin<'A', 11, Output>>,
|
||||
row_pos: u16,
|
||||
row_buffer: [Complex<f32>; 128],
|
||||
row_buffer_count: usize,
|
||||
max_mag: f32,
|
||||
|
||||
encoder: qei::Qei<TIM2>,
|
||||
last_encoder_pos: u32,
|
||||
carrier_freq: u32,
|
||||
ui: UI,
|
||||
}
|
||||
|
||||
#[shared]
|
||||
|
@ -138,12 +130,29 @@ mod app {
|
|||
|
||||
let board_led = gpioc.pc13.into_push_pull_output();
|
||||
|
||||
let enc_a = gpioa.pa0.into_input();
|
||||
let enc_b = gpioa.pa1.into_input();
|
||||
/*
|
||||
let enc_a = gpioa.pa0.into_input();
|
||||
let enc_b = gpioa.pa1.into_input();
|
||||
|
||||
let encoder = qei::Qei::new(cx.device.TIM2, (enc_a, enc_b));
|
||||
let encoder = qei::Qei::new(cx.device.TIM2, (enc_a, enc_b));
|
||||
|
||||
defmt::info!("Encoder Setup done");
|
||||
defmt::info!("Encoder Setup done");
|
||||
*/
|
||||
|
||||
let ui = UI::setup(
|
||||
&clocks,
|
||||
gpioa.pa0.into_input(),
|
||||
gpioa.pa1.into_input(),
|
||||
cx.device.TIM2,
|
||||
gpioa.pa11.into_push_pull_output(),
|
||||
gpioa.pa12.into_push_pull_output(),
|
||||
gpioa.pa10.into_push_pull_output(),
|
||||
gpioa.pa15.into_push_pull_output(),
|
||||
gpiob.pb3.into_alternate(),
|
||||
gpiob.pb5.into_alternate(),
|
||||
cx.device.SPI1,
|
||||
cx.core.SYST,
|
||||
);
|
||||
|
||||
let scl = gpiob.pb6.into_alternate_open_drain();
|
||||
let sda = gpiob.pb7.into_alternate_open_drain();
|
||||
|
@ -181,37 +190,6 @@ mod app {
|
|||
|
||||
defmt::info!("PLL chip setup done");
|
||||
|
||||
let mut disp_led = gpioa.pa10.into_push_pull_output();
|
||||
disp_led.set_high();
|
||||
let mut disp_cs = gpioa.pa15.into_push_pull_output();
|
||||
disp_cs.set_low();
|
||||
|
||||
let disp_rst = gpioa.pa11.into_push_pull_output();
|
||||
let disp_dc = gpioa.pa12.into_push_pull_output();
|
||||
|
||||
let disp_sck = gpiob.pb3.into_alternate();
|
||||
let disp_mosi = gpiob.pb5.into_alternate();
|
||||
let spi1 = Spi::new(
|
||||
cx.device.SPI1,
|
||||
(disp_sck, spi::NoMiso::new(), disp_mosi),
|
||||
spi::Mode {
|
||||
polarity: spi::Polarity::IdleLow,
|
||||
phase: spi::Phase::CaptureOnFirstTransition,
|
||||
},
|
||||
16.MHz(),
|
||||
&clocks,
|
||||
);
|
||||
|
||||
let mut disp = ST7735::new(spi1, disp_dc, disp_rst, true, false, 160, 128);
|
||||
|
||||
let mut delay = cx.core.SYST.delay(&clocks);
|
||||
|
||||
disp.init(&mut delay).unwrap();
|
||||
disp.set_orientation(&Orientation::Landscape).unwrap();
|
||||
disp.clear(Rgb565::BLACK).unwrap();
|
||||
|
||||
defmt::info!("Display setup done");
|
||||
|
||||
let i_in = gpioa.pa2.into_analog();
|
||||
let q_in = gpioa.pa3.into_analog();
|
||||
|
||||
|
@ -313,104 +291,14 @@ mod app {
|
|||
pwm_transfer,
|
||||
audio_max_duty,
|
||||
|
||||
disp_led,
|
||||
disp_cs,
|
||||
disp,
|
||||
row_pos: 0,
|
||||
row_buffer: [Complex::<f32>::new(0.0, 0.0); 128],
|
||||
row_buffer_count: 0,
|
||||
max_mag: 0.0,
|
||||
|
||||
encoder,
|
||||
last_encoder_pos: 0,
|
||||
carrier_freq: 7_100_000,
|
||||
ui,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[task(priority = 0, local = [disp, row_pos, row_buffer, row_buffer_count, encoder, last_encoder_pos, carrier_freq, pll, i2c])]
|
||||
#[task(priority = 0, local = [ui])]
|
||||
async fn update_display(cx: update_display::Context, mut row: [Complex<f32>; 128]) {
|
||||
let buffers_per_row = 4;
|
||||
|
||||
let row = cfft_128(&mut row);
|
||||
|
||||
for idx in 0..row.len() {
|
||||
cx.local.row_buffer[idx] += row[idx] / buffers_per_row as f32;
|
||||
}
|
||||
|
||||
*cx.local.row_buffer_count += 1;
|
||||
|
||||
if *cx.local.row_buffer_count > buffers_per_row {
|
||||
*cx.local.row_buffer_count = 0;
|
||||
|
||||
let gradient = colorous::TURBO;
|
||||
|
||||
for idx in 0..128 {
|
||||
let intens: f32 =
|
||||
cx.local.row_buffer[idx].re.pow(2) + cx.local.row_buffer[idx].im.pow(2);
|
||||
|
||||
let log_intens = intens.log10() / 2.0 * 10.0;
|
||||
let norm_intens = (log_intens + 18.0) / 18.0;
|
||||
|
||||
let color = gradient.eval_continuous(norm_intens as f64);
|
||||
|
||||
let x = if idx < 64 { 64 + idx } else { idx - 64 };
|
||||
Pixel(
|
||||
Point::new(32 + x as i32, 28 + *cx.local.row_pos as i32),
|
||||
Rgb565::new(color.r >> 3, color.g >> 2, color.b >> 3),
|
||||
)
|
||||
.draw(cx.local.disp)
|
||||
.unwrap();
|
||||
|
||||
cx.local.row_buffer[idx] = Complex::new(0.0, 0.0);
|
||||
}
|
||||
|
||||
*cx.local.row_pos = (*cx.local.row_pos + 1) % 100;
|
||||
Line::new(
|
||||
Point::new(32, 28 + *cx.local.row_pos as i32),
|
||||
Point::new(159, 28 + *cx.local.row_pos as i32),
|
||||
)
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb565::BLACK, 1))
|
||||
.draw(cx.local.disp)
|
||||
.unwrap();
|
||||
|
||||
defmt::info!("Position is {}", cx.local.row_pos);
|
||||
}
|
||||
|
||||
let encoder_pos = cx.local.encoder.count();
|
||||
let diff = encoder_pos.wrapping_sub(*cx.local.last_encoder_pos) as i32 / 4;
|
||||
|
||||
if diff >= 1 || diff <= -1 {
|
||||
*cx.local.carrier_freq = (*cx.local.carrier_freq as i32 + diff * 100) as u32;
|
||||
cx.local
|
||||
.pll
|
||||
.set_pll_freq(cx.local.i2c, si5153::PLL::A, *cx.local.carrier_freq * 100);
|
||||
cx.local.pll.set_ms_freq(
|
||||
cx.local.i2c,
|
||||
si5153::Multisynth::MS0,
|
||||
*cx.local.carrier_freq,
|
||||
);
|
||||
cx.local.pll.set_ms_freq(
|
||||
cx.local.i2c,
|
||||
si5153::Multisynth::MS1,
|
||||
*cx.local.carrier_freq,
|
||||
);
|
||||
|
||||
Rectangle::new(Point::new(0, 0), Size::new(160, 28))
|
||||
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
|
||||
.draw(cx.local.disp)
|
||||
.unwrap();
|
||||
|
||||
let mut freq_txt = arrayvec::ArrayString::<11>::new();
|
||||
write!(freq_txt, "{}", cx.local.carrier_freq).unwrap();
|
||||
let text_style = MonoTextStyle::new(&PROFONT_14_POINT, Rgb565::WHITE);
|
||||
Text::new(&freq_txt, Point::new(8, 16), text_style)
|
||||
.draw(cx.local.disp)
|
||||
.unwrap();
|
||||
|
||||
*cx.local.last_encoder_pos = encoder_pos;
|
||||
}
|
||||
defmt::info!("Carrier freq is {}", cx.local.carrier_freq);
|
||||
cx.local.ui.update_display(row);
|
||||
}
|
||||
|
||||
#[task(binds = DMA2_STREAM0, local = [adc_transfer, iq_buffer, board_led, i_offset, q_offset, usb_filter, audio_max_duty], shared = [audio_buffer])]
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
use stm32f4xx_hal::{
|
||||
adc::{
|
||||
self,
|
||||
config::{
|
||||
AdcConfig, Continuous, Dma, ExternalTrigger, SampleTime, Scan, Sequence, TriggerMode,
|
||||
},
|
||||
Adc,
|
||||
},
|
||||
dma::{self, config::DmaConfig, PeripheralToMemory, Stream0, Stream7, StreamsTuple, Transfer},
|
||||
gpio::{self, Alternate, Analog, Input, Output, PushPull},
|
||||
i2c::{self, I2c},
|
||||
pac::{ADC1, DMA1, DMA2, I2C1, SPI1, SYST, TIM2, TIM4},
|
||||
prelude::*,
|
||||
qei, rcc,
|
||||
spi::{self, Spi},
|
||||
timer::{
|
||||
self, Channel, Channel1, Channel3, ChannelBuilder, CounterHz, Event, PwmHz, CCR, CCR3,
|
||||
},
|
||||
};
|
||||
|
||||
use st7735_lcd::{Orientation, ST7735};
|
||||
|
||||
use embedded_graphics::{
|
||||
mono_font::MonoTextStyle,
|
||||
pixelcolor::Rgb565,
|
||||
prelude::*,
|
||||
primitives::rectangle::Rectangle,
|
||||
primitives::{Line, PrimitiveStyle},
|
||||
text::Text,
|
||||
};
|
||||
use profont::PROFONT_14_POINT;
|
||||
|
||||
use microfft::complex::cfft_128;
|
||||
use num::Complex;
|
||||
use num_traits::{float::Float, Pow};
|
||||
|
||||
use core::fmt::Write;
|
||||
|
||||
type EncoderA = gpio::Pin<'A', 0, Input>;
|
||||
type EncoderB = gpio::Pin<'A', 1, Input>;
|
||||
|
||||
type DisplaySPI = Spi<SPI1>;
|
||||
type DisplayRST = gpio::Pin<'A', 11, Output>;
|
||||
type DisplayDC = gpio::Pin<'A', 12, Output>;
|
||||
type DisplayLed = gpio::Pin<'A', 10, Output<PushPull>>;
|
||||
type DisplayCS = gpio::Pin<'A', 15, Output<PushPull>>;
|
||||
type DisplaySCK = gpio::Pin<'B', 3, Alternate<5>>;
|
||||
type DisplayMOSI = gpio::Pin<'B', 5, Alternate<5>>;
|
||||
|
||||
pub struct UI {
|
||||
disp_led: DisplayLed,
|
||||
disp_cs: DisplayCS,
|
||||
disp: ST7735<DisplaySPI, DisplayDC, DisplayRST>,
|
||||
row_pos: u16,
|
||||
row_buffer: [Complex<f32>; 128],
|
||||
row_buffer_count: usize,
|
||||
max_mag: f32,
|
||||
|
||||
encoder: qei::Qei<TIM2>,
|
||||
last_encoder_pos: u32,
|
||||
carrier_freq: u32,
|
||||
}
|
||||
|
||||
impl UI {
|
||||
pub fn setup(
|
||||
clocks: &rcc::Clocks,
|
||||
|
||||
enc_a: EncoderA,
|
||||
enc_b: EncoderB,
|
||||
tim2: TIM2,
|
||||
|
||||
disp_rst: DisplayRST,
|
||||
disp_dc: DisplayDC,
|
||||
mut disp_led: DisplayLed,
|
||||
mut disp_cs: DisplayCS,
|
||||
disp_sck: DisplaySCK,
|
||||
disp_mosi: DisplayMOSI,
|
||||
spi1: SPI1,
|
||||
syst: SYST,
|
||||
) -> UI {
|
||||
let encoder = qei::Qei::new(tim2, (enc_a, enc_b));
|
||||
defmt::info!("[UI] Encoder Setup done");
|
||||
|
||||
disp_led.set_high();
|
||||
disp_cs.set_low();
|
||||
|
||||
let spi1 = Spi::new(
|
||||
spi1,
|
||||
(disp_sck, spi::NoMiso::new(), disp_mosi),
|
||||
spi::Mode {
|
||||
polarity: spi::Polarity::IdleLow,
|
||||
phase: spi::Phase::CaptureOnFirstTransition,
|
||||
},
|
||||
16.MHz(),
|
||||
&clocks,
|
||||
);
|
||||
|
||||
let mut disp = ST7735::new(spi1, disp_dc, disp_rst, true, false, 160, 128);
|
||||
|
||||
let mut delay = syst.delay(&clocks);
|
||||
|
||||
disp.init(&mut delay).unwrap();
|
||||
disp.set_orientation(&Orientation::Landscape).unwrap();
|
||||
disp.clear(Rgb565::BLACK).unwrap();
|
||||
|
||||
defmt::info!("[UI] Display setup done");
|
||||
|
||||
UI {
|
||||
disp_led,
|
||||
disp_cs,
|
||||
disp,
|
||||
row_pos: 0,
|
||||
row_buffer: [Complex::<f32>::new(0.0, 0.0); 128],
|
||||
row_buffer_count: 0,
|
||||
max_mag: 0.0,
|
||||
encoder,
|
||||
last_encoder_pos: 0,
|
||||
carrier_freq: 7_100_000,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_display(&mut self, mut row: [Complex<f32>; 128]) {
|
||||
let buffers_per_row = 4;
|
||||
|
||||
let row = cfft_128(&mut row);
|
||||
|
||||
for idx in 0..row.len() {
|
||||
self.row_buffer[idx] += row[idx] / buffers_per_row as f32;
|
||||
}
|
||||
|
||||
self.row_buffer_count += 1;
|
||||
|
||||
if self.row_buffer_count > buffers_per_row {
|
||||
self.row_buffer_count = 0;
|
||||
|
||||
let gradient = colorous::TURBO;
|
||||
|
||||
for idx in 0..128 {
|
||||
let intens: f32 = self.row_buffer[idx].re.pow(2) + self.row_buffer[idx].im.pow(2);
|
||||
|
||||
let log_intens = intens.log10() / 2.0 * 10.0;
|
||||
let norm_intens = (log_intens + 18.0) / 18.0;
|
||||
|
||||
let color = gradient.eval_continuous(norm_intens as f64);
|
||||
|
||||
let x = if idx < 64 { 64 + idx } else { idx - 64 };
|
||||
Pixel(
|
||||
Point::new(32 + x as i32, 28 + self.row_pos as i32),
|
||||
Rgb565::new(color.r >> 3, color.g >> 2, color.b >> 3),
|
||||
)
|
||||
.draw(&mut self.disp)
|
||||
.unwrap();
|
||||
|
||||
self.row_buffer[idx] = Complex::new(0.0, 0.0);
|
||||
}
|
||||
|
||||
self.row_pos = (self.row_pos + 1) % 100;
|
||||
Line::new(
|
||||
Point::new(32, 28 + self.row_pos as i32),
|
||||
Point::new(159, 28 + self.row_pos as i32),
|
||||
)
|
||||
.into_styled(PrimitiveStyle::with_stroke(Rgb565::BLACK, 1))
|
||||
.draw(&mut self.disp)
|
||||
.unwrap();
|
||||
|
||||
defmt::info!("Position is {}", self.row_pos);
|
||||
}
|
||||
|
||||
let encoder_pos = self.encoder.count();
|
||||
let diff = encoder_pos.wrapping_sub(self.last_encoder_pos) as i32 / 4;
|
||||
|
||||
if diff >= 1 || diff <= -1 {
|
||||
self.carrier_freq = (self.carrier_freq as i32 + diff * 100) as u32;
|
||||
/*
|
||||
self.pll
|
||||
.set_pll_freq(self.i2c, si5153::PLL::A, self.carrier_freq * 100);
|
||||
self.pll
|
||||
.set_ms_freq(self.i2c, si5153::Multisynth::MS0, *cx.local.carrier_freq);
|
||||
cx.local.pll.set_ms_freq(
|
||||
cx.local.i2c,
|
||||
si5153::Multisynth::MS1,
|
||||
*cx.local.carrier_freq,
|
||||
);
|
||||
*/
|
||||
Rectangle::new(Point::new(0, 0), Size::new(160, 28))
|
||||
.into_styled(PrimitiveStyle::with_fill(Rgb565::BLACK))
|
||||
.draw(&mut self.disp)
|
||||
.unwrap();
|
||||
|
||||
let mut freq_txt = arrayvec::ArrayString::<11>::new();
|
||||
write!(freq_txt, "{}", self.carrier_freq).unwrap();
|
||||
let text_style = MonoTextStyle::new(&PROFONT_14_POINT, Rgb565::WHITE);
|
||||
Text::new(&freq_txt, Point::new(8, 16), text_style)
|
||||
.draw(&mut self.disp)
|
||||
.unwrap();
|
||||
|
||||
self.last_encoder_pos = encoder_pos;
|
||||
}
|
||||
defmt::info!("Carrier freq is {}", self.carrier_freq);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue