| @@ -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. | |||
| } | |||
| @@ -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(); | |||
| } | |||
| @@ -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; | |||
| } | |||
| } | |||
| @@ -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"> | |||
| @@ -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(); | |||
| @@ -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; | |||
| @@ -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; | |||
| @@ -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 | |||
| @@ -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) | |||