Forum Rule: Always post complete source code & details to reproduce any issue!
Page 17 of 17 FirstFirst ... 7 15 16 17
Results 401 to 416 of 416

Thread: ADC library update, now with support for Teensy 3.1

  1. #401
    Junior Member
    Join Date
    Apr 2018
    Posts
    4
    Hello ,

    I am looking to use Teensy 3.2 with the ADC to acquire data, to then run some signal processing. I read the thread, and trid to find relevant information with the search engine, but I failed.

    I need accurate sample timing, as for any signal processing data, and from what I read in the thread, it means using PDB. For this there are some good examples for this nice libraries.
    Ideally, a DMA memory transfer would be nice to have.

    I found an example with the DMA + ring buffer, but I didn't find examples with DMA+ring buffer + ADC triggered using PDB.
    Does any of you do have such an example?

    I did not fully understood how the ADC was trigerred in the DMA example . Free running ADC, and DMA stores as soon as a sample is available? Is this correct?

    Thanks a lot, and thanks to PEDVIDE for his awsome work.

    Olivier.

  2. #402
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,688
    @Paul, @Pedvide - Not sure what version of sources are in current beta. Some of the test cases did not compile, I edited one and adc_pdb and when I compared my possible push up to github, it showed more differences... So don't think the current beta release matches github\pedvide master? - Code is using old way to specify speeds...

    Also when I tried the ringbuffer DMA example it did not appear to do any conversions... I have not debugged...

    As I mentioned in the Well monitoring thread, I am playing around with my own version (@hobi not sure if this one will work for you or not).

    When I converted to try to use both ADC0 and ADC1 using DMA and PDB, it worked first time, hung second time. Figured out a fix that got it to work... Wonder if maybe should update ADC stopPDB method to zero out the appropriate(PDB0_CH1C1 or PDB0_CH0C1), doing that allowed it to work multiple times.

    Not sure if anyone will find this version interesting or not... Again WIP...
    Code:
    #include <ADC.h>
    #include <DMAChannel.h>
    #define BUFFER_SIZE 100
    
    ADC adc;
    
    // Variables for ADC0
    volatile DMAMEM uint16_t adc0_buf[BUFFER_SIZE]; // buffer 1...
    volatile uint8_t adc0_busy = 0;
    DMAChannel adc0_dma;
    
    // Variables for ADC1
    volatile DMAMEM uint16_t adc1_buf[BUFFER_SIZE];
    volatile uint8_t adc1_busy = 0;
    DMAChannel adc1_dma;
    
    // References for ISRs...
    extern void adc0_dma_isr(void);
    extern void adc1_dma_isr(void);
    
    
    void setup() {
      while (!Serial && millis() < 3000) ;
      Serial.begin(115200);
      Serial.println("Test DMA Analog Read");
    
      // Initialize the
      adc.setAveraging(4);
      adc.setResolution(12);
      adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_0); // change the conversion speed
      adc.setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_0); // change the sampling speed
    
    
      adc.setAveraging(4, ADC_1);
      adc.setResolution(12, ADC_1);
      adc.setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED, ADC_1); // change the conversion speed
      adc.setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED, ADC_1); // change the sampling speed
      Serial.printf("First Read of A13: %d\n", adc.analogRead(A13));
      Serial.printf("First Read of A14: %d\n", adc.analogRead(A14));
      Serial.printf("First Read of A15: %d\n", adc.analogRead(A15));
      Serial.printf("First Read of A16: %d\n", adc.analogRead(A16));
    
      // Lets setup Analog 0 dma
      adc0_dma.source((volatile uint16_t&)ADC0_RA);
      adc0_dma.destinationBuffer(adc0_buf, sizeof(adc0_buf));
      adc0_dma.triggerAtHardwareEvent (DMAMUX_SOURCE_ADC0);
      adc0_dma.interruptAtCompletion();
      adc0_dma.disableOnCompletion();
      adc0_dma.attachInterrupt(&adc0_dma_isr);
      NVIC_DISABLE_IRQ(IRQ_PDB); // we don't want or need the PDB interrupt
    
    
      // Lets setup Analog 1 dma
      adc1_dma.source((volatile uint16_t&)ADC1_RA);
      adc1_dma.destinationBuffer(adc1_buf, sizeof(adc1_buf));
      adc1_dma.triggerAtHardwareEvent (DMAMUX_SOURCE_ADC1);
      adc1_dma.interruptAtCompletion();
      adc1_dma.disableOnCompletion();
      adc1_dma.attachInterrupt(&adc1_dma_isr);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      Serial.println("Enter any key to run sample");
      while (Serial.read() == -1) ;
      while (Serial.read() != -1) ;
      Serial.println("Start Sample");
      memset((void*)adc0_buf, 0, sizeof(adc0_buf));
      memset((void*)adc1_buf, 0, sizeof(adc1_buf));
      uint32_t start_time = millis();
    
      // Start 0
      adc0_busy = 1;
      adc1_busy = 1;
      adc.adc0->startSingleRead(A14);
      adc.adc1->startSingleRead(A13);
      adc0_dma.enable();
      adc1_dma.enable();
      adc.enableDMA(ADC_0);
      adc.enableDMA(ADC_1);
      adc0_dma.enable();
      adc1_dma.enable();
      adc.adc0->startPDB(60 * 50);
      adc.adc1->startPDB(60 * 50);
    
      dumpDMA_TCD("ADC_0", &adc0_dma);
      dumpDMA_TCD("ADC_1", &adc1_dma);
    
      while (adc0_busy || adc1_busy) {
        if ((millis() - start_time) > 1000) {
          Serial.printf("Timeout %d %d\n", adc0_busy, adc1_busy);
          break;
        }
      }
      
      PDB0_CH1C1 = 0;
      PDB0_CH0C1 = 0;
    
      adc.adc0->stopPDB();
      adc0_dma.disable();
      adc.disableDMA(ADC_0);
      adc0_dma.disable();
    
      adc.adc1->stopPDB();
      adc.adc1->stopPDB();
      adc1_dma.disable();
      adc.disableDMA(ADC_1);
    
      dumpDMA_TCD("ADC_0", &adc0_dma);
      dumpDMA_TCD("ADC_1", &adc1_dma);
    
      Serial.printf("Sample completed: %d\n", millis() - start_time);
      for (int i = 0; i < BUFFER_SIZE; i++) {
        Serial.printf("%4u ", adc0_buf[i]);
        if ((i % 20) == 19) Serial.println();
      }
      Serial.println("\n");
    
      for (int i = 0; i < BUFFER_SIZE; i++) {
        Serial.printf("%4u ", adc1_buf[i]);
        if ((i % 20) == 19) Serial.println();
      }
      Serial.println();
    
    
    }
    
    
    void adc0_dma_isr(void)
    {
      adc0_busy = false;
      adc0_dma.clearInterrupt();
      adc0_dma.clearComplete();
    }
    
    void adc1_dma_isr(void)
    {
      adc1_busy = false;
      adc1_dma.clearInterrupt();
      adc1_dma.clearComplete();
    }
    
    
    
    typedef struct  __attribute__((packed, aligned(4))) {
      uint32_t SADDR;
      int16_t SOFF;
      uint16_t ATTR;
      uint32_t NBYTES;
      int32_t SLAST;
      uint32_t DADDR;
      int16_t DOFF;
      uint16_t CITER;
      int32_t DLASTSGA;
      uint16_t CSR;
      uint16_t BITER;
    } TCD_DEBUG;
    
    void dumpDMA_TCD(const char *psz, DMABaseClass *dmabc)
    {
      Serial.printf("%s %08x %08x:", psz, (uint32_t)dmabc, (uint32_t)dmabc->TCD);
      TCD_DEBUG *tcd = (TCD_DEBUG*)dmabc->TCD;
      Serial.printf("%08x %04x %04x %08x %08x ", tcd->SADDR, tcd->SOFF, tcd->ATTR, tcd->NBYTES, tcd->SLAST);
      Serial.printf("%08x %04x %04x %08x %04x %04x\n", tcd->DADDR, tcd->DOFF, tcd->CITER, tcd->DLASTSGA,
                    tcd->CSR, tcd->BITER);
    
    }
    Adding the lines in RED was what got it to work multiple times... Now back to next part of what I mentioned in well monitor...

  3. #403
    Junior Member
    Join Date
    Apr 2018
    Posts
    4
    KurtE,

    I will have a look, but I think it will help.

    I have one basic question. For me the dma should work fully in the background without any cpu need. Do we really need to have an adc isr ?? As long as we have that Adc isr executing it removes the whole point of having a dma running in the background.... do I get it right?

    Hobi

  4. #404
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,688
    Hi, if you are talking about my two interrupts:
    Code:
    void adc0_dma_isr(void)
    {
      adc0_busy = false;
      adc0_dma.clearInterrupt();
      adc0_dma.clearComplete();
    }
    
    void adc1_dma_isr(void)
    {
      adc1_busy = false;
      adc1_dma.clearInterrupt();
      adc1_dma.clearComplete();
    }
    I asked for them. In particular I asked for 100 elements to be read. These ISRs are called when those 100 reads are done.. If you don't want the interrupt, you don't need to ask for them.

    Example in the code that asks for them: adc0_dma.interruptAtCompletion();

  5. #405
    Junior Member
    Join Date
    Apr 2018
    Posts
    4
    OOOps, you are right,

    I got confused with the naming. These are DMA interrupts, not ADC ones! Ok, very clear. Thanks for the reply!

    Olivier.
    Last edited by hobi; 04-06-2018 at 08:01 AM.

  6. #406
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    3,688
    You are welcome... And in this case, the code could have also enabled interrupts for the PDB as well... Some turn these on during debug, in order to be able to monitor when the ADC is being triggered... I do not have these enabled...

  7. #407
    Senior Member Epyon's Avatar
    Join Date
    Apr 2013
    Location
    Belgium
    Posts
    443
    I also have a question regarding the interrupts. I need to sample both ADCs simultaneously at fixed intervals. I looked into the analogReadIntervalTimer example. This however uses only one ADC to multiplex two pin readings, which has me confused about how to trigger an interrupt when using both ADCs.

    The examples uses a function called adc0_isr() to process the results when the conversion is done, but nowhere does the sketch indicate when this particular function should be called. Does the library assume you name the ISR function this way? And what if you only want to trigger the ISR when both ADC conversions are done? enableInterrupts(ADC_x) requires you to specifically declare which ADC you want to fire the interrupt.

  8. #408
    Junior Member
    Join Date
    Apr 2018
    Posts
    4
    Hi folks,

    Just wanted to be sure the simple code i wrote does what it intends to do. Simple single ended ADC acquisition at 6000Hz, precisely timed, for signal processing.

    Thank you for your help.

    Here is the code :

    Code:
    #define BTSERIAL Serial1
    #include <ADC.h>
    
    const int readPin = A14; // ADC0
    ADC *adc = new ADC(); // adc object;
    boolean inc=true, led = false, nval=false;
    int value, val=0;
    uint32_t ifreq = 6000; // ADC sampling frequency 6000Hz
    
    
    void setup() {
    Serial.begin(230400);
    BTSERIAL.begin(230400);
    pinMode(LED_BUILTIN, OUTPUT);
    pinMode(readPin, INPUT);
    Serial.println("Begin setup");
    
    ///// ADC0 only ////
    adc->setAveraging(32); // set number of averages
    adc->setResolution(16); // set bits of resolution
    adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0);
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::MED_SPEED); // change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::MED_SPEED); // change the sampling speed
    
    Serial.print("Start pdb 6000Hz ");
    adc->adc0->stopPDB();
    adc->adc0->startSingleRead(readPin); // call this to setup everything before the pdb starts, differential is also possible
    adc->enableInterrupts(ADC_0);
    adc->adc0->startPDB(ifreq); //frequency in Hz
       
     Serial.println("End setup");
    }
    
    void loop() 
    {
        if (nval)
        {
          Serial.write((char)(0x00ff&&value));
          Serial.write(((char)(value>>8)));
          BTSERIAL.write((char)(0x00ff&&value));
          BTSERIAL.write(((char)(value>>8)));
          nval = false;
          digitalWrite(LED_BUILTIN,led);
          led = !led;    
        }   
    }
    
    void adc0_isr() {
        // Goal is to read very accurately at 6000Hz the ADC to get as accurate as possible the sample timing. Hence using PDB.
        // Serial outputs are likely to interfere as they are interrupt driven, and were mooved to the main loop.
        // readSingle as a result of PDB trigerring the conversion
        value = (uint16_t)adc->adc0->readSingle();
        nval = true;
    }
    
    void pdb_isr(void) 
    {
            PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
    }
    Last edited by defragster; 06-17-2018 at 08:56 AM. Reason: Added # Code tag for readability

  9. #409
    Junior Member
    Join Date
    Aug 2018
    Posts
    1

    ADC bug or ...?

    Hello to all.

    I little modified previous code ,and put to ADC input A4 not DC coupled 10Hz sinus ~170mVpp with midpoint 1,65V offset.
    Output sinus on DAC has strange distortion - it seems like jump adc value in two points !
    Teensy 3.5 board.

    Code:
    #include <ADC.h>
    
    const int readPin = A4; // ADC0=A14
    ADC *adc = new ADC(); // adc object;
    boolean inc=true, led = false, nval=false;
    int value, val=0;
    uint32_t ifreq = 60000; // ADC sampling frequency 6000Hz, MAX is 250khz
    
    
    void setup() {
    
    pinMode(readPin, INPUT);
    analogWriteResolution(12);
    
    ///// ADC0 only ////
    adc->setAveraging(0); // set number of averages
    adc->setResolution(12); // set bits of resolution
    adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0);
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIGH_SPEED); // change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SPEED); // change the sampling speed
    
    adc->adc0->stopPDB();
    adc->adc0->startSingleRead(readPin); // call this to setup everything before the pdb starts, differential is also possible
    adc->enableInterrupts(ADC_0);
    adc->adc0->startPDB(ifreq); //frequency in Hz
       
    }
    
    void loop() 
    {
        analogWrite(A21, value);
    }
    
    void adc0_isr() {
        // Goal is to read very accurately at 6000Hz the ADC to get as accurate as possible the sample timing. Hence using PDB.
        // Serial outputs are likely to interfere as they are interrupt driven, and were mooved to the main loop.
        // readSingle as a result of PDB trigerring the conversion
        value = (uint16_t)adc->adc0->readSingle();
        nval = true;
    }
    
    void pdb_isr(void) 
    {
            PDB0_SC &=~PDB_SC_PDBIF; // clear interrupt
    }

  10. #410
    Junior Member
    Join Date
    Aug 2018
    Posts
    1
    @KurtE Thank you very much for your simple fix of how to stop PDB by zeroing PDB0_CH0C1. My project using Teensy 3.2 finally!!!! works reliably without random hanging. It probably should be a part of stopPDB() ...

    p.s. I also suggest @Pedvide to include your code from post #402 as an easy to understand and nice example of using ADC with PDB and DMA... I was struggling to find something like this for a long time...
    Last edited by cyboff; 08-30-2018 at 09:39 AM.

  11. #411
    Actually I have teensy 3.1 boards. I just had the setting for the ide on 3.0 for testing if it would compile.
    For the actual project I will not need synchronous ADC.
    Pedro should get the feedback. That's al

  12. #412
    Junior Member
    Join Date
    Sep 2018
    Posts
    5
    Hello

    I have a question. I'm using teensy 3.6 and ADC, i would like to increase the speed of reading. I read a Voltage for one second and i get allwasy 13750-13760 Sample. It is 12 Bit.
    My code
    #include <ADC.h>

    volatile int elapsed;
    int readPin = A9; // ADC0
    ADC *adc = new ADC();; // adc object
    int value1 = 0;

    void setup() {

    //pinMode(LED_BUILTIN, OUTPUT);
    pinMode(readPin, INPUT);
    Serial.begin(9600);
    adc->setAveraging(0, ADC_0); // set number of averages
    adc->setResolution(12, ADC_0); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPE ED, ADC_0); // , change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::LOW_SPEED, ADC_0); // change the sampling speed
    while(!Serial){};
    }

    void loop() {
    elapsedMicros elapsed;
    while (elapsed <= 1000000)
    {
    value1 = adc->adc0->analogRead(readPin);
    Serial.println(value1);
    }
    exit(0);
    }
    I tried also

    #include <ADC.h>

    ADC *adc = new ADC();; // adc object
    volatile int elapsed;
    int readPin = A9; // ADC0
    int value = 0;

    void setup() {

    //pinMode(LED_BUILTIN, OUTPUT);
    pinMode(readPin, INPUT);
    Serial.begin(9600);
    adc->setAveraging(0); // set number of averages
    adc->setResolution(12); // set bits of resolution
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIG H_SPEED); // , change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SP EED); // change the sampling speed
    adc->startContinuous(readPin, ADC_0);
    while(!Serial){};
    }

    void loop() {
    elapsedMicros elapsed;
    while (elapsed <= 1000000)
    {
    value = (uint16_t)adc->analogReadContinuous(ADC_0); // the unsigned is necessary for 16 bits, otherwise values larger than 3.3/2 V are negative!
    Serial.println(value, DEC);
    }
    exit(0);
    }
    But the result is exactly the same.
    And it doesn't matter if i change Speed to VERY_HIGH_SPEED or to LOW_SPEED it is always 13.7 k
    adc->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPE ED, ADC_0);
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED , ADC_0);
    Do you have any idea how can i speed up it?

  13. #413
    Junior Member
    Join Date
    Sep 2015
    Location
    Mechelen, Belgium
    Posts
    15
    Hello,

    Looking at your code I see some strange "spaces" in the lines where you set the Conversion speed & Sampling speed.
    Is this also in your actual code? Do you get compiler warnings/errors?

    Regards, Otto

  14. #414
    Junior Member
    Join Date
    Sep 2018
    Posts
    5
    No, there is no spaces, i see it here too.

    Thats how it look like:

    adc->setConversionSpeed(ADC_CONVERSION_SPEED::VERY_HIG H_SPEED); // , change the conversion speed
    adc->setSamplingSpeed(ADC_SAMPLING_SPEED::VERY_HIGH_SP EED); // change the sampling speed

    edit

    Ok i don't know what is happening but in code i don't have these spaces

  15. #415
    Junior Member
    Join Date
    Oct 2018
    Posts
    1
    Hi Kranvonkyln,

    there are a few parts where I would search for problems:
    1) When does elapsedMicros start to count? I prefer to use e.g. unsigned long duration; before code to be tested: duration = microes(); after code to be tested: duration = microes() - duration; to be sure, that you get the right elapsed time

    2) You include Serial.println(value, DEC) in the loop and you measure it! It takes a hell of a lot more time that the analogRead statement - so whatever you try to improve whith that statement, you will never really see something happening!

    Kind regards,
    Stefan

  16. #416
    Hello everyone!
    I have a question. If I use continuous reading on both ADC 0 and 1 at A9 and A1 and use also simultaneously single reading on A2 all going smooth and working but if I enable interruptions for ADCís then I cannot get to work simultaneously single reading anymore on any analog inputs.
    Sorry for noobies question, it is normal?
    I just learning how to use ADC library and interrupts 😃 in other ways.
    I was tested it on original example analog continuous read, without modifications.

Posting Permissions

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