Teensy 4.0 which pins for which ADC

Status
Not open for further replies.
@defragster - yep it would make sense to add. I mainly put in the else stuff including the is Complete as a quick and dirty test to make sure my settings were not screwed up, such that the conversion/collection time does not exceed the interval time.

I was trying to decide how far to take it, example could aim it toward the other thread, and see about, how well I could write the data out to SDCard...

Example could setup to read N channels at some rate and see how long I might be able to write to the SD card before I run out of memory... That is for example the code could allocate lets say a buffer size that works well with SDFat. When the Interval timer, fills this buffer, it will add it to a linked list of items waiting for the main loop to take items off the list and do a write to the SDCARD. In the mean time the Interval timer will look at another chain for free buffers, If none available, malloc a new one... When SDCard finishes the write, it puts that buffer onto the free list...

Question is, is this something I feel like trying or not? Likewise what format to store the data. Should all of the analog channels be interspersed, or do you write separate blocks for each analog channel. Like maybe where each block on SD has maybe has some header data like; which Analog, count, checksum? ... Or probably KISS!...

But again do I feel like doing it? I am not sure... So many other possible fun distractions. Although maybe it would test my T4's sdcard... But now need to figure out what to add to test on the 2" ST7789 display ;)
 
Just seeing if I paid enough attention to read the code right :) Maybe I'll get a chance to work with it.

I'd say super … KISsS. If there are read not ready fails - mark them for spacing and read to blocks of 512KB for SD write test would be good. Keeping the data mixed would fill usable blocks faster without having multiple active for reading into, would simplify the queueing of blocks to SD write and return for read use.

Will be interesting to see it work on a twin pair of 6's for that other 'simple' log thread
 
Yep - I have a hacked up version now, that is reasonably KISS... It compiles, but I have not tried it yet:
Code:
/*
    This example shows how to use the IntervalTimer library and the ADC library in the Teensy 4.

    It uses the SD library to try to write the data to disk.

*/
#include "ADCL_t4.h"
#include <IntervalTimer.h>
#include <SD.h>
#include <SD_t3.h>

const int ledPin = LED_BUILTIN;
//-----------------------------------------------------------------
// Define some of the analog settings, like which pins, how fast...
//-----------------------------------------------------------------
const uint8_t ADC0_pins[] = {A0, A1};
const uint8_t ADC1_pins[] = {A2, A3};
#define COUNT_PINS_PER_ADC  sizeof(ADC0_pins)

const int interval_period = 100; // us
ADCL *adc = new ADCL(); // adc object

IntervalTimer timer; // timers

//-----------------------------------------------------------------
// SD file info
//-----------------------------------------------------------------
File log_file;
char file_name[80] = "RAWANALOG.DAT";
//-----------------------------------------------------------------
// Define a link list of buffers for us to store data in
//-----------------------------------------------------------------
typedef struct _sample_buffer_t{
    volatile struct _sample_buffer_t *next;  // pointer to next one...
    uint16_t buffer[256];   // buffer of samples to write to disk 512 bytes...
} sample_buffer_t;

volatile sample_buffer_t *current_adc_buffer = nullptr;
volatile sample_buffer_t *first_buffer_to_write_to_sd = nullptr;
volatile sample_buffer_t *free_buffers = nullptr;

//-----------------------------------------------------------------
// Other globals
//-----------------------------------------------------------------
volatile uint8_t ADCPinIndex = 0;
volatile uint16_t adc_samples_buffer_index = 0;

volatile bool continue_to_collect_data = false;
volatile bool samples_completed = false;
uint32_t start_time;
uint32_t last_report_time;
uint32_t count_buffers_output;

//-----------------------------------------------------------------
// Forward references.
//-----------------------------------------------------------------
extern void timer_callback(void);


//==============================================================
// setup: Arduino setup function
//==============================================================
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");
    allocate_timer_buffer();    // make sure we have a buffer for the timer. 
    delay(500);
}

//==============================================================
// Loop: Main Arduino loop
//==============================================================
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 (!continue_to_collect_data) {
            // Lets try to open the SD File...
            log_file = SD.open(file_name, FILE_WRITE);
            if (!log_file) {
                Serial.println("*** Failed to create SD file ***");
                return;
            }

            samples_completed = false;
            ADCPinIndex = 0;

            last_report_time = start_time = millis();
            count_buffers_output = 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");
                continue_to_collect_data = true;
            }
        } else {
            // we should try to kill the timer...
            continue_to_collect_data = false;  
        }
    }

    // See if we have any data to try to write out to SD Card.
    if (first_buffer_to_write_to_sd) {
        digitalWriteFast(ledPin, !digitalReadFast(ledPin));
        volatile sample_buffer_t *buffer_to_write = first_buffer_to_write_to_sd;

        log_file.write((uint8_t*)buffer_to_write->buffer, 512); // note should parameterize size here
        count_buffers_output++;
        __disable_irq();
        first_buffer_to_write_to_sd = buffer_to_write->next;    // unlink us
        buffer_to_write->next = free_buffers;
        free_buffers = buffer_to_write;
        __enable_irq();
    } else  if (samples_completed) {
        Serial.printf("collection ended after %d seconds with output count: %d\n", millis() - start_time, count_buffers_output);
        samples_completed = false;  // only report once
    }
    if (continue_to_collect_data && ((millis()-last_report_time) > 5000)) {
        Serial.printf("Running for %d seconds output count: %d\n", millis() - start_time, count_buffers_output);
        last_report_time = millis();
    }
    delay(10);
}

//==============================================================
// allocate_timer_buffer:
//==============================================================
bool allocate_timer_buffer() {
    //__disable_irq();
    if (free_buffers) {
        current_adc_buffer = free_buffers;
        free_buffers = free_buffers->next;
    } else {
        current_adc_buffer = (sample_buffer_t*)malloc (sizeof(sample_buffer_t));
    }
    //__enable_irq();
    if (current_adc_buffer) {
        current_adc_buffer->next = nullptr;
        adc_samples_buffer_index = 0;
        return true;     
    }
    return false;
}

//==============================================================
// Timer callback
//==============================================================
void timer_callback(void) {

    if (!current_adc_buffer) {
        if (!allocate_timer_buffer()) {
            // something wrong!
            timer.end();
            continue_to_collect_data = false;
            samples_completed = true;
        }

    }
    // try to grab data from ADC_0
    if (adc->adc0->isComplete()) {
        current_adc_buffer->buffer[adc_samples_buffer_index++] = adc->adc0->readSingle();
    } else {
        Serial.println("ADC_0: did not complete");
        current_adc_buffer->buffer[adc_samples_buffer_index++] = 0xffff;
    }
    if (adc->adc1->isComplete()) {
        current_adc_buffer->buffer[adc_samples_buffer_index++] = adc->adc1->readSingle();
    } else {
        Serial.println("ADC_1: did not complete");
        current_adc_buffer->buffer[adc_samples_buffer_index++] = 0xffff;
    }

    // Again should paramertize this... 
    if (adc_samples_buffer_index == 256) {
        // Have a full buffer... 
        // Should add it to the end of the list for main code to process.
        if (first_buffer_to_write_to_sd) {
            volatile sample_buffer_t *psb = first_buffer_to_write_to_sd;
            while (psb->next) psb = psb->next;
            psb->next = current_adc_buffer;
        } else {
          first_buffer_to_write_to_sd = current_adc_buffer;
        }
        if (continue_to_collect_data) {
            if (!allocate_timer_buffer()) continue_to_collect_data = false;
        }    
        if (!continue_to_collect_data) {
            timer.end();
            samples_completed = true;
        }
    }
    if (current_adc_buffer) { // something to test to know we are still active...
        ADCPinIndex++;
        if (ADCPinIndex >= sizeof(ADC0_pins)) ADCPinIndex = 0;
        adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
        adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
    }
}
 
@KurtE
Gave it test spin. Having a problem with the SD card believe it or not. Card gets initialized but comes back that it can't create the file. So I ran the datalogger example from the SD card library and it worked fine, file created and had data in it. tried a couple of things but something is not quite right. Going to keep looking though.
 
FYI - I changed over to SDFat Beta...

Code:
/*
    This example shows how to use the IntervalTimer library and the ADC library in the Teensy 4.

    It uses the SD library to try to write the data to disk.

*/
#include "ADCL_t4.h"
#include <IntervalTimer.h>
//#include <SD.h>
#include "SdFat.h"
#define SD_FAT_TYPE 3

const int ledPin = LED_BUILTIN;
//-----------------------------------------------------------------
// Define some of the analog settings, like which pins, how fast...
//-----------------------------------------------------------------
const uint8_t ADC0_pins[] = {A0, A1};
const uint8_t ADC1_pins[] = {A2, A3};
#define COUNT_PINS_PER_ADC  sizeof(ADC0_pins)

const int interval_period = 500; // us
ADCL *adc = new ADCL(); // adc object

IntervalTimer timer; // timers

//-----------------------------------------------------------------
// SD file info
//-----------------------------------------------------------------
//File log_file;
SdFs sd;
FsFile log_file;

char file_name[80] = "datalog.txt";
//-----------------------------------------------------------------
// Define a link list of buffers for us to store data in
//-----------------------------------------------------------------
typedef struct _sample_buffer_t {
  volatile struct _sample_buffer_t *next;  // pointer to next one...
  uint16_t buffer[256];   // buffer of samples to write to disk 512 bytes...
} sample_buffer_t;

volatile sample_buffer_t *current_adc_buffer = nullptr;
volatile sample_buffer_t *first_buffer_to_write_to_sd = nullptr;
volatile sample_buffer_t *free_buffers = nullptr;
uint32_t count_buffers_allocated = 0;

//-----------------------------------------------------------------
// Other globals
//-----------------------------------------------------------------
volatile uint8_t ADCPinIndex = 0;
volatile uint16_t adc_samples_buffer_index = 0;

volatile bool continue_to_collect_data = false;
volatile bool samples_completed = false;
uint32_t start_time;
uint32_t last_report_time;
uint32_t count_buffers_output;

//-----------------------------------------------------------------
// Forward references.
//-----------------------------------------------------------------
extern void timer_callback(void);


//==============================================================
// setup: Arduino setup function
//==============================================================
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");
  allocate_timer_buffer();    // make sure we have a buffer for the timer.
  delay(500);
}

//==============================================================
// Loop: Main Arduino loop
//==============================================================
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 (!continue_to_collect_data) {
      // Lets try to open the SD File...
      if (!sd.begin(SdioConfig(DMA_SDIO))) {
        Serial.println("** SD.begin failed ***");
      }
      delay(250);
      
      if (!log_file.open(file_name, O_RDWR | O_CREAT)) {
        Serial.printf("*** Failed to create SD file (%s) ***\n", file_name);
        return;
      }

      samples_completed = false;
      ADCPinIndex = 0;

      last_report_time = start_time = millis();
      count_buffers_output = 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");
        continue_to_collect_data = true;
      }
    } else {
      // we should try to kill the timer...
      continue_to_collect_data = false;
    }
  }

  // See if we have any data to try to write out to SD Card.
  if (first_buffer_to_write_to_sd) {
    digitalWriteFast(ledPin, !digitalReadFast(ledPin));
    volatile sample_buffer_t *buffer_to_write = first_buffer_to_write_to_sd;

    log_file.write((uint8_t*)buffer_to_write->buffer, 512); // note should parameterize size here
    count_buffers_output++;
    __disable_irq();
    first_buffer_to_write_to_sd = buffer_to_write->next;    // unlink us
    buffer_to_write->next = free_buffers;
    free_buffers = buffer_to_write;
    __enable_irq();
  } else  if (samples_completed) {
    Serial.printf("collection ended after %d seconds with output count: %d\n", millis() - start_time, count_buffers_output);
    samples_completed = false;  // only report once
  }
  if (continue_to_collect_data && ((millis() - last_report_time) > 5000)) {
    Serial.printf("Running for %d seconds output count:%d buffers allocated: %d\n", millis() - start_time, count_buffers_output, count_buffers_allocated);
    last_report_time = millis();
  }
  delay(10);
}

//==============================================================
// allocate_timer_buffer:
//==============================================================
bool allocate_timer_buffer() {
  //__disable_irq();
  if (free_buffers) {
    current_adc_buffer = free_buffers;
    free_buffers = free_buffers->next;
  } else {
    current_adc_buffer = (sample_buffer_t*)malloc (sizeof(sample_buffer_t));
    count_buffers_allocated++;
  }
  //__enable_irq();
  if (current_adc_buffer) {
    current_adc_buffer->next = nullptr;
    adc_samples_buffer_index = 0;
    return true;
  }
  return false;
}

//==============================================================
// Timer callbck
//==============================================================
void timer_callback(void) {

  if (!current_adc_buffer) {
    if (!allocate_timer_buffer()) {
      // something wrong!
      timer.end();
      continue_to_collect_data = false;
      samples_completed = true;
    }

  }
  // try to grab data from ADC_0
  if (adc->adc0->isComplete()) {
    current_adc_buffer->buffer[adc_samples_buffer_index++] = adc->adc0->readSingle();
  } else {
    Serial.println("ADC_0: did not complete");
    current_adc_buffer->buffer[adc_samples_buffer_index++] = 0xffff;
  }
  if (adc->adc1->isComplete()) {
    current_adc_buffer->buffer[adc_samples_buffer_index++] = adc->adc1->readSingle();
  } else {
    Serial.println("ADC_1: did not complete");
    current_adc_buffer->buffer[adc_samples_buffer_index++] = 0xffff;
  }

  // Again should paramertize this...
  if (adc_samples_buffer_index == 256) {
    // Have a full buffer...
    // Should add it to the end of the list for main code to process.
    if (first_buffer_to_write_to_sd) {
      volatile sample_buffer_t *psb = first_buffer_to_write_to_sd;
      while (psb->next) psb = psb->next;
      psb->next = current_adc_buffer;
    } else {
      first_buffer_to_write_to_sd = current_adc_buffer;
    }
    if (continue_to_collect_data) {
      if (!allocate_timer_buffer()) continue_to_collect_data = false;
    }
    if (!continue_to_collect_data) {
      timer.end();
      samples_completed = true;
    }
  }
  if (current_adc_buffer) { // something to test to know we are still active...
    ADCPinIndex++;
    if (ADCPinIndex >= sizeof(ADC0_pins)) ADCPinIndex = 0;
    adc->adc0->startSingleRead(ADC0_pins[ADCPinIndex]);
    adc->adc1->startSingleRead(ADC1_pins[ADCPinIndex]);
  }
}
Which is showing some outputs. I changed timer interval to 500, so should interrupt 2000 times per second, with two readings, so about 4000 samples per second recorded.

I have not verified the data on the SDCARD yet, but maybe good enough to push up to github...

EDIT: Pushed example up to github... Note I am in master branch...
 
@mjs513, @defragster... I extracted my DMA processing out of my example sketch and into some external files.

I think the example app is still working OK... let me know what you think.

Kurt
 
Last edited by a moderator:
@KurtE
Been playing with the updated lib. Tried everything but the logger sketch:
1. Compare sketch works but there is an error I had to fix. Looks like you have the outdated sketch: analogReadCmp -> analogRead
2. Continuous example works, nothing broke
3. RMS sketch still works
4. DMA - doesn't seem to be working. ISR not firing - have to go back and see the old one still works.

Logger sketch - will test in the morning.

Mike
 
@KurtE - @defragster

I copied the sketch in post #106 and downloaded the latest core files as well as the latest SDFat lib. Compiled with out issue I did have to make one change;
Code:
  } else  if (samples_completed) {
    Serial.printf("collection ended after %d seconds with output count: %d\n", millis() - start_time, count_buffers_output);
    samples_completed = false;  // only report once
[COLOR="#FF0000"]  log_file.close();
  Serial.println(F("Done"));[[/COLOR]/CODE]  added log_file close, if I didn't and I ended the test the file would be empty.  But now here is the problem, the resultant text file is all gibberish - not sure what format the data is in?

EDIT:  Looking at SDfat advdatalogger example think the file created is a binary file format.
 
Last edited:
Sorry for interrupting (pun not intended), but I recently verified the following approach works on Teensy 3.2.

  • The ADCx is in software trigger mode.
  • One DMA channel is used to transfer samples from ADCx_R0 register to a DMA buffer, triggered by the DMAMUX_SOURCE_ADCx hardware trigger, i.e. whenever ADCx conversion is complete.
  • Another DMA channel is used to transfer ADC channel selectors from a circular buffer to register ADCx_SC1A ( ADCx_HC0 for Teensy 4.0). Because the ADC is in software trigger mode, this triggers a new conversion.
The interesting thing here is that no interrupts are needed at all for continuous operation, which should cause the least interference with other stuff, like SD card access.

I believe that for Teensy 3.2, TPM2 is the optimum choice to generate the trigger events for the second DMA channel. If both ADCs are used, they will sample at the same rate, using the two channels of TPM2 to choose the relative phase of the sampling triggers. I still have to verify this part and clean up the code for public view, though. The sampling is extremely regular, with minimal jitter. To use both ADCs at the same total sample rate, TPM2 and four DMA channels suffice, which is nice.

Both DMA channels can use a circular buffer. For the sample buffer, the .TCD->CITER_ELINKNO field of the DMAChannel object can be used to track the current position (assuming buffer is at most 32767 samples long, otherwise you need to link DMA channels). You do need to use a separate DMASettings object to replace the DMAChannel settings on completion for circular buffer operation. (If you use the settings in the DMAChannel itself, it will just get stuck on the last transfer.)

The sampled input pin order or density is arbitrary -- you can do e.g. [ A2, A3, A2, A12 ] to get A2 at twice the sample rate of A3 and A12 --, but the samples will be interleaved in the DMA buffer. (The source DMA buffer size is not tied to the size of the sample buffer in any way.)

When applying changes, the only race window is the possible completion of the last ADC sample. This can be avoided by stopping the timer first, then the second DMA channel, and then disabling the conversion by selecting the disable channel by writing 31 to ADCx_SC1A on Teensy 3.2 or ADCx_HC0 on Teensy 4.0, and finally stopping the first DMA channel. When starting, the timer should be enabled last. This gives a very well controlled, robust implementation.

The annoying part is to determine the mapping between pins to ADCx channels.
Code:
Teensy 3.2 analog input ADC channel mapping:

Teensyduino     Pin         ADC0 Channel    ADC1 Channel
 14 A0          PTD1         5
 15 A1          PTC0        14
 16 A2          PTB0         8               8
 17 A3          PTB1         9               9
 18 A4          PTB3        13
 19 A5          PTB2        12
 20 A6          PTD5         6
 21 A7          PTD6         7
 22 A8          PTC1        15
 23 A9          PTC2         4
 34 A10         ADC0_DP0     0
 35 A11         ADC0_DM0    19
 36 A12         ADC0_DP3     3               0
 37 A13         ADC0_DM3    21              19
 40 A14         DAC0        23
 26 A15         PTE1       (Not supported, would require MUXSEL=0)
 27 A16         PTC9                         5
 28 A17         PTC8                         4
 29 A18         PTC10                        6
 30 A19         PTC11                        7
 31 A20         PTE0       (Not supported, would require MUXSEL=0)
 38             TEMP        26              26
                BANDGAP     27              27
                VREFH       29              29
                VREFL       30              30
                1.2VREF     22              18

PGA uses channel 2 for both ADCs.

I do also have a 4.0 and according to the datasheet, the same approach works there; I just haven't verified it in practice.
Code:
Teensy 4.0 analog input ADC channel mapping:

Teensyduino     Pin         ADC1 Channel    ADC2 Channel
 14 A0          AD_B1_02     7               7
 15 A1          AD_B1_03     8               8
 16 A2          AD_B1_07    12              12
 17 A3          AD_B1_06    11              11
 18 A4          AD_B1_01     6               6
 19 A5          AD_B1_00     5               5
 20 A6          AD_B1_10    15              15
 21 A7          AD_B1_11     0               0
 22 A8          AD_B1_08    13              13
 23 A9          AD_B1_09    14              14
 22 A10         AD_B0_12     1
 23 A11         AD_B0_13     2
 23 A12         AD_B1_14                     3
 24 A13         AD_B1_15                     4

Has anyone collated similar tables for LC, 3.0/3.1, 3.5, and/or 3.6?

If you were already well aware of this method, apologies for stating the obvious! :eek:
Perhaps we could format the information in nice tables for a sticky post or a Teensyduino Reference page at the PJRC website?
 
Last edited:
@KurtE - @defragster

I copied the sketch in post #106 and downloaded the latest core files as well as the latest SDFat lib. Compiled with out issue I did have to make one change;
Code:
  } else  if (samples_completed) {
    Serial.printf("collection ended after %d seconds with output count: %d\n", millis() - start_time, count_buffers_output);
    samples_completed = false;  // only report once
[COLOR="#FF0000"]  log_file.close();
  Serial.println(F("Done"));[[/COLOR]/CODE]  added log_file close, if I didn't and I ended the test the file would be empty.  But now here is the problem, the resultant text file is all gibberish - not sure what format the data is in?

EDIT:  Looking at SDfat advdatalogger example think the file created is a binary file format.[/QUOTE]
Yep - Thanks, I forgot to put the close in... 

Yep - Currently a binary format, 2 bytes per sample.   

Obviously we could hack this up more to have something like a CSV file.   Would add a little complexity of not having buffers fill the same, probably keep a size field in the buffer structure, and either tell system to write them when they are filled or at some percentage full, ... Do you think it would make it more useful as an example?  Could make it a choice in the code...
 
@nominal animal - DMA examples - There is sort of an example for doing DMA with both ADCs that is part of the ADC library

There are issues, with the ringBufferDMA as part of that project... I had my own code for T3.5/6 that used the DMA with a PDB... with two on each one, that I toggled between...

Still working on T4 stuff in our probably temporary project ADCL_t4, where I have my own DMA buffer class...
As for interrupts, I do have this code setup to interrupt as each buffer is completed. One could set this up to not interrupt and do query, but I don't think one interrupt per in the case I was playing at something like 3000 samples is going to be too bad.

Analog IO pins: Have you looked at the main forum page that Pedro setup for the ADC library? https://forum.pjrc.com/threads/25532-ADC-library-update-now-with-support-for-Teensy-3-1
If you scroll down the page, there is a section talking about pins.


I also have some of my own excel documents, which I have done during each of the more recent beta time frames that are now up at: https://github.com/KurtE/TeensyDocuments
The T4 document has a column that shows the Analog pins. like 14/A0 pin is on A1:7 and A2:7 ...

The K66 Beta file (T3.6/T3.5) has sheets labeled like Pin Mux Table T3.6, and in this it shows for example: Pin 14: ADC0_SE5b Which you can deduce the data from...
 
Yep - Thanks, I forgot to put the close in...

Yep - Currently a binary format, 2 bytes per sample.

Obviously we could hack this up more to have something like a CSV file. Would add a little complexity of not having buffers fill the same, probably keep a size field in the buffer structure, and either tell system to write them when they are filled or at some percentage full, ... Do you think it would make it more useful as an example? Could make it a choice in the code...

Probably need to hack it up to write it as a CSV file, would be easier to the read the data from the file. The other possibility is that I started hacking up Bill G's code to read a binary file and the write a csv or view the data. Having a problem with the SD card. Also not 100% sure about what the metadata is. Problem it is not seeing any files on the card. Here it is if you want to play:

View attachment AdvDataLoggerRead.zip

meta data is really then 2bytes per pincount. so for adc0 and adc1 pincount = 4 would be 4x2. And that is all that is being written.
 
@mjs513 - Yep I am hacking up my example sketch to allow it to either output CSV or raw...
Would make it easier to look at...
 
@mjs513, @defragster...- I updated the test program, to give option to output binary or CSV files.

Also allows you to type in name of file...
If first character of line is a , the file will output CSV.
If first char is # it will output binary.

Characters after that are file name.
Simply entering CR - will default to last file name and last format...
 
@KurtE
Download and ran updated sketch - no issues. Compiled out of the box. Used ",datalog.csv" to create a csv.
Code:
Configure ADC 1 and 2Press any key to run test

If line starts with , -> CSV file, # -> binary file, followed by optional filename

Output to datalog.csv CSV:1
Starting Timer

Timer started

Running for 5005 seconds sample count: 10009 buffer output count:131 buffers allocated: 2
Running for 10007 seconds sample count: 20013 buffer output count:262 buffers allocated: 2
Running for 15008 seconds sample count: 30017 buffer output count:393 buffers allocated: 2
Closing down sampling

collection ended after 18351 seconds sample Count:36642 with buffer output count: 481

Opened csv file in excel and data looked good. I did make one change though:
Code:
output_bytes_to_csv_buffer("\n\r");
changed to
Code:
output_bytes_to_csv_buffer("\n");
other wise you get an extra blank line in the excel file or whatever you are using to read the csv file

EDIT: Guess now back to DMA.
 
@mjs513 - Updated (\n)

I did a quick check back to your WIP branch and as far as I can tell everything in master is up to date with changes there?

Sounds good!
 
I agree - all compare stuff is in there from what I can except for the example: T4_ADC_Compare:

this line:
Code:
value = adc->analogReadCmp(pin_cmp, 0);
needs to change to
Code:
value = adc->analogRead(pin_cmp, 0);

EDIT: Been playing around ring buffer DMA sketch. The dma ISR never fires. I just ran it on the T3.6 (ADC Lib version - and looked like the buffer was updating) - strange.
 
Looks promising! Will get to it shortly and double check. Was using laptop at TV so just happy to get the twin sets of three reading fast and not bother yet with the SD. Will double check the libs here at desk.
 
Warning I have not done anything with the T4_ADC_ringBufferDMA sketch yet... Maybe I should make at least a partial fix to this one...

I have/had my own example: Tr_ADC_DMA_RMS, which I extracted my own buffer class, which still appears to run...

With my RMS, I keep meaning to make change to it, to remember the average value from previous pass, as a way to get better data process....

Edit: actually it sort of runs...

That is if you first type in: s<cr>
It will start up DMA.

Then if you type in: c<cr>
It will start the conversions, which will then call then start calling the dma buffer...

At which point it will endlessly give you these call backs...

You then run into all of the issues of the CircularBufferDMA code, like who turns it on/off...
Like functions like read, isEmpty, isFull make no sense as there is no real buffer code here... Just setup of DMA operation which interrupts on halfcomplete and complete. Also issues, like the top half of memory does not get data...

Some if can probably be fixed, but not sure what would be wanted, which is why I did that different class...
 
Last edited:
Yeah. The analogbufferdma works no issue. The RingbufferDMA is the one that I can’t seem to get to work. Probably something simple .
 
Got logged CSV data files from ...\ADCL_t4\Examples\T4_analogReadMultiIntervalTimer\T4_analogReadMultiIntervalTimer.ino with:
Code:
const uint8_t ADC0_pins[] = {16,17,20};
const uint8_t ADC1_pins[] = {21,26,27};
//...
const int interval_period = 30; // us
//…
    adc->setAveraging(2); // set number of averages

Didn't hook any known input values - so far floating pins:
Output to foo.csv CSV:1
Starting Timer
Timer started
collection ended after 16603 seconds sample Count:127317 with buffer output count: 1246

Now to set input values and look at data ...
 
Status
Not open for further replies.
Back
Top