defragster
Senior Member+
IDE 1.8.9 builds much faster AFAIK - 1.8.10 does mega rebuild on the tiniest change on Audio sketch.
while (!(_padc.HS & ADC_HS_COCO0))
elapsedMillis timeout;
int ADCL_Module::getAdcCompareRes(uint8_t acmp_pin)
{
uint8_t ch = ADCL::mapPinToChannel(acmp_pin, 0);
if (ch == 0xff) {
fail_flag |= ADC_ERROR::WRONG_PIN;
return ADC_ERROR_VALUE;
}
timeout = 0;
_padc.HC0 = ch;
while (!(_padc.HS & ADC_HS_COCO0)){
if(timeout > 100){
timeout = 0; // wait
return 0;
}
}
int temp = _padc.R0;
return 1;
}
for (int i = 0; i < ArrayMax-1; i++) {
v1[i] = T4AnalogRead(A0, 1);
}
for (int i = 0; i < ArrayMax-1; i++) {
Serial.print(v1[i]);
}
#include <Audio.h>
#define POT_PIN 14
int last_pot_val = 0xffff;
int led_on_time = 256;
int led_off_time = 256;
elapsedMillis led_timer;
// GUItool: begin automatically generated code
AudioSynthWaveform waveform1; //xy=110,75
AudioOutputAnalogStereo audioOutput;
AudioConnection patchCord1(waveform1, 0, audioOutput, 0);
AudioConnection patchCord2(waveform1, 0, audioOutput, 1);
// GUItool: end automatically generated code
void setup() {
pinMode(13, OUTPUT);
Serial.begin(115200);
AudioMemory(15);
audioOutput.analogReference(DEFAULT);
waveform1.begin(WAVEFORM_SINE);
waveform1.frequency(60);
waveform1.amplitude(0.99);
analogReadResolution(12); // 12 bit resolution
led_timer = 0;
}
void loop() {
int pot_val = analogRead(POT_PIN); // lets reduce noise
if (abs(pot_val - last_pot_val) > 8) {
last_pot_val = pot_val;
float new_amp = (float)last_pot_val / 4096.0;
led_on_time = new_amp * 512;
led_off_time = 512 - led_on_time;
waveform1.amplitude(new_amp);
if (Serial) {
Serial.print("New Amp: ");
Serial.print(new_amp, 4);
Serial.print("(");
Serial.print(pot_val, DEC);
Serial.println(")");
}
}
if (digitalReadFast(13)) {
if (led_timer > led_on_time) {
digitalWriteFast(13, LOW);
led_timer = 0;
}
} else if (led_timer > led_off_time) {
digitalWriteFast(13, HIGH);
led_timer = 0;
}
}
/*
It doesn't work for Teensy LC yet!
*/
#include <ADCL_t4.h>
#include <DMAChannel.h>
const int readPin = 15;
ADCL *adc = new ADCL(); // adc object
DMAChannel* dmaChannel;
extern void dumpDMA_TCD(DMABaseClass *dmabc);
volatile uint32_t dma_complete_dt = 0;
volatile uint32_t dma_interrupt_count = 0;
// Define the array that holds the conversions here.
// buffer_size must be a power of two.
// The buffer is stored with the correct alignment in the DMAMEM section
// the +0 in the aligned attribute is necessary b/c of a bug in gcc.
const uint32_t buffer_size = 3200;
const uint32_t HALF_BUFFER = buffer_size / 2;
DMAMEM static volatile int16_t __attribute__((aligned(32))) dma_buffer[buffer_size];
// use dma with ADC0
//RingBufferDMA *dmaBuffer = new RingBufferDMA(buffer, buffer_size, ADC_0);
#if ADC_NUM_ADCS>1
//const int buffer_size2 = 8;
//DMAMEM static volatile int16_t __attribute__((aligned(buffer_size2+0))) buffer2[buffer_size2];
//
//// use dma with ADC1
//RingBufferDMA *dmaBuffer2 = new RingBufferDMA(buffer2, buffer_size2, ADC_1);
#endif // defined
void setup() {
while (!Serial && millis() < 5000) ;
pinMode(LED_BUILTIN, OUTPUT);
pinMode(readPin, INPUT); //pin 23 single ended
Serial.begin(9600);
Serial.println("Setup");
// reference can be ADC_REFERENCE::REF_3V3, ADC_REFERENCE::REF_1V2 (not for Teensy LC) or ADC_REF_EXT.
//adc->setReference(ADC_REFERENCE::REF_1V2, ADC_0); // change all 3.3 to 1.2 if you change the reference to 1V2
adc->setAveraging(8); // set number of averages
adc->setResolution(12); // set bits of resolution
// always call the compare functions after changing the resolution!
//adc->enableCompare(1.0/3.3*adc->getMaxValue(ADC_0), 0, ADC_0); // measurement will be ready if value < 1.0V
//adc->enableCompareRange(1.0*adc->getMaxValue(ADC_1)/3.3, 2.0*adc->getMaxValue(ADC_1)/3.3, 0, 1, ADC_1); // ready if value lies out of [1.0,2.0] V
// enable DMA and interrupts
Serial.println("before enableDMA"); Serial.flush();
// setup a DMA Channel.
dmaChannel = new DMAChannel(); // reserve a DMA channel
// Now lets see the different things that RingbufferDMA setup for us before
dmaChannel->source(ADC1_R0);
dmaChannel->destinationCircular((uint16_t*)dma_buffer, sizeof(dma_buffer)); // 2*b_size is necessary for some reason
dmaChannel->transferSize(2); // both SRC and DST size
dmaChannel->transferCount(sizeof(dma_buffer) / sizeof(dma_buffer[0])); // transfer b_size values
dmaChannel->interruptAtHalf(); //interruptAtHalf or interruptAtCompletion
dmaChannel->interruptAtCompletion(); //interruptAtHalf or interruptAtCompletion
dmaChannel->attachInterrupt(dmaBuffer_isr);
dmaChannel->triggerAtHardwareEvent(DMAMUX_SOURCE_ADC1); // start DMA channel when ADC finishes a conversion
arm_dcache_flush((void*)dmaChannel, sizeof(dmaChannel));
dmaChannel->enable();
dumpDMA_TCD(dmaChannel);
Serial.printf("ADC1: HC0:%x HS:%x CFG:%x GC:%x GS:%x\n", ADC1_HC0, ADC1_HS, ADC1_CFG, ADC1_GC, ADC1_GS);
adc->enableDMA(ADC_0);
// ADC interrupt enabled isn't mandatory for DMA to work.
// Serial.println("before enableInterrupts"); Serial.flush();
// adc->enableInterrupts(ADC_0);
// Start the dma operation..
adc->analogRead(readPin, ADC_0);
Serial.println("End Setup");
}
char c = 0;
int average_value = 2048;
void loop() {
if (dma_complete_dt) {
// Lets find min/max and compute average...
uint32_t sum_values = 0;
uint16_t min_val = 0xffff;
uint16_t max_val = 0;
uint16_t *pbuffer = &dma_buffer[(dma_interrupt_count & 1) ? 0 : HALF_BUFFER];
uint16_t *end_pbuffer = pbuffer + HALF_BUFFER;
float sum_delta_sq = 0.0;
arm_dcache_delete((void*)pbuffer, sizeof(dma_buffer)/2);
while (pbuffer < end_pbuffer) {
if (*pbuffer < min_val) min_val = *pbuffer;
if (*pbuffer > max_val) max_val = *pbuffer;
sum_values += *pbuffer;
int delta_from_center = (int) * pbuffer - average_value;
sum_delta_sq += delta_from_center * delta_from_center;
pbuffer++;
}
float rms = sqrt(sum_delta_sq / HALF_BUFFER);
Serial.printf("%u(%u): %u <= %u <= %u %f\n", dma_interrupt_count, dma_complete_dt, min_val, sum_values / HALF_BUFFER, max_val, rms);
dma_complete_dt = 0;
}
}
uint32_t last_isr_time = 0;
void dmaBuffer_isr() {
uint32_t cur_time = millis();
digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
//Serial.printf("dmaBuffer_isr: %u\n", cur_time-last_isr_time);
dma_complete_dt = cur_time - last_isr_time;
dma_interrupt_count++;
last_isr_time = cur_time;
// update the internal buffer positions
dmaChannel->clearInterrupt();
asm("DSB");
}
Setup ADC_0
before enableDMA
before enableDMA
20001160 400e9000:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200000 DO: 2 CI:640 DL:20001140 CS:12 BI:640
200010e0 20001100:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200000 DO: 2 CI:640 DL:20001140 CS:12 BI:640
20001120 20001140:SA:400c4024 SO:0 AT:101 NB:2 SL:0 DA:20200c80 DO: 2 CI:640 DL:20001100 CS:12 BI:640
ADC1: HC0:1f HS:1 CFG:47bb GC:20 GS:0
Setup ADC_1
before enableDMA
20001220 400e9020:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20201900 DO: 2 CI:640 DL:20001200 CS:12 BI:640
200011a0 200011c0:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20201900 DO: 2 CI:640 DL:20001200 CS:12 BI:640
200011e0 20001200:SA:400c8024 SO:0 AT:101 NB:2 SL:0 DA:20202580 DO: 2 CI:640 DL:200011c0 CS:12 BI:640
ADC2: HC0:1f HS:1 CFG:47bb GC:20 GS:0
End Setup
From T4 beta testing, i had a proof-of-concept sketch for ADC with double-buffered DMA. I only count ticks in the half/complete ISR.Quick update:
I updated the above sketch not to use the DestinationCircular and interrupt on half way to instead be a setup of two different buffers, each pointed to by a dmaSetting object and then one dmaChannel object which is setup to the same as the first setting...
I am now getting what looks like reasonable values for my averages/counts...
So I added this as an example sketch, which you can play with.
I also updated the Sine wave sketch to be mine with the ability to use a pot to adjust the amplitude... So I have a T3.5 DAC0 pin connected up to the T4 ...
So far this DMA test goes as fast as DMA will run... Have not done the timer through ADC_ETC and XBar...
Maybe first will add 2nd DAC -> other Analog pin ...
Maybe better output stuff...
void ADCL::enableDMA(int8_t adc_num)
{
if (adc_num == 1)
[COLOR="#FF0000"]adc1->enableDMA();[/COLOR]
else
adc0->enableDMA();
}
#ifdef PROCECESS_2_PINS
if ( abdma1.interrupt_delta_time && abdma2.interrupt_delta_time) {
if (abdma1.interrupt_delta_time) ProcessAnalogData(&abdma1, 0);
if (abdma2.interrupt_delta_time) ProcessAnalogData(&abdma2, 1);
Serial.println();
}
Yep. Didn't pick up the bug fix in adcl_t4.cpp. When i copied the example forgot to copy the updates to the lib. Oh I already changed the && to ||. Like you said other wise nothing prints.KurtE said:Make sure you picked up the bug fix to enableDMA in adcl_t4.cpp
@manitou - …..
What I am/was curious about, is suppose I wish to read in example 8 Analog pins, and maybe try to set them up to read 4 per ADC.
….....
The question is, do I extract the simple class I put into the sketch and make it a reasonable library class object. If so should probably clean up, probably remove direct access to variables, but instead have helper functions for set and query...Yep. Didn't pick up the bug fix in adcl_t4.cpp. When i copied the example forgot to copy the updates to the lib. Oh I already changed the && to ||. Like you said other wise nothing prints.
Now its working fine. Man its fast Looks like you got that solved. Almost time to include it in the lib and get rid of ringBuffer?
Oh, just did a wacky test. I removed the connections to pins 14 and 15 and the isr's keep firing, it keeps printing out the last values read I think. If I plug the pins back in it picks up where it started.
Was looking at "I could get ADC and PIT/XBAR to work together https://github.com/manitou48/teensy4...pitxbaradc.ino" and what it is doing is chaining A0 and A1 and then the PIT triggers using XBARA to link to ADC module the read of the of A0 and A1, think that's what you are referring to.
Of, @manitou could answer this one better.
The question is, do I extract the simple class I put into the sketch and make it a reasonable library class object. If so should probably clean up, probably remove direct access to variables, but instead have helper functions for set and query...
Yep it does make a difference otherwise things get screwy.I noticed a comment in his code that the size of buffer needed to be a power of 2
Always the best way to go. Don't change what you know works especially on the T4.When I used DMAMEM it was never showing up, when I removed DMAMEM the T4 crashed... So I went to a way that I knew works..
Looking at the RM is should work with a Software Trigger as well. There are use cases in the SDK that use a hardware trigger as well as a software trigger. Haven't looked at them yet. I did run @manitou's example and it does work well.Looks like an interesting case. In this test case using PIT to trigger, wonder if it would also work with Software trigger of the first one...
If something like this works, wonder if it would make sense to create some member function(s) to read multiple pins... Probably won't have time to look at it for a few days..
@mjs513 will cleanup...
Also may try an intervalTimer example and see if it works.
Probably won’t be the same as the main ADC library one, but simpler...
/*
This example shows how to use the IntervalTimer library and the ADC library in the Teensy 3.0/3.1
*/
#include "ADCL_t4.h"
#include <IntervalTimer.h>
const int ledPin = LED_BUILTIN;
#define SAMPLES_COUNT 512
const uint8_t ADC0_pins[] = {A0, A1};
const uint8_t ADC1_pins[] = {A2, A3};
#define COUNT_PINS_PER_ADC sizeof(ADC1_pins)
volatile uint8_t ADCPinIndex = 0;
volatile uint16_t samplesIndex = 0;
DMAMEM uint16_t samples[SAMPLES_COUNT * COUNT_PINS_PER_ADC * 2];
volatile bool timer_running = false;
volatile bool samples_completed = false;
const int interval_period = 100; // us
ADCL *adc = new ADCL(); // adc object
IntervalTimer timer; // timers
extern void timer_callback(void);
void setup() {
pinMode(ledPin, OUTPUT); // led blinks every loop
while (!Serial && millis() < 4000) ;
Serial.begin(9600);
delay(1000);
///// ADC0 ////
Serial.printf("Configure ADC 1 and 2");
adc->setAveraging(8); // set number of averages
adc->setResolution(12); // set bits of resolution
adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // change the sampling speed
adc->setAveraging(8); // set number of averages
adc->setResolution(12); // set bits of resolution
adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // change the conversion speed
adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // change the sampling speed
Serial.println("Press any key to run test");
delay(500);
}
void loop() {
// First test is to run 512 samples of each analog
if (Serial.available()) {
while (Serial.read() != -1) ;
// first pass just toggle on/off test
if (!timer_running) {
samples_completed = false;
ADCPinIndex = 0;
samplesIndex = 0;
adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
Serial.println("Starting Timer");
if (!timer.begin(timer_callback, interval_period)) {
Serial.println("Failed to start interval timer");
} else {
Serial.println("Timer started");
timer_running = true;
}
} else {
// we should try to kill the timer...
timer.end();
Serial.println("Stopped timer");
}
}
if (timer_running) Serial.println(samplesIndex, DEC);
if (samples_completed) {
Serial.println("Completed samples");
samples_completed = false; // only report once
}
delay(10);
}
//==============================================================
// Timer callbck
//==============================================================
void timer_callback(void) {
digitalWriteFast(ledPin, !digitalReadFast(ledPin));
// try to grab data from ADC_0
if (adc->adc0->isComplete()) {
samples[samplesIndex++] = adc->adc0->readSingle();
} else {
Serial.println("ADC_0: did not complete");
}
if (adc->adc1->isComplete()) {
samples[samplesIndex++] = adc->adc1->readSingle();
} else {
Serial.println("ADC_1: did not complete");
}
if (samplesIndex >= (sizeof(samples) / sizeof(samples[0]))) {
timer.end();
timer_running = false;
samples_completed = true;
} else {
ADCPinIndex++;
if (ADCPinIndex >= sizeof(ADC0_pins)) ADCPinIndex = 0;
adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
}
}
else {
Serial.println("ADC_0: did not complete");
samples[samplesIndex++] = 65535;
}