Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 22 of 22

Thread: Satus of Teensy 4.0 ADC?

  1. #1
    Senior Member
    Join Date
    Mar 2015
    Posts
    159

    Satus of Teensy 4.0 ADC?

    What is the status of Teensy 4.0 ADC support, using Teensyuino1.53 (or other version if better)

    I find the information very scattered, what is supported and not for Teensy 4.0 and how to use it correctly

    There is formal documentation for ADC.h but find it easier to find the information reading the actual files, but even with that it is difficult as they speak of many Teensy versions.

    The DMA examples I do not get running, and find them difficult too, they are trying to do too many things with too many Teensy versions.

    I thought it would be possible to set up continious reading so that it is reading many channels, but seems not It seems it can read only one pin per ADC.

    I understood that Teensy 4.0 has only one ADC, but seems to have two, I got this working and providing correct values.


    Code:
    #include <ADC.h>
    ADC *adc = new ADC();
    
    void setup() {
        adc->adc0->setAveraging( 32 ); 
        adc->adc0->setResolution( 12 );      
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::VERY_LOW_SPEED );
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::VERY_LOW_SPEED );
        delay(100);
        adc->adc0->recalibrate();
        delay(100);
        adc->adc1->setAveraging( 32 ); 
        adc->adc1->setResolution( 12 );      
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::VERY_LOW_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::VERY_LOW_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
    
        pinMode(14, INPUT_DISABLE); //Potentiometer 1 (iris)
        pinMode(15, INPUT_DISABLE); //Potentiometer 2 (focus)
        pinMode(16, INPUT_DISABLE); //Joystick X
        pinMode(17, INPUT_DISABLE); //Joystick Y
    
        
        adc->adc0->startContinuous(14);
        adc->adc1->startContinuous(15);
    
    
        delay(1000);
        uint16_t value14 = (uint16_t)adc->adc0->analogReadContinuous()/4;
        Serial.println(value14);
        uint16_t value15 = (uint16_t)adc->adc1->analogReadContinuous()/4;
        Serial.println(value15);
    }
    But would need to read 4 inputs at relatively fast rate.

    Reading them all with analogRead(pin);works, but the documentation says

    "It waits until the value is read and then returns the result. " so not nice when trying to read all channels 10 kHz, and need to do many other things also.

    Is it possible to mix analogReadContinuous(); and analogRead(pin);? I will try.

    What I really would like to have is all 4 channels read with DMA at least 100 samples, 150 times per second, possible? how?

    The 100 or more samples should distribute about evenly during the 6,6 ms sampling time, but it is ok if there is some missed samples between the 150 samplings per second as these readings would be used for weighted averaging and speed calculation, 150 times per second, it does not need to be sliding.

    While testing DMA so far I got strange hysteresis on pin 15 readings, potentiometer moves couple of degrees before changing the value. The pins are set as suggested by some who had the same problem

    pinMode(15, INPUT_DISABLE); //Potentiometer 2 (focus)

    But this does not help

    Code:
        Serial.println(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_02, BIN);//pin14
        Serial.println(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_03, BIN);//pin15
        Serial.println(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07, BIN);//pin16
        Serial.println(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_06, BIN);//pin17
    Gives the same for all pins

    10000000000111000
    10000000000111000
    10000000000111000
    10000000000111000


    I find that a bit strange as this indicates the hysteresis is active and output driver is set to strong strength, but changing these does not help to the problem. It is high quality potentiometer, but problem could be also that it is broken, but do not think so.

    about the

    adc->adc1->recalibrate();

    I added that because without that the range was 0 to 1021, now it is correctly 0 to 1023 (I do filtering with 12 bits and divide result by 4)
    Last edited by Garug; 05-24-2021 at 08:41 AM.

  2. #2
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    See :: <TD Install>\hardware\teensy\avr\libraries\ADC\index.h tml

    It is included with TeensyDuino. Not sure of last updates that may be in TD 1.54 Beta 9 or on github.

    Any problems or issues try github first.

  3. #3
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    But what exactly am I looking here

    file:///Users/.../Desktop/Teensyduino%201.53.app/Contents/Java/hardware/teensy/avr/libraries/ADC/index.html

    or here

    https://github.com/pedvide/ADC/tree/master/examples

    The guestions I have are:

    - what are the known problems with Teensy 4.0 and ACD.h
    - does Teensy 4.0 support DMA ADC with this library, where is a working example that shows how to do this. Is it possible to what is reguested above, 100 samples, 150 times per second, on 4 channels
    - Is there way the setup analogReadContinuous(); to work on 4 pins simultaneously
    - If not is there problems foreseen if configuring it for two ADC like above and reading the other two with analogRead();
    - Over all what is the best way to read 4 channels 10kHz+ each, noise vs. MCU time consumption.

  4. #4
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    The DMA examples compile but never enter setup, or at least do not print Serial.print("START"); that is right after the while (!Serial && millis() < 5000) ; when cleaning them up of all the #if defined that makes it totally unreadable for me and assuming Teensy 4.0 has dual ADC as it seems I get

    undefined reference to `AnalogBufferDMA::init(ADC*, signed char)'

    cleaned it up for one ADC but still same error and does not compile

    Code:
    
    #include <ADC.h>
    #include <DMAChannel.h>
    #include <AnalogBufferDMA.h>
    
    
    const int readPin_adc_0 = 14;
    const int readPin_adc_1 = 15;
    
    ADC *adc = new ADC(); // adc object
    const uint32_t initial_average_value = 2048;
    
    extern void dumpDMA_structures(DMABaseClass *dmabc);
    elapsedMillis elapsed_sinc_last_display;
    
    // Going to try two buffers here  using 2 dmaSettings and a DMAChannel
    
    const uint32_t buffer_size = 1600;
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);
    
    
    
    
    void setup() {
      Serial.begin(9600);
    delay(1000);
    Serial.print("START");
    
      pinMode(LED_BUILTIN, OUTPUT);
      pinMode(readPin_adc_0, INPUT); // Not sure this does anything for us
     
      pinMode(readPin_adc_1, INPUT);
     
      
      Serial.println("Setup both ADCs");
    
      adc->adc0->setAveraging(8); // set number of averages
      adc->adc0->setResolution(12); // set bits of resolution
      
    
    
      abdma1.init(adc, ADC_0/*, DMAMUX_SOURCE_ADC_ETC*/);
      abdma1.userData(initial_average_value); // save away initial starting average
    
    
      // Start the dma operation..
      adc->adc0->startSingleRead(readPin_adc_0); // call this to setup everything before the Timer starts, differential is also possible
      adc->adc0->startTimer(3000); //frequency in Hz
    
    
      Serial.println("End Setup");
      elapsed_sinc_last_display = 0;
    }
    
    void loop() {
    
      // Maybe only when both have triggered?
    
      if ( abdma1.interrupted() ) {
        if ( abdma1.interrupted()) {
          ProcessAnalogData(&abdma1, 0);
        }
      
        Serial.println();
        elapsed_sinc_last_display = 0;
      }
    
    }
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      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++;
      }
    
      int rms = sqrt(sum_delta_sq / buffer_size);
      average_value = sum_values / buffer_size;
      Serial.printf(" %d - %u(%u): %u <= %u <= %u %d ", adc_num, pabdma->interruptCount(), pabdma->interruptDeltaTime(), min_val,
                    average_value, max_val, rms);
      pabdma->clearInterrupt();
    
      pabdma->userData(average_value);
    }

  5. #5
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    Ok, so the problem was the old libraries on Teensyuino 1.53. I deleted the /ADC contents and copied the Ginthub contents there and now get it compiling and this seems to work

    Code:
    #include <ADC.h>
    #include <DMAChannel.h>
    #include <AnalogBufferDMA.h>
    
    
    const int readPin_adc_0 = 14;//define your pin here
    
    ADC *adc = new ADC(); // adc object
    const uint32_t initial_average_value = 2048;
    
    extern void dumpDMA_structures(DMABaseClass *dmabc);
    elapsedMillis elapsed_sinc_last_display;
    
    // Going to try two buffers here  using 2 dmaSettings and a DMAChannel
    
    const uint32_t buffer_size = 1600;
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);
    
    
    
    
    void setup() {
    
    delay(2000);
    Serial.println("START");
    
      pinMode(LED_BUILTIN, OUTPUT);
      pinMode(readPin_adc_0, INPUT); // Not sure this does anything for us
     
      pinMode(readPin_adc_1, INPUT);
     
      
      Serial.println("Setup ADC");
    
      adc->adc0->setAveraging(8); // set number of averages
      adc->adc0->setResolution(12); // set bits of resolution
      
    
    
      abdma1.init(adc, ADC_0);
      abdma1.userData(initial_average_value); // save away initial starting average
    
    
      // Start the dma operation..
      adc->adc0->startSingleRead(readPin_adc_0); // call this to setup everything before the Timer starts, differential is also possible
      adc->adc0->startTimer(3000); //frequency in Hz
    
    
      Serial.println("End Setup");
      elapsed_sinc_last_display = 0;
    }
    
    void loop() {
    
      
        if ( abdma1.interrupted()) {
          ProcessAnalogData(&abdma1, 0);
        
      
        Serial.println();
        elapsed_sinc_last_display = 0;
      }
    
    }
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      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++;
      }
    
      int rms = sqrt(sum_delta_sq / buffer_size);
      average_value = sum_values / buffer_size;
      Serial.printf(" %d - %u(%u): %u <= %u <= %u %d ", adc_num, pabdma->interruptCount(), pabdma->interruptDeltaTime(), min_val,
                    average_value, max_val, rms);
      pabdma->clearInterrupt();
    
      pabdma->userData(average_value);
    }
    Now the question is can it be modified to read 4 channels 6.6 ms intervals and provide good amount of samples.

  6. #6
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    I got this working surprisingly well with quick and thirty method, modifying it from the exambles. There is currently at least the problem that

    pabdma->userData(average_value);

    does not get correct average_value.

    To run this the latest version of ADC needs to be installed on Teensyuino 1.53, tested with Teensy 4.0.

    Code:
    /*4xADC with DMA
        
        using AnalogBufferDMA with two buffers, this runs in continuous mode and when one buffer fills
        an interrupt is signaled, which sets flag saying it has data, which this test application
        scans the data, and computes things like a minimum, maximum, average values and an RMS value.
        For the RMS it keeps the average from the previous set of data.
    
        This alternates the 2 available ADC for X, Y Joystick or potentiometers, so the readings are 
        not continious, but ok for reading this kind of controls
    */
    
    #include <ADC.h>
    #include <AnalogBufferDMA.h>
    ADC *adc = new ADC(); // adc object
    
    //Define your pins here
    const int readPin_adc_0 = 16;
    const int readPin_adc_1 = 17;
    const int readPin_adc_2 = 14;
    const int readPin_adc_3 = 15;
    
    const uint32_t buffer_size = 100; //how many samples per read
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff2[buffer_size];
    AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size, dma_adc2_buff2, buffer_size);
    
    
    
    bool SwapUpper = true; 
    void setup() {
        
        delay(1000);
    
        pinMode(readPin_adc_0, INPUT_DISABLE); 
        pinMode(readPin_adc_1, INPUT_DISABLE);
        pinMode(readPin_adc_2, INPUT_DISABLE); 
        pinMode(readPin_adc_3, INPUT_DISABLE);
     
        Serial.println("Setup ADC_0");
        adc->adc0->setAveraging(32); 
        adc->adc0->setResolution(12); 
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::MED_SPEED );
    
        abdma1.init(adc, ADC_0);
        abdma1.userData(2048); // initial starting average
    
        adc->adc0->startContinuous(readPin_adc_0);   
    
        Serial.println("Setup ADC_1");
        adc->adc1->setAveraging(32); 
        adc->adc1->setResolution(12); 
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::MED_SPEED );
        
        abdma2.init(adc, ADC_1);
        abdma2.userData(2048); 
        
        adc->adc1->startContinuous(readPin_adc_1);
    
        Serial.println("End Setup");
    }
    
    
    
    void loop() {
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == true) {
            adc->adc0->startContinuous(readPin_adc_0);  
            adc->adc1->startContinuous(readPin_adc_1);  
            ProcessAnalogData(&abdma1, 0);
            ProcessAnalogData(&abdma2, 1);
            SwapUpper = false;
             }
             
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == false) {
            adc->adc0->startContinuous(readPin_adc_2);  
            adc->adc1->startContinuous(readPin_adc_3);  
            ProcessAnalogData(&abdma1, 2);
            ProcessAnalogData(&abdma2, 3);
            SwapUpper = true;
            Serial.println(); }
             }
    
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      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++;
      }
    
      int rms = sqrt(sum_delta_sq / buffer_size);
      average_value = sum_values / buffer_size;
      Serial.printf(" %u <= %u <= %u  ",  min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
    
      pabdma->userData(average_value);
    }
    This reads 100 values for Joystick X and Y axis and then changes the pins and reads 100 values for potentiometers 1 and 2. So it is not continuous 4 channel reading but for the purpose ok.

    The averages have already good stability and it will improve with some advanced calculation. Currently it calculates in addition also min and max but from the data it is easy to calculate speed also etc.

    The question I have before starting implementing this to the actual aplication, is there better way to do this?

    Also I am a bit worried doing the pin change like this. It would be good if the DMA transfer stops after the set 100 samples, pin change is done correctly and then new DMA sampling for next 100 samples is started. How to do this?

  7. #7
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    Great to see you made headway.

    Time was short here and the link to the installed web page of documentation provided has links to the github where known issues will be posted as well.

    Glad the updated library was found - it is a work in progress but is generally functional with the Teensy 4.x having just two ADC units.

    Some samples have been done here - using 'lists' of pins to read in turn. That and other examples are posted on the forum.

  8. #8
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    This works now pretty nicely, but update rates are much lower than above.

    Value up to 10 000 Hz can be put to startTimer(4000); //frequency in Hz but it provides no better update-rates than 4000 Hz.

    the

    adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::LOW_SPEED );
    adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::LOW_SPEED );

    seem not to do anything

    and small error remain despite adc->adc1->recalibrate();

    is there way to use adc->adc0->startSingleRead(readPin_adc_0); so that sampling happens at natural frequency like with adc->adc1->startContinuous(readPin_adc_1);, or better the adc->adc1->startContinuous(readPin_adc_1); so that it stops after buffer is full and waits new start command?

    Code:
    /*
        reads 4 analogue channels with DMA using Teensy 4.0 also computes minimum, maximum and average
        values and stores them in MinAvgMax[4][3];.
       
    
        This alternates the 2 available ADC for X, Y Joystick or potentiometers, so the readings are 
        not continious, but ok for reading this kind of controls
    */
    
    #include <ADC.h>
    #include <AnalogBufferDMA.h>
    ADC *adc = new ADC(); // adc object
    
    //Define your pins here
    const int readPin_adc_0 = 16;
    const int readPin_adc_1 = 17;
    const int readPin_adc_2 = 14;
    const int readPin_adc_3 = 15;
    
    const uint32_t buffer_size = 10; //how many samples per read
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size);
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
    AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size);
    
    
    bool SwapUpper = true; 
    uint16_t  MinAvgMax[4][3];
    uint32_t  synchTime;
    uint16_t  SPS;
    
    
    void setup() {
        
        delay(1000);
    
        pinMode(readPin_adc_0, INPUT_DISABLE); 
        pinMode(readPin_adc_1, INPUT_DISABLE);
        pinMode(readPin_adc_2, INPUT_DISABLE); 
        pinMode(readPin_adc_3, INPUT_DISABLE);
     
        Serial.println("Setup ADC_0");
        adc->adc0->setAveraging(32); 
        adc->adc0->setResolution(12); 
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::LOW_SPEED );//do not seem to make any effect?
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::LOW_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
    
        abdma1.init(adc, ADC_0);
        abdma1.userData(2048); // initial starting average
       
        adc->adc0->startSingleRead(readPin_adc_0);
        adc->adc0->startTimer(3000); //frequency in Hz   
    
        Serial.println("Setup ADC_1");
        adc->adc1->setAveraging(32); 
        adc->adc1->setResolution(12); 
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::LOW_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::LOW_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
        
        abdma2.init(adc, ADC_1);
        abdma2.userData(2048); 
        
        adc->adc1->startSingleRead(readPin_adc_1);
        adc->adc1->startTimer(4000); //frequency in Hz
    
        Serial.println("End Setup");
    }
    
    
    
    void loop() {
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == true) {
    
            SPS = (1000000/(micros()-synchTime)); 
            Serial.printf("SPS: %d   ", SPS);
            synchTime = micros();
    
            ProcessAnalogData(&abdma1, 0);
            ProcessAnalogData(&abdma2, 1);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_2);
            adc->adc1->startSingleRead(readPin_adc_3);
            SwapUpper = false;
             }
             
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == false) {
    
    
            ProcessAnalogData(&abdma1, 2);
            ProcessAnalogData(&abdma2, 3);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_0);
            adc->adc1->startSingleRead(readPin_adc_1);
            SwapUpper = true;
            Serial.println(); }
             }
    
    
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      while (pbuffer < end_pbuffer) {
        if (*pbuffer < min_val) min_val = *pbuffer;
        if (*pbuffer > max_val) max_val = *pbuffer;
        sum_values += *pbuffer;
    
        pbuffer++;
      }
    
      average_value = sum_values / buffer_size;
      
      MinAvgMax[adc_num][0] = min_val;
      MinAvgMax[adc_num][1] = average_value;
      MinAvgMax[adc_num][2] = max_val;
    
     
      Serial.printf(" %u:  %u < %u < %u    ",  adc_num, min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
      pabdma->userData(average_value);
    }

  9. #9
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    The _SPEED chosen does have a direct effect on the ADC hardware setup to return at chosen rates. LOW_SPEED will be more limited.

    A high speed sample alternating pins on both ADC units was posted and the only in depth example I did - but not finding the code now from a year or so back - it is on the forum but not sure of search terms ...

    The usage for this case would be two pins for ADC0 and two for ADC1 - the code will read and swap continuously providing the observed values. Perhaps that would give better results in this case?

  10. #10
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    It is totally ok to read Joystick X and Y for 6 ms and then Potentiometer 1 and 2 for 6 seconds and continue like that. But I would like to have as many good samples during the 6 ms as possible so that that can be then further processed. It actually is probably better to read in burst so that the analogue pin is not switched for every read.

    The above example using the startContinuous() gives 154 samples per second and each sample has 50 readings. The data looks like this

    Click image for larger version. 

Name:	Screenshot 2021-05-24 at 21.24.21.jpg 
Views:	10 
Size:	304.8 KB 
ID:	24884

    The example using the startSingleRead() gives 150 SPS but only with 10 readings per sample. The setConversionSpeed(), setSamplingSpeed () and not even setAveraging(32) do not seem to affect the sampling speed, only the startTimer(4000); //frequency in Hz but only in few steps, 4000 provides same result as 10000. The data looks like this.

    Click image for larger version. 

Name:	Screenshot 2021-05-24 at 21.28.15.jpg 
Views:	10 
Size:	311.1 KB 
ID:	24885

    so the startContinuous() would be better to use, but I do not trust that is, by my changes, coded correctly. However both provide very good result, at 12 bit only the last bit is changing, on first picture only few times. Note though that though the average is more stabile in startContinuous() the min and max have occasional bigger jumps that indicates something went maybe wrong.(probably because the channels are changed, in middle it has possibly already started filling the other buffer.)

    Here is still both codes as there has been some changes

    Code:
    /*  Uses startContinuous();
     
        4x analogue read with DMA 
        
        using AnalogBufferDMA with two buffers, this runs in continuous mode and when one buffer fills
        an interrupt is signaled, which sets flag saying it has data, which this test application
        scans the data, and computes things like a minimum, maximum, average values and an RMS value.
        For the RMS it keeps the average from the previous set of data.
    
        This alternates the 2 available ADC for X, Y Joystick or potentiometers, so the readings are 
        not continious, but ok for reading this kind of controls
    */
    
    #include <ADC.h>
    #include <AnalogBufferDMA.h>
    ADC *adc = new ADC(); // adc object
    
    //Define your pins here
    const int readPin_adc_0 = 16;
    const int readPin_adc_1 = 17;
    const int readPin_adc_2 = 14;
    const int readPin_adc_3 = 15;
    
    const uint32_t buffer_size = 50; //how many samples per read
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff2[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size, dma_adc_buff2, buffer_size);
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff2[buffer_size];
    AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size, dma_adc2_buff2, buffer_size);
    
    
    
    bool SwapUpper = true; 
    uint16_t  MinAvgMax[4][3];
    uint32_t  synchTime;
    uint16_t  SPS;
    
    
    void setup() {
        
        delay(1000);
    
        pinMode(readPin_adc_0, INPUT_DISABLE); 
        pinMode(readPin_adc_1, INPUT_DISABLE);
        pinMode(readPin_adc_2, INPUT_DISABLE); 
        pinMode(readPin_adc_3, INPUT_DISABLE);
     
        Serial.println("Setup ADC_0");
        adc->adc0->setAveraging(32); 
        adc->adc0->setResolution(12); 
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::MED_SPEED );
    
        abdma1.init(adc, ADC_0);
        abdma1.userData(2048); // initial starting average
    
        adc->adc0->startContinuous(readPin_adc_0);   
    
        Serial.println("Setup ADC_1");
        adc->adc1->setAveraging(32); 
        adc->adc1->setResolution(12); 
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::MED_SPEED );
        
        abdma2.init(adc, ADC_1);
        abdma2.userData(2048); 
        
        adc->adc1->startContinuous(readPin_adc_1);
    
        Serial.println("End Setup");
    }
    
    
    
    void loop() {
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == true) {
    
            SPS = (1000000/(micros()-synchTime)); 
            Serial.printf("SPS: %d   ", SPS);
            synchTime = micros();
            adc->adc0->startContinuous(readPin_adc_0);  
            adc->adc1->startContinuous(readPin_adc_1);  
            ProcessAnalogData(&abdma1, 0);
            ProcessAnalogData(&abdma2, 1);
            SwapUpper = false;
             }
             
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == false) {
            adc->adc0->startContinuous(readPin_adc_2);  
            adc->adc1->startContinuous(readPin_adc_3);  
            ProcessAnalogData(&abdma1, 2);
            ProcessAnalogData(&abdma2, 3);
            SwapUpper = true;
            Serial.println(); }
             }
    
    
    
    
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      while (pbuffer < end_pbuffer) {
        if (*pbuffer < min_val) min_val = *pbuffer;
        if (*pbuffer > max_val) max_val = *pbuffer;
        sum_values += *pbuffer;
    
        pbuffer++;
      }
    
      average_value = sum_values / buffer_size;
      
      MinAvgMax[adc_num][0] = min_val;
      MinAvgMax[adc_num][1] = average_value;
      MinAvgMax[adc_num][2] = max_val;
    
      Serial.printf(" %u:  %u < %u < %u    ",  adc_num, min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
      pabdma->userData(average_value);
    }
    
    void ProcessAnalogData2(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      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++;
      }
    
      int rms = sqrt(sum_delta_sq / buffer_size);
      average_value = sum_values / buffer_size;
      Serial.printf(" %u <= %u <= %u  ",  min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
    
      pabdma->userData(average_value);
    }

    Code:
    /*  uses startSingleRead()
     
        Reads 4 analogue channels with DMA using Teensy 4.0 also computes minimum, maximum and average
        values and stores them in MinAvgMax[4][3];.
       
        This alternates the 2 available ADC for X, Y Joystick or potentiometers, so the readings are 
        not continious, but ok for reading this kind of controls
    */
    
    #include <ADC.h>
    #include <AnalogBufferDMA.h>
    ADC *adc = new ADC(); // adc object
    
    //Define your pins here
    const int readPin_adc_0 = 16;
    const int readPin_adc_1 = 17;
    const int readPin_adc_2 = 14;
    const int readPin_adc_3 = 15;
    
    const uint32_t buffer_size = 10; //how many samples per read
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size);
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
    AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size);
    
    
    bool SwapUpper = true; 
    uint16_t  MinAvgMax[4][3];
    uint32_t  synchTime;
    uint16_t  SPS;
    
    
    void setup() {
        
        delay(1000);
    
        pinMode(readPin_adc_0, INPUT_DISABLE); 
        pinMode(readPin_adc_1, INPUT_DISABLE);
        pinMode(readPin_adc_2, INPUT_DISABLE); 
        pinMode(readPin_adc_3, INPUT_DISABLE);
     
        Serial.println("Setup ADC_0");
        adc->adc0->setAveraging(32); 
        adc->adc0->setResolution(12); 
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::LOW_SPEED );//do not seem to make any effect?
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::LOW_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
    
        abdma1.init(adc, ADC_0);
        abdma1.userData(2048); // initial starting average
       
        adc->adc0->startSingleRead(readPin_adc_0);
        adc->adc0->startTimer(3000); //frequency in Hz   
    
        Serial.println("Setup ADC_1");
        adc->adc1->setAveraging(32); 
        adc->adc1->setResolution(12); 
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::LOW_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::LOW_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
        
        abdma2.init(adc, ADC_1);
        abdma2.userData(2048); 
        
        adc->adc1->startSingleRead(readPin_adc_1);
        adc->adc1->startTimer(4000); //frequency in Hz
    
        Serial.println("End Setup");
    }
    
    
    
    void loop() {
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == true) {
    
            SPS = (1000000/(micros()-synchTime)); 
            Serial.printf("SPS: %d   ", SPS);
            synchTime = micros();
    
            ProcessAnalogData(&abdma1, 0);
            ProcessAnalogData(&abdma2, 1);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_2);
            adc->adc1->startSingleRead(readPin_adc_3);
            SwapUpper = false;
             }
             
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == false) {
    
    
            ProcessAnalogData(&abdma1, 2);
            ProcessAnalogData(&abdma2, 3);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_0);
            adc->adc1->startSingleRead(readPin_adc_1);
            SwapUpper = true;
            Serial.println(); }
             }
    
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      while (pbuffer < end_pbuffer) {
        if (*pbuffer < min_val) min_val = *pbuffer;
        if (*pbuffer > max_val) max_val = *pbuffer;
        sum_values += *pbuffer;
    
        pbuffer++;
      }
    
      average_value = sum_values / buffer_size;
      
      MinAvgMax[adc_num][0] = min_val;
      MinAvgMax[adc_num][1] = average_value;
      MinAvgMax[adc_num][2] = max_val;
    
      Serial.printf(" %u:  %u < %u < %u    ",  adc_num, min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
      pabdma->userData(average_value);
    }
    Last edited by Garug; 05-24-2021 at 06:49 PM.

  11. #11
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    Found the sample I was referring to: Teensy-4-Global-vs-local-variables-speed-of-execution

    That example has two sets of pins that can be read in turn on ADC0 and ADC1 and get 25K samples per second.

    For this use case if two pins on each of ADC0 and ADC1 they could be read and be quick fast to keep after that analog values.

  12. #12
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    I am not sure if I did read long enough but looks like that uses analogueRead() that waits for the reading to be ready.

    The reason I want to use DMA is to free processor resources and keep reading even when busy doing other tasks. The reason for the about 6 ms sycle time for reading the samples with DMA is that the same MCU controls a display that runs 140 fps. The display update is now with DMA, but before update all pixels need to be calculated and that takes a lot of resources.

    I tried interrupt timer to keep consistent ADC sampling ant that works, but do not like that approach for high speed sampling with blocking analogueRead(). analogReadContinuous(); would be better, but seems to be only for one ADC at the time. Using analogReadContinuous(); with interupt timer and swapping analogue input for every read could be a solution, but really prefer if getting it to work reliably with DMA, reading 2 ADC for 3 ms as many good samples as possible and then switching the analogue channels and doing it again.

    I have not tested yet how it works with the display code, but think the above methods should work and not consume much MCU time. Should still get swapping the channels with interrupt and so that ADC clocks run at native speed, but the DMA stops after buffer is full and waits for a new start.

  13. #13
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    Yeah - that wasn't far enough into the thread: Post #55 ... Teensy-4-Global-vs-local-variables-speed-of-execution

    It seems to develop more into Post #61

    And perhaps more to post #75

    Tweaks may continue to p#77 with :: running 133,386 reads of 10 pins per second.

    Some cleanup to apply to your case and further tweaks to get the speed and accuracy as desired and picking the valid pins at hand for the ADC's that can access them

  14. #14
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    ... as far as the status of ADC - it is good and solid - just takes finding examples and reading the docs and code to see the features.

    That example at one point had a print ADC errors commented out - that will tell if the chosen ADC channel cannot access the indicated pin or other problems occur.

    Putting all 4 pins on one channel might be an option versus two each on two channels - that and speed, resolution and averaging values will help tailor the desired speed and accuracy to keep an accurate view of the reported values.

  15. #15
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    The startSynchronizedSingleRead() sounds interesting but should get that working with DMA. Maybe that is what is happening with the above /* uses startSingleRead() example, should just find how to set it so that after buffer is full there is interrupt, then I could change the analogue pins to read and start it again, in well controlled manner.

    What I would like to have is read 2 analogue inputs for 3 ms, change the inputs and read 3ms again. with this I would have the 4 channels updated every 6 ms, and hopefully around 50 to 100 samples for each channel + the 32 samples smoothing. This should happen with help of the DMA to keep the reading speed constant and reduce the MCU load.

    Then I could then synchronise the analogue reads and processing with the about 140 fps display update.

    This is how it looks now https://vimeo.com/554612698



    The 30 fps video does not quite show the smoothness of 140 fps display update

    This video is just testing the primitives. the UI will be much different, though using these elements. The changes I am now trying to do with the analogue reads is more affecting how it all works under the hood and freeing up some resources.
    Last edited by Garug; 05-25-2021 at 07:15 AM.

  16. #16
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    Have fun. It doesn't do DMA auto reading in that example, just does the read asynchronously, it starts when called and then can be checked for completion.

    Doing one on each channel then - advancing to the next pair of channel reads.

    It may not suit desired use case - but it does return many 10K's of reads per second with lots of time in between to 'cipher' the results.

    There may be other options to explore in the index.html linked - that user wanted to read 10 drum head piezos at the speed of sound to coordinate midi output.

    The someWork in that code burned up 3.5ns each cycle to simulate the 'ciphering' he might be doing on the values received.

  17. #17
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    Currently I get around 10k speeds when the MCU is not busy doing anything else. the problem is, when there is movement on the screen, there is a lot of pixels to calculate and the analogue read speeds get more to the frame rate 140 Hz and that causes problems with filtering...

    I tried the interrupt timer and that works, but not good to make that many interrupts.

    There is may ways around the problems, I hope the DMA is the solution.

  18. #18
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,796
    did you try teensythreading?

  19. #19
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    Now, but in practise how would that be different by doing it with interrupt timer?

    Could the teensythreading use the CPU time for something else while the analogueRead() waits the conversion to be ready and how well would it work when that happens 40 000 per second?

  20. #20
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    14,094
    TeensyThreads : <your install>\hardware\teensy\avr\libraries\TeensyThrea ds\readme.md

    Included in TeensyDuino from github indicated in that ReadMe

    Allows timeslice in Milli or Micro second.

    The linked code code likely put that code in loop() in a thread and read prior values and start the next async read and then thread.yield() to return exit that thread. On next entry prior data should be complete.
    > That .yield() would be done in place of :: someWork in that code burned up 3.5ns

    Using DMA - some number of reads will pile up and it seems only the last would have value.

  21. #21
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,796
    interrupt timers.... use interrupts. teensythreads shares timeslice of cpu to run multiple tasks without using interrupts. if your timer uses slow code call function everything has to wait for it... on a thread however it can take it's sweet time and allow other interrupts to work too, while sharing time slices with different tasks/loop. I've used it for 2 UART LCDs. the speed was visually faster than running in a single loop.

  22. #22
    Senior Member
    Join Date
    Mar 2015
    Posts
    159
    There was stubit mistake I had, forgot the adc->adc0->startTimer(18000); //frequency in Hz is for both separatelly and one of them was at 3000 so it was limiting also the other one.

    This is working good, it provides 155 loops in a second, each loop has 50 readings for each 4 channels. it provides good stability on readings.

    Code:
    /*  uses startSingleRead()
     
        Reads 4 analogue channels with DMA using Teensy 4.0 also computes minimum, maximum and average
        values and stores them in MinAvgMax[4][3];.
       
        This alternates the 2 available ADC for X, Y Joystick or potentiometers, so the readings are 
        not continious, but ok for reading this kind of controls
    */
    
    #include <ADC.h>
    #include <AnalogBufferDMA.h>
    ADC *adc = new ADC(); // adc object
    
    //Define your pins here
    const int readPin_adc_0 = 16;
    const int readPin_adc_1 = 17;
    const int readPin_adc_2 = 14;
    const int readPin_adc_3 = 15;
    
    const uint32_t buffer_size = 50; //how many samples per read
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc_buff1[buffer_size];
    AnalogBufferDMA abdma1(dma_adc_buff1, buffer_size);
    
    DMAMEM static volatile uint16_t __attribute__((aligned(32))) dma_adc2_buff1[buffer_size];
    AnalogBufferDMA abdma2(dma_adc2_buff1, buffer_size);
    
    
    bool SwapUpper = true; 
    uint16_t  MinAvgMax[4][3];
    uint32_t  synchTime;
    uint16_t  SPS;
    
    
    void setup() {
        
        delay(1000);
    
        pinMode(readPin_adc_0, INPUT_DISABLE); 
        pinMode(readPin_adc_1, INPUT_DISABLE);
        pinMode(readPin_adc_2, INPUT_DISABLE); 
        pinMode(readPin_adc_3, INPUT_DISABLE);
     
        Serial.println("Setup ADC_0");
        adc->adc0->setAveraging(32); 
        adc->adc0->setResolution(12); 
        adc->adc0->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );//do not seem to make any effect?
        adc->adc0->setSamplingSpeed( ADC_SAMPLING_SPEED::HIGH_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
    
        abdma1.init(adc, ADC_0);
        abdma1.userData(2048); // initial starting average
       
        adc->adc0->startSingleRead(readPin_adc_0);
        adc->adc0->startTimer(18000); //frequency in Hz   
    
        Serial.println("Setup ADC_1");
        adc->adc1->setAveraging(32); 
        adc->adc1->setResolution(12); 
        adc->adc1->setConversionSpeed( ADC_CONVERSION_SPEED::MED_SPEED );
        adc->adc1->setSamplingSpeed( ADC_SAMPLING_SPEED::HIGH_SPEED );
        delay(100);
        adc->adc1->recalibrate();
        delay(100);
        
        abdma2.init(adc, ADC_1);
        abdma2.userData(2048); 
        
        adc->adc1->startSingleRead(readPin_adc_1);
        adc->adc1->startTimer(18000); //frequency in Hz
    
        Serial.println("End Setup");
    }
    
    
    
    void loop() {
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == true) {
    
            SPS = (1000000/(micros()-synchTime)); 
            Serial.printf("SPS: %d   ", SPS);
            synchTime = micros();
    
            ProcessAnalogData(&abdma1, 0);
            ProcessAnalogData(&abdma2, 1);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_2);
            adc->adc1->startSingleRead(readPin_adc_3);
            SwapUpper = false;
             }
             
    
        if ( abdma1.interrupted() && abdma2.interrupted() && SwapUpper == false) {
    
    
            ProcessAnalogData(&abdma1, 2);
            ProcessAnalogData(&abdma2, 3);
            abdma1.clearCompletion();
            abdma2.clearCompletion();
            adc->adc0->startSingleRead(readPin_adc_0);
            adc->adc1->startSingleRead(readPin_adc_1);
            SwapUpper = true;
            Serial.println(); }
             }
    
    
    void ProcessAnalogData(AnalogBufferDMA *pabdma, int8_t adc_num) {
      uint32_t sum_values = 0;
      uint16_t min_val = 0xffff;
      uint16_t max_val = 0;
    
      uint32_t average_value = pabdma->userData();
    
      volatile uint16_t *pbuffer = pabdma->bufferLastISRFilled();
      volatile uint16_t *end_pbuffer = pbuffer + pabdma->bufferCountLastISRFilled();
    
      float sum_delta_sq = 0.0;
      if ((uint32_t)pbuffer >= 0x20200000u)  arm_dcache_delete((void*)pbuffer, sizeof(dma_adc_buff1));
      while (pbuffer < end_pbuffer) {
        if (*pbuffer < min_val) min_val = *pbuffer;
        if (*pbuffer > max_val) max_val = *pbuffer;
        sum_values += *pbuffer;
    
        pbuffer++;
      }
    
      average_value = sum_values / buffer_size;
      
      MinAvgMax[adc_num][0] = min_val;
      MinAvgMax[adc_num][1] = average_value;
      MinAvgMax[adc_num][2] = max_val;
    
      Serial.printf(" %u:  %u < %u < %u    ",  adc_num, min_val, average_value, max_val);
                    
      pabdma->clearInterrupt();
      pabdma->userData(average_value);
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •