Explorar el Código

Make input ADC and output DAC play nicely together

dds
PaulStoffregen hace 10 años
padre
commit
bdd67504ef
Se han modificado 10 ficheros con 86 adiciones y 191 borrados
  1. +0
    -41
      examples/HardwareTesting/PassThroughAnalog/PassThroughAnalog.ino
  2. +41
    -0
      examples/HardwareTesting/PassThroughMono/PassThroughMono.ino
  3. +0
    -95
      examples/HardwareTesting/PassThroughPlusTone/PassThroughPlusTone.ino
  4. +0
    -0
      examples/HardwareTesting/PassThroughStereo/PassThroughStereo.ino
  5. +5
    -11
      gui/list.html
  6. +24
    -35
      input_adc.cpp
  7. +2
    -2
      input_adc.h
  8. +12
    -5
      output_dac.cpp
  9. +1
    -1
      output_pwm.h
  10. +1
    -1
      utility/pdb.h

+ 0
- 41
examples/HardwareTesting/PassThroughAnalog/PassThroughAnalog.ino Ver fichero

@@ -1,41 +0,0 @@
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>


// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
AudioInputAnalog analogPinInput(A2); // analog A2 (pin 16)
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
AudioOutputPWM pwmOutput; // audio output with PWM on pins 3 & 4

// Create Audio connections between the components
//
AudioConnection c1(analogPinInput, 0, audioOutput, 0);
AudioConnection c2(analogPinInput, 0, audioOutput, 1);
AudioConnection c3(analogPinInput, 0, pwmOutput, 0);

// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;


void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);

// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.volume(0.6);
}

void loop() {
// Do nothing here. The Audio flows automatically

// When AudioInputAnalog is running, analogRead() must NOT be used.
}



+ 41
- 0
examples/HardwareTesting/PassThroughMono/PassThroughMono.ino Ver fichero

@@ -0,0 +1,41 @@
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "utility/pdb.h"

// GUItool: begin automatically generated code
AudioInputAnalog adc1; //xy=161,80
AudioOutputAnalog dac1; //xy=329,47
AudioOutputPWM pwm1; //xy=331,125
AudioConnection patchCord1(adc1, dac1);
AudioConnection patchCord2(adc1, pwm1);
// GUItool: end automatically generated code

void setup() {
// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);
}

void loop() {
// Do nothing here. The Audio flows automatically

// When AudioInputAnalog is running, analogRead() must NOT be used.
delay(200);
Serial.print("PDB: SC=");
Serial.print(PDB0_SC, HEX);
Serial.print(", CONFIG=");
Serial.print(PDB_CONFIG, HEX);
Serial.print(", MOD=");
Serial.print(PDB0_MOD);
Serial.print(", IDLY=");
Serial.print(PDB0_IDLY);
Serial.print(", CH0C1=");
Serial.print(PDB0_CH0C1);
Serial.print(", DMA: ");
Serial.print(dma_channel_allocated_mask, HEX);
Serial.println();
}



+ 0
- 95
examples/HardwareTesting/PassThroughPlusTone/PassThroughPlusTone.ino Ver fichero

@@ -1,95 +0,0 @@
#include <Audio.h>
#include <Bounce.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>

const int myInput = AUDIO_INPUT_LINEIN;
//const int myInput = AUDIO_INPUT_MIC;

// Create the Audio components. These should be created in the
// order data flows, inputs/sources -> processing -> outputs
//
//AudioInputAnalog analogPinInput(16); // analog A2 (pin 16)
AudioInputI2S audioInput; // audio shield: mic or line-in
AudioSynthWaveform toneLow(AudioWaveformSine);
AudioSynthWaveform toneHigh(AudioWaveformTriangle);
AudioMixer4 mixerLeft;
AudioMixer4 mixerRight;
AudioOutputI2S audioOutput; // audio shield: headphones & line-out
AudioOutputPWM pwmOutput; // audio output with PWM on pins 3 & 4

// Create Audio connections between the components
//
AudioConnection c1(audioInput, 0, mixerLeft, 0);
AudioConnection c2(audioInput, 1, mixerRight, 0);
AudioConnection c3(toneHigh, 0, mixerLeft, 1);
AudioConnection c4(toneHigh, 0, mixerRight, 1);
AudioConnection c5(toneLow, 0, mixerLeft, 2);
AudioConnection c6(toneLow, 0, mixerRight, 2);
AudioConnection c7(mixerLeft, 0, audioOutput, 0);
AudioConnection c8(mixerRight, 0, audioOutput, 1);
AudioConnection c9(mixerLeft, 0, pwmOutput, 0);

// Create an object to control the audio shield.
//
AudioControlSGTL5000 audioShield;


// Bounce objects to read two pushbuttons (pins 0 and 1)
//
Bounce button0 = Bounce(0, 12);
Bounce button1 = Bounce(1, 12); // 12 ms debounce time


void setup() {
pinMode(0, INPUT_PULLUP);
pinMode(1, INPUT_PULLUP);

// Audio connections require memory to work. For more
// detailed information, see the MemoryAndCpuUsage example
AudioMemory(12);

// Enable the audio shield and set the output volume.
audioShield.enable();
audioShield.inputSelect(myInput);
audioShield.volume(0.60);
}

elapsedMillis volmsec=0;

void loop() {
// Check each button
button0.update();
button1.update();

// fallingEdge = high (not pressed - voltage from pullup resistor)
// to low (pressed - button connects pin to ground)
if (button0.fallingEdge()) {
toneLow.frequency(256);
toneLow.amplitude(0.4);
}
if (button1.fallingEdge()) {
toneHigh.frequency(980);
toneHigh.amplitude(0.25);
}

// risingEdge = low (pressed - button connects pin to ground)
// to high (not pressed - voltage from pullup resistor)
if (button0.risingEdge()) {
toneLow.amplitude(0);
}
if (button1.risingEdge()) {
toneHigh.amplitude(0);
}

// every 50 ms, adjust the volume
if (volmsec > 50) {
float vol = analogRead(15);
vol = vol / 10.24;
audioShield.volume(vol);
volmsec = 0;
}
}



examples/HardwareTesting/PassThrough/PassThrough.ino → examples/HardwareTesting/PassThroughStereo/PassThroughStereo.ino Ver fichero


+ 5
- 11
gui/list.html Ver fichero

@@ -112,7 +112,7 @@


<script type="text/javascript">
RED.nodes.registerType('AudioInputADC',{
RED.nodes.registerType('AudioInputAnalog',{
shortName: "adc",
inputs:0,
outputs:1,
@@ -121,7 +121,7 @@
icon: "arrow-in.png"
});
</script>
<script type="text/x-red" data-help-name="AudioInputADC">
<script type="text/x-red" data-help-name="AudioInputAnalog">
<h3>Summary</h3>
<p>Receive audio using the built-in analog to digital converter.</p>
<h3>Audio Connections</h3>
@@ -129,18 +129,12 @@
<tr class=top><th>Port</th><th>Purpose</th></tr>
<tr class=odd><td align=center>Out 0</td><td>Audio Channel</td></tr>
</table>
<h3>Parameters</h3>
<table class=doc align=center cellpadding=3>
<tr class=top><th>Name</th><th>Type</th><th>Function</th></tr>
<tr class=odd><td align=center>Pin</td><td>Integer</td><td>Analog Pin To Use</td></tr>
</table>
<p>The pin number should be specified as "A0" to "A20"</p>
<p align=center><img src="adcpins2.jpg"></p>
<p align=center><img src="adcpins1.jpg"></p>
<h3>Functions</h3>
<p>This object has no functions to call from the Arduino sketch. It
simply streams data from the ADC to its output port.</p>
<h3>Hardware</h3>
<p>Pin A2 is used for audio input.</p>
<p align=center><img src="adcpins2.jpg"></p>
<p>Signal range is 0 to 1.2V</p>
<p>Need for DC bias, approx 0.6V</p>
<p>TODO: suggested circuity for signal input</p>
@@ -151,7 +145,7 @@
<p>TODO: actual noise measurements with different input circuitry
(it's not nearly as quiet as the audio shield)</p>
</script>
<script type="text/x-red" data-template-name="AudioInputADC">
<script type="text/x-red" data-template-name="AudioInputAnalog">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Name">

+ 24
- 35
input_adc.cpp Ver fichero

@@ -33,34 +33,17 @@ uint16_t AudioInputAnalog::block_offset = 0;
bool AudioInputAnalog::update_responsibility = false;
DMAChannel AudioInputAnalog::dma;

// #define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT)
// #define PDB_PERIOD 1087 // 48e6 / 44100

void AudioInputAnalog::begin(unsigned int pin)
AudioInputAnalog::AudioInputAnalog() : AudioStream(0, NULL)
{
unsigned int pin = A2;
uint32_t i, sum=0;

// pin specified in user sketches should be A0 to A13
// numbers can be used, but the recommended usage is
// with the named constants A0 to A13
// constants A0-A9 are actually 14 to 23
// constants A10-A13 are actually 34 to 37
if (pin > 23 && !(pin >= 34 && pin <= 37)) return;

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

//pinMode(2, OUTPUT);
//pinMode(3, OUTPUT);
//digitalWriteFast(3, HIGH);
//delayMicroseconds(500);
//digitalWriteFast(3, LOW);

// Configure the ADC and run at least one software-triggered
// conversion. This completes the self calibration stuff and
// leaves the ADC in a state that's mostly ready to use
analogReadRes(16);
analogReference(INTERNAL); // range 0 to 1.2 volts
//analogReference(DEFAULT); // range 0 to 3.3 volts
analogReadAveraging(8);
// Actually, do many normal reads, to start with a nice DC level
for (i=0; i < 1024; i++) {
@@ -68,22 +51,25 @@ void AudioInputAnalog::begin(unsigned int pin)
}
dc_average = sum >> 10;

// testing only, enable adc interrupt
//ADC0_SC1A |= ADC_SC1_AIEN;
//while ((ADC0_SC1A & ADC_SC1_COCO) == 0) ; // wait
//NVIC_ENABLE_IRQ(IRQ_ADC0);

// set the programmable delay block to trigger the ADC at 44.1 kHz
SIM_SCGC6 |= SIM_SCGC6_PDB;
PDB0_MOD = PDB_PERIOD;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
PDB0_CH0C1 = 0x0101;
if (!(SIM_SCGC6 & SIM_SCGC6_PDB)
|| (PDB0_SC & PDB_CONFIG) != PDB_CONFIG
|| PDB0_MOD != PDB_PERIOD
|| PDB0_IDLY != 1
|| PDB0_CH0C1 != 0x0101) {
SIM_SCGC6 |= SIM_SCGC6_PDB;
PDB0_IDLY = 1;
PDB0_MOD = PDB_PERIOD;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
PDB0_CH0C1 = 0x0101;
}

// enable the ADC for hardware trigger and DMA
ADC0_SC2 |= ADC_SC2_ADTRG | ADC_SC2_DMAEN;

// set up a DMA channel to store the ADC data
dma.begin(true);
dma.TCD->SADDR = &ADC0_RA;
dma.TCD->SOFF = 0;
dma.TCD->ATTR = DMA_TCD_ATTR_SSIZE(1) | DMA_TCD_ATTR_DSIZE(1);
@@ -101,6 +87,7 @@ void AudioInputAnalog::begin(unsigned int pin)
dma.attachInterrupt(isr);
}


void AudioInputAnalog::isr(void)
{
uint32_t daddr, offset;
@@ -108,7 +95,7 @@ void AudioInputAnalog::isr(void)
uint16_t *dest_left;
audio_block_t *left;

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

@@ -117,26 +104,26 @@ void AudioInputAnalog::isr(void)
// need to remove data from the second half
src = (uint16_t *)&analog_rx_buffer[AUDIO_BLOCK_SAMPLES/2];
end = (uint16_t *)&analog_rx_buffer[AUDIO_BLOCK_SAMPLES];
if (AudioInputAnalog::update_responsibility) AudioStream::update_all();
if (update_responsibility) AudioStream::update_all();
} else {
// DMA is receiving to the second half of the buffer
// need to remove data from the first half
src = (uint16_t *)&analog_rx_buffer[0];
end = (uint16_t *)&analog_rx_buffer[AUDIO_BLOCK_SAMPLES/2];
}
left = AudioInputAnalog::block_left;
left = block_left;
if (left != NULL) {
offset = AudioInputAnalog::block_offset;
offset = block_offset;
if (offset > AUDIO_BLOCK_SAMPLES/2) offset = AUDIO_BLOCK_SAMPLES/2;
//if (offset <= AUDIO_BLOCK_SAMPLES/2) {
dest_left = (uint16_t *)&(left->data[offset]);
AudioInputAnalog::block_offset = offset + AUDIO_BLOCK_SAMPLES/2;
block_offset = offset + AUDIO_BLOCK_SAMPLES/2;
do {
*dest_left++ = *src++;
} while (src < end);
//}
}
//digitalWriteFast(3, LOW);
digitalWriteFast(2, LOW);
}


@@ -157,6 +144,8 @@ void AudioInputAnalog::update(void)
unsigned int dc, offset;
int16_t s, *p, *end;

//Serial.println("update");

// allocate new block (ok if NULL)
new_left = allocate();


+ 2
- 2
input_adc.h Ver fichero

@@ -33,9 +33,9 @@
class AudioInputAnalog : public AudioStream
{
public:
AudioInputAnalog(unsigned int pin) : AudioStream(0, NULL) { begin(pin); }
AudioInputAnalog();
virtual void update(void);
void begin(unsigned int pin);
friend void dma_ch9_isr(void);
private:
static audio_block_t *block_left;
static uint16_t block_offset;

+ 12
- 5
output_dac.cpp Ver fichero

@@ -48,11 +48,18 @@ void AudioOutputAnalog::begin(void)
}

// set the programmable delay block to trigger DMA requests
SIM_SCGC6 |= SIM_SCGC6_PDB;
PDB0_IDLY = 1;
PDB0_MOD = PDB_PERIOD;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG | PDB_SC_PDBIE | PDB_SC_DMAEN;
if (!(SIM_SCGC6 & SIM_SCGC6_PDB)
|| (PDB0_SC & PDB_CONFIG) != PDB_CONFIG
|| PDB0_MOD != PDB_PERIOD
|| PDB0_IDLY != 1
|| PDB0_CH0C1 != 0x0101) {
SIM_SCGC6 |= SIM_SCGC6_PDB;
PDB0_IDLY = 1;
PDB0_MOD = PDB_PERIOD;
PDB0_SC = PDB_CONFIG | PDB_SC_LDOK;
PDB0_SC = PDB_CONFIG | PDB_SC_SWTRIG;
PDB0_CH0C1 = 0x0101;
}

dma.TCD->SADDR = dac_buffer;
dma.TCD->SOFF = 2;

+ 1
- 1
output_pwm.h Ver fichero

@@ -35,7 +35,6 @@ class AudioOutputPWM : public AudioStream
public:
AudioOutputPWM(void) : AudioStream(1, inputQueueArray) { begin(); }
virtual void update(void);
void begin(void);
private:
static audio_block_t *block_1st;
static audio_block_t *block_2nd;
@@ -45,6 +44,7 @@ private:
audio_block_t *inputQueueArray[1];
static DMAChannel dma;
static void isr(void);
void begin(void);
};

#endif

+ 1
- 1
utility/pdb.h Ver fichero

@@ -33,7 +33,7 @@
// to set their sample rate. They must all configure the same
// period to avoid chaos.

#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT)
#define PDB_CONFIG (PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | PDB_SC_CONT | PDB_SC_PDBIE | PDB_SC_DMAEN)

#if F_BUS == 60000000
#define PDB_PERIOD (1360-1)

Cargando…
Cancelar
Guardar