input_spdif3.cpp 7.3KB

pirms 4 gadiem
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. /* Audio Library for Teensy 3.X
  2. * Copyright (c) 2019, Paul Stoffregen, paul@pjrc.com
  3. *
  4. * Development of this audio library was funded by PJRC.COM, LLC by sales of
  5. * Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
  6. * open source software by purchasing Teensy or other PJRC products.
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice, development funding notice, and this permission
  16. * notice shall be included in all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. /*
  27. by Frank Bösing
  28. */
  29. #if defined(__IMXRT1052__) || defined(__IMXRT1062__)
  30. #include <Arduino.h>
  31. #include "input_spdif3.h"
  32. #include "output_spdif3.h"
  33. #include "utility/imxrt_hw.h"
  34. DMAMEM __attribute__((aligned(32)))
  35. static uint32_t spdif_rx_buffer[AUDIO_BLOCK_SAMPLES * 4];
  36. audio_block_t * AudioInputSPDIF3::block_left = NULL;
  37. audio_block_t * AudioInputSPDIF3::block_right = NULL;
  38. uint16_t AudioInputSPDIF3::block_offset = 0;
  39. bool AudioInputSPDIF3::update_responsibility = false;
  40. DMAChannel AudioInputSPDIF3::dma(false);
  41. FLASHMEM
  42. void AudioInputSPDIF3::begin(void)
  43. {
  44. dma.begin(true); // Allocate the DMA channel first
  45. AudioOutputSPDIF3::config_spdif3();
  46. const int nbytes_mlno = 2 * 4; // 8 Bytes per minor loop
  47. dma.TCD->SADDR = &SPDIF_SRL;
  48. dma.TCD->SOFF = 4;
  49. dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(2) | DMA_TCD_ATTR_DSIZE(2);
  50. dma.TCD->NBYTES_MLNO = DMA_TCD_NBYTES_MLOFFYES_NBYTES(nbytes_mlno) | DMA_TCD_NBYTES_SMLOE |
  51. DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8);
  52. dma.TCD->SLAST = -8;
  53. dma.TCD->DADDR = spdif_rx_buffer;
  54. dma.TCD->DOFF = 4;
  55. dma.TCD->DLASTSGA = -sizeof(spdif_rx_buffer);
  56. dma.TCD->CITER_ELINKNO = sizeof(spdif_rx_buffer) / nbytes_mlno;
  57. dma.TCD->BITER_ELINKNO = sizeof(spdif_rx_buffer) / nbytes_mlno;
  58. dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
  59. dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SPDIF_RX);
  60. update_responsibility = update_setup();
  61. dma.attachInterrupt(isr);
  62. dma.enable();
  63. SPDIF_SRCD = 0;
  64. SPDIF_SCR |= SPDIF_SCR_DMA_RX_EN;
  65. CORE_PIN15_CONFIG = 3;
  66. IOMUXC_SPDIF_IN_SELECT_INPUT = 0; // GPIO_AD_B1_03_ALT3
  67. //pinMode(13, OUTPUT);
  68. }
  69. void AudioInputSPDIF3::isr(void)
  70. {
  71. uint32_t daddr, offset;
  72. const int32_t *src, *end;
  73. int16_t *dest_left, *dest_right;
  74. audio_block_t *left, *right;
  75. dma.clearInterrupt();
  76. //digitalWriteFast(13, !digitalReadFast(13));
  77. if (AudioInputSPDIF3::update_responsibility) AudioStream::update_all();
  78. daddr = (uint32_t)(dma.TCD->DADDR);
  79. if (daddr < (uint32_t)spdif_rx_buffer + sizeof(spdif_rx_buffer) / 2) {
  80. // DMA is receiving to the first half of the buffer
  81. // need to remove data from the second half
  82. src = (int32_t *)&spdif_rx_buffer[AUDIO_BLOCK_SAMPLES * 2];
  83. end = (int32_t *)&spdif_rx_buffer[AUDIO_BLOCK_SAMPLES * 4];
  84. } else {
  85. // DMA is receiving to the second half of the buffer
  86. // need to remove data from the first half
  87. src = (int32_t *)&spdif_rx_buffer[0];
  88. end = (int32_t *)&spdif_rx_buffer[AUDIO_BLOCK_SAMPLES*2];
  89. }
  90. left = AudioInputSPDIF3::block_left;
  91. right = AudioInputSPDIF3::block_right;
  92. if (left != NULL && right != NULL) {
  93. offset = AudioInputSPDIF3::block_offset;
  94. if (offset <= AUDIO_BLOCK_SAMPLES*2) {
  95. dest_left = &(left->data[offset]);
  96. dest_right = &(right->data[offset]);
  97. AudioInputSPDIF3::block_offset = offset + AUDIO_BLOCK_SAMPLES*2;
  98. do {
  99. #if IMXRT_CACHE_ENABLED >=1
  100. SCB_CACHE_DCIMVAC = (uintptr_t)src;
  101. asm("dsb":::"memory");
  102. #endif
  103. *dest_left++ = (*src++) >> 8;
  104. *dest_right++ = (*src++) >> 8;
  105. *dest_left++ = (*src++) >> 8;
  106. *dest_right++ = (*src++) >> 8;
  107. *dest_left++ = (*src++) >> 8;
  108. *dest_right++ = (*src++) >> 8;
  109. *dest_left++ = (*src++) >> 8;
  110. *dest_right++ = (*src++) >> 8;
  111. } while (src < end);
  112. }
  113. }
  114. else if (left != NULL) {
  115. offset = AudioInputSPDIF3::block_offset;
  116. if (offset <= AUDIO_BLOCK_SAMPLES*2) {
  117. dest_left = &(left->data[offset]);
  118. AudioInputSPDIF3::block_offset = offset + AUDIO_BLOCK_SAMPLES*2;
  119. do {
  120. #if IMXRT_CACHE_ENABLED >=1
  121. SCB_CACHE_DCIMVAC = (uintptr_t)src;
  122. asm("dsb":::"memory");
  123. #endif
  124. *dest_left++ = (*src++) >> 8;
  125. src++;
  126. *dest_left++ = (*src++) >> 8;
  127. src++;
  128. *dest_left++ = (*src++) >> 8;
  129. src++;
  130. *dest_left++ = (*src++) >> 8;
  131. src++;
  132. } while (src < end);
  133. }
  134. }
  135. else if (right != NULL) {
  136. offset = AudioInputSPDIF3::block_offset;
  137. if (offset <= AUDIO_BLOCK_SAMPLES*2) {
  138. dest_right = &(right->data[offset]);
  139. AudioInputSPDIF3::block_offset = offset + AUDIO_BLOCK_SAMPLES*2;
  140. do {
  141. #if IMXRT_CACHE_ENABLED >=1
  142. SCB_CACHE_DCIMVAC = (uintptr_t)src;
  143. asm("dsb":::"memory");
  144. #endif
  145. src++;
  146. *dest_right++ = (*src++) >> 8;
  147. src++;
  148. *dest_right++ = (*src++) >> 8;
  149. src++;
  150. *dest_right++ = (*src++) >> 8;
  151. src++;
  152. *dest_right++ = (*src++) >> 8;
  153. } while (src < end);
  154. }
  155. }
  156. }
  157. void AudioInputSPDIF3::update(void)
  158. {
  159. audio_block_t *new_left=NULL, *new_right=NULL, *out_left=NULL, *out_right=NULL;
  160. // allocate 2 new blocks, but if one fails, allocate neither
  161. new_left = allocate();
  162. if (new_left != NULL) {
  163. new_right = allocate();
  164. if (new_right == NULL) {
  165. release(new_left);
  166. new_left = NULL;
  167. }
  168. }
  169. __disable_irq();
  170. if (block_offset >= AUDIO_BLOCK_SAMPLES) {
  171. // the DMA filled 2 blocks, so grab them and get the
  172. // 2 new blocks to the DMA, as quickly as possible
  173. out_left = block_left;
  174. block_left = new_left;
  175. out_right = block_right;
  176. block_right = new_right;
  177. block_offset = 0;
  178. __enable_irq();
  179. // then transmit the DMA's former blocks
  180. transmit(out_left, 0);
  181. release(out_left);
  182. transmit(out_right, 1);
  183. release(out_right);
  184. //Serial.print(".");
  185. } else if (new_left != NULL) {
  186. // the DMA didn't fill blocks, but we allocated blocks
  187. if (block_left == NULL) {
  188. // the DMA doesn't have any blocks to fill, so
  189. // give it the ones we just allocated
  190. block_left = new_left;
  191. block_right = new_right;
  192. block_offset = 0;
  193. __enable_irq();
  194. } else {
  195. // the DMA already has blocks, doesn't need these
  196. __enable_irq();
  197. release(new_left);
  198. release(new_right);
  199. }
  200. } else {
  201. // The DMA didn't fill blocks, and we could not allocate
  202. // memory... the system is likely starving for memory!
  203. // Sadly, there's nothing we can do.
  204. __enable_irq();
  205. }
  206. }
  207. bool AudioInputSPDIF3::pllLocked(void)
  208. {
  209. return (SPDIF_SRPC & SPDIF_SRPC_LOCK) == SPDIF_SRPC_LOCK ? true:false;
  210. }
  211. unsigned int AudioInputSPDIF3::sampleRate(void) {
  212. if (!pllLocked()) return 0;
  213. return (float)((uint64_t)F_BUS_ACTUAL * SPDIF_SRFM) / (0x8000000ULL * AudioOutputSPDIF3::dpll_Gain()) + 0.5F;
  214. }
  215. #endif