channel linking 6 adc channels using dma controller

Status
Not open for further replies.

1.618

Member
Hello, I really appreciate everyone that helps us inexperienced programmers on here. I'm starting a project using a 3.6 and I have no code yet because I'd like to hear any input on where to start and maybe see other projects/threads that would help me get off the ground. I have had no luck so far finding any projects on here like what I'm starting.
My project is a 3 phase power meter that will be sampling 6 sine waves using ADC0. From what I have learned so far is to use freqmeasure to continuously capture the time between rising edges of the digital sync pin and use that period to set the pdb to trigger the adc channel linking 128 times(size buffer) per cycle. I would like to store each channels result to a buffer for math to be done once all buffers are filled. i.e RMS, power etc.

Thank you for taking your time, any help guidance would be greatly appreciated.

-Chris
 
I would start by doing some timing tests to determine how fast you can collect data. Doing captures sequentially will introduce phase errors that you need to know. Here's a sketch to see how fast you can collect and store data and from one channel. Also, the T3 and T4 series allow dual synchronized ADCs which you will likely want to use. One ADC can read an A/C input value while the other can read the output from the same phase line.

Code:
// ADC_Speed_Test
#include <ADC.h>                        // ADC internal routines
#include <ADC_util.h>                   // ADC support

// Define constants
#define TEENSY_DELAY    3000            // Serial port does not start immediately
#define READ_PIN        A2              // Left ADC read pin
#define BAUD            115200          // Really fast
#define CYCLES          1000            // Test times through loop

uint16_t    result;                     // Data from ADC
uint32_t    nowTime;                    // CPU present time 
uint16_t    data[CYCLES];               // Data results
ADC *adc = new ADC();                   // ADC object

void setup() {
    Serial.begin( BAUD );               // Start the serial port
    while ( !Serial && ( millis() < TEENSY_DELAY ) );   // Wait for serial connect
    delay( 10 );                        // Let things settle
    
    ///// ADC0 ////
    adc->adc0->setAveraging( 3 );       // Set number of averages
    adc->adc0->setResolution( 12 );     // Set bits of resolution
    // Change the conversion speed
    adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::HIGH_SPEED );
    // Change the sampling speed 
    adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::HIGH_SPEED );
}

void loop() {
    nowTime = micros();                         // Remember the time
    for( uint16_t i; i < CYCLES; i++ )          // Do a bunch for averaging
    {
        data[i] = adc->analogRead( READ_PIN );  // Read and storee
    }
    Serial.println( float( micros() - nowTime ) / float( CYCLES ), 3 ); // usec
    while( 1 ){};                               // Stall here
}
 
Good morning Eddie, I will be using ADC1 for other sampling down the line for things not so time sensitive so I would like to keep that module free. I have done some benchmark testing using just adc->adc0->analogread() on each of the 6 pins using a loop to go though the pins using intervalTimer and there was more than enough time to do all the samples but because the cpu was handling everything, the math being at the end of the cycle caused it to step on itself.
So I would now like to have the ftm, pdb, adc and dma handing all the sampling and putting the values in the buffers while the cpu does the math at the end of each cycle.
 
That should work fine. If the math is float intensive then consider the T4 with the internal FPU. One thing I've found strange is that the ADC sync example does not work if you use A2 and A9 as shown. However, A2 and A3 are OK. This is the case with the T3.2, T3.6, and T4.0.

My present projects do the same kind of thing with a T4 in that they collect dual ADC data, process, and output via DAC while running as fast as possible. One project is a digital stereo hearing aid and the other is a dual side scan sonar. The T4 does all the work with minimal supporting chips.
 
I like the t4 but it just doesn't have enough pins for my project so until I can learn to work with multiplexers I'm stuck with the 3.6 for the moment. Do you happen to have a public github with your projects that I could poke around? I will also have 3 pwm outputs for harmonic correction which I also want to be handled by dma.
Thank you for your time.
 
The T3.6 will probably handle your project nicely. Watch for updates as the T4.1 is due shortly. It has nearly all of the pins brought out to the board edge like the T3.6. You could develop your project on the T3.6 then switch over to the T4.1 with minimal changes.

I don't have a public github as my projects change several times a day. Today i finished the sliding partial window DFT filter for the sonar and tomorrow I'll add the CHIRP transmit and detection function.
 
Thank you, I will keep and eye on that thread.

Bare with me for a second, the period of 60Hz is 16.6ms which that period is captured by the flexTimer using edge capture mode. If I prescaled that by 128 I would get 129.6875μs.

My thought is every time a rising edge is flagged, the pit or pdb(whatever is better?) triggers the dma to get the result from ADC0_SE5b and put it into an array and then repeat with ADC0_SE14 and so on for all six adc channels then do nothing until the 129.6875μs pre triggered time is triggered and the chain starts again but pointing at the next address in each array filling 6 arrays of 128. Once the 6 arrays are filled, the cpu can do the math that I will need to print on the tft.

If you have a few moments could you pseudocode what you would do if this is what you had to do. I understand it can all be handled by the tcd and dmamux from countless hours on nxp forums but unfortunately my only way to learn this chip is asking a million trivial questions trying to piece things together because there is no tutorials on youtube or udemy or google for working with this chip and its peripherals that I have found.
 
Unfortunately, I have little experience using DMA or internal hardware register commands so can't help much there. There are several members on this forum that can steer you in the right direction. There are also some examples in the IDE file/examples menu for Teensy/ADC using timers and DMA. The examples are short so you might be able to combine some of the code.

Have you tried a timing test to see how long it takes to capture and store an ADC value sequentially from six sources via the internal multiplexer?
 
Status
Not open for further replies.
Back
Top