You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

484 lines
17KB

  1. // Copyright 2014 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. // See http://creativecommons.org/licenses/MIT/ for more information.
  24. //
  25. // -----------------------------------------------------------------------------
  26. //
  27. // WM8371 Codec support.
  28. #include "elements/drivers/codec.h"
  29. #include <string.h>
  30. #define CODEC_I2C I2C2
  31. #define CODEC_I2C_CLK RCC_APB1Periph_I2C2
  32. #define CODEC_I2C_GPIO_CLOCK RCC_AHB1Periph_GPIOB
  33. #define CODEC_I2C_GPIO_AF GPIO_AF_I2C2
  34. #define CODEC_I2C_GPIO GPIOB
  35. #define CODEC_I2C_SCL_PIN GPIO_Pin_10
  36. #define CODEC_I2C_SDA_PIN GPIO_Pin_11
  37. #define CODEC_I2C_SCL_PINSRC GPIO_PinSource10
  38. #define CODEC_I2C_SDA_PINSRC GPIO_PinSource11
  39. #define CODEC_TIMEOUT ((uint32_t)0x1000)
  40. #define CODEC_LONG_TIMEOUT ((uint32_t)(300 * CODEC_TIMEOUT))
  41. #define CODEC_I2C_SPEED 100000
  42. #define CODEC_I2S SPI2
  43. #define CODEC_I2S_EXT I2S2ext
  44. #define CODEC_I2S_CLK RCC_APB1Periph_SPI2
  45. #define CODEC_I2S_ADDRESS 0x4000380C
  46. #define CODEC_I2S_EXT_ADDRESS 0x4000340C
  47. #define CODEC_I2S_GPIO_AF GPIO_AF_SPI2
  48. #define CODEC_I2S_IRQ SPI2_IRQn
  49. #define CODEC_I2S_EXT_IRQ SPI2_IRQn
  50. #define CODEC_I2S_GPIO_CLOCK (RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOB)
  51. #define CODEC_I2S_WS_PIN GPIO_Pin_12
  52. #define CODEC_I2S_SCK_PIN GPIO_Pin_13
  53. #define CODEC_I2S_SDI_PIN GPIO_Pin_14
  54. #define CODEC_I2S_SDO_PIN GPIO_Pin_15
  55. #define CODEC_I2S_MCK_PIN GPIO_Pin_6
  56. #define CODEC_I2S_WS_PINSRC GPIO_PinSource12
  57. #define CODEC_I2S_SCK_PINSRC GPIO_PinSource13
  58. #define CODEC_I2S_SDI_PINSRC GPIO_PinSource14
  59. #define CODEC_I2S_SDO_PINSRC GPIO_PinSource15
  60. #define CODEC_I2S_MCK_PINSRC GPIO_PinSource6
  61. #define CODEC_I2S_GPIO GPIOB
  62. #define CODEC_I2S_MCK_GPIO GPIOC
  63. #define AUDIO_I2S_IRQHandler SPI2_IRQHandler
  64. #define AUDIO_DMA_PERIPH_DATA_SIZE DMA_PeripheralDataSize_HalfWord
  65. #define AUDIO_DMA_MEM_DATA_SIZE DMA_MemoryDataSize_HalfWord
  66. #define AUDIO_I2S_DMA_CLOCK RCC_AHB1Periph_DMA1
  67. #define AUDIO_I2S_DMA_STREAM DMA1_Stream4
  68. #define AUDIO_I2S_DMA_DREG CODEC_I2S_ADDRESS
  69. #define AUDIO_I2S_DMA_CHANNEL DMA_Channel_0
  70. #define AUDIO_I2S_DMA_IRQ DMA1_Stream4_IRQn
  71. #define AUDIO_I2S_DMA_FLAG_TC DMA_FLAG_TCIF4
  72. #define AUDIO_I2S_DMA_FLAG_HT DMA_FLAG_HTIF4
  73. #define AUDIO_I2S_DMA_FLAG_FE DMA_FLAG_FEIF4
  74. #define AUDIO_I2S_DMA_FLAG_TE DMA_FLAG_TEIF4
  75. #define AUDIO_I2S_DMA_FLAG_DME DMA_FLAG_DMEIF4
  76. #define AUDIO_I2S_EXT_DMA_STREAM DMA1_Stream3
  77. #define AUDIO_I2S_EXT_DMA_DREG CODEC_I2S_EXT_ADDRESS
  78. #define AUDIO_I2S_EXT_DMA_CHANNEL DMA_Channel_3
  79. #define AUDIO_I2S_EXT_DMA_IRQ DMA1_Stream3_IRQn
  80. #define AUDIO_I2S_EXT_DMA_FLAG_TC DMA_FLAG_TCIF3
  81. #define AUDIO_I2S_EXT_DMA_FLAG_HT DMA_FLAG_HTIF3
  82. #define AUDIO_I2S_EXT_DMA_FLAG_FE DMA_FLAG_FEIF3
  83. #define AUDIO_I2S_EXT_DMA_FLAG_TE DMA_FLAG_TEIF3
  84. #define AUDIO_I2S_EXT_DMA_FLAG_DME DMA_FLAG_DMEIF3
  85. #define AUDIO_I2S_EXT_DMA_REG DMA1
  86. #define AUDIO_I2S_EXT_DMA_ISR LISR
  87. #define AUDIO_I2S_EXT_DMA_IFCR LIFCR
  88. #define W8731_ADDR_0 0x1A
  89. #define W8731_ADDR_1 0x1B
  90. #define W8731_NUM_REGS 10
  91. #define CODEC_ADDRESS (W8731_ADDR_0 << 1)
  92. #define WAIT_LONG(x) { \
  93. uint32_t timeout = CODEC_LONG_TIMEOUT; \
  94. while (x) { if ((timeout--) == 0) return false; } \
  95. }
  96. #define WAIT(x) { \
  97. uint32_t timeout = CODEC_TIMEOUT; \
  98. while (x) { if ((timeout--) == 0) return false; } \
  99. }
  100. namespace elements {
  101. /* static */
  102. Codec* Codec::instance_;
  103. enum CodecRegister {
  104. CODEC_REG_LEFT_LINE_IN = 0x00,
  105. CODEC_REG_RIGHT_LINE_IN = 0x01,
  106. CODEC_REG_LEFT_HEADPHONES_OUT = 0x02,
  107. CODEC_REG_RIGHT_HEADPHONES_OUT = 0x03,
  108. CODEC_REG_ANALOGUE_ROUTING = 0x04,
  109. CODEC_REG_DIGITAL_ROUTING = 0x05,
  110. CODEC_REG_POWER_MANAGEMENT = 0x06,
  111. CODEC_REG_DIGITAL_FORMAT = 0x07,
  112. CODEC_REG_SAMPLE_RATE = 0x08,
  113. CODEC_REG_ACTIVE = 0x09,
  114. CODEC_REG_RESET = 0x0f,
  115. };
  116. bool Codec::InitializeGPIO() {
  117. GPIO_InitTypeDef gpio_init;
  118. // Start GPIO peripheral clocks.
  119. RCC_AHB1PeriphClockCmd(CODEC_I2C_GPIO_CLOCK | CODEC_I2S_GPIO_CLOCK, ENABLE);
  120. // Initialize I2C pins
  121. gpio_init.GPIO_Pin = CODEC_I2C_SCL_PIN | CODEC_I2C_SDA_PIN;
  122. gpio_init.GPIO_Mode = GPIO_Mode_AF;
  123. gpio_init.GPIO_Speed = GPIO_Speed_25MHz;
  124. gpio_init.GPIO_OType = GPIO_OType_OD;
  125. gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
  126. GPIO_Init(CODEC_I2C_GPIO, &gpio_init);
  127. // Connect pins to I2C peripheral
  128. GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SCL_PINSRC, CODEC_I2C_GPIO_AF);
  129. GPIO_PinAFConfig(CODEC_I2C_GPIO, CODEC_I2C_SDA_PINSRC, CODEC_I2C_GPIO_AF);
  130. // Initialize I2S pins
  131. gpio_init.GPIO_Pin = CODEC_I2S_SCK_PIN | CODEC_I2S_SDO_PIN | \
  132. CODEC_I2S_SDI_PIN | CODEC_I2S_WS_PIN;
  133. gpio_init.GPIO_Mode = GPIO_Mode_AF;
  134. gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
  135. gpio_init.GPIO_OType = GPIO_OType_PP;
  136. gpio_init.GPIO_PuPd = GPIO_PuPd_NOPULL;
  137. GPIO_Init(CODEC_I2S_GPIO, &gpio_init);
  138. gpio_init.GPIO_Pin = CODEC_I2S_MCK_PIN;
  139. GPIO_Init(CODEC_I2S_MCK_GPIO, &gpio_init);
  140. // Connect pins to I2S peripheral.
  141. GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_WS_PINSRC, CODEC_I2S_GPIO_AF);
  142. GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SCK_PINSRC, CODEC_I2S_GPIO_AF);
  143. GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDO_PINSRC, CODEC_I2S_GPIO_AF);
  144. GPIO_PinAFConfig(CODEC_I2S_GPIO, CODEC_I2S_SDI_PINSRC, CODEC_I2S_GPIO_AF);
  145. GPIO_PinAFConfig(CODEC_I2S_MCK_GPIO, CODEC_I2S_MCK_PINSRC, CODEC_I2S_GPIO_AF);
  146. return true;
  147. }
  148. bool Codec::InitializeControlInterface() {
  149. I2C_InitTypeDef i2c_init;
  150. // Initialize I2C
  151. RCC_APB1PeriphClockCmd(CODEC_I2C_CLK, ENABLE);
  152. I2C_DeInit(CODEC_I2C);
  153. i2c_init.I2C_Mode = I2C_Mode_I2C;
  154. i2c_init.I2C_DutyCycle = I2C_DutyCycle_2;
  155. i2c_init.I2C_OwnAddress1 = 0x33;
  156. i2c_init.I2C_Ack = I2C_Ack_Enable;
  157. i2c_init.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  158. i2c_init.I2C_ClockSpeed = CODEC_I2C_SPEED;
  159. I2C_Init(CODEC_I2C, &i2c_init);
  160. I2C_Cmd(CODEC_I2C, ENABLE);
  161. return true;
  162. }
  163. bool Codec::InitializeAudioInterface(
  164. uint32_t sample_rate,
  165. CodecProtocol protocol,
  166. CodecFormat format) {
  167. // Configure PLL and I2S master clock.
  168. RCC_I2SCLKConfig(RCC_I2S2CLKSource_PLLI2S);
  169. // The following values have been computed for a 8Mhz external crystal!
  170. RCC_PLLI2SCmd(DISABLE);
  171. if (sample_rate == 48000) {
  172. // 47.992kHz
  173. RCC_PLLI2SConfig(258, 3);
  174. } else if (sample_rate == 44100) {
  175. // 44.11kHz
  176. RCC_PLLI2SConfig(271, 6);
  177. } else if (sample_rate == 32000) {
  178. // 32.003kHz
  179. RCC_PLLI2SConfig(426, 4);
  180. } else if (sample_rate == 96000) {
  181. // 95.95 kHz
  182. RCC_PLLI2SConfig(393, 4);
  183. } else {
  184. // Unsupported sample rate!
  185. return false;
  186. }
  187. RCC_PLLI2SCmd(ENABLE);
  188. WAIT(RCC_GetFlagStatus(RCC_FLAG_PLLI2SRDY) == RESET);
  189. RCC_APB1PeriphClockCmd(CODEC_I2S_CLK, ENABLE);
  190. // Initialize I2S
  191. I2S_InitTypeDef i2s_init;
  192. SPI_I2S_DeInit(CODEC_I2S);
  193. i2s_init.I2S_AudioFreq = sample_rate;
  194. i2s_init.I2S_Standard = protocol;
  195. i2s_init.I2S_DataFormat = format;
  196. i2s_init.I2S_CPOL = I2S_CPOL_Low;
  197. i2s_init.I2S_Mode = I2S_Mode_MasterTx;
  198. i2s_init.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
  199. // Initialize the I2S main channel for TX
  200. I2S_Init(CODEC_I2S, &i2s_init);
  201. // Initialize the I2S extended channel for RX
  202. I2S_FullDuplexConfig(CODEC_I2S_EXT, &i2s_init);
  203. return true;
  204. }
  205. bool Codec::WriteControlRegister(uint8_t address, uint16_t data) {
  206. uint8_t byte_1 = ((address << 1) & 0xfe) | ((data >> 8) & 0x01);
  207. uint8_t byte_2 = data & 0xff;
  208. WAIT_LONG(I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BUSY));
  209. I2C_GenerateSTART(CODEC_I2C, ENABLE);
  210. WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_MODE_SELECT));
  211. I2C_Send7bitAddress(CODEC_I2C, CODEC_ADDRESS, I2C_Direction_Transmitter);
  212. WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));
  213. I2C_SendData(CODEC_I2C, byte_1);
  214. WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
  215. I2C_SendData(CODEC_I2C, byte_2);
  216. WAIT(!I2C_CheckEvent(CODEC_I2C, I2C_EVENT_MASTER_BYTE_TRANSMITTING));
  217. WAIT_LONG(!I2C_GetFlagStatus(CODEC_I2C, I2C_FLAG_BTF));
  218. I2C_GenerateSTOP(CODEC_I2C, ENABLE);
  219. return true;
  220. }
  221. bool Codec::InitializeCodec(
  222. uint32_t sample_rate,
  223. CodecProtocol protocol,
  224. CodecFormat format) {
  225. bool s = true; // success;
  226. s = s && WriteControlRegister(CODEC_REG_RESET, 0);
  227. // Configure L&R inputs
  228. s = s && WriteControlRegister(CODEC_REG_LEFT_LINE_IN, CODEC_INPUT_0_DB);
  229. s = s && WriteControlRegister(CODEC_REG_RIGHT_LINE_IN, CODEC_INPUT_0_DB);
  230. // Configure L&R headphone outputs
  231. s = s && WriteControlRegister(CODEC_REG_LEFT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
  232. s = s && WriteControlRegister(CODEC_REG_RIGHT_HEADPHONES_OUT, CODEC_HEADPHONES_MUTE);
  233. // Configure analog routing
  234. s = s && WriteControlRegister(
  235. CODEC_REG_ANALOGUE_ROUTING,
  236. CODEC_MIC_MUTE | CODEC_ADC_LINE | CODEC_OUTPUT_DAC_ENABLE);
  237. // Configure digital routing
  238. s = s && WriteControlRegister(CODEC_REG_DIGITAL_ROUTING, CODEC_DEEMPHASIS_NONE);
  239. // Configure power management
  240. s = s && WriteControlRegister(
  241. CODEC_REG_POWER_MANAGEMENT,
  242. CODEC_POWER_DOWN_OSCILLATOR | \
  243. CODEC_POWER_DOWN_CLOCK_OUTPUT | \
  244. CODEC_POWER_DOWN_MIC);
  245. uint8_t format_byte = CODEC_FORMAT_SLAVE;
  246. if (protocol == CODEC_PROTOCOL_PHILIPS) {
  247. format_byte |= CODEC_PROTOCOL_MASK_PHILIPS;
  248. } else if (protocol == CODEC_PROTOCOL_MSB_FIRST) {
  249. format_byte |= CODEC_PROTOCOL_MASK_MSB_FIRST;
  250. } else if (protocol == CODEC_PROTOCOL_LSB_FIRST) {
  251. format_byte |= CODEC_PROTOCOL_MASK_LSB_FIRST;
  252. }
  253. if (format == CODEC_FORMAT_16_BIT) {
  254. format_byte |= CODEC_FORMAT_MASK_16_BIT;
  255. } else if (format == CODEC_FORMAT_24_BIT) {
  256. format_byte |= CODEC_FORMAT_MASK_24_BIT;
  257. } else if (format == CODEC_FORMAT_32_BIT) {
  258. format_byte |= CODEC_FORMAT_MASK_32_BIT;
  259. }
  260. s = s && WriteControlRegister(CODEC_REG_DIGITAL_FORMAT, format_byte);
  261. uint8_t rate_byte = 0;
  262. // According to the WM8731 datasheet, the 32kHz and 96kHz modes require the
  263. // master clock to be at 12.288 MHz (384 fs / 128 fs). The STM32F4 I2S clock
  264. // is always at 256 fs. So the 32kHz and 96kHz modes are achieved by
  265. // pretending that we are doing 48kHz, but with a slower or faster master
  266. // clock.
  267. rate_byte = sample_rate == 44100 ? CODEC_RATE_44K_44K : CODEC_RATE_48K_48K;
  268. s = s && WriteControlRegister(CODEC_REG_SAMPLE_RATE, rate_byte);
  269. // For now codec is not active.
  270. s = s && WriteControlRegister(CODEC_REG_ACTIVE, 0x00);
  271. return s;
  272. }
  273. bool Codec::InitializeDMA() {
  274. RCC_AHB1PeriphClockCmd(AUDIO_I2S_DMA_CLOCK, ENABLE);
  275. // DMA setup for TX.
  276. DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
  277. DMA_DeInit(AUDIO_I2S_DMA_STREAM);
  278. dma_init_tx_.DMA_Channel = AUDIO_I2S_DMA_CHANNEL;
  279. dma_init_tx_.DMA_PeripheralBaseAddr = AUDIO_I2S_DMA_DREG;
  280. dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)0;
  281. dma_init_tx_.DMA_DIR = DMA_DIR_MemoryToPeripheral;
  282. dma_init_tx_.DMA_BufferSize = (uint32_t)0xFFFE;
  283. dma_init_tx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  284. dma_init_tx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
  285. dma_init_tx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  286. dma_init_tx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  287. dma_init_tx_.DMA_Mode = DMA_Mode_Circular;
  288. dma_init_tx_.DMA_Priority = DMA_Priority_High;
  289. dma_init_tx_.DMA_FIFOMode = DMA_FIFOMode_Disable;
  290. dma_init_tx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
  291. dma_init_tx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  292. dma_init_tx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  293. DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
  294. // DMA setup for RX.
  295. DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
  296. DMA_DeInit(AUDIO_I2S_EXT_DMA_STREAM);
  297. dma_init_rx_.DMA_Channel = AUDIO_I2S_EXT_DMA_CHANNEL;
  298. dma_init_rx_.DMA_PeripheralBaseAddr = AUDIO_I2S_EXT_DMA_DREG;
  299. dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)0;
  300. dma_init_rx_.DMA_DIR = DMA_DIR_PeripheralToMemory;
  301. dma_init_rx_.DMA_BufferSize = (uint32_t)0xFFFE;
  302. dma_init_rx_.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  303. dma_init_rx_.DMA_MemoryInc = DMA_MemoryInc_Enable;
  304. dma_init_rx_.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  305. dma_init_rx_.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
  306. dma_init_rx_.DMA_Mode = DMA_Mode_Circular;
  307. dma_init_rx_.DMA_Priority = DMA_Priority_High;
  308. dma_init_rx_.DMA_FIFOMode = DMA_FIFOMode_Disable;
  309. dma_init_rx_.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
  310. dma_init_rx_.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  311. dma_init_rx_.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  312. DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);
  313. // Enable the interrupts.
  314. DMA_ITConfig(AUDIO_I2S_EXT_DMA_STREAM, DMA_IT_TC | DMA_IT_HT, ENABLE);
  315. // Enable the IRQ.
  316. NVIC_EnableIRQ(AUDIO_I2S_EXT_DMA_IRQ);
  317. // Start DMA from/to codec.
  318. SPI_I2S_DMACmd(CODEC_I2S, SPI_I2S_DMAReq_Tx, ENABLE);
  319. SPI_I2S_DMACmd(CODEC_I2S_EXT, SPI_I2S_DMAReq_Rx, ENABLE);
  320. return true;
  321. }
  322. bool Codec::Init(
  323. uint32_t sample_rate,
  324. CodecProtocol protocol,
  325. CodecFormat format) {
  326. rx_buffer_.Init();
  327. tx_buffer_.Init();
  328. Frame s;
  329. s.l = s.r = 0;
  330. for (size_t i = 0; i < rx_buffer_.capacity() >> 1; ++i) {
  331. rx_buffer_.Overwrite(s);
  332. tx_buffer_.Overwrite(s);
  333. }
  334. instance_ = this;
  335. callback_ = NULL;
  336. return InitializeGPIO() && \
  337. InitializeControlInterface() && \
  338. InitializeAudioInterface(sample_rate, protocol, format) && \
  339. InitializeCodec(sample_rate, protocol, format) && \
  340. InitializeDMA();
  341. }
  342. bool Codec::Start(FillBufferCallback callback) {
  343. // Start the codec.
  344. if (!WriteControlRegister(CODEC_REG_ACTIVE, 0x01)) {
  345. return false;
  346. }
  347. callback_ = callback;
  348. client_tx_ = NULL;
  349. client_rx_ = NULL;
  350. transmitted_ = 0;
  351. processed_ = 0;
  352. // Enable the I2S TX and RX peripherals.
  353. if ((CODEC_I2S->I2SCFGR & 0x0400) == 0){
  354. I2S_Cmd(CODEC_I2S, ENABLE);
  355. }
  356. if ((CODEC_I2S_EXT->I2SCFGR & 0x0400) == 0){
  357. I2S_Cmd(CODEC_I2S_EXT, ENABLE);
  358. }
  359. dma_init_tx_.DMA_Memory0BaseAddr = (uint32_t)(tx_dma_buffer_);
  360. dma_init_rx_.DMA_Memory0BaseAddr = (uint32_t)(rx_dma_buffer_);
  361. dma_init_tx_.DMA_BufferSize = kAudioChunkSize * 2 * 2;
  362. dma_init_rx_.DMA_BufferSize = kAudioChunkSize * 2 * 2;
  363. DMA_Init(AUDIO_I2S_DMA_STREAM, &dma_init_tx_);
  364. DMA_Init(AUDIO_I2S_EXT_DMA_STREAM, &dma_init_rx_);
  365. DMA_Cmd(AUDIO_I2S_DMA_STREAM, ENABLE);
  366. DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, ENABLE);
  367. return true;
  368. }
  369. void Codec::Stop() {
  370. DMA_Cmd(AUDIO_I2S_DMA_STREAM, DISABLE);
  371. DMA_Cmd(AUDIO_I2S_EXT_DMA_STREAM, DISABLE);
  372. }
  373. void Codec::Fill(size_t offset) {
  374. if (kNumFIFOChunks) {
  375. // Write input samples to FIFO, Read output samples from FIFO
  376. rx_buffer_.Overwrite(&rx_dma_buffer_[offset], kAudioChunkSize);
  377. tx_buffer_.ImmediateRead(&tx_dma_buffer_[offset], kAudioChunkSize);
  378. } else if (callback_) {
  379. (*callback_)(
  380. &rx_dma_buffer_[offset],
  381. &tx_dma_buffer_[offset],
  382. kAudioChunkSize);
  383. } else {
  384. // Inform the client that some data is ready, and store pointers to the
  385. // valid section of the ring buffer.
  386. ++transmitted_;
  387. client_rx_ = &rx_dma_buffer_[offset];
  388. client_tx_ = &tx_dma_buffer_[offset];
  389. }
  390. }
  391. } // namespace elements
  392. extern "C" {
  393. // Do not call into the firmware library to save on calls/jumps.
  394. // if (DMA_GetFlagStatus(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC) != RESET) {
  395. // DMA_ClearFlag(AUDIO_I2S_EXT_DMA_STREAM, AUDIO_I2S_EXT_DMA_FLAG_TC);
  396. void DMA1_Stream3_IRQHandler(void) {
  397. if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_TC) {
  398. AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_TC;
  399. elements::Codec::GetInstance()->Fill(elements::kAudioChunkSize);
  400. }
  401. if (AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_ISR & AUDIO_I2S_EXT_DMA_FLAG_HT) {
  402. AUDIO_I2S_EXT_DMA_REG->AUDIO_I2S_EXT_DMA_IFCR = AUDIO_I2S_EXT_DMA_FLAG_HT;
  403. elements::Codec::GetInstance()->Fill(0);
  404. }
  405. }
  406. }