Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. //! I2S interface with DMA data transfer.
  2. use cortex_m::interrupt;
  3. use stm32f4xx_hal::dma;
  4. use stm32f4xx_hal::dma::traits::Stream;
  5. use stm32f4xx_hal::gpio::gpiob::{PB12, PB13, PB14, PB15};
  6. use stm32f4xx_hal::gpio::gpioc::PC6;
  7. use stm32f4xx_hal::gpio::{Alternate, AF5, AF6};
  8. use stm32f4xx_hal::stm32::{DMA1, I2S2EXT, RCC, SPI2};
  9. use crate::audio_buffer::{AudioBuffer, ReadPacket, WritePacket, CHANNELS, SAMPLES_PER_PACKET};
  10. /// Clocks for the I2S peripheral.
  11. #[derive(Clone, Copy)]
  12. pub struct I2SClocks {
  13. plli2sclk: u32,
  14. }
  15. impl I2SClocks {
  16. /// Initializes the I2S clocks.
  17. ///
  18. /// This function must only be called once at startup. It assumes that the HSE is already
  19. /// initialized and the HSE frequency is 8MHz.
  20. pub unsafe fn init() -> I2SClocks {
  21. // The following values result in a sample frequency of 47991.07Hz:
  22. // - PLLI2SN = 43
  23. // - PLLI2SR = 4
  24. // - I2SDIV = 3
  25. // - I2SODD = 1
  26. let rcc = &*RCC::ptr();
  27. // Configure PLL.
  28. rcc.plli2scfgr
  29. .modify(|_, w| w.plli2sn().bits(43).plli2sq().bits(4).plli2sr().bits(4));
  30. // Enable PLL.
  31. rcc.cr.modify(|_, w| w.plli2son().set_bit());
  32. // Wait for PLL to stabilise
  33. while rcc.cr.read().plli2srdy().bit_is_clear() {}
  34. // Ensure that the PLL is selected as the I2S clock source.
  35. rcc.cfgr.modify(|_, w| w.i2ssrc().clear_bit());
  36. I2SClocks {
  37. plli2sclk: 86000000,
  38. }
  39. }
  40. }
  41. pub type I2S2 = (SPI2, I2S2EXT);
  42. pub type I2S3 = (SPI3, I2S3EXT);
  43. /// Trait for master clock pins.
  44. pub trait MCK<I2S> {}
  45. impl MCK<I2S2> for PC6<Alternate5> {}
  46. impl MCK<I2S3> for PC7<Alternate6> {}
  47. /// Trait for word select pins.
  48. pub trait WS<I2S> {}
  49. impl WS<I2S3> for PA4<Alternate6> {}
  50. impl WS<I2S3> for PA15<Alternate6> {}
  51. impl WS<I2S2> for PB9<Alternate5> {}
  52. impl WS<I2S2> for PB12<Alternate5> {}
  53. impl WS<I2S2> for PI0<Alternate5> {}
  54. /// Trait for bit clock pins.
  55. pub trait CK<I2S> {}
  56. impl CK<I2S3> for PB3<Alternate6> {}
  57. impl CK<I2S2> for PB10<Alternate5> {}
  58. impl CK<I2S2> for PB13<Alternate5> {}
  59. impl CK<I2S3> for PC10<Alternate6> {}
  60. impl CK<I2S2> for PD3<Alternate5> {}
  61. impl CK<I2S2> for PI1<Alternate5> {}
  62. /// Trait for serial data input pins.
  63. pub trait SDI<I2S> {}
  64. impl SDI<I2S3> for PB4<Alternate7> {}
  65. impl SDI<I2S2> for PB14<Alternate6> {}
  66. impl SDI<I2S2> for PC2<Alternate6> {}
  67. impl SDI<I2S3> for PC11<Alternate5> {}
  68. impl SDI<I2S2> for PI2<Alternate6> {}
  69. /// Trait for serial data output pins.
  70. pub trait SDO<I2S> {}
  71. impl SDO<I2S3> for PB5<Alternate6> {}
  72. impl SDO<I2S2> for PB15<Alternate5> {}
  73. impl SDO<I2S2> for PC3<Alternate5> {}
  74. impl SDO<I2S3> for PC12<Alternate6> {}
  75. impl SDO<I2S3> for PD6<Alternate5> {}
  76. impl SDO<I2S2> for PI3<Alternate5> {}
  77. /// I2S interface with DMA data transfer.
  78. pub struct I2S<SPI, I2SEXT> {
  79. spi: SPI,
  80. i2sext: I2SEXT,
  81. rx_dma: dma::Stream3<DMA1>, // TODO: Correct DMA unit?
  82. tx_dma: dma::Stream4<DMA1>,
  83. in_: &'static AudioBuffer,
  84. in_packets: [Option<WritePacket>; 2],
  85. out: &'static AudioBuffer,
  86. out_packets: [Option<ReadPacket>; 2],
  87. }
  88. macro_rules! i2s_impl {
  89. ($SPIX:ident, $I2SXEXT:ident, $spiXen:ident,$spiXrst:ident) => {
  90. impl I2S<SPIX, I2SXEXT> {
  91. /// Initializes the I2S interface to read from/write to the specified buffers.
  92. ///
  93. /// The interface is only started when the `start()` function is called.
  94. pub fn new(
  95. spi: SPIX,
  96. i2sext: I2SXEXT,
  97. mut rx_dma: dma::Stream3<DMA1>, // TODO: Correct DMA streams
  98. mut tx_dma: dma::Stream4<DMA1>,
  99. mck: MCK<(SPIX, I2SXEXT)>,
  100. ws: WS<(SPIX, I2SXEXT)>,
  101. ck: CK<(SPIX, I2SXEXT)>,
  102. sdin: SDI<(SPIX, I2SXEXT)>,
  103. sdout: SDO<(SPIX, I2SXEXT)>,
  104. in_: &'static AudioBuffer,
  105. out: &'static AudioBuffer,
  106. _clocks: I2SClocks,
  107. ) -> Self {
  108. // Enable and reset the peripheral.
  109. let rcc = unsafe { &*RCC::ptr() };
  110. rcc.apb1enr.modify(|_, w| w.spi2en().set_bit());
  111. rcc.apb1rstr.modify(|_, w| w.spi2rst().set_bit());
  112. rcc.apb1rstr.modify(|_, w| w.spi2rst().clear_bit());
  113. //rcc.ahb1enr.modify(|_, w| w.dma1en().set_bit());
  114. // Disable SS output.
  115. spi.cr2.write(|w| w.ssoe().clear_bit());
  116. // Configure the pins.
  117. // TODO
  118. // Configure the clocks.
  119. // For the values, see the comment in I2SClocks::init().
  120. spi.i2spr
  121. .write(|w| unsafe { w.mckoe().set_bit().odd().set_bit().i2sdiv().bits(3) });
  122. i2sext
  123. .i2spr
  124. .write(|w| unsafe { w.mckoe().set_bit().odd().set_bit().i2sdiv().bits(3) });
  125. // Configure I2S.
  126. spi.i2scfgr.modify(|_, w| unsafe {
  127. w.i2smod()
  128. .set_bit()
  129. .i2se()
  130. .clear_bit()
  131. .i2scfg()
  132. .master_tx()
  133. .i2sstd()
  134. .bits(0b01)
  135. .ckpol()
  136. .idle_high()
  137. .datlen()
  138. .bits(0b10)
  139. .chlen()
  140. .set_bit()
  141. });
  142. i2sext.i2scfgr.modify(|_, w| unsafe {
  143. w.i2smod()
  144. .set_bit()
  145. .i2se()
  146. .clear_bit()
  147. .i2scfg()
  148. .slave_rx()
  149. .i2sstd()
  150. .bits(0b01)
  151. .ckpol()
  152. .idle_high()
  153. .datlen()
  154. .bits(0b10)
  155. .chlen()
  156. .set_bit()
  157. });
  158. i2sext.cr2.modify(|_, w| w.rxdmaen().set_bit());
  159. spi.cr2.modify(|_, w| w.txdmaen().set_bit());
  160. rx_dma.set_channel(dma::Channel3);
  161. rx_dma.clear_interrupts();
  162. unsafe {
  163. rx_dma.set_memory_size(1);
  164. rx_dma.set_peripheral_size(1);
  165. }
  166. rx_dma.set_memory_increment(true);
  167. rx_dma.set_direction(dma::PeripheralToMemory);
  168. rx_dma.set_interrupts_enable(true, false, true, true);
  169. rx_dma.set_double_buffer(true);
  170. rx_dma.set_fifo_enable(false);
  171. rx_dma.set_number_of_transfers((SAMPLES_PER_PACKET * CHANNELS * 2) as u16);
  172. tx_dma.set_channel(dma::Channel0);
  173. tx_dma.clear_interrupts();
  174. unsafe {
  175. tx_dma.set_memory_size(1);
  176. tx_dma.set_peripheral_size(1);
  177. }
  178. tx_dma.set_memory_increment(true);
  179. tx_dma.set_direction(dma::MemoryToPeripheral);
  180. tx_dma.set_interrupts_enable(true, false, true, true);
  181. tx_dma.set_double_buffer(true);
  182. tx_dma.set_fifo_enable(false);
  183. tx_dma.set_number_of_transfers((SAMPLES_PER_PACKET * CHANNELS * 2) as u16);
  184. const DR_OFFSET: usize = 0x0c;
  185. let spi_dr = SPI2::ptr() as usize + DR_OFFSET;
  186. let i2sext_dr = I2S2EXT::ptr() as usize + DR_OFFSET;
  187. rx_dma.set_peripheral_address(i2sext_dr as u32);
  188. tx_dma.set_peripheral_address(spi_dr as u32);
  189. I2S {
  190. spi,
  191. i2sext,
  192. rx_dma,
  193. tx_dma,
  194. in_,
  195. in_packets: [None, None],
  196. out,
  197. out_packets: [None, None],
  198. }
  199. }
  200. /// Starts the data stream of the I2S interface.
  201. pub fn start(&mut self) {
  202. interrupt::free(|cs| {
  203. for i in 0..2 {
  204. self.in_packets[i] = self.in_.borrow_write(cs);
  205. }
  206. for i in 0..2 {
  207. self.out_packets[i] = self.out.borrow_read(cs);
  208. }
  209. });
  210. // The system was just started, and some buffers were filled with dummy data, so we can
  211. // assume that borrowing was successful.
  212. let in_0 = self.in_packets[0].as_mut().unwrap().as_mut().as_ptr() as usize as u32;
  213. let in_1 = self.in_packets[1].as_mut().unwrap().as_mut().as_ptr() as usize as u32;
  214. self.rx_dma.set_memory_address(in_0);
  215. self.rx_dma.set_memory_double_buffer_address(in_1);
  216. /*self.dma.st[3].m0ar.write(|w| unsafe { w.bits(in_0) });
  217. self.dma.st[3].m1ar.write(|w| unsafe { w.bits(in_1) });*/
  218. let out_0 = self.out_packets[0].as_ref().unwrap().as_ref().as_ptr() as usize as u32;
  219. let out_1 = self.out_packets[1].as_ref().unwrap().as_ref().as_ptr() as usize as u32;
  220. self.tx_dma.set_memory_address(out_0);
  221. self.tx_dma.set_memory_double_buffer_address(out_1);
  222. /*self.dma.st[4].m0ar.write(|w| unsafe { w.bits(out_0) });
  223. self.dma.st[4].m1ar.write(|w| unsafe { w.bits(out_1) });*/
  224. // Enable DMA and activate the I2S peripherals.
  225. /*self.dma.st[3].cr.modify(|_, w| w.en().set_bit());
  226. self.dma.st[4].cr.modify(|_, w| w.en().set_bit());*/
  227. unsafe {
  228. self.rx_dma.enable();
  229. self.tx_dma.enable();
  230. }
  231. self.i2sext.i2scfgr.modify(|_, w| w.i2se().set_bit());
  232. self.spi.i2scfgr.modify(|_, w| w.i2se().set_bit());
  233. /*loop {
  234. if self.spi.sr.read().txe().bit_is_set() {
  235. self.spi.dr.write(|w| unsafe { w.bits(0xaaaa) });
  236. }
  237. if self.i2sext.sr.read().rxne().bit_is_set() {
  238. self.i2sext.dr.read();
  239. }
  240. }*/
  241. }
  242. /// Reads data from the output audio buffer and writes to the input audio buffer as required.
  243. ///
  244. /// This function needs to be called from the DMA interrupt handler.
  245. pub fn poll(&mut self) {
  246. // TODO
  247. }
  248. }
  249. // TODO
  250. };
  251. }
  252. i2s_impl!(SPI2, I2S2EXT, spi2en, spi2rst);
  253. i2s_impl!(SPI3, I2S3EXT, spi3en, spi3rst);