Skip to content

Commit

Permalink
Playing playlist works
Browse files Browse the repository at this point in the history
  • Loading branch information
ceigel committed Oct 1, 2020
1 parent f4d6b1b commit 82750c7
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 95 deletions.
5 changes: 3 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ cortex-m-log = {"version"="0.6.1", features=["itm", "log-integration"]}

[dependencies.stm32f3xx-hal]
features = ["stm32f303xc", "rt"]
version = "0.4.2"
version = "0.4.3"
path = "../stm32f3xx-hal/"

[dependencies.cast]
default-features = false
Expand All @@ -35,4 +36,4 @@ debug = true # symbols are nice and they don't increase the size on Flash
lto = true # better optimizations

[profile.dev]
opt-level = 0
opt-level = 3
2 changes: 1 addition & 1 deletion openocd.gdb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ break DefaultHandler
break HardFault
break rust_begin_unwind

#break sound_device.rs:171
#break sound_device.rs:176
#break main.rs:235
#break main.rs:215
# *try* to stop at the user entry point (it might be gone due to inlining)
Expand Down
30 changes: 14 additions & 16 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ const APP: () = {
&mut buffers.dma_buffer,
clocks.sysclk(),
device.TIM2,
device.TIM7,
device.DAC,
device.DMA2,
);
Expand Down Expand Up @@ -213,6 +212,7 @@ const APP: () = {
});
match next_playlist {
Ok(playlist) => {
info!("Starting playlist: {}", playlist.name());
if cx.resources.current_playlist.replace(playlist).is_none() {
cx.spawn.playlist_next().expect("to spawn playlist next");
}
Expand Down Expand Up @@ -293,7 +293,7 @@ const APP: () = {
}
}

#[task(capacity=1, priority=8, resources=[playing_resources])]
#[task(capacity=1, priority=8, resources=[playing_resources], spawn=[playlist_next])]
fn process_dma_request(cx: process_dma_request::Context, new_state: DmaState) {
let pr = cx.resources.playing_resources;
match new_state {
Expand All @@ -304,13 +304,20 @@ const APP: () = {
} else {
1
};
let fil_res =
pr.sound_device
.fill_pcm_buffer(index, &mut pr.mp3_player, &mut pr.card_reader);
if fil_res.is_err() {
pr.sound_device.stop_playing();
match pr.sound_device.fill_pcm_buffer(
index,
&mut pr.mp3_player,
&mut pr.card_reader,
) {
Err(_) => {
cx.spawn.playlist_next().unwrap();
}
_ => {}
}
}
DmaState::Stopped => {
cx.spawn.playlist_next().unwrap();
}
_ => {}
}
}
Expand All @@ -324,15 +331,6 @@ const APP: () = {
}
}

#[task(binds = TIM7, priority=1, resources=[playing_resources], spawn=[playlist_next])]
fn tim7(mut cx: tim7::Context) {
debug!("Tim7 called, now: {:?}", Instant::now());
cx.resources.playing_resources.lock(|pr| {
pr.sound_device.playing_stop_timer_interrupt();
});
cx.spawn.playlist_next().unwrap();
}

extern "C" {
fn EXTI0();
fn EXTI1();
Expand Down
35 changes: 16 additions & 19 deletions src/mp3_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ impl<'a> Mp3Player<'a> {
data_reader.file_name(),
data_reader.remaining()
);
self.reset(file_reader);
self.current_song.replace(data_reader);
self.skip_id3v2_header(file_reader)?;
self.init_buffer(file_reader)?;
Expand Down Expand Up @@ -101,6 +102,15 @@ impl<'a> Mp3Player<'a> {
self.fill_buffer_intern(file_reader)
}

fn reset(&mut self, file_reader: &mut impl FileReader) {
self.read_index = 0;
self.write_index = 0;
self.last_frame_rate = None;
if let Some(current_song) = self.current_song.take() {
current_song.close(file_reader);
}
}

fn init_buffer(&mut self, file_reader: &mut impl FileReader) -> Result<(), PlayError> {
self.fill_buffer_intern(file_reader)
}
Expand Down Expand Up @@ -129,28 +139,19 @@ impl<'a> Mp3Player<'a> {
.current_song
.as_mut()
.expect("prepare_read to have returned");
debug!(
"Will read from card: {}..{}",
self.write_index,
self.mp3_data.len()
);
let out_slice = &mut self.mp3_data[self.write_index..];
let bytes_red = data_reader.read_data(file_reader, out_slice)?;
debug!(
"Read {}, Remaining {} bytes",
bytes_red,
data_reader.remaining()
);
let bytes_red = data_reader.read_data(file_reader, out_slice);
if bytes_red.is_err() {
error!("Error reading data: {:?}", bytes_red);
return bytes_red.map(|_| ()).map_err(|e| PlayError::from(e));
}
let bytes_red = bytes_red.unwrap();
self.write_index += bytes_red;
}
Ok(())
}

pub fn next_frame(&mut self, dma_buffer: &mut [u16]) -> usize {
debug!(
"Next frame: read_index: {}, write_index: {}",
self.read_index, self.write_index
);
let mp3: &[u8] = &self.mp3_data[self.read_index..self.write_index];
if mp3.len() == 0 {
return 0;
Expand All @@ -160,10 +161,6 @@ impl<'a> Mp3Player<'a> {
loop {
match decode_result {
mp3::DecodeResult::Successful(bytes_read, frame) => {
debug!(
"Decoding successful: {} read_index: {}",
bytes_read, self.read_index
);
self.last_frame_rate.replace(frame.sample_rate.hz());
self.read_index += bytes_read;
let samples = pcm_buffer
Expand Down
110 changes: 53 additions & 57 deletions src/sound_device.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use crate::data_reader::FileReader;
use crate::mp3_player::{Mp3Player, PlayError};
use cast::{u16, u32};
use log::{debug, error, info};
use log::{error, info};
use rtfm::cyccnt::Instant;
use stm32f3xx_hal::stm32 as stm32f303;
use stm32f3xx_hal::stm32::Interrupt;
use stm32f3xx_hal::time;

pub(crate) const DMA_LENGTH: usize = 2 * (mp3::MAX_SAMPLES_PER_FRAME / 2);
const PLAYING_DONE_DELAY: u16 = 2_000; // ms

pub fn apb1enr() -> &'static stm32f303::rcc::APB1ENR {
unsafe { &(*stm32f303::RCC::ptr()).apb1enr }
Expand All @@ -26,10 +24,6 @@ fn enable_dma2_ch3_interrupt() {
unsafe { stm32f303::NVIC::unmask(Interrupt::DMA2_CH3) };
}

fn enable_tim7_interrupt() {
unsafe { stm32f303::NVIC::unmask(Interrupt::TIM7) };
}

#[derive(PartialEq, Debug)]
pub enum DmaState {
HalfTrigger,
Expand All @@ -39,23 +33,39 @@ pub enum DmaState {
Unknown,
}

#[derive(Debug)]
pub struct DebuggingData {
pub trigger_complete_count: u32,
pub half_trigger_count: u32,
pub unknown_count: u32,
}

impl DebuggingData {
pub fn new() -> Self {
DebuggingData {
trigger_complete_count: 0,
half_trigger_count: 0,
unknown_count: 0,
}
}
}

pub struct SoundDevice<'a> {
dma_buffer: &'a mut [u16; DMA_LENGTH],
stop_at_buffer_len: Option<u16>,
stop_at_buffer_len: Option<usize>,
dma2: stm32f303::DMA2,
dac: stm32f303::DAC,
tim2: stm32f303::TIM2,
tim7: stm32f303::TIM7,
sysclk_freq: time::Hertz,
pub stopping: bool,
pub debug_data: DebuggingData,
}

impl<'a> SoundDevice<'a> {
pub fn new(
dma_buffer: &'a mut [u16; DMA_LENGTH],
sysclk: time::Hertz,
tim2: stm32f303::TIM2,
tim7: stm32f303::TIM7,
dac: stm32f303::DAC,
dma2: stm32f303::DMA2,
) -> Self {
Expand All @@ -65,15 +75,14 @@ impl<'a> SoundDevice<'a> {
dma_buffer,
stop_at_buffer_len: None,
tim2,
tim7,
dma2,
dac,
sysclk_freq: sysclk,
stopping: false,
debug_data: DebuggingData::new(),
};
let apb1rstr = apb1rstr();
obj.init_tim2(apb1enr, apb1rstr);
obj.init_tim7(apb1enr, apb1rstr);
obj.init_dac1(apb1enr);
obj.init_dma2(ahbenr);
obj
Expand All @@ -85,6 +94,7 @@ impl<'a> SoundDevice<'a> {
file_reader: &mut impl FileReader,
) -> Result<(), PlayError> {
info!("start playing");
self.stop_playing();
self.fill_pcm_buffer(0, mp3_player, file_reader)?;
self.fill_pcm_buffer(1, mp3_player, file_reader)?;
let freq = mp3_player
Expand All @@ -95,6 +105,7 @@ impl<'a> SoundDevice<'a> {
self.tim2.cr1.modify(|_, w| w.cen().enabled());
self.dma2.ch3.cr.modify(|_, w| w.en().enabled());
self.stopping = false;
self.stop_at_buffer_len = None;
Ok(())
}

Expand All @@ -111,22 +122,21 @@ impl<'a> SoundDevice<'a> {
_ => panic!("Buffer index {} not expected", buffer_index),
};
let filled = mp3_player.next_frame(dma_buffer_slice);
let end_index = filled + buffer_index * (buffer_len / 2);
if filled < buffer_len / 2 {
let filled = (filled + buffer_index * (buffer_len / 2)) as u16;
info!(
"Finishing music buffer_index: {}, filled:{}, now: {:?}",
buffer_index,
filled,
Instant::now()
);
self.stop_at_buffer_len = Some(filled);
if buffer_index == 1 || filled == 0 {
self.set_dma_stop();
debug!("Set dma stop");
}
self.stop_at_buffer_len = Some(end_index);
Ok(())
} else {
mp3_player.fill_buffer(file_reader)
mp3_player.fill_buffer(file_reader).map_err(|e| {
self.stop_playing();
e
})
}
}

Expand All @@ -151,39 +161,44 @@ impl<'a> SoundDevice<'a> {
DmaState::Unknown
};

if !self.stopping
&& self.stop_at_buffer_len.is_some()
if self.stopping {
self.stop_playing();
state = DmaState::Stopped;
} else if self.stop_at_buffer_len.is_some()
&& (state == DmaState::TriggerComplete || state == DmaState::HalfTrigger)
{
self.set_dma_stop();
state = DmaState::Stopped;
state = self.set_dma_stop(state);
}
state
}

pub fn playing_stop_timer_interrupt(&self) {
self.tim7.sr.write(|w| w.uif().clear_bit());
self.stop_playing();
}

pub fn stop_playing(&self) {
debug!("Stop playing");
self.tim2.cr1.modify(|_, w| w.cen().disabled());
self.dma2.ch3.cr.modify(|_, w| w.en().disabled());
}

pub fn set_dma_stop(&mut self) {
let stop_index = self.stop_at_buffer_len.expect("To have stop_index set");
pub fn set_dma_stop(&mut self, state: DmaState) -> DmaState {
self.stopping = true;
let stop_index = self.stop_at_buffer_len.expect("To have stop_index set");
self.dma2.ch3.cr.modify(|_, w| w.en().disabled());
if stop_index != 0 {
self.dma2.ch3.ndtr.write(|w| w.ndt().bits(stop_index));
if (stop_index == 0 && state == DmaState::TriggerComplete)
|| (stop_index == self.dma_buffer.len() / 2 && state == DmaState::HalfTrigger)
{
self.stop_playing();
DmaState::Stopped
} else {
self.dma2.ch3.cr.modify(|_, w| {
w.tcie().enabled(); // trigger an interrupt when transfer is complete
w.htie().disabled(); // trigger an interrupt when half the transfer is complete
w.circ().disabled() // dma mode is circular
});
self.dma2
.ch3
.ndtr
.write(|w| w.ndt().bits(stop_index as u16));
self.dma2.ch3.cr.modify(|_, w| w.en().enabled());
state
}
self.dma2.ch3.cr.modify(|_, w| {
w.circ().disabled() // dma mode is circular
});
self.dma2.ch3.cr.modify(|_, w| w.en().enabled());
self.trigger_playing_stop_timer();
}

fn init_tim2(&self, apb1enr: &stm32f303::rcc::APB1ENR, apb1rstr: &stm32f303::rcc::APB1RSTR) {
Expand All @@ -193,25 +208,6 @@ impl<'a> SoundDevice<'a> {
self.tim2.cr2.write(|w| w.mms().update());
}

fn init_tim7(&self, apb1enr: &stm32f303::rcc::APB1ENR, apb1rstr: &stm32f303::rcc::APB1RSTR) {
apb1rstr.modify(|_, w| w.tim7rst().reset());
apb1rstr.modify(|_, w| w.tim7rst().clear_bit());
apb1enr.modify(|_, w| w.tim7en().set_bit());
self.tim7.cr1.write(|w| w.opm().enabled().cen().disabled());
let psc_ms = u16((self.sysclk_freq.0 / 72000) - 1).unwrap();
let arr = PLAYING_DONE_DELAY;
self.tim7.psc.write(|w| w.psc().bits(psc_ms));
self.tim7.arr.write(|w| unsafe { w.bits(u32(arr)) });
self.tim7.egr.write(|w| w.ug().update());
self.tim7.sr.modify(|_, w| w.uif().clear());
self.tim7.dier.write(|w| w.uie().enabled());
enable_tim7_interrupt();
}

fn trigger_playing_stop_timer(&self) {
self.tim7.cr1.modify(|_, w| w.cen().enabled());
}

fn init_dac1(&self, apb1enr: &stm32f303::rcc::APB1ENR) {
apb1enr.modify(|_, w| w.dac1en().set_bit());
self.dac.cr.write(|w| {
Expand Down

0 comments on commit 82750c7

Please sign in to comment.