Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

140 lines
3.5KB

  1. #include "output_dac.h"
  2. #include "utility/pdb.h"
  3. #if defined(__MK20DX256__)
  4. DMAMEM static uint16_t dac_buffer[AUDIO_BLOCK_SAMPLES*2];
  5. audio_block_t * AudioOutputAnalog::block_left_1st = NULL;
  6. audio_block_t * AudioOutputAnalog::block_left_2nd = NULL;
  7. bool AudioOutputAnalog::update_responsibility = false;
  8. void AudioOutputAnalog::begin(void)
  9. {
  10. SIM_SCGC2 |= SIM_SCGC2_DAC0;
  11. DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V VDDA is DACREF_2
  12. // slowly ramp up to DC voltage, approx 1/4 second
  13. for (int16_t i=0; i<128; i++) {
  14. analogWrite(A14, i);
  15. delay(2);
  16. }
  17. // set the programmable delay block to trigger DMA requests
  18. SIM_SCGC6 |= SIM_SCGC6_PDB;
  19. PDB0_IDLY = 1;
  20. PDB0_MOD = PDB_PERIOD;
  21. PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
  22. PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN;
  23. SIM_SCGC7 |= SIM_SCGC7_DMA;
  24. SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
  25. DMA_CR = 0;
  26. DMA_TCD4_SADDR = dac_buffer;
  27. DMA_TCD4_SOFF = 2;
  28. DMA_TCD4_ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
  29. DMA_TCD4_NBYTES_MLNO = 2;
  30. DMA_TCD4_SLAST = -sizeof(dac_buffer);
  31. DMA_TCD4_DADDR = &DAC0_DAT0L;
  32. DMA_TCD4_DOFF = 0;
  33. DMA_TCD4_CITER_ELINKNO = sizeof(dac_buffer) / 2;
  34. DMA_TCD4_DLASTSGA = 0;
  35. DMA_TCD4_BITER_ELINKNO = sizeof(dac_buffer) / 2;
  36. DMA_TCD4_CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
  37. DMAMUX0_CHCFG4 = DMAMUX_DISABLE;
  38. DMAMUX0_CHCFG4 = DMAMUX_SOURCE_PDB | DMAMUX_ENABLE;
  39. update_responsibility = update_setup();
  40. DMA_SERQ = 4;
  41. NVIC_ENABLE_IRQ(IRQ_DMA_CH4);
  42. }
  43. void AudioOutputAnalog::analogReference(int ref)
  44. {
  45. // TODO: this should ramp gradually to the new DC level
  46. if (ref == INTERNAL) {
  47. DAC0_C0 &= ~DAC_C0_DACRFS; // 1.2V
  48. } else {
  49. DAC0_C0 |= DAC_C0_DACRFS; // 3.3V
  50. }
  51. }
  52. void AudioOutputAnalog::update(void)
  53. {
  54. audio_block_t *block;
  55. block = receiveReadOnly(0); // input 0
  56. if (block) {
  57. __disable_irq();
  58. if (block_left_1st == NULL) {
  59. block_left_1st = block;
  60. __enable_irq();
  61. } else if (block_left_2nd == NULL) {
  62. block_left_2nd = block;
  63. __enable_irq();
  64. } else {
  65. audio_block_t *tmp = block_left_1st;
  66. block_left_1st = block_left_2nd;
  67. block_left_2nd = block;
  68. __enable_irq();
  69. release(tmp);
  70. }
  71. }
  72. }
  73. // TODO: the DAC has much higher bandwidth than the datasheet says
  74. // can we output a 2X oversampled output, for easier filtering?
  75. void dma_ch4_isr(void)
  76. {
  77. const int16_t *src, *end;
  78. int16_t *dest;
  79. audio_block_t *block;
  80. uint32_t saddr;
  81. saddr = (uint32_t)DMA_TCD4_SADDR;
  82. DMA_CINT = 4;
  83. if (saddr < (uint32_t)dac_buffer + sizeof(dac_buffer) / 2) {
  84. // DMA is transmitting the first half of the buffer
  85. // so we must fill the second half
  86. dest = (int16_t *)&dac_buffer[AUDIO_BLOCK_SAMPLES];
  87. end = (int16_t *)&dac_buffer[AUDIO_BLOCK_SAMPLES*2];
  88. } else {
  89. // DMA is transmitting the second half of the buffer
  90. // so we must fill the first half
  91. dest = (int16_t *)dac_buffer;
  92. end = (int16_t *)&dac_buffer[AUDIO_BLOCK_SAMPLES];
  93. }
  94. block = AudioOutputAnalog::block_left_1st;
  95. if (block) {
  96. src = block->data;
  97. do {
  98. // TODO: this should probably dither
  99. *dest++ = ((*src++) + 32767) >> 4;
  100. } while (dest < end);
  101. AudioStream::release(block);
  102. AudioOutputAnalog::block_left_1st = AudioOutputAnalog::block_left_2nd;
  103. AudioOutputAnalog::block_left_2nd = NULL;
  104. } else {
  105. do {
  106. *dest++ = 2047;
  107. } while (dest < end);
  108. }
  109. if (AudioOutputAnalog::update_responsibility) AudioStream::update_all();
  110. }
  111. #else
  112. void AudioOutputAnalog::begin(void)
  113. {
  114. }
  115. void AudioOutputAnalog::update(void)
  116. {
  117. audio_block_t *block;
  118. block = receiveReadOnly(0); // input 0
  119. if (block) release(block);
  120. }
  121. #endif // defined(__MK20DX256__)