Skip to content

Commit

Permalink
Provided for_each audio API
Browse files Browse the repository at this point in the history
  • Loading branch information
CorvusPrudens committed Oct 24, 2024
1 parent a04b80e commit 958b4ea
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 92 deletions.
47 changes: 32 additions & 15 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Hardware Abstraction Layer implementation for Daisy boards"
keywords = ["cortex-m", "stm32h7xx", "stm32h750", "hal", "daisy"]
readme = "README.md"
name = "libdaisy"
version = "0.1.0"
version = "0.2.0"
license = "MIT"
repository = "https://github.com/mtthw-meyer/libdaisy-rust.git"
documentation = "https://docs.rs/libdaisy"
Expand All @@ -14,28 +14,45 @@ exclude = [".gitignore"]
[dependencies]
cfg-if = "1"
cortex-m = "0.7"
cortex-m-log = { version = "0.8", features = ["itm", "semihosting", "log-integration"], optional = true }
cortex-m-log = { version = "0.8", features = [
"itm",
"semihosting",
"log-integration",
], optional = true }
cortex-m-rtic = "1"
cortex-m-semihosting = { version = "0.5", optional = true }
cortex-m-semihosting = { version = "0.5", optional = true }
debouncr = "0.2.2"
lazy_static = { version = "1.4.0", features = ["spin_no_std"], optional = true }
lazy_static = { version = "1.4.0", features = ["spin_no_std"], optional = true }
log = "0.4"
micromath = "2"
panic-halt = "0.2.0"
panic-itm = { version = "0.4", optional = true }
panic-itm = { version = "0.4", optional = true }
panic-rtt-target = { version = "0.1.3", optional = true }
panic-semihosting = { version = "0.6", optional = true }
panic-semihosting = { version = "0.6", optional = true }
rtt-target = { version = "0.5.0", optional = true }
stm32-fmc = "0.3.0"
stm32h7xx-hal = { version = "0.16.0", features = ["stm32h750v","rt","fmc", "xspi", "sdmmc", "sdmmc-fatfs", "usb_hs"] }
stm32h7xx-hal = { version = "0.16.0", features = [
"stm32h750v",
"rt",
"fmc",
"xspi",
"sdmmc",
"sdmmc-fatfs",
"usb_hs",
] }

[features]
default = []

log-itm = ["panic-itm", "lazy_static", "cortex-m-log"]
log-none = []
log-rtt = ["rtt-target", "panic-rtt-target"]
log-semihosting = ["panic-semihosting", "lazy_static", "cortex-m-log", "cortex-m-semihosting"]
log-semihosting = [
"panic-semihosting",
"lazy_static",
"cortex-m-log",
"cortex-m-semihosting",
]

# this lets you use `cargo fix`!
#[[bin]]
Expand All @@ -44,18 +61,18 @@ log-semihosting = ["panic-semihosting", "lazy_static", "cortex-m-log", "cortex-m
#bench = false

[profile.dev]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size in flash
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size in flash
incremental = false
opt-level = "s" # optimize for binary size
opt-level = "s" # optimize for binary size

[profile.release]
codegen-units = 1 # better optimizations
debug = true # symbols are nice and they don't increase the size in flash
lto = true # better optimizations
opt-level = "s" # optimize for binary size
debug = true # symbols are nice and they don't increase the size in flash
lto = true # better optimizations
opt-level = "s" # optimize for binary size

[dev_dependencies]
[dev-dependencies]
embedded-sdmmc = "0.4"
libm = "0.2"
num_enum = { version = "0.5", default-features = false }
Expand Down
15 changes: 2 additions & 13 deletions examples/passthru.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ mod app {
#[local]
struct Local {
audio: audio::Audio,
buffer: audio::AudioBuffer,
}

#[init]
Expand All @@ -32,15 +31,12 @@ mod app {
let ccdr = system::System::init_clocks(device.PWR, device.RCC, &device.SYSCFG);
let system = libdaisy::system_init!(core, device, ccdr, BLOCK_SIZE);

let buffer = [(0.0, 0.0); audio::BLOCK_SIZE_MAX];

info!("Startup done!!");

(
Shared {},
Local {
audio: system.audio,
buffer,
},
init::Monotonics(),
)
Expand All @@ -56,17 +52,10 @@ mod app {
}

// Interrupt handler for audio
#[task(binds = DMA1_STR1, local = [audio, buffer], priority = 8)]
#[task(binds = DMA1_STR1, local = [audio], priority = 8)]
fn audio_handler(ctx: audio_handler::Context) {
let audio = ctx.local.audio;
let buffer = ctx.local.buffer;

if audio.get_stereo(buffer) {
for (left, right) in &buffer.as_slice()[..BLOCK_SIZE] {
let _ = audio.push_stereo((*left, *right));
}
} else {
info!("Error reading data!");
}
audio.for_each(|left, right| (left, right));
}
}
11 changes: 3 additions & 8 deletions examples/usb_midi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,6 @@ mod app {
let _ = ccdr.clocks.hsi48_ck().expect("HSI48 must run");
ccdr.peripheral.kernel_usb_clk_mux(UsbClkSel::Hsi48);

/*
unsafe {
let pwr = &*stm32::PWR::ptr();
pwr.cr3.modify(|_, w| w.usbregen().set_bit());
while pwr.cr3.read().usb33rdy().bit_is_clear() {}
}
*/

let mut timer2 = device.TIM2.timer(
MilliSeconds::from_ticks(200).into_rate(),
ccdr.peripheral.TIM2,
Expand All @@ -79,6 +71,7 @@ mod app {

let gpio = gpio::GPIO::init(
gpioc.pc7,
gpiog.pg3,
Some(gpiob.pb12),
Some(gpioc.pc11),
Some(gpioc.pc10),
Expand Down Expand Up @@ -110,6 +103,8 @@ mod app {
Some(gpioa.pa2),
Some(gpiob.pb14),
Some(gpiob.pb15),
None,
None,
);

let (pin_dm, pin_dp) = { (gpioa.pa11.into_alternate(), gpioa.pa12.into_alternate()) };
Expand Down
26 changes: 9 additions & 17 deletions examples/volume.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ mod app {
#[local]
struct Local {
audio: audio::Audio,
buffer: AudioBuffer,
adc1: adc::Adc<stm32::ADC1, adc::Enabled>,
timer2: Timer<stm32::TIM2>,
}
Expand All @@ -35,7 +34,6 @@ mod app {
let device = ctx.device;
let ccdr = system::System::init_clocks(device.PWR, device.RCC, &device.SYSCFG);
let mut system = libdaisy::system_init!(core, device, ccdr);
let buffer = [(0.0, 0.0); audio::BLOCK_SIZE_MAX];

info!("Enable adc1");
let mut adc1 = system.adc1.enable();
Expand Down Expand Up @@ -64,7 +62,6 @@ mod app {
Shared { control1 },
Local {
audio: system.audio,
buffer,
adc1,
timer2,
},
Expand All @@ -82,21 +79,16 @@ mod app {
}

// Interrupt handler for audio
#[task(binds = DMA1_STR1, local = [audio, buffer], shared = [control1], priority = 8)]
#[task(binds = DMA1_STR1, local = [audio], shared = [control1], priority = 8)]
fn audio_handler(mut ctx: audio_handler::Context) {
let audio_handler::LocalResources { audio, buffer } = ctx.local;

if audio.get_stereo(buffer) {
for (left, right) in buffer.iter_mut() {
ctx.shared.control1.lock(|c| {
let volume = c.get_value();
info!("{}", volume);
*left *= volume;
*right *= volume;
audio.push_stereo((*left, *right)).unwrap();
});
}
}
let audio = ctx.local.audio;

ctx.shared.control1.lock(|c| {
let volume = c.get_value();
info!("{}", volume);

audio.for_each(|left, right| (left * volume, right * volume));
});
}

#[task(binds = TIM2, local = [timer2, adc1], shared = [control1])]
Expand Down
87 changes: 60 additions & 27 deletions src/audio.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//! Audio module. Handles audio startup and I/O.
//! As well as converting between the S24 input and f32 for processing.
use core::convert::Infallible;
use cortex_m::prelude::_embedded_hal_blocking_i2c_Write;
use log::info;
use stm32h7xx_hal::{
Expand Down Expand Up @@ -261,8 +262,14 @@ impl Audio {
});

let max_transfer_size = block_size * 2;
let input = Input::new(unsafe { &mut RX_BUFFER }, max_transfer_size);
let output = Output::new(unsafe { &mut TX_BUFFER }, max_transfer_size);
let input = Input::new(
unsafe { &*core::ptr::addr_of!(RX_BUFFER) },
max_transfer_size,
);
let output = Output::new(
unsafe { &mut *core::ptr::addr_of_mut!(TX_BUFFER) },
max_transfer_size,
);

info!(
"Setup up Audio DMA: input: {:?}, output: {:?}",
Expand Down Expand Up @@ -360,20 +367,23 @@ impl Audio {
sai.enable_dma(SaiChannel::ChannelB);
});

output_stream.start(|sai1_rb| {
// There is no need to wait in this configuration.
output_stream.start(|_sai1_rb| {
sai.enable_dma(SaiChannel::ChannelA);

// wait until sai1's fifo starts to receive data
info!("Sai1 fifo waiting to receive data.");
while sai1_rb.cha().sr.read().flvl().is_empty() {}
info!("Audio started!");
sai.enable();
sai.try_send(0, 0).unwrap();
});

info!("Audio started!");
sai.enable();

let max_transfer_size = block_size * 2;
let input = Input::new(unsafe { &mut RX_BUFFER }, max_transfer_size);
let output = Output::new(unsafe { &mut TX_BUFFER }, max_transfer_size);
let input = Input::new(
unsafe { &*core::ptr::addr_of!(RX_BUFFER) },
max_transfer_size,
);
let output = Output::new(
unsafe { &mut *core::ptr::addr_of_mut!(TX_BUFFER) },
max_transfer_size,
);

info!(
"Setup up Audio DMA: input: {:?}, output: {:?}",
Expand Down Expand Up @@ -431,21 +441,6 @@ impl Audio {
}
}

/// Directly pass received audio to output without any processing.
pub fn passthru(&mut self) {
// Copy data
if self.read() {
let mut index = 0;
let mut out_index = self.output.index;
while index < self.max_transfer_size {
self.output.buffer[out_index] = self.input.buffer[index + self.input.index];
self.output.buffer[out_index + 1] = self.input.buffer[index + self.input.index + 1];
index += 2;
out_index += 2;
}
}
}

/// Gets the audio input from the DMA memory and writes it to buffer
pub fn get_stereo(&mut self, buffer: &mut AudioBuffer) -> bool {
if self.read() {
Expand All @@ -471,6 +466,44 @@ impl Audio {
None
}

/// Process audio frame-by-frame.
#[inline]
pub fn for_each<F>(&mut self, mut process: F)
where
F: FnMut(f32, f32) -> (f32, f32),
{
self.try_for_each::<_, Infallible>(|left, right| Ok(process(left, right)))
.unwrap()
}

/// Process audio frame-by-frame.
///
/// If the process closure returns an error,
/// it's bubbled up to the callsite of this method.
pub fn try_for_each<F, E>(&mut self, mut process: F) -> Result<(), E>
where
F: FnMut(f32, f32) -> Result<(f32, f32), E>,
{
if self.read() {
let input = self.input.buffer
[self.input.index..self.input.index + self.max_transfer_size]
.chunks_exact(2);

let output = self.output.buffer
[self.output.index..self.output.index + self.max_transfer_size]
.chunks_exact_mut(2);

for (input, output) in input.zip(output) {
let (left, right) =
process(S24(input[0] as i32).into(), S24(input[1] as i32).into())?;
output[0] = S24::from(left).into();
output[1] = S24::from(right).into();
}
}

Ok(())
}

/// Push data to the DMA buffer for output
/// Call this once per sample per call to [get_stereo()](Audio#get_stereo)
#[allow(clippy::result_unit_err)]
Expand Down
10 changes: 5 additions & 5 deletions src/flash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,8 +195,8 @@ impl Flash {
/// - Erasing sets all the bits in the given area to `1`.
/// - The memory array of the IS25LP064A/032A is organized into uniform 4
/// Kbyte sectors or
/// 32/64 Kbyte uniform blocks (a block consists of eight/sixteen adjacent
/// sectors respectively).
/// 32/64 Kbyte uniform blocks (a block consists of eight/sixteen adjacent
/// sectors respectively).
pub fn erase(&mut self, op: FlashErase) -> NBFlashResult<()> {
match self.state {
FlashState::Erasing(e) => {
Expand Down Expand Up @@ -266,9 +266,9 @@ impl Flash {
/// to a 1.
/// - The starting byte can be anywhere within the page (256 byte chunk).
/// When the end of the
/// page is reached, the address will wrap around to the beginning of the
/// same page. If the data to be programmed are less than a full page,
/// the data of all other bytes on the same page will remain unchanged.
/// page is reached, the address will wrap around to the beginning of the
/// same page. If the data to be programmed are less than a full page,
/// the data of all other bytes on the same page will remain unchanged.
pub fn program(&mut self, address: u32, data: &[u8]) -> NBFlashResult<()> {
let prog = |flash: &mut Self, chunk_index: u32| -> NBFlashResult<()> {
if let Some(chunk) = data.chunks(32).nth(chunk_index as usize) {
Expand Down
9 changes: 2 additions & 7 deletions src/hid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,13 +273,8 @@ where

/// Set the brightness of the LED from 0.0 to 1.0.
pub fn set_brightness(&mut self, value: f32) {
let value = if value > 1.0 {
1.0
} else if value < 0.0 {
0.0
} else {
value
};
let value = value.clamp(0., 1.);

match self.invert {
// Bias for slower transitions in the low brightness range
// TODO configurable?
Expand Down

0 comments on commit 958b4ea

Please sign in to comment.