Ver código fonte

Merge pull request #1 from PaulStoffregen/master

update
dds
Frank 4 anos atrás
pai
commit
6decc27093
Nenhuma conta vinculada ao e-mail do autor do commit
37 arquivos alterados com 2094 adições e 286 exclusões
  1. +4
    -0
      Audio.h
  2. +5
    -0
      control_cs42448.cpp
  3. +4
    -1
      effect_delay.h
  4. +149
    -0
      examples/Analysis/PeakAndRMSMeter8Channel/PeakAndRMSMeter8Channel.ino
  5. +12
    -11
      examples/HardwareTesting/WM8731MikroSine/WM8731MikroSine.ino
  6. +1
    -1
      examples/Recorder/Recorder.ino
  7. +20
    -20
      gui/index.html
  8. +29
    -16
      input_i2s.cpp
  9. +6
    -9
      input_i2s2.cpp
  10. +247
    -0
      input_i2s_hex.cpp
  11. +54
    -0
      input_i2s_hex.h
  12. +263
    -0
      input_i2s_oct.cpp
  13. +56
    -0
      input_i2s_oct.h
  14. +53
    -2
      input_i2s_quad.cpp
  15. +10
    -5
      input_pdm.cpp
  16. +4
    -5
      input_tdm.cpp
  17. +2
    -2
      input_tdm2.cpp
  18. +4
    -0
      keywords.txt
  19. +3
    -0
      output_adat.cpp
  20. +86
    -136
      output_i2s.cpp
  21. +8
    -0
      output_i2s.h
  22. +26
    -20
      output_i2s2.cpp
  23. +355
    -0
      output_i2s_hex.cpp
  24. +65
    -0
      output_i2s_hex.h
  25. +419
    -0
      output_i2s_oct.cpp
  26. +71
    -0
      output_i2s_oct.h
  27. +60
    -12
      output_i2s_quad.cpp
  28. +16
    -6
      output_pt8211.cpp
  29. +9
    -4
      output_spdif.cpp
  30. +24
    -15
      output_tdm.cpp
  31. +7
    -11
      output_tdm2.cpp
  32. +2
    -2
      play_queue.cpp
  33. +7
    -1
      play_queue.h
  34. +4
    -4
      record_queue.cpp
  35. +7
    -1
      record_queue.h
  36. +1
    -1
      utility/imxrt_hw.cpp
  37. +1
    -1
      utility/imxrt_hw.h

+ 4
- 0
Audio.h Ver arquivo

@@ -93,6 +93,8 @@
#include "input_i2s.h"
#include "input_i2s2.h"
#include "input_i2s_quad.h"
#include "input_i2s_hex.h"
#include "input_i2s_oct.h"
#include "input_tdm.h"
#include "input_tdm2.h"
#include "input_pdm.h"
@@ -102,6 +104,8 @@
#include "output_i2s.h"
#include "output_i2s2.h"
#include "output_i2s_quad.h"
#include "output_i2s_hex.h"
#include "output_i2s_oct.h"
#include "output_mqs.h"
#include "output_pwm.h"
#include "output_spdif.h"

+ 5
- 0
control_cs42448.cpp Ver arquivo

@@ -78,6 +78,11 @@
// then un-mute the DACs.
// 9. Normal operation begins.

// Some people have found their CS42448 goes into a strange mode where VQ is 1.25V
// instead of the normal 2.5V. Apparently there is a workaround for this problem
// which involves writing to an undocumented bit. Details here:
// https://forum.pjrc.com/threads/41371?p=215881&viewfull=1#post215881

static const uint8_t default_config[] = {
0xF4, // CS42448_Functional_Mode = slave mode, MCLK 25.6 MHz max
0x76, // CS42448_Interface_Formats = TDM mode

+ 4
- 1
effect_delay.h Ver arquivo

@@ -30,7 +30,10 @@
#include "AudioStream.h"
#include "utility/dspinst.h"

#if defined(__MK66FX1M0__)
#if defined(__IMXRT1062__)
// 4.00 second maximum on Teensy 4.0
#define DELAY_QUEUE_SIZE (176512 / AUDIO_BLOCK_SAMPLES)
#elif defined(__MK66FX1M0__)
// 2.41 second maximum on Teensy 3.6
#define DELAY_QUEUE_SIZE (106496 / AUDIO_BLOCK_SAMPLES)
#elif defined(__MK64FX512__)

+ 149
- 0
examples/Analysis/PeakAndRMSMeter8Channel/PeakAndRMSMeter8Channel.ino Ver arquivo

@@ -0,0 +1,149 @@
/* Show levels (RMS & Peak) for 8 I2S microphone inputs
*
* Connect 8 INMP411 I2S microphones to Teensy 4.0
* Pin 8 SD on mics #1 and #2
* Pin 6 SD on mics #3 and #4
* Pin 9 SD on mics #5 and #6
* Pin 32 SD on mics #7 and #8
* Pin 20 WS on all mics
* Pin 21 SCK on all mics
*
* Each mic needs GND to Teensy GND, VCC to Teensy 3.3V.
* Connect L/R to GND on the odd numbered mics
* and L/R to 3.3V on the even numbered mics.
*
* Optional - connect a Teensy Audio Shield or other I2S
* output device, but do not connect it to pin 8, because
* the INMP411 mics #1 & #2 send their signal to pin 8.
*
* This example code is in the public domain
*/

#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

// If INMP411 mics are not available, the audio shield mic can
// be used, but it will send a single signal to inputs #1 & #2
// (if connected to pin 8).
//const int myInput = AUDIO_INPUT_LINEIN;
const int myInput = AUDIO_INPUT_MIC;

AudioInputI2SOct audioInput; // audio shield: mic or line-in
AudioAmplifier amp1;
AudioAmplifier amp2;
AudioAmplifier amp3;
AudioAmplifier amp4;
AudioAmplifier amp5;
AudioAmplifier amp6;
AudioAmplifier amp7;
AudioAmplifier amp8;
AudioAnalyzeRMS rms1;
AudioAnalyzeRMS rms2;
AudioAnalyzeRMS rms3;
AudioAnalyzeRMS rms4;
AudioAnalyzeRMS rms5;
AudioAnalyzeRMS rms6;
AudioAnalyzeRMS rms7;
AudioAnalyzeRMS rms8;
AudioAnalyzePeak peak1;
AudioAnalyzePeak peak2;
AudioAnalyzePeak peak3;
AudioAnalyzePeak peak4;
AudioAnalyzePeak peak5;
AudioAnalyzePeak peak6;
AudioAnalyzePeak peak7;
AudioAnalyzePeak peak8;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out

// Send all microphone signals to amps
AudioConnection r1(audioInput, 0, amp1, 0);
AudioConnection r2(audioInput, 1, amp2, 0);
AudioConnection r3(audioInput, 2, amp3, 0);
AudioConnection r4(audioInput, 3, amp4, 0);
AudioConnection r5(audioInput, 4, amp5, 0);
AudioConnection r6(audioInput, 5, amp6, 0);
AudioConnection r7(audioInput, 6, amp7, 0);
AudioConnection r8(audioInput, 7, amp8, 0);

// Connect the amps to RMS and Peak analyzers
AudioConnection a1(amp1, 0, rms1, 0);
AudioConnection a2(amp2, 0, rms2, 0);
AudioConnection a3(amp3, 0, rms3, 0);
AudioConnection a4(amp4, 0, rms4, 0);
AudioConnection a5(amp5, 0, rms5, 0);
AudioConnection a6(amp6, 0, rms6, 0);
AudioConnection a7(amp7, 0, rms7, 0);
AudioConnection a8(amp8, 0, rms8, 0);
AudioConnection p1(amp1, 0, peak1, 0);
AudioConnection p2(amp2, 0, peak2, 0);
AudioConnection p3(amp3, 0, peak3, 0);
AudioConnection p4(amp4, 0, peak4, 0);
AudioConnection p5(amp5, 0, peak5, 0);
AudioConnection p6(amp6, 0, peak6, 0);
AudioConnection p7(amp7, 0, peak7, 0);
AudioConnection p8(amp8, 0, peak8, 0);

// Also connect 2 of the amps to an I2S output (Pin 8)
// to be able to listen to the sound.
AudioConnection c10(amp1, 0, audioOutput, 0);
AudioConnection c11(amp2, 0, audioOutput, 1);
AudioControlSGTL5000 audioShield;


void setup() {
AudioMemory(26);
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.micGain(12);
audioShield.volume(0.5);
const float microphoneAmplification = 72.0;
amp1.gain(microphoneAmplification);
amp2.gain(microphoneAmplification);
amp3.gain(microphoneAmplification);
amp4.gain(microphoneAmplification);
amp5.gain(microphoneAmplification);
amp6.gain(microphoneAmplification);
amp7.gain(microphoneAmplification);
amp8.gain(microphoneAmplification);
Serial.begin(9600);
}

elapsedMillis fps;

void loop() {
if (fps > 24) {
fps = 0;
const int digits = 8;
print_bar(1, rms1.read(), peak1.readPeakToPeak()/2, digits);
print_bar(2, rms2.read(), peak2.readPeakToPeak()/2, digits);
print_bar(3, rms3.read(), peak3.readPeakToPeak()/2, digits);
print_bar(4, rms4.read(), peak4.readPeakToPeak()/2, digits);
print_bar(5, rms5.read(), peak5.readPeakToPeak()/2, digits);
print_bar(6, rms6.read(), peak6.readPeakToPeak()/2, digits);
print_bar(7, rms7.read(), peak7.readPeakToPeak()/2, digits);
print_bar(8, rms8.read(), peak8.readPeakToPeak()/2, digits);
Serial.println();
}
}

void print_bar(int in, float rms, float peak, int digits) {
Serial.print(in);
Serial.print(":");
int num_rms = roundf(rms * digits);
int num_peak = roundf(peak * digits);
for (int i=0; i < digits; i++) {
if (i < num_rms) {
Serial.print("*");
} else if (i < num_peak) {
Serial.print(">");
} else {
Serial.print(" ");
}
}
Serial.print(" ");
}

+ 12
- 11
examples/HardwareTesting/WM8731MikroSine/WM8731MikroSine.ino Ver arquivo

@@ -11,17 +11,17 @@
//
// Recommended connections:
//
// Mikroe Teensy 3.1
// ------ ----------
// SCK 9
// MISO 13
// MOSI 22
// ADCL 23 (yes, ADCL & DACL connect together)
// DACL 23
// SDA 18
// SCL 19
// 3.3V +3.3V
// GND GND
// MikroE Teensy 3 Teensy 4
// ------ -------- --------
// SCK 9 21
// MISO 13 8
// MOSI 22 7
// ADCL 23 20 (yes, ADCL & DACL connect together)
// DACL 23 20
// SDA 18 18
// SCL 19 19
// 3.3V +3.3V +3.3V
// GND GND GND
//
// For connection using I2S master mode (WM8731 in slave mode, with MCLK):
// https://forum.pjrc.com/threads/53854?p=198733&viewfull=1#post198733
@@ -50,6 +50,7 @@ AudioControlWM8731master wm8731m1; //xy=292,379


void setup() {
delay(1000); // allow the WM7831 extra time to power up
wm8731m1.enable();

AudioMemory(15);

+ 1
- 1
examples/Recorder/Recorder.ino Ver arquivo

@@ -162,7 +162,7 @@ void continueRecording() {
memcpy(buffer+256, queue1.readBuffer(), 256);
queue1.freeBuffer();
// write all 512 bytes to the SD card
elapsedMicros usec = 0;
//elapsedMicros usec = 0;
frec.write(buffer, 512);
// Uncomment these lines to see how long SD writes
// are taking. A pair of audio blocks arrives every

+ 20
- 20
gui/index.html Ver arquivo

@@ -440,11 +440,11 @@ span.mainfunction {color: #993300; font-weight: bolder}
<p>The I2S signals are used in "master" mode, where Teensy creates
all 3 clock signals and controls all data timing.</p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td>BCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>11</td><td>MCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>13</td><td>RX</td><td>Input</td></tr>
<tr class=odd><td align=center>23</td><td>LRCLK</td><td>Output</td></tr>
<tr class=top><th>T3.x<br>Pin</th><th>T4.0<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td align=center>21</td><td>BCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>11</td><td align=center>23</td><td>MCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>13</td><td align=center>8</td><td>RX</td><td>Input</td></tr>
<tr class=odd><td align=center>23</td><td align=center>20</td><td>LRCLK</td><td>Output</td></tr>
</table>
<p>Audio from
master mode I2S may be used in the same project as ADC, DAC and
@@ -755,11 +755,11 @@ span.mainfunction {color: #993300; font-weight: bolder}
<a href="https://forum.pjrc.com/threads/42894">Invensense ICS-52000 microphones</a>.
</p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td>BCLK</td><td>Output, 11.3 MHz</td></tr>
<tr class=odd><td align=center>11</td><td>MCLK</td><td>Output, 22.6 MHz</td></tr>
<tr class=odd><td align=center>13</td><td>RX</td><td>Input, 11.3 Mbit/sec</td></tr>
<tr class=odd><td align=center>23</td><td>FS</td><td>Output</td></tr>
<tr class=top><th>T3.x<br>Pin</th><th>T4.0<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td align=center>21</td><td>BCLK</td><td>Output, 11.3 MHz</td></tr>
<tr class=odd><td align=center>11</td><td align=center>23</td><td>MCLK</td><td>Output, 22.6 MHz</td></tr>
<tr class=odd><td align=center>13</td><td align=center>8</td><td>RX</td><td>Input, 11.3 Mbit/sec</td></tr>
<tr class=odd><td align=center>23</td><td align=center>21</td><td>FS</td><td>Output</td></tr>
</table>
<p>Audio from
master mode TDM may be used in the same project as ADC, DAC and
@@ -896,11 +896,11 @@ span.mainfunction {color: #993300; font-weight: bolder}
<p>The I2S signals are used in "master" mode, where Teensy creates
all 3 clock signals and controls all data timing.</p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td>BCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>11</td><td>MCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>22</td><td>TX</td><td>Output</td></tr>
<tr class=odd><td align=center>23</td><td>LRCLK</td><td>Output</td></tr>
<tr class=top><th>T3.x<br>Pin</th><th>T4.0<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td align=center>21</td><td>BCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>11</td><td align=center>23</td><td>MCLK</td><td>Output</td></tr>
<tr class=odd><td align=center>22</td><td align=center>7</td><td>TX</td><td>Output</td></tr>
<tr class=odd><td align=center>23</td><td align=center>20</td><td>LRCLK</td><td>Output</td></tr>
</table>
<p>Audio from
master mode I2S may be used in the same project as ADC, DAC and
@@ -1325,11 +1325,11 @@ span.mainfunction {color: #993300; font-weight: bolder}
CS42448 Circuit Board</a>.
</p>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td>BCLK</td><td>Output, 11.3 MHz</td></tr>
<tr class=odd><td align=center>11</td><td>MCLK</td><td>Output, 22.6 MHz</td></tr>
<tr class=odd><td align=center>22</td><td>TX</td><td>Output, 11.3 Mbit/sec</td></tr>
<tr class=odd><td align=center>23</td><td>WS</td><td>Output</td></tr>
<tr class=top><th>T3.x<br>Pin</th><th>T4.0<br>Pin</th><th>Signal</th><th>Direction</th></tr>
<tr class=odd><td align=center>9</td><td align=center>21</td><td>BCLK</td><td>Output, 11.3 MHz</td></tr>
<tr class=odd><td align=center>11</td><td align=center>23</td><td>MCLK</td><td>Output, 22.6 MHz</td></tr>
<tr class=odd><td align=center>22</td><td align=center>7</td><td>TX</td><td>Output, 11.3 Mbit/sec</td></tr>
<tr class=odd><td align=center>23</td><td align=center>20</td><td>WS</td><td>Output</td></tr>
</table>
<p>Audio from
master mode TDM may be used in the same project as ADC, DAC and

+ 29
- 16
input_i2s.cpp Ver arquivo

@@ -65,16 +65,12 @@ void AudioInputI2S::begin(void)

I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

#if defined(__IMXRT1062__)
#elif defined(__IMXRT1062__)
CORE_PIN8_CONFIG = 3; //1:RX_DATA0
#elif defined(__IMXRT1052__)
CORE_PIN7_CONFIG = 3; //1:RX_DATA0
#endif
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2;
dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0+2);

dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 2);
dma.TCD->SOFF = 0;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLNO = 2;
@@ -87,15 +83,11 @@ void AudioInputI2S::begin(void)
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);

I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE;
I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE;

I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
#endif

update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
//pinMode(13, OUTPUT);
}

void AudioInputI2S::isr(void)
@@ -105,11 +97,11 @@ void AudioInputI2S::isr(void)
int16_t *dest_left, *dest_right;
audio_block_t *left, *right;

//digitalWriteFast(13, HIGH);
#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(KINETISK) || defined(__IMXRT1062__)
daddr = (uint32_t)(dma.TCD->DADDR);
#endif
dma.clearInterrupt();
//Serial.println("isr");

if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) {
// DMA is receiving to the first half of the buffer
@@ -142,7 +134,6 @@ void AudioInputI2S::isr(void)
} while (src < end);
}
}
//digitalWriteFast(13, LOW);
}


@@ -233,7 +224,29 @@ void AudioInputI2Sslave::begin(void)
I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX
dma.attachInterrupt(isr);
#endif

#elif defined(__IMXRT1062__)
CORE_PIN8_CONFIG = 3; //1:RX_DATA0
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2;

dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 2);
dma.TCD->SOFF = 0;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLNO = 2;
dma.TCD->SLAST = 0;
dma.TCD->DADDR = i2s_rx_buffer;
dma.TCD->DOFF = 2;
dma.TCD->CITER_ELINKNO = sizeof(i2s_rx_buffer) / 2;
dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer);
dma.TCD->BITER_ELINKNO = sizeof(i2s_rx_buffer) / 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);
dma.enable();

I2S1_RCSR = 0;
I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
update_responsibility = update_setup();
dma.attachInterrupt(isr);
#endif
}


+ 6
- 9
input_i2s2.cpp Ver arquivo

@@ -25,7 +25,7 @@
*/


#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)
#include <Arduino.h>
#include "input_i2s2.h"
#include "output_i2s2.h"
@@ -48,8 +48,8 @@ void AudioInputI2S2::begin(void)
// TODO: should we set & clear the I2S_RCSR_SR bit here?
AudioOutputI2S2::config_i2s();

CORE_PIN33_CONFIG = 2; //2:RX_DATA0
IOMUXC_SAI2_RX_DATA0_SELECT_INPUT = 0;
CORE_PIN5_CONFIG = 2; //EMC_08, 2=SAI2_RX_DATA, page 434
IOMUXC_SAI2_RX_DATA0_SELECT_INPUT = 0; // 0=GPIO_EMC_08_ALT2, page 876

dma.TCD->SADDR = (void *)((uint32_t)&I2S2_RDR0+2);
dma.TCD->SOFF = 0;
@@ -63,14 +63,13 @@ void AudioInputI2S2::begin(void)
dma.TCD->BITER_ELINKNO = sizeof(i2s2_rx_buffer) / 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI2_RX);
dma.enable();

I2S2_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE;
I2S2_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE;
I2S2_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR; // page 2099
I2S2_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // page 2087

update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
//pinMode(13, OUTPUT);
}

void AudioInputI2S2::isr(void)
@@ -80,7 +79,6 @@ void AudioInputI2S2::isr(void)
int16_t *dest_left, *dest_right;
audio_block_t *left, *right;

//digitalWriteFast(13, HIGH);
daddr = (uint32_t)(dma.TCD->DADDR);
dma.clearInterrupt();

@@ -115,7 +113,6 @@ void AudioInputI2S2::isr(void)
} while (src < end);
}
}
//digitalWriteFast(13, LOW);
}



+ 247
- 0
input_i2s_hex.cpp Ver arquivo

@@ -0,0 +1,247 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <Arduino.h>
#include "input_i2s_hex.h"
#include "output_i2s.h"

DMAMEM __attribute__((aligned(32))) static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES*3];
audio_block_t * AudioInputI2SHex::block_ch1 = NULL;
audio_block_t * AudioInputI2SHex::block_ch2 = NULL;
audio_block_t * AudioInputI2SHex::block_ch3 = NULL;
audio_block_t * AudioInputI2SHex::block_ch4 = NULL;
audio_block_t * AudioInputI2SHex::block_ch5 = NULL;
audio_block_t * AudioInputI2SHex::block_ch6 = NULL;
uint16_t AudioInputI2SHex::block_offset = 0;
bool AudioInputI2SHex::update_responsibility = false;
DMAChannel AudioInputI2SHex::dma(false);

#if defined(__IMXRT1062__)

void AudioInputI2SHex::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

const int pinoffset = 0; // TODO: make this configurable...
AudioOutputI2S::config_i2s();
I2S1_RCR3 = I2S_RCR3_RCE_3CH << pinoffset;
switch (pinoffset) {
case 0:
CORE_PIN8_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; // GPIO_B1_00_ALT3, pg 873
IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873
IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1; // GPIO_B0_11_ALT3, pg 874
break;
case 1:
CORE_PIN6_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873
IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1; // GPIO_B0_11_ALT3, pg 874
IOMUXC_SAI1_RX_DATA3_SELECT_INPUT = 1; // GPIO_B0_12_ALT3, pg 875
break;
}
dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 2 + pinoffset * 4);
dma.TCD->SOFF = 4;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-12) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(6);
dma.TCD->SLAST = -12;
dma.TCD->DADDR = i2s_rx_buffer;
dma.TCD->DOFF = 2;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer);
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);

//I2S1_RCSR = 0;
//I2S1_RCR3 = I2S_RCR3_RCE_2CH << pinoffset;
I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
}

void AudioInputI2SHex::isr(void)
{
uint32_t daddr, offset;
const int16_t *src;
int16_t *dest1, *dest2, *dest3, *dest4, *dest5, *dest6;

//digitalWriteFast(3, HIGH);
daddr = (uint32_t)(dma.TCD->DADDR);
dma.clearInterrupt();

if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) {
// DMA is receiving to the first half of the buffer
// need to remove data from the second half
src = (int16_t *)((uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2);
if (update_responsibility) update_all();
} else {
// DMA is receiving to the second half of the buffer
// need to remove data from the first half
src = (int16_t *)&i2s_rx_buffer[0];
}
if (block_ch1) {
offset = block_offset;
if (offset <= AUDIO_BLOCK_SAMPLES/2) {
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2);
block_offset = offset + AUDIO_BLOCK_SAMPLES/2;
dest1 = &(block_ch1->data[offset]);
dest2 = &(block_ch2->data[offset]);
dest3 = &(block_ch3->data[offset]);
dest4 = &(block_ch4->data[offset]);
dest5 = &(block_ch5->data[offset]);
dest6 = &(block_ch6->data[offset]);
for (int i=0; i < AUDIO_BLOCK_SAMPLES/2; i++) {
*dest1++ = *src++;
*dest3++ = *src++;
*dest5++ = *src++;
*dest2++ = *src++;
*dest4++ = *src++;
*dest6++ = *src++;
}
}
}
//digitalWriteFast(3, LOW);
}


void AudioInputI2SHex::update(void)
{
audio_block_t *new1, *new2, *new3, *new4, *new5, *new6;
audio_block_t *out1, *out2, *out3, *out4, *out5, *out6;

// allocate 6 new blocks
new1 = allocate();
new2 = allocate();
new3 = allocate();
new4 = allocate();
new5 = allocate();
new6 = allocate();
// but if any fails, allocate none
if (!new1 || !new2 || !new3 || !new4 || !new5 || !new6) {
if (new1) {
release(new1);
new1 = NULL;
}
if (new2) {
release(new2);
new2 = NULL;
}
if (new3) {
release(new3);
new3 = NULL;
}
if (new4) {
release(new4);
new4 = NULL;
}
if (new5) {
release(new5);
new5 = NULL;
}
if (new6) {
release(new6);
new6 = NULL;
}
}
__disable_irq();
if (block_offset >= AUDIO_BLOCK_SAMPLES) {
// the DMA filled 4 blocks, so grab them and get the
// 4 new blocks to the DMA, as quickly as possible
out1 = block_ch1;
block_ch1 = new1;
out2 = block_ch2;
block_ch2 = new2;
out3 = block_ch3;
block_ch3 = new3;
out4 = block_ch4;
block_ch4 = new4;
out5 = block_ch5;
block_ch5 = new5;
out6 = block_ch6;
block_ch6 = new6;
block_offset = 0;
__enable_irq();
// then transmit the DMA's former blocks
transmit(out1, 0);
release(out1);
transmit(out2, 1);
release(out2);
transmit(out3, 2);
release(out3);
transmit(out4, 3);
release(out4);
transmit(out5, 4);
release(out5);
transmit(out6, 5);
release(out6);
} else if (new1 != NULL) {
// the DMA didn't fill blocks, but we allocated blocks
if (block_ch1 == NULL) {
// the DMA doesn't have any blocks to fill, so
// give it the ones we just allocated
block_ch1 = new1;
block_ch2 = new2;
block_ch3 = new3;
block_ch4 = new4;
block_ch5 = new5;
block_ch6 = new6;
block_offset = 0;
__enable_irq();
} else {
// the DMA already has blocks, doesn't need these
__enable_irq();
release(new1);
release(new2);
release(new3);
release(new4);
release(new5);
release(new6);
}
} else {
// The DMA didn't fill blocks, and we could not allocate
// memory... the system is likely starving for memory!
// Sadly, there's nothing we can do.
__enable_irq();
}
}

#else // not supported

void AudioInputI2SHex::begin(void)
{
}



#endif


+ 54
- 0
input_i2s_hex.h Ver arquivo

@@ -0,0 +1,54 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef _input_i2s_hex_h_
#define _input_i2s_hex_h_

#include "Arduino.h"
#include "AudioStream.h"
#include "DMAChannel.h"

class AudioInputI2SHex : public AudioStream
{
public:
AudioInputI2SHex(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
private:
static bool update_responsibility;
static DMAChannel dma;
static void isr(void);
static audio_block_t *block_ch1;
static audio_block_t *block_ch2;
static audio_block_t *block_ch3;
static audio_block_t *block_ch4;
static audio_block_t *block_ch5;
static audio_block_t *block_ch6;
static uint16_t block_offset;
};


#endif

+ 263
- 0
input_i2s_oct.cpp Ver arquivo

@@ -0,0 +1,263 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <Arduino.h>
#include "input_i2s_oct.h"
#include "output_i2s.h"

DMAMEM __attribute__((aligned(32))) static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES*4];
audio_block_t * AudioInputI2SOct::block_ch1 = NULL;
audio_block_t * AudioInputI2SOct::block_ch2 = NULL;
audio_block_t * AudioInputI2SOct::block_ch3 = NULL;
audio_block_t * AudioInputI2SOct::block_ch4 = NULL;
audio_block_t * AudioInputI2SOct::block_ch5 = NULL;
audio_block_t * AudioInputI2SOct::block_ch6 = NULL;
audio_block_t * AudioInputI2SOct::block_ch7 = NULL;
audio_block_t * AudioInputI2SOct::block_ch8 = NULL;
uint16_t AudioInputI2SOct::block_offset = 0;
bool AudioInputI2SOct::update_responsibility = false;
DMAChannel AudioInputI2SOct::dma(false);

#if defined(__IMXRT1062__)

void AudioInputI2SOct::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

AudioOutputI2S::config_i2s();
I2S1_RCR3 = I2S_RCR3_RCE_4CH;
CORE_PIN8_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; // GPIO_B1_00_ALT3, pg 873
IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873
IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1; // GPIO_B0_11_ALT3, pg 874
IOMUXC_SAI1_RX_DATA3_SELECT_INPUT = 1; // GPIO_B0_12_ALT3, pg 875

dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 2);
dma.TCD->SOFF = 4;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-16) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
dma.TCD->SLAST = -16;
dma.TCD->DADDR = i2s_rx_buffer;
dma.TCD->DOFF = 2;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer);
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);

I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
}

void AudioInputI2SOct::isr(void)
{
uint32_t daddr, offset;
const int16_t *src;
int16_t *dest1, *dest2, *dest3, *dest4, *dest5, *dest6, *dest7, *dest8;

//digitalWriteFast(3, HIGH);
daddr = (uint32_t)(dma.TCD->DADDR);
dma.clearInterrupt();

if (daddr < (uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2) {
// DMA is receiving to the first half of the buffer
// need to remove data from the second half
src = (int16_t *)((uint32_t)i2s_rx_buffer + sizeof(i2s_rx_buffer) / 2);
if (update_responsibility) update_all();
} else {
// DMA is receiving to the second half of the buffer
// need to remove data from the first half
src = (int16_t *)&i2s_rx_buffer[0];
}
if (block_ch1) {
offset = block_offset;
if (offset <= AUDIO_BLOCK_SAMPLES/2) {
arm_dcache_delete((void *)src, sizeof(i2s_rx_buffer) / 2);
block_offset = offset + AUDIO_BLOCK_SAMPLES/2;
dest1 = &(block_ch1->data[offset]);
dest2 = &(block_ch2->data[offset]);
dest3 = &(block_ch3->data[offset]);
dest4 = &(block_ch4->data[offset]);
dest5 = &(block_ch5->data[offset]);
dest6 = &(block_ch6->data[offset]);
dest7 = &(block_ch7->data[offset]);
dest8 = &(block_ch8->data[offset]);
for (int i=0; i < AUDIO_BLOCK_SAMPLES/2; i++) {
*dest1++ = *src++;
*dest3++ = *src++;
*dest5++ = *src++;
*dest7++ = *src++;
*dest2++ = *src++;
*dest4++ = *src++;
*dest6++ = *src++;
*dest8++ = *src++;
}
}
}
//digitalWriteFast(3, LOW);
}


void AudioInputI2SOct::update(void)
{
audio_block_t *new1, *new2, *new3, *new4, *new5, *new6, *new7, *new8;
audio_block_t *out1, *out2, *out3, *out4, *out5, *out6, *out7, *out8;

// allocate 8 new blocks
new1 = allocate();
new2 = allocate();
new3 = allocate();
new4 = allocate();
new5 = allocate();
new6 = allocate();
new7 = allocate();
new8 = allocate();
// but if any fails, allocate none
if (!new1 || !new2 || !new3 || !new4 || !new5 || !new6 || !new7 || !new8) {
if (new1) {
release(new1);
new1 = NULL;
}
if (new2) {
release(new2);
new2 = NULL;
}
if (new3) {
release(new3);
new3 = NULL;
}
if (new4) {
release(new4);
new4 = NULL;
}
if (new5) {
release(new5);
new5 = NULL;
}
if (new6) {
release(new6);
new6 = NULL;
}
if (new7) {
release(new7);
new7 = NULL;
}
if (new8) {
release(new8);
new8 = NULL;
}
}
__disable_irq();
if (block_offset >= AUDIO_BLOCK_SAMPLES) {
// the DMA filled 4 blocks, so grab them and get the
// 8 new blocks to the DMA, as quickly as possible
out1 = block_ch1;
block_ch1 = new1;
out2 = block_ch2;
block_ch2 = new2;
out3 = block_ch3;
block_ch3 = new3;
out4 = block_ch4;
block_ch4 = new4;
out5 = block_ch5;
block_ch5 = new5;
out6 = block_ch6;
block_ch6 = new6;
out7 = block_ch7;
block_ch7 = new7;
out8 = block_ch8;
block_ch8 = new8;
block_offset = 0;
__enable_irq();
// then transmit the DMA's former blocks
transmit(out1, 0);
release(out1);
transmit(out2, 1);
release(out2);
transmit(out3, 2);
release(out3);
transmit(out4, 3);
release(out4);
transmit(out5, 4);
release(out5);
transmit(out6, 5);
release(out6);
transmit(out7, 6);
release(out7);
transmit(out8, 7);
release(out8);
} else if (new1 != NULL) {
// the DMA didn't fill blocks, but we allocated blocks
if (block_ch1 == NULL) {
// the DMA doesn't have any blocks to fill, so
// give it the ones we just allocated
block_ch1 = new1;
block_ch2 = new2;
block_ch3 = new3;
block_ch4 = new4;
block_ch5 = new5;
block_ch6 = new6;
block_ch7 = new7;
block_ch8 = new8;
block_offset = 0;
__enable_irq();
} else {
// the DMA already has blocks, doesn't need these
__enable_irq();
release(new1);
release(new2);
release(new3);
release(new4);
release(new5);
release(new6);
release(new7);
release(new8);
}
} else {
// The DMA didn't fill blocks, and we could not allocate
// memory... the system is likely starving for memory!
// Sadly, there's nothing we can do.
__enable_irq();
}
}

#else // not supported

void AudioInputI2SOct::begin(void)
{
}



#endif


+ 56
- 0
input_i2s_oct.h Ver arquivo

@@ -0,0 +1,56 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef _input_i2s_oct_h_
#define _input_i2s_oct_h_

#include "Arduino.h"
#include "AudioStream.h"
#include "DMAChannel.h"

class AudioInputI2SOct : public AudioStream
{
public:
AudioInputI2SOct(void) : AudioStream(0, NULL) { begin(); }
virtual void update(void);
void begin(void);
private:
static bool update_responsibility;
static DMAChannel dma;
static void isr(void);
static audio_block_t *block_ch1;
static audio_block_t *block_ch2;
static audio_block_t *block_ch3;
static audio_block_t *block_ch4;
static audio_block_t *block_ch5;
static audio_block_t *block_ch6;
static audio_block_t *block_ch7;
static audio_block_t *block_ch8;
static uint16_t block_offset;
};


#endif

+ 53
- 2
input_i2s_quad.cpp Ver arquivo

@@ -27,8 +27,9 @@
#include <Arduino.h>
#include "input_i2s_quad.h"
#include "output_i2s_quad.h"
#include "output_i2s.h"

DMAMEM static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES*2];
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_rx_buffer[AUDIO_BLOCK_SAMPLES*2];
audio_block_t * AudioInputI2SQuad::block_ch1 = NULL;
audio_block_t * AudioInputI2SQuad::block_ch2 = NULL;
audio_block_t * AudioInputI2SQuad::block_ch3 = NULL;
@@ -37,12 +38,13 @@ uint16_t AudioInputI2SQuad::block_offset = 0;
bool AudioInputI2SQuad::update_responsibility = false;
DMAChannel AudioInputI2SQuad::dma(false);

#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)

void AudioInputI2SQuad::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

#if defined(KINETISK)
// TODO: should we set & clear the I2S_RCSR_SR bit here?
AudioOutputI2SQuad::config_i2s();

@@ -73,6 +75,54 @@ void AudioInputI2SQuad::begin(void)
I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX
dma.attachInterrupt(isr);

#elif defined(__IMXRT1062__)
const int pinoffset = 0; // TODO: make this configurable...
AudioOutputI2S::config_i2s();
I2S1_RCR3 = I2S_RCR3_RCE_2CH << pinoffset;
switch (pinoffset) {
case 0:
CORE_PIN8_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2; // GPIO_B1_00_ALT3, pg 873
IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873
break;
case 1:
CORE_PIN6_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
IOMUXC_SAI1_RX_DATA1_SELECT_INPUT = 1; // GPIO_B0_10_ALT3, pg 873
IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1; // GPIO_B0_11_ALT3, pg 874
break;
case 2:
CORE_PIN9_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
IOMUXC_SAI1_RX_DATA2_SELECT_INPUT = 1; // GPIO_B0_11_ALT3, pg 874
IOMUXC_SAI1_RX_DATA3_SELECT_INPUT = 1; // GPIO_B0_12_ALT3, pg 875
break;
}
dma.TCD->SADDR = (void *)((uint32_t)&I2S1_RDR0 + 2 + pinoffset * 4);
dma.TCD->SOFF = 4;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_SMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(4);
dma.TCD->SLAST = -8;
dma.TCD->DADDR = i2s_rx_buffer;
dma.TCD->DOFF = 2;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -sizeof(i2s_rx_buffer);
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_RX);

I2S1_RCSR = 0;
I2S1_RCR3 = I2S_RCR3_RCE_2CH << pinoffset;

I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
#endif
}

void AudioInputI2SQuad::isr(void)
@@ -98,6 +148,7 @@ void AudioInputI2SQuad::isr(void)
if (block_ch1) {
offset = block_offset;
if (offset <= AUDIO_BLOCK_SAMPLES/2) {
arm_dcache_delete(src, sizeof(i2s_rx_buffer) / 2);
block_offset = offset + AUDIO_BLOCK_SAMPLES/2;
dest1 = &(block_ch1->data[offset]);
dest2 = &(block_ch2->data[offset]);

+ 10
- 5
input_pdm.cpp Ver arquivo

@@ -84,12 +84,17 @@ DMAChannel AudioInputPDM::dma(false);
#define MCLK_MULT 1
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 8
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 4
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV 17
@@ -1714,4 +1719,4 @@ for ($n=0; $n < 512; $n += 8) {
print "\n};\n";
print "// max=$max, min=$min\n";
*/
#endif
#endif

+ 4
- 5
input_tdm.cpp Ver arquivo

@@ -27,7 +27,7 @@
#include <Arduino.h>
#include "input_tdm.h"
#include "output_tdm.h"
#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(KINETISK) || defined(__IMXRT1062__)
#include "utility/imxrt_hw.h"

DMAMEM __attribute__((aligned(32)))
@@ -66,8 +66,8 @@ void AudioInputTDM::begin(void)
I2S0_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE; // TX clock enable, because sync'd to TX
dma.attachInterrupt(isr);
#else
CORE_PIN7_CONFIG = 3; //RX_DATA0
#elif defined(__IMXRT1062__)
CORE_PIN8_CONFIG = 3; //RX_DATA0
IOMUXC_SAI1_RX_DATA0_SELECT_INPUT = 2;
dma.TCD->SADDR = &I2S1_RDR0;
dma.TCD->SOFF = 0;
@@ -84,8 +84,7 @@ void AudioInputTDM::begin(void)
update_responsibility = update_setup();
dma.enable();

I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE;
I2S1_RCSR = I2S_RCSR_RE | I2S_RCSR_BCE | I2S_RCSR_FRDE | I2S_RCSR_FR;
dma.attachInterrupt(isr);
#endif
}

+ 2
- 2
input_tdm2.cpp Ver arquivo

@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/

#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)
#include <Arduino.h>
#include "input_tdm2.h"
#include "output_tdm2.h"
@@ -47,7 +47,7 @@ void AudioInputTDM2::begin(void)
// TODO: should we set & clear the I2S_RCSR_SR bit here?
AudioOutputTDM2::config_tdm();

CORE_PIN33_CONFIG = 2; //2:RX_DATA0
CORE_PIN5_CONFIG = 2; //2:RX_DATA0
IOMUXC_SAI2_RX_DATA0_SELECT_INPUT = 0;
dma.TCD->SADDR = &I2S2_RDR0;
dma.TCD->SOFF = 0;

+ 4
- 0
keywords.txt Ver arquivo

@@ -3,6 +3,8 @@ AudioConnection KEYWORD2
AudioInputI2S KEYWORD2
AudioInputI2S2 KEYWORD2
AudioInputI2SQuad KEYWORD2
AudioInputI2SHex KEYWORD2
AudioInputI2SOct KEYWORD2
AudioInputI2Sslave KEYWORD2
AudioInputTDM KEYWORD2
AudioInputTDM2 KEYWORD2
@@ -11,6 +13,8 @@ AudioInputUSB KEYWORD2
AudioOutputI2S KEYWORD2
AudioOutputI2S2 KEYWORD2
AudioOutputI2SQuad KEYWORD2
AudioOutputI2SHex KEYWORD2
AudioOutputI2SOct KEYWORD2
AudioOutputI2Sslave KEYWORD2
AudioOutputSPDIF KEYWORD2
AudioOutputSPDIF2 KEYWORD2

+ 3
- 0
output_adat.cpp Ver arquivo

@@ -700,6 +700,9 @@ void AudioOutputADAT::setI2SFreq(int freq) {
const tmclk clkArr[numfreqs] = {{32, 3375}, {49, 3750}, {64, 3375}, {49, 1875}, {128, 3375}, {98, 1875}, {8, 153}, {64, 1125}, {196, 1875}, {16, 153}, {128, 1125}, {226, 1081}, {32, 153}, {147, 646} };
#elif (F_PLL==240000000)
const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#elif (F_PLL==256000000)
// TODO: fix these...
const tmclk clkArr[numfreqs] = {{16, 1875}, {29, 2466}, {32, 1875}, {89, 3784}, {64, 1875}, {147, 3125}, {4, 85}, {32, 625}, {205, 2179}, {8, 85}, {64, 625}, {89, 473}, {16, 85}, {128, 625} };
#endif

for (int f = 0; f < numfreqs; f++) {

+ 86
- 136
output_i2s.cpp Ver arquivo

@@ -38,9 +38,9 @@ bool AudioOutputI2S::update_responsibility = false;
DMAChannel AudioOutputI2S::dma(false);
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES];

#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)
#include "utility/imxrt_hw.h"
#endif

void AudioOutputI2S::begin(void)
{
@@ -50,74 +50,54 @@ void AudioOutputI2S::begin(void)
block_right_1st = NULL;

config_i2s();
#if defined(__IMXRT1052__)
CORE_PIN6_CONFIG = 3; //1:TX_DATA0
#elif defined(__IMXRT1062__)
CORE_PIN7_CONFIG = 3; //1:TX_DATA0
#endif

#if defined(KINETISK)
CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0

dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLNO = 2;
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)((uint32_t)&I2S0_TDR0 + 2);
dma.TCD->DOFF = 0;
dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->DLASTSGA = 0;
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2);
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);

I2S1_RCSR |= I2S_RCSR_RE;
I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;

update_responsibility = update_setup();
dma.attachInterrupt(isr);
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
dma.enable();
}

#endif

#if defined(KINETISK)
void AudioOutputI2S::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

block_left_1st = NULL;
block_right_1st = NULL;

// TODO: should we set & clear the I2S_TCSR_SR bit here?
config_i2s();
CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0
I2S0_TCSR = I2S_TCSR_SR;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;

#elif defined(__IMXRT1062__)
CORE_PIN7_CONFIG = 3; //1:TX_DATA0
dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLNO = 2;
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)((uint32_t)&I2S0_TDR0 + 2);
dma.TCD->DOFF = 0;
dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->DLASTSGA = 0;
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;

dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
update_responsibility = update_setup();
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2);
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
dma.enable();


I2S0_TCSR = I2S_TCSR_SR;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
#endif
update_responsibility = update_setup();
dma.attachInterrupt(isr);
}
#endif

void AudioOutputI2S::isr(void)
{
#if defined(KINETISK) || defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(KINETISK) || defined(__IMXRT1062__)
int16_t *dest;
audio_block_t *blockL, *blockR;
uint32_t saddr, offsetL, offsetR;
@@ -154,10 +134,8 @@ void AudioOutputI2S::isr(void)
memset(dest,0,AUDIO_BLOCK_SAMPLES * 2);
}

#if IMXRT_CACHE_ENABLED >= 2
arm_dcache_flush_delete(dest, sizeof(i2s_tx_buffer) / 2 );
#endif

if (offsetL < AUDIO_BLOCK_SAMPLES) {
AudioOutputI2S::block_left_offset = offsetL;
} else {
@@ -323,12 +301,17 @@ void AudioOutputI2S::update(void)
#define MCLK_MULT 1
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 8
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 4
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV 17
@@ -386,9 +369,14 @@ void AudioOutputI2S::config_i2s(void)
CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)
CORE_PIN9_CONFIG = PORT_PCR_MUX(6); // pin 9, PTC3, I2S0_TX_BCLK
CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK
#elif ( defined(__IMXRT1052__) || defined(__IMXRT1062__) )

#elif defined(__IMXRT1062__)

CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);

// if either transmitter or receiver is enabled, do nothing
if (I2S1_TCSR & I2S_TCSR_TE) return;
if (I2S1_RCSR & I2S_RCSR_RE) return;
//PLL:
int fs = AUDIO_SAMPLE_RATE_EXACT;
// PLL between 27*24 = 648MHz und 54*24=1296MHz
@@ -408,18 +396,14 @@ void AudioOutputI2S::config_i2s(void)
| CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
| CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f

IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK

// if either transmitter or receiver is enabled, do nothing
if (I2S1_TCSR & I2S_TCSR_TE) return;
if (I2S1_RCSR & I2S_RCSR_RE) return;
// Select MCLK
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1
& ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0));

CORE_PIN23_CONFIG = 3; //1:MCLK
CORE_PIN21_CONFIG = 3; //1:RX_BCLK
CORE_PIN20_CONFIG = 3; //1:RX_SYNC
// CORE_PIN6_CONFIG = 3; //1:TX_DATA0
// CORE_PIN7_CONFIG = 3; //1:RX_DATA0

int rsync = 0;
int tsync = 1;
@@ -430,7 +414,8 @@ void AudioOutputI2S::config_i2s(void)
I2S1_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async;
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1));
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF | I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
I2S1_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF
| I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
I2S1_TCR5 = I2S_TCR5_WNW((32-1)) | I2S_TCR5_W0W((32-1)) | I2S_TCR5_FBT((32-1));

I2S1_RMR = 0;
@@ -439,7 +424,8 @@ void AudioOutputI2S::config_i2s(void)
I2S1_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async;
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1));
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF | I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S1_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S1_RCR5 = I2S_RCR5_WNW((32-1)) | I2S_RCR5_W0W((32-1)) | I2S_RCR5_FBT((32-1));

#endif
@@ -453,7 +439,6 @@ void AudioOutputI2Sslave::begin(void)

dma.begin(true); // Allocate the DMA channel first

//pinMode(2, OUTPUT);
block_left_1st = NULL;
block_right_1st = NULL;

@@ -473,50 +458,45 @@ void AudioOutputI2Sslave::begin(void)
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
dma.enable();

I2S0_TCSR = I2S_TCSR_SR;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;

#elif 0 && ( defined(__IMXRT1052__) || defined(__IMXRT1062__) )
#if defined(SAI1)
CORE_PIN6_CONFIG = 3; //1:TX_DATA0
//CORE_PIN7_CONFIG = 3; //1:RX_DATA0
#elif defined(SAI2)
CORE_PIN2_CONFIG = 2; //2:TX_DATA0
//CORE_PIN33_CONFIG = 2; //2:RX_DATA0
#endif
#elif defined(__IMXRT1062__)
CORE_PIN7_CONFIG = 3; //1:TX_DATA0
dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLNO = 2;
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)&i2s->TX.DR16[1];
dma.TCD->DOFF = 0;
dma.TCD->CITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.TCD->DLASTSGA = 0;
dma.TCD->BITER_ELINKNO = sizeof(i2s_tx_buffer) / 2;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI2_TX);
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2);
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
dma.enable();

I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
#endif

update_responsibility = update_setup();
dma.enable();
dma.attachInterrupt(isr);
}

void AudioOutputI2Sslave::config_i2s(void)
{
#if defined(KINETISK)
// if either transmitter or receiver is enabled, do nothing
if (I2S0_TCSR & I2S_TCSR_TE) return;
if (I2S0_RCSR & I2S_RCSR_RE) return;

SIM_SCGC6 |= SIM_SCGC6_I2S;
SIM_SCGC7 |= SIM_SCGC7_DMA;
SIM_SCGC6 |= SIM_SCGC6_DMAMUX;
// configure pin mux for 3 clock signals

CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)
CORE_PIN9_CONFIG = PORT_PCR_MUX(6); // pin 9, PTC3, I2S0_TX_BCLK
CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK
// if either transmitter or receiver is enabled, do nothing
if (I2S0_TCSR & I2S_TCSR_TE) return;
if (I2S0_RCSR & I2S_RCSR_RE) return;

// Select input clock 0
// Configure to input the bit-clock from pin, bypasses the MCLK divider
I2S0_MCR = I2S_MCR_MICS(0);
@@ -544,73 +524,43 @@ void AudioOutputI2Sslave::config_i2s(void)

I2S0_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

#elif 0 && (defined(__IMXRT1052__) || defined(__IMXRT1062__) )
// configure pin mux for 3 clock signals
CORE_PIN23_CONFIG = PORT_PCR_MUX(6); // pin 23, PTC2, I2S0_TX_FS (LRCLK)
CORE_PIN9_CONFIG = PORT_PCR_MUX(6); // pin 9, PTC3, I2S0_TX_BCLK
CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK

#if defined(SAI1)
i2s = ((I2S_STRUCT *)0x40384000);
// if either transmitter or receiver is enabled, do nothing
if (i2s->TX.CSR & I2S_TCSR_TE) return;
if (i2s->RX.CSR & I2S_RCSR_RE) return;
#elif defined(__IMXRT1062__)

CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);
/*
CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI1_CLK_SEL_MASK))
| CCM_CSCMR1_SAI1_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4
CCM_CS1CDR = (CCM_CS1CDR & ~(CCM_CS1CDR_SAI1_CLK_PRED_MASK | CCM_CS1CDR_SAI1_CLK_PODF_MASK))
| CCM_CS1CDR_SAI1_CLK_PRED(n1-1) // &0x07
| CCM_CS1CDR_SAI1_CLK_PODF(n2-1); // &0x3f
*/
//TODO:
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK | ((uint32_t)(1<<20)) ))
| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK

CORE_PIN23_CONFIG = 3; //1:MCLK
CORE_PIN21_CONFIG = 3; //1:RX_BCLK
CORE_PIN20_CONFIG = 3; //1:RX_SYNC
int rsync = 0;
int tsync = 1;
#elif defined(SAI2)
i2s = ((I2S_STRUCT *)0x40388000);
if (i2s->TX.CSR & I2S_TCSR_TE) return;
if (i2s->RX.CSR & I2S_RCSR_RE) return;

CCM_CCGR5 |= CCM_CCGR5_SAI2(CCM_CCGR_ON);
/*
CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI2_CLK_SEL_MASK))
| CCM_CSCMR1_SAI2_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4,
CCM_CS2CDR = (CCM_CS2CDR & ~(CCM_CS2CDR_SAI2_CLK_PRED_MASK | CCM_CS2CDR_SAI2_CLK_PODF_MASK))
| CCM_CS2CDR_SAI2_CLK_PRED(n1-1) | CCM_CS2CDR_SAI2_CLK_PODF(n2-1);
*/
//TODO:

IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL_MASK | ((uint32_t)(1<<19)) ))
/*| (IOMUXC_GPR_GPR1_SAI2_MCLK_DIR*/ | IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL(0); //Select MCLK

CORE_PIN5_CONFIG = 2; //2:MCLK
CORE_PIN4_CONFIG = 2; //2:TX_BCLK
CORE_PIN3_CONFIG = 2; //2:TX_SYNC
int rsync = 1;
int tsync = 0;

#endif
// if either transmitter or receiver is enabled, do nothing
if (I2S1_TCSR & I2S_TCSR_TE) return;
if (I2S1_RCSR & I2S_RCSR_RE) return;

// not using MCLK in slave mode - hope that's ok?
//CORE_PIN23_CONFIG = 3; // AD_B1_09 ALT3=SAI1_MCLK
CORE_PIN21_CONFIG = 3; // AD_B1_11 ALT3=SAI1_RX_BCLK
CORE_PIN20_CONFIG = 3; // AD_B1_10 ALT3=SAI1_RX_SYNC
IOMUXC_SAI1_RX_BCLK_SELECT_INPUT = 1; // 1=GPIO_AD_B1_11_ALT3, page 868
IOMUXC_SAI1_RX_SYNC_SELECT_INPUT = 1; // 1=GPIO_AD_B1_10_ALT3, page 872

// configure transmitter
i2s->TX.MR = 0;
i2s->TX.CR1 = I2S_TCR1_RFW(1); // watermark at half fifo size
i2s->TX.CR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP;
i2s->TX.CR3 = I2S_TCR3_TCE;
i2s->TX.CR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(31) | I2S_TCR4_MF
| I2S_TCR4_FSE | I2S_TCR4_FSP;
i2s->TX.CR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);
I2S1_TMR = 0;
I2S1_TCR1 = I2S_TCR1_RFW(1); // watermark at half fifo size
I2S1_TCR2 = I2S_TCR2_SYNC(1) | I2S_TCR2_BCP;
I2S1_TCR3 = I2S_TCR3_TCE;
I2S1_TCR4 = I2S_TCR4_FRSZ(1) | I2S_TCR4_SYWD(31) | I2S_TCR4_MF
| I2S_TCR4_FSE | I2S_TCR4_FSP | I2S_RCR4_FSD;
I2S1_TCR5 = I2S_TCR5_WNW(31) | I2S_TCR5_W0W(31) | I2S_TCR5_FBT(31);

// configure receiver
i2s->RX.MR = 0;
i2s->RX.CR1 = I2S_RCR1_RFW(1);
i2s->RX.CR2 = I2S_RCR2_SYNC(rsync) | I2S_TCR2_BCP;
i2s->RX.CR3 = I2S_RCR3_RCE;
i2s->RX.CR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(31) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
i2s->RX.CR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);
I2S1_RMR = 0;
I2S1_RCR1 = I2S_RCR1_RFW(1);
I2S1_RCR2 = I2S_RCR2_SYNC(0) | I2S_TCR2_BCP;
I2S1_RCR3 = I2S_RCR3_RCE;
I2S1_RCR4 = I2S_RCR4_FRSZ(1) | I2S_RCR4_SYWD(31) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP;
I2S1_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

#endif
}

+ 8
- 0
output_i2s.h Ver arquivo

@@ -38,6 +38,14 @@ public:
virtual void update(void);
void begin(void);
friend class AudioInputI2S;
#if defined(__IMXRT1062__)
friend class AudioOutputI2SQuad;
friend class AudioInputI2SQuad;
friend class AudioOutputI2SHex;
friend class AudioInputI2SHex;
friend class AudioOutputI2SOct;
friend class AudioInputI2SOct;
#endif
protected:
AudioOutputI2S(int dummy): AudioStream(2, inputQueueArray) {} // to be used only inside AudioOutputI2Sslave !!
static void config_i2s(void);

+ 26
- 20
output_i2s2.cpp Ver arquivo

@@ -23,7 +23,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)
#include <Arduino.h>
#include "output_i2s2.h"
#include "memcpy_audio.h"
@@ -49,7 +49,12 @@ void AudioOutputI2S2::begin(void)
block_right_1st = NULL;

config_i2s();
CORE_PIN2_CONFIG = 2; //2:TX_DATA0

// if AudioInputI2S2 set I2S_TCSR_TE (for clock sync), disable it
I2S2_TCSR = 0;
while (I2S2_TCSR & I2S_TCSR_TE) ; //wait for transmit disabled

CORE_PIN2_CONFIG = 2; //EMC_04, 2=SAI2_TX_DATA, page 428

dma.TCD->SADDR = i2s2_tx_buffer;
dma.TCD->SOFF = 2;
@@ -63,16 +68,17 @@ void AudioOutputI2S2::begin(void)
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.TCD->DADDR = (void *)((uint32_t)&I2S2_TDR0 + 2);
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI2_TX);
// I2S2_RCSR |= I2S_RCSR_RE;
I2S2_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
dma.enable();

I2S2_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;

update_responsibility = update_setup();
dma.attachInterrupt(isr);
dma.enable();
}

void AudioOutputI2S2::isr(void)
{
int16_t *dest, *dc;
int16_t *dest;
audio_block_t *blockL, *blockR;
uint32_t saddr, offsetL, offsetR;

@@ -184,6 +190,10 @@ void AudioOutputI2S2::update(void)
void AudioOutputI2S2::config_i2s(void)
{
CCM_CCGR5 |= CCM_CCGR5_SAI2(CCM_CCGR_ON);

// if either transmitter or receiver is enabled, do nothing
if (I2S2_TCSR & I2S_TCSR_TE) return;
if (I2S2_RCSR & I2S_RCSR_RE) return;
//PLL:
int fs = AUDIO_SAMPLE_RATE_EXACT;
// PLL between 27*24 = 648MHz und 54*24=1296MHz
@@ -200,20 +210,14 @@ void AudioOutputI2S2::config_i2s(void)
CCM_CSCMR1 = (CCM_CSCMR1 & ~(CCM_CSCMR1_SAI2_CLK_SEL_MASK))
| CCM_CSCMR1_SAI2_CLK_SEL(2); // &0x03 // (0,1,2): PLL3PFD0, PLL5, PLL4,
CCM_CS2CDR = (CCM_CS2CDR & ~(CCM_CS2CDR_SAI2_CLK_PRED_MASK | CCM_CS2CDR_SAI2_CLK_PODF_MASK))
| CCM_CS2CDR_SAI2_CLK_PRED(n1-1)
| CCM_CS2CDR_SAI2_CLK_PRED(n1-1)
| CCM_CS2CDR_SAI2_CLK_PODF(n2-1);
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL_MASK))
| (IOMUXC_GPR_GPR1_SAI2_MCLK_DIR | IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL(0)); //Select MCLK

// if either transmitter or receiver is enabled, do nothing
if (I2S2_TCSR & I2S_TCSR_TE) return;
if (I2S2_RCSR & I2S_RCSR_RE) return;

CORE_PIN5_CONFIG = 2; //2:MCLK
CORE_PIN4_CONFIG = 2; //2:TX_BCLK
CORE_PIN3_CONFIG = 2; //2:TX_SYNC
// CORE_PIN2_CONFIG = 2; //2:TX_DATA0
// CORE_PIN33_CONFIG = 2; //2:RX_DATA0
CORE_PIN33_CONFIG = 2; //EMC_07, 2=SAI2_MCLK
CORE_PIN4_CONFIG = 2; //EMC_06, 2=SAI2_TX_BCLK
CORE_PIN3_CONFIG = 2; //EMC_05, 2=SAI2_TX_SYNC, page 429

int rsync = 1;
int tsync = 0;
@@ -222,18 +226,20 @@ void AudioOutputI2S2::config_i2s(void)
//I2S2_TCSR = (1<<25); //Reset
I2S2_TCR1 = I2S_TCR1_RFW(1);
I2S2_TCR2 = I2S_TCR2_SYNC(tsync) | I2S_TCR2_BCP // sync=0; tx is async;
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1));
| (I2S_TCR2_BCD | I2S_TCR2_DIV((1)) | I2S_TCR2_MSEL(1));
I2S2_TCR3 = I2S_TCR3_TCE;
I2S2_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF | I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
I2S2_TCR4 = I2S_TCR4_FRSZ((2-1)) | I2S_TCR4_SYWD((32-1)) | I2S_TCR4_MF
| I2S_TCR4_FSD | I2S_TCR4_FSE | I2S_TCR4_FSP;
I2S2_TCR5 = I2S_TCR5_WNW((32-1)) | I2S_TCR5_W0W((32-1)) | I2S_TCR5_FBT((32-1));

I2S2_RMR = 0;
//I2S2_RCSR = (1<<25); //Reset
I2S2_RCR1 = I2S_RCR1_RFW(1);
I2S2_RCR2 = I2S_RCR2_SYNC(rsync) | I2S_RCR2_BCP // sync=0; rx is async;
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1));
| (I2S_RCR2_BCD | I2S_RCR2_DIV((1)) | I2S_RCR2_MSEL(1));
I2S2_RCR3 = I2S_RCR3_RCE;
I2S2_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF | I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S2_RCR4 = I2S_RCR4_FRSZ((2-1)) | I2S_RCR4_SYWD((32-1)) | I2S_RCR4_MF
| I2S_RCR4_FSE | I2S_RCR4_FSP | I2S_RCR4_FSD;
I2S2_RCR5 = I2S_RCR5_WNW((32-1)) | I2S_RCR5_W0W((32-1)) | I2S_RCR5_FBT((32-1));

}

+ 355
- 0
output_i2s_hex.cpp Ver arquivo

@@ -0,0 +1,355 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <Arduino.h>
#include "output_i2s_hex.h"
#include "output_i2s.h"
#include "memcpy_audio.h"

#if defined(__IMXRT1062__)
#include "utility/imxrt_hw.h"

audio_block_t * AudioOutputI2SHex::block_ch1_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch2_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch3_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch4_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch5_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch6_1st = NULL;
audio_block_t * AudioOutputI2SHex::block_ch1_2nd = NULL;
audio_block_t * AudioOutputI2SHex::block_ch2_2nd = NULL;
audio_block_t * AudioOutputI2SHex::block_ch3_2nd = NULL;
audio_block_t * AudioOutputI2SHex::block_ch4_2nd = NULL;
audio_block_t * AudioOutputI2SHex::block_ch5_2nd = NULL;
audio_block_t * AudioOutputI2SHex::block_ch6_2nd = NULL;
uint16_t AudioOutputI2SHex::ch1_offset = 0;
uint16_t AudioOutputI2SHex::ch2_offset = 0;
uint16_t AudioOutputI2SHex::ch3_offset = 0;
uint16_t AudioOutputI2SHex::ch4_offset = 0;
uint16_t AudioOutputI2SHex::ch5_offset = 0;
uint16_t AudioOutputI2SHex::ch6_offset = 0;
bool AudioOutputI2SHex::update_responsibility = false;
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*3];
DMAChannel AudioOutputI2SHex::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

void AudioOutputI2SHex::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

block_ch1_1st = NULL;
block_ch2_1st = NULL;
block_ch3_1st = NULL;
block_ch4_1st = NULL;
block_ch5_1st = NULL;
block_ch6_1st = NULL;

const int pinoffset = 0; // TODO: make this configurable...
memset(i2s_tx_buffer, 0, sizeof(i2s_tx_buffer));
AudioOutputI2S::config_i2s();
I2S1_TCR3 = I2S_TCR3_TCE_3CH << pinoffset;
switch (pinoffset) {
case 0:
CORE_PIN7_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
break;
case 1:
CORE_PIN32_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
}
dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-12) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(6);
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2 + pinoffset * 4);
dma.TCD->DOFF = 4;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -12;
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
dma.enable();
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
I2S1_TCR3 = I2S_TCR3_TCE_3CH << pinoffset;
update_responsibility = update_setup();
dma.attachInterrupt(isr);
}

void AudioOutputI2SHex::isr(void)
{
uint32_t saddr;
const int16_t *src1, *src2, *src3, *src4, *src5, *src6;
const int16_t *zeros = (const int16_t *)zerodata;
int16_t *dest;

saddr = (uint32_t)(dma.TCD->SADDR);
dma.clearInterrupt();
if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) {
// DMA is transmitting the first half of the buffer
// so we must fill the second half
dest = (int16_t *)((uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2);
if (update_responsibility) update_all();
} else {
dest = (int16_t *)i2s_tx_buffer;
}

src1 = (block_ch1_1st) ? block_ch1_1st->data + ch1_offset : zeros;
src2 = (block_ch2_1st) ? block_ch2_1st->data + ch2_offset : zeros;
src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;
src5 = (block_ch5_1st) ? block_ch5_1st->data + ch5_offset : zeros;
src6 = (block_ch6_1st) ? block_ch6_1st->data + ch6_offset : zeros;
#if 0
// TODO: optimized 6 channel copy...
memcpy_tointerleaveQuad(dest, src1, src2, src3, src4);
#else
int16_t *p=dest;
for (int i=0; i < AUDIO_BLOCK_SAMPLES/2; i++) {
*p++ = *src1++;
*p++ = *src3++;
*p++ = *src5++;
*p++ = *src2++;
*p++ = *src4++;
*p++ = *src6++;
}
#endif
arm_dcache_flush_delete(dest, sizeof(i2s_tx_buffer) / 2);

if (block_ch1_1st) {
if (ch1_offset == 0) {
ch1_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch1_offset = 0;
release(block_ch1_1st);
block_ch1_1st = block_ch1_2nd;
block_ch1_2nd = NULL;
}
}
if (block_ch2_1st) {
if (ch2_offset == 0) {
ch2_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch2_offset = 0;
release(block_ch2_1st);
block_ch2_1st = block_ch2_2nd;
block_ch2_2nd = NULL;
}
}
if (block_ch3_1st) {
if (ch3_offset == 0) {
ch3_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch3_offset = 0;
release(block_ch3_1st);
block_ch3_1st = block_ch3_2nd;
block_ch3_2nd = NULL;
}
}
if (block_ch4_1st) {
if (ch4_offset == 0) {
ch4_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch4_offset = 0;
release(block_ch4_1st);
block_ch4_1st = block_ch4_2nd;
block_ch4_2nd = NULL;
}
}
if (block_ch5_1st) {
if (ch5_offset == 0) {
ch5_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch5_offset = 0;
release(block_ch5_1st);
block_ch5_1st = block_ch5_2nd;
block_ch5_2nd = NULL;
}
}
if (block_ch6_1st) {
if (ch6_offset == 0) {
ch6_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch6_offset = 0;
release(block_ch6_1st);
block_ch6_1st = block_ch6_2nd;
block_ch6_2nd = NULL;
}
}
}


void AudioOutputI2SHex::update(void)
{
audio_block_t *block, *tmp;

block = receiveReadOnly(0); // channel 1
if (block) {
__disable_irq();
if (block_ch1_1st == NULL) {
block_ch1_1st = block;
ch1_offset = 0;
__enable_irq();
} else if (block_ch1_2nd == NULL) {
block_ch1_2nd = block;
__enable_irq();
} else {
tmp = block_ch1_1st;
block_ch1_1st = block_ch1_2nd;
block_ch1_2nd = block;
ch1_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(1); // channel 2
if (block) {
__disable_irq();
if (block_ch2_1st == NULL) {
block_ch2_1st = block;
ch2_offset = 0;
__enable_irq();
} else if (block_ch2_2nd == NULL) {
block_ch2_2nd = block;
__enable_irq();
} else {
tmp = block_ch2_1st;
block_ch2_1st = block_ch2_2nd;
block_ch2_2nd = block;
ch2_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(2); // channel 3
if (block) {
__disable_irq();
if (block_ch3_1st == NULL) {
block_ch3_1st = block;
ch3_offset = 0;
__enable_irq();
} else if (block_ch3_2nd == NULL) {
block_ch3_2nd = block;
__enable_irq();
} else {
tmp = block_ch3_1st;
block_ch3_1st = block_ch3_2nd;
block_ch3_2nd = block;
ch3_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(3); // channel 4
if (block) {
__disable_irq();
if (block_ch4_1st == NULL) {
block_ch4_1st = block;
ch4_offset = 0;
__enable_irq();
} else if (block_ch4_2nd == NULL) {
block_ch4_2nd = block;
__enable_irq();
} else {
tmp = block_ch4_1st;
block_ch4_1st = block_ch4_2nd;
block_ch4_2nd = block;
ch4_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(4); // channel 5
if (block) {
__disable_irq();
if (block_ch5_1st == NULL) {
block_ch5_1st = block;
ch5_offset = 0;
__enable_irq();
} else if (block_ch5_2nd == NULL) {
block_ch5_2nd = block;
__enable_irq();
} else {
tmp = block_ch5_1st;
block_ch5_1st = block_ch5_2nd;
block_ch5_2nd = block;
ch5_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(5); // channel 6
if (block) {
__disable_irq();
if (block_ch6_1st == NULL) {
block_ch6_1st = block;
ch6_offset = 0;
__enable_irq();
} else if (block_ch6_2nd == NULL) {
block_ch6_2nd = block;
__enable_irq();
} else {
tmp = block_ch6_1st;
block_ch6_1st = block_ch6_2nd;
block_ch6_2nd = block;
ch6_offset = 0;
__enable_irq();
release(tmp);
}
}
}


#else // not supported

void AudioOutputI2SHex::begin(void)
{
}

void AudioOutputI2SHex::update(void)
{
audio_block_t *block;

block = receiveReadOnly(0);
if (block) release(block);
block = receiveReadOnly(1);
if (block) release(block);
block = receiveReadOnly(2);
if (block) release(block);
block = receiveReadOnly(3);
if (block) release(block);
block = receiveReadOnly(4);
if (block) release(block);
block = receiveReadOnly(5);
if (block) release(block);
}

#endif

+ 65
- 0
output_i2s_hex.h Ver arquivo

@@ -0,0 +1,65 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef output_i2s_hex_h_
#define output_i2s_hex_h_

#include "Arduino.h"
#include "AudioStream.h"
#include "DMAChannel.h"

class AudioOutputI2SHex : public AudioStream
{
public:
AudioOutputI2SHex(void) : AudioStream(6, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
private:
static audio_block_t *block_ch1_1st;
static audio_block_t *block_ch2_1st;
static audio_block_t *block_ch3_1st;
static audio_block_t *block_ch4_1st;
static audio_block_t *block_ch5_1st;
static audio_block_t *block_ch6_1st;
static bool update_responsibility;
static DMAChannel dma;
static void isr(void);
static audio_block_t *block_ch1_2nd;
static audio_block_t *block_ch2_2nd;
static audio_block_t *block_ch3_2nd;
static audio_block_t *block_ch4_2nd;
static audio_block_t *block_ch5_2nd;
static audio_block_t *block_ch6_2nd;
static uint16_t ch1_offset;
static uint16_t ch2_offset;
static uint16_t ch3_offset;
static uint16_t ch4_offset;
static uint16_t ch5_offset;
static uint16_t ch6_offset;
audio_block_t *inputQueueArray[6];
};

#endif

+ 419
- 0
output_i2s_oct.cpp Ver arquivo

@@ -0,0 +1,419 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#include <Arduino.h>
#include "output_i2s_oct.h"
#include "output_i2s.h"
#include "memcpy_audio.h"

#if defined(__IMXRT1062__)
#include "utility/imxrt_hw.h"

audio_block_t * AudioOutputI2SOct::block_ch1_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch2_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch3_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch4_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch5_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch6_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch7_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch8_1st = NULL;
audio_block_t * AudioOutputI2SOct::block_ch1_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch2_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch3_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch4_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch5_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch6_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch7_2nd = NULL;
audio_block_t * AudioOutputI2SOct::block_ch8_2nd = NULL;
uint16_t AudioOutputI2SOct::ch1_offset = 0;
uint16_t AudioOutputI2SOct::ch2_offset = 0;
uint16_t AudioOutputI2SOct::ch3_offset = 0;
uint16_t AudioOutputI2SOct::ch4_offset = 0;
uint16_t AudioOutputI2SOct::ch5_offset = 0;
uint16_t AudioOutputI2SOct::ch6_offset = 0;
uint16_t AudioOutputI2SOct::ch7_offset = 0;
uint16_t AudioOutputI2SOct::ch8_offset = 0;
bool AudioOutputI2SOct::update_responsibility = false;
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*4];
DMAChannel AudioOutputI2SOct::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

void AudioOutputI2SOct::begin(void)
{
dma.begin(true); // Allocate the DMA channel first

block_ch1_1st = NULL;
block_ch2_1st = NULL;
block_ch3_1st = NULL;
block_ch4_1st = NULL;
block_ch5_1st = NULL;
block_ch6_1st = NULL;

memset(i2s_tx_buffer, 0, sizeof(i2s_tx_buffer));
AudioOutputI2S::config_i2s();
I2S1_TCR3 = I2S_TCR3_TCE_4CH;
CORE_PIN7_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-16) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(8);
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2);
dma.TCD->DOFF = 4;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -16;
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
dma.enable();
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
//I2S1_TCR3 = I2S_TCR3_TCE_4CH;
update_responsibility = update_setup();
dma.attachInterrupt(isr);
}

void AudioOutputI2SOct::isr(void)
{
uint32_t saddr;
const int16_t *src1, *src2, *src3, *src4, *src5, *src6, *src7, *src8;
const int16_t *zeros = (const int16_t *)zerodata;
int16_t *dest;

saddr = (uint32_t)(dma.TCD->SADDR);
dma.clearInterrupt();
if (saddr < (uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2) {
// DMA is transmitting the first half of the buffer
// so we must fill the second half
dest = (int16_t *)((uint32_t)i2s_tx_buffer + sizeof(i2s_tx_buffer) / 2);
if (update_responsibility) update_all();
} else {
dest = (int16_t *)i2s_tx_buffer;
}

src1 = (block_ch1_1st) ? block_ch1_1st->data + ch1_offset : zeros;
src2 = (block_ch2_1st) ? block_ch2_1st->data + ch2_offset : zeros;
src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;
src5 = (block_ch5_1st) ? block_ch5_1st->data + ch5_offset : zeros;
src6 = (block_ch6_1st) ? block_ch6_1st->data + ch6_offset : zeros;
src7 = (block_ch7_1st) ? block_ch7_1st->data + ch7_offset : zeros;
src8 = (block_ch8_1st) ? block_ch8_1st->data + ch8_offset : zeros;
#if 0
// TODO: optimized 8 channel copy...
memcpy_tointerleaveQuad(dest, src1, src2, src3, src4);
#else
int16_t *p=dest;
for (int i=0; i < AUDIO_BLOCK_SAMPLES/2; i++) {
*p++ = *src1++;
*p++ = *src3++;
*p++ = *src5++;
*p++ = *src7++;
*p++ = *src2++;
*p++ = *src4++;
*p++ = *src6++;
*p++ = *src8++;
}
#endif
arm_dcache_flush_delete(dest, sizeof(i2s_tx_buffer) / 2);

if (block_ch1_1st) {
if (ch1_offset == 0) {
ch1_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch1_offset = 0;
release(block_ch1_1st);
block_ch1_1st = block_ch1_2nd;
block_ch1_2nd = NULL;
}
}
if (block_ch2_1st) {
if (ch2_offset == 0) {
ch2_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch2_offset = 0;
release(block_ch2_1st);
block_ch2_1st = block_ch2_2nd;
block_ch2_2nd = NULL;
}
}
if (block_ch3_1st) {
if (ch3_offset == 0) {
ch3_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch3_offset = 0;
release(block_ch3_1st);
block_ch3_1st = block_ch3_2nd;
block_ch3_2nd = NULL;
}
}
if (block_ch4_1st) {
if (ch4_offset == 0) {
ch4_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch4_offset = 0;
release(block_ch4_1st);
block_ch4_1st = block_ch4_2nd;
block_ch4_2nd = NULL;
}
}
if (block_ch5_1st) {
if (ch5_offset == 0) {
ch5_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch5_offset = 0;
release(block_ch5_1st);
block_ch5_1st = block_ch5_2nd;
block_ch5_2nd = NULL;
}
}
if (block_ch6_1st) {
if (ch6_offset == 0) {
ch6_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch6_offset = 0;
release(block_ch6_1st);
block_ch6_1st = block_ch6_2nd;
block_ch6_2nd = NULL;
}
}
if (block_ch7_1st) {
if (ch7_offset == 0) {
ch7_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch7_offset = 0;
release(block_ch7_1st);
block_ch7_1st = block_ch7_2nd;
block_ch7_2nd = NULL;
}
}
if (block_ch8_1st) {
if (ch8_offset == 0) {
ch8_offset = AUDIO_BLOCK_SAMPLES/2;
} else {
ch8_offset = 0;
release(block_ch8_1st);
block_ch8_1st = block_ch8_2nd;
block_ch8_2nd = NULL;
}
}
}


void AudioOutputI2SOct::update(void)
{
audio_block_t *block, *tmp;

block = receiveReadOnly(0); // channel 1
if (block) {
__disable_irq();
if (block_ch1_1st == NULL) {
block_ch1_1st = block;
ch1_offset = 0;
__enable_irq();
} else if (block_ch1_2nd == NULL) {
block_ch1_2nd = block;
__enable_irq();
} else {
tmp = block_ch1_1st;
block_ch1_1st = block_ch1_2nd;
block_ch1_2nd = block;
ch1_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(1); // channel 2
if (block) {
__disable_irq();
if (block_ch2_1st == NULL) {
block_ch2_1st = block;
ch2_offset = 0;
__enable_irq();
} else if (block_ch2_2nd == NULL) {
block_ch2_2nd = block;
__enable_irq();
} else {
tmp = block_ch2_1st;
block_ch2_1st = block_ch2_2nd;
block_ch2_2nd = block;
ch2_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(2); // channel 3
if (block) {
__disable_irq();
if (block_ch3_1st == NULL) {
block_ch3_1st = block;
ch3_offset = 0;
__enable_irq();
} else if (block_ch3_2nd == NULL) {
block_ch3_2nd = block;
__enable_irq();
} else {
tmp = block_ch3_1st;
block_ch3_1st = block_ch3_2nd;
block_ch3_2nd = block;
ch3_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(3); // channel 4
if (block) {
__disable_irq();
if (block_ch4_1st == NULL) {
block_ch4_1st = block;
ch4_offset = 0;
__enable_irq();
} else if (block_ch4_2nd == NULL) {
block_ch4_2nd = block;
__enable_irq();
} else {
tmp = block_ch4_1st;
block_ch4_1st = block_ch4_2nd;
block_ch4_2nd = block;
ch4_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(4); // channel 5
if (block) {
__disable_irq();
if (block_ch5_1st == NULL) {
block_ch5_1st = block;
ch5_offset = 0;
__enable_irq();
} else if (block_ch5_2nd == NULL) {
block_ch5_2nd = block;
__enable_irq();
} else {
tmp = block_ch5_1st;
block_ch5_1st = block_ch5_2nd;
block_ch5_2nd = block;
ch5_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(5); // channel 6
if (block) {
__disable_irq();
if (block_ch6_1st == NULL) {
block_ch6_1st = block;
ch6_offset = 0;
__enable_irq();
} else if (block_ch6_2nd == NULL) {
block_ch6_2nd = block;
__enable_irq();
} else {
tmp = block_ch6_1st;
block_ch6_1st = block_ch6_2nd;
block_ch6_2nd = block;
ch6_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(6); // channel 7
if (block) {
__disable_irq();
if (block_ch7_1st == NULL) {
block_ch7_1st = block;
ch7_offset = 0;
__enable_irq();
} else if (block_ch7_2nd == NULL) {
block_ch7_2nd = block;
__enable_irq();
} else {
tmp = block_ch7_1st;
block_ch7_1st = block_ch7_2nd;
block_ch7_2nd = block;
ch7_offset = 0;
__enable_irq();
release(tmp);
}
}
block = receiveReadOnly(7); // channel 8
if (block) {
__disable_irq();
if (block_ch8_1st == NULL) {
block_ch8_1st = block;
ch8_offset = 0;
__enable_irq();
} else if (block_ch8_2nd == NULL) {
block_ch8_2nd = block;
__enable_irq();
} else {
tmp = block_ch8_1st;
block_ch8_1st = block_ch8_2nd;
block_ch8_2nd = block;
ch8_offset = 0;
__enable_irq();
release(tmp);
}
}
}


#else // not supported

void AudioOutputI2SOct::begin(void)
{
}

void AudioOutputI2SOct::update(void)
{
audio_block_t *block;

block = receiveReadOnly(0);
if (block) release(block);
block = receiveReadOnly(1);
if (block) release(block);
block = receiveReadOnly(2);
if (block) release(block);
block = receiveReadOnly(3);
if (block) release(block);
block = receiveReadOnly(4);
if (block) release(block);
block = receiveReadOnly(5);
if (block) release(block);
block = receiveReadOnly(6);
if (block) release(block);
block = receiveReadOnly(7);
if (block) release(block);
}

#endif

+ 71
- 0
output_i2s_oct.h Ver arquivo

@@ -0,0 +1,71 @@
/* Audio Library for Teensy 3.X
* Copyright (c) 2014, Paul Stoffregen, paul@pjrc.com
*
* Development of this audio library was funded by PJRC.COM, LLC by sales of
* Teensy and Audio Adaptor boards. Please support PJRC's efforts to develop
* open source software by purchasing Teensy or other PJRC products.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice, development funding notice, and this permission
* notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/

#ifndef output_i2s_oct_h_
#define output_i2s_oct_h_

#include "Arduino.h"
#include "AudioStream.h"
#include "DMAChannel.h"

class AudioOutputI2SOct : public AudioStream
{
public:
AudioOutputI2SOct(void) : AudioStream(8, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
private:
static audio_block_t *block_ch1_1st;
static audio_block_t *block_ch2_1st;
static audio_block_t *block_ch3_1st;
static audio_block_t *block_ch4_1st;
static audio_block_t *block_ch5_1st;
static audio_block_t *block_ch6_1st;
static audio_block_t *block_ch7_1st;
static audio_block_t *block_ch8_1st;
static bool update_responsibility;
static DMAChannel dma;
static void isr(void);
static audio_block_t *block_ch1_2nd;
static audio_block_t *block_ch2_2nd;
static audio_block_t *block_ch3_2nd;
static audio_block_t *block_ch4_2nd;
static audio_block_t *block_ch5_2nd;
static audio_block_t *block_ch6_2nd;
static audio_block_t *block_ch7_2nd;
static audio_block_t *block_ch8_2nd;
static uint16_t ch1_offset;
static uint16_t ch2_offset;
static uint16_t ch3_offset;
static uint16_t ch4_offset;
static uint16_t ch5_offset;
static uint16_t ch6_offset;
static uint16_t ch7_offset;
static uint16_t ch8_offset;
audio_block_t *inputQueueArray[8];
};

#endif

+ 60
- 12
output_i2s_quad.cpp Ver arquivo

@@ -26,9 +26,14 @@

#include <Arduino.h>
#include "output_i2s_quad.h"
#include "output_i2s.h"
#include "memcpy_audio.h"

#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
#if defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__) || defined(__IMXRT1062__)

#if defined(__IMXRT1062__)
#include "utility/imxrt_hw.h"
#endif

audio_block_t * AudioOutputI2SQuad::block_ch1_1st = NULL;
audio_block_t * AudioOutputI2SQuad::block_ch2_1st = NULL;
@@ -42,16 +47,14 @@ uint16_t AudioOutputI2SQuad::ch1_offset = 0;
uint16_t AudioOutputI2SQuad::ch2_offset = 0;
uint16_t AudioOutputI2SQuad::ch3_offset = 0;
uint16_t AudioOutputI2SQuad::ch4_offset = 0;
//audio_block_t * AudioOutputI2SQuad::inputQueueArray[4];
bool AudioOutputI2SQuad::update_responsibility = false;
DMAMEM static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*2];
DMAMEM __attribute__((aligned(32))) static uint32_t i2s_tx_buffer[AUDIO_BLOCK_SAMPLES*2];
DMAChannel AudioOutputI2SQuad::dma(false);

static const uint32_t zerodata[AUDIO_BLOCK_SAMPLES/4] = {0};

void AudioOutputI2SQuad::begin(void)
{
#if 1
dma.begin(true); // Allocate the DMA channel first

block_ch1_1st = NULL;
@@ -59,6 +62,7 @@ void AudioOutputI2SQuad::begin(void)
block_ch3_1st = NULL;
block_ch4_1st = NULL;

#if defined(KINETISK)
// TODO: can we call normal config_i2s, and then just enable the extra output?
config_i2s();
CORE_PIN22_CONFIG = PORT_PCR_MUX(6); // pin 22, PTC1, I2S0_TXD0 -> ch1 & ch2
@@ -82,6 +86,45 @@ void AudioOutputI2SQuad::begin(void)
I2S0_TCSR = I2S_TCSR_SR;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
dma.attachInterrupt(isr);

#elif defined(__IMXRT1062__)
const int pinoffset = 0; // TODO: make this configurable...
memset(i2s_tx_buffer, 0, sizeof(i2s_tx_buffer));
AudioOutputI2S::config_i2s();
I2S1_TCR3 = I2S_TCR3_TCE_2CH << pinoffset;
switch (pinoffset) {
case 0:
CORE_PIN7_CONFIG = 3;
CORE_PIN32_CONFIG = 3;
break;
case 1:
CORE_PIN32_CONFIG = 3;
CORE_PIN9_CONFIG = 3;
break;
case 2:
CORE_PIN9_CONFIG = 3;
CORE_PIN6_CONFIG = 3;
}
dma.TCD->SADDR = i2s_tx_buffer;
dma.TCD->SOFF = 2;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
dma.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
DMA_TCD_NBYTES_MLOFFYES_MLOFF(-8) |
DMA_TCD_NBYTES_MLOFFYES_NBYTES(4);
dma.TCD->SLAST = -sizeof(i2s_tx_buffer);
dma.TCD->DADDR = (void *)((uint32_t)&I2S1_TDR0 + 2 + pinoffset * 4);
dma.TCD->DOFF = 4;
dma.TCD->CITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->DLASTSGA = -8;
dma.TCD->BITER_ELINKNO = AUDIO_BLOCK_SAMPLES * 2;
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;
dma.triggerAtHardwareEvent(DMAMUX_SOURCE_SAI1_TX);
dma.enable();
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
I2S1_TCR3 = I2S_TCR3_TCE_2CH << pinoffset;
update_responsibility = update_setup();
dma.attachInterrupt(isr);
#endif
}

@@ -108,7 +151,6 @@ void AudioOutputI2SQuad::isr(void)
src3 = (block_ch3_1st) ? block_ch3_1st->data + ch3_offset : zeros;
src4 = (block_ch4_1st) ? block_ch4_1st->data + ch4_offset : zeros;

// TODO: fast 4-way interleaved memcpy...
#if 1
memcpy_tointerleaveQuad(dest, src1, src2, src3, src4);
#else
@@ -119,6 +161,7 @@ void AudioOutputI2SQuad::isr(void)
*dest++ = *src4++;
}
#endif
arm_dcache_flush_delete(dest, sizeof(i2s_tx_buffer) / 2 );

if (block_ch1_1st) {
if (ch1_offset == 0) {
@@ -245,7 +288,7 @@ void AudioOutputI2SQuad::update(void)
}
}

#if defined(KINETISK)
// MCLK needs to be 48e6 / 1088 * 256 = 11.29411765 MHz -> 44.117647 kHz sample rate
//
#if F_CPU == 96000000 || F_CPU == 48000000 || F_CPU == 24000000
@@ -272,12 +315,17 @@ void AudioOutputI2SQuad::update(void)
#define MCLK_MULT 1
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 8
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 4
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV 17
@@ -333,10 +381,10 @@ void AudioOutputI2SQuad::config_i2s(void)
CORE_PIN9_CONFIG = PORT_PCR_MUX(6); // pin 9, PTC3, I2S0_TX_BCLK
CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK
}
#endif // KINETISK


#else // not __MK20DX256__

#else // not supported

void AudioOutputI2SQuad::begin(void)
{

+ 16
- 6
output_pt8211.cpp Ver arquivo

@@ -71,8 +71,11 @@ void AudioOutputPT8211::begin(void)
dma.TCD->CSR = DMA_TCD_CSR_INTHALF | DMA_TCD_CSR_INTMAJOR;

dma.triggerAtHardwareEvent(DMAMUX_SOURCE_I2S0_TX);
update_responsibility = update_setup();
dma.attachInterrupt(isr);
dma.enable();
I2S0_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE | I2S_TCSR_FR;

return;
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)

#if defined(__IMXRT1052__)
@@ -96,10 +99,12 @@ void AudioOutputPT8211::begin(void)

I2S1_RCSR |= I2S_RCSR_RE;
I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
#endif
update_responsibility = update_setup();
dma.attachInterrupt(isr);
dma.enable();
return;
#endif
}

void AudioOutputPT8211::isr(void)
@@ -429,12 +434,17 @@ void AudioOutputPT8211::update(void)
#define MCLK_MULT 1
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 8
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 4
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV 17

+ 9
- 4
output_spdif.cpp Ver arquivo

@@ -327,12 +327,17 @@ void AudioOutputSPDIF::update(void)
#define MCLK_MULT 1
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 8
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 4
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 16000000
#define MCLK_MULT 12
#define MCLK_DIV 17

+ 24
- 15
output_tdm.cpp Ver arquivo

@@ -72,8 +72,8 @@ void AudioOutputTDM::begin(void)

I2S0_TCSR = I2S_TCSR_SR;
I2S0_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
CORE_PIN6_CONFIG = 3; //1:TX_DATA0
#elif defined(__IMXRT1062__)
CORE_PIN7_CONFIG = 3; //1:TX_DATA0

dma.TCD->SADDR = tdm_tx_buffer;
dma.TCD->SOFF = 4;
@@ -91,8 +91,8 @@ void AudioOutputTDM::begin(void)
update_responsibility = update_setup();
dma.enable();

I2S1_RCSR |= I2S_RCSR_RE;
I2S1_TCSR |= I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;
I2S1_RCSR |= I2S_RCSR_RE | I2S_RCSR_BCE;
I2S1_TCSR = I2S_TCSR_TE | I2S_TCSR_BCE | I2S_TCSR_FRDE;

#endif
dma.attachInterrupt(isr);
@@ -125,7 +125,7 @@ static void memcpy_tdm_tx(uint32_t *dest, const uint32_t *src1, const uint32_t *

void AudioOutputTDM::isr(void)
{
uint32_t *dest, *dc;
uint32_t *dest;
const uint32_t *src1, *src2;
uint32_t i, saddr;

@@ -141,7 +141,11 @@ void AudioOutputTDM::isr(void)
dest = tdm_tx_buffer;
}
if (update_responsibility) AudioStream::update_all();
dc = dest;

#if IMXRT_CACHE_ENABLED >= 2
uint32_t *dc = dest;
#endif
for (i=0; i < 16; i += 2) {
src1 = block_input[i] ? (uint32_t *)(block_input[i]->data) : zeros;
src2 = block_input[i+1] ? (uint32_t *)(block_input[i+1]->data) : zeros;
@@ -205,12 +209,17 @@ void AudioOutputTDM::update(void)
#define MCLK_MULT 2
#define MCLK_DIV 17
#elif F_CPU == 216000000
#define MCLK_MULT 16
#define MCLK_DIV 153
#define MCLK_SRC 0
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#elif F_CPU == 240000000
#define MCLK_MULT 8
#define MCLK_MULT 2
#define MCLK_DIV 85
#define MCLK_SRC 0
#elif F_CPU == 256000000
#define MCLK_MULT 12
#define MCLK_DIV 17
#define MCLK_SRC 1
#else
#error "This CPU Clock Speed is not supported by the Audio library";
#endif
@@ -265,8 +274,12 @@ void AudioOutputTDM::config_tdm(void)
CORE_PIN9_CONFIG = PORT_PCR_MUX(6); // pin 9, PTC3, I2S0_TX_BCLK - 11.2 MHz
CORE_PIN11_CONFIG = PORT_PCR_MUX(6); // pin 11, PTC6, I2S0_MCLK - 22.5 MHz

#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
#elif defined(__IMXRT1062__)
CCM_CCGR5 |= CCM_CCGR5_SAI1(CCM_CCGR_ON);

// if either transmitter or receiver is enabled, do nothing
if (I2S1_TCSR & I2S_TCSR_TE) return;
if (I2S1_RCSR & I2S_RCSR_RE) return;
//PLL:
int fs = AUDIO_SAMPLE_RATE_EXACT;
// PLL between 27*24 = 648MHz und 54*24=1296MHz
@@ -291,10 +304,6 @@ void AudioOutputTDM::config_tdm(void)
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL_MASK))
| (IOMUXC_GPR_GPR1_SAI1_MCLK_DIR | IOMUXC_GPR_GPR1_SAI1_MCLK1_SEL(0)); //Select MCLK

// if either transmitter or receiver is enabled, do nothing
if (I2S1_TCSR & I2S_TCSR_TE) return;
if (I2S1_RCSR & I2S_RCSR_RE) return;

// configure transmitter
int rsync = 0;
int tsync = 1;

+ 7
- 11
output_tdm2.cpp Ver arquivo

@@ -24,7 +24,7 @@
* THE SOFTWARE.
*/

#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)
#include <Arduino.h>
#include "output_tdm2.h"
#include "memcpy_audio.h"
@@ -159,8 +159,11 @@ void AudioOutputTDM2::update(void)

void AudioOutputTDM2::config_tdm(void)
{

CCM_CCGR5 |= CCM_CCGR5_SAI2(CCM_CCGR_ON);

// if either transmitter or receiver is enabled, do nothing
if (I2S2_TCSR & I2S_TCSR_TE) return;
if (I2S2_RCSR & I2S_RCSR_RE) return;
//PLL:
int fs = AUDIO_SAMPLE_RATE_EXACT; //176.4 khZ
// PLL between 27*24 = 648MHz und 54*24=1296MHz
@@ -186,12 +189,6 @@ void AudioOutputTDM2::config_tdm(void)
IOMUXC_GPR_GPR1 = (IOMUXC_GPR_GPR1 & ~(IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL_MASK))
| (IOMUXC_GPR_GPR1_SAI2_MCLK_DIR | IOMUXC_GPR_GPR1_SAI2_MCLK3_SEL(0)); //Select MCLK



// if either transmitter or receiver is enabled, do nothing
if (I2S2_TCSR & I2S_TCSR_TE) return;
if (I2S2_RCSR & I2S_RCSR_RE) return;

// configure transmitter
int rsync = 1;
int tsync = 0;
@@ -215,10 +212,9 @@ void AudioOutputTDM2::config_tdm(void)
| I2S_RCR4_FSE | I2S_RCR4_FSD;
I2S2_RCR5 = I2S_RCR5_WNW(31) | I2S_RCR5_W0W(31) | I2S_RCR5_FBT(31);

CORE_PIN5_CONFIG = 2; //2:MCLK
CORE_PIN33_CONFIG = 2; //2:MCLK
CORE_PIN4_CONFIG = 2; //2:TX_BCLK
CORE_PIN3_CONFIG = 2; //2:TX_SYNC

}

#endif
#endif

+ 2
- 2
play_queue.cpp Ver arquivo

@@ -52,7 +52,7 @@ void AudioPlayQueue::playBuffer(void)

if (!userblock) return;
h = head + 1;
if (h >= 32) h = 0;
if (h >= max_buffers) h = 0;
while (tail == h) ; // wait until space in the queue
queue[h] = userblock;
head = h;
@@ -66,7 +66,7 @@ void AudioPlayQueue::update(void)

t = tail;
if (t != head) {
if (++t >= 32) t = 0;
if (++t >= max_buffers) t = 0;
block = queue[t];
tail = t;
transmit(block);

+ 7
- 1
play_queue.h Ver arquivo

@@ -32,6 +32,12 @@

class AudioPlayQueue : public AudioStream
{
private:
#if defined(__IMXRT1062__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
static const int max_buffers = 80;
#else
static const int max_buffers = 32;
#endif
public:
AudioPlayQueue(void) : AudioStream(0, NULL),
userblock(NULL), head(0), tail(0) { }
@@ -44,7 +50,7 @@ public:
//bool isPlaying(void) { return playing; }
virtual void update(void);
private:
audio_block_t *queue[32];
audio_block_t *queue[max_buffers];
audio_block_t *userblock;
volatile uint8_t head, tail;
};

+ 4
- 4
record_queue.cpp Ver arquivo

@@ -36,7 +36,7 @@ int AudioRecordQueue::available(void)
h = head;
t = tail;
if (h >= t) return h - t;
return 53 + h - t;
return max_buffers + h - t;
}

void AudioRecordQueue::clear(void)
@@ -49,7 +49,7 @@ void AudioRecordQueue::clear(void)
}
t = tail;
while (t != head) {
if (++t >= 53) t = 0;
if (++t >= max_buffers) t = 0;
release(queue[t]);
}
tail = t;
@@ -62,7 +62,7 @@ int16_t * AudioRecordQueue::readBuffer(void)
if (userblock) return NULL;
t = tail;
if (t == head) return NULL;
if (++t >= 53) t = 0;
if (++t >= max_buffers) t = 0;
userblock = queue[t];
tail = t;
return userblock->data;
@@ -87,7 +87,7 @@ void AudioRecordQueue::update(void)
return;
}
h = head + 1;
if (h >= 53) h = 0;
if (h >= max_buffers) h = 0;
if (h == tail) {
release(block);
} else {

+ 7
- 1
record_queue.h Ver arquivo

@@ -32,6 +32,12 @@

class AudioRecordQueue : public AudioStream
{
private:
#if defined(__IMXRT1062__) || defined(__MK66FX1M0__) || defined(__MK64FX512__)
static const int max_buffers = 209;
#else
static const int max_buffers = 53;
#endif
public:
AudioRecordQueue(void) : AudioStream(1, inputQueueArray),
userblock(NULL), head(0), tail(0), enabled(0) { }
@@ -49,7 +55,7 @@ public:
virtual void update(void);
private:
audio_block_t *inputQueueArray[1];
audio_block_t * volatile queue[53];
audio_block_t * volatile queue[max_buffers];
audio_block_t *userblock;
volatile uint8_t head, tail, enabled;
};

+ 1
- 1
utility/imxrt_hw.cpp Ver arquivo

@@ -31,7 +31,7 @@
#include "imxrt_hw.h"

PROGMEM
void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force = false) // sets PLL4
void set_audioClock(int nfact, int32_t nmult, uint32_t ndiv, bool force) // sets PLL4
{
if (!force && (CCM_ANALOG_PLL_AUDIO & CCM_ANALOG_PLL_AUDIO_ENABLE)) return;


+ 1
- 1
utility/imxrt_hw.h Ver arquivo

@@ -27,7 +27,7 @@
(c) Frank B
*/

#if defined(__IMXRT1052__) || defined(__IMXRT1062__)
#if defined(__IMXRT1062__)

#ifndef imxr_hw_h_
#define imxr_hw_h_

Carregando…
Cancelar
Salvar