diff --git a/Cargo.toml b/Cargo.toml index 9c40280..05d34fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 @@ -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 diff --git a/openocd.gdb b/openocd.gdb index 0fdd863..c192097 100644 --- a/openocd.gdb +++ b/openocd.gdb @@ -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) diff --git a/src/main.rs b/src/main.rs index ce87ea8..e247282 100644 --- a/src/main.rs +++ b/src/main.rs @@ -184,7 +184,6 @@ const APP: () = { &mut buffers.dma_buffer, clocks.sysclk(), device.TIM2, - device.TIM7, device.DAC, device.DMA2, ); @@ -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"); } @@ -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 { @@ -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(); + } _ => {} } } @@ -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(); diff --git a/src/mp3_player.rs b/src/mp3_player.rs index 9b2900c..947e655 100644 --- a/src/mp3_player.rs +++ b/src/mp3_player.rs @@ -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)?; @@ -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) } @@ -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; @@ -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 diff --git a/src/sound_device.rs b/src/sound_device.rs index 844fa4f..9dcd5ea 100644 --- a/src/sound_device.rs +++ b/src/sound_device.rs @@ -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 } @@ -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, @@ -39,15 +33,32 @@ 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, + stop_at_buffer_len: Option, 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> { @@ -55,7 +66,6 @@ impl<'a> SoundDevice<'a> { dma_buffer: &'a mut [u16; DMA_LENGTH], sysclk: time::Hertz, tim2: stm32f303::TIM2, - tim7: stm32f303::TIM7, dac: stm32f303::DAC, dma2: stm32f303::DMA2, ) -> Self { @@ -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 @@ -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 @@ -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(()) } @@ -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 + }) } } @@ -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) { @@ -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| {