Forum Rule: Always post complete source code & details to reproduce any issue!
Page 8 of 9 FirstFirst ... 6 7 8 9 LastLast
Results 176 to 200 of 202

Thread: Teensy 4.0 which pins for which ADC

  1. #176
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    Quote Originally Posted by KurtE View Post
    FYI - Your test sketch does not compile on his branch as there is no such define as TIMEOUT as an error...
    Thanks that's why. Like I said think I am going to punt now and see what he comes up with

  2. #177
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    @mjs513 - I agree that right now doing much on the ADCL_t4, may not be that productive for us... I will spend some time trying to see how to migrate some of our additions/examples over for him to see, and potentially integrate into library.

    Example his code has current code has none of the timed reads capability for T4.

    Currently he has two different timing read mechanisms...
    T3.2 use PGA
    T3.x use PDB
    TLC None
    T4 None

    But I have examples now using QTimer... The question will be to him, on add it? Is it some other different set of methods specific to T4?

    That is instead of specific functions like:
    Code:
        #if ADC_USE_PDB
    
        //! Start PDB triggering the ADC at the frequency
        /** Call startSingleRead or startSingleDifferential on the pin that you want to measure before calling this function.
        *   See the example adc_pdb.ino.
        *   \param freq is the frequency of the ADC conversion, it can't be lower that 1 Hz
        */
        void startPDB(uint32_t freq);
    
        //! Stop the PDB
        void stopPDB();
    
        //! Return the PDB's frequency
        uint32_t getPDBFrequency();
        #endif
    Could be more generic... like:
    Code:
    void startTimedReads(uint32_t freq);
    void stopTimedReads()
    uint32 getTimedReadsFrequency();

  3. #178
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE

    That actually sound good but think a lot is going to be in how to make the setups for timers and configs generic functions. Was starting to look at making some things generic like in some of those function calls I was using. DMA stuff is still magic to me so maybe by the time T4.x comes I can get less confused

  4. #179
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    @mjs513 @pedvide (and others) -

    Here is the dma (not using timers) example ported over to his library branch Teensy4.

    I put the library for DMA as files within the sketch:

    I ran it on T3.6 3.2 and T4. Compiles for 3.5, but my main T3.5 test board has the dual sine wave output on it... I know I have another one around somewhere, but...

    T-LC does not compile yet, as I need to change to not using chainging of DMA settings as TLC does not have this...

    I might fix T-LC...

    But may wait until QTimer version...
    Attached Files Attached Files

  5. #180
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    Merry Christmas!

    FYI - I pushed up a version of the above dma_rms sketch up to a new branch of ADC (branch is based on Teensy4 branch)...
    https://github.com/KurtE/ADC/tree/Te..._class_example

    I believe it is working now for LC. With LC it can not chain two DMA Settings to each other as it does not have this capability, so instead it runs one, and in the interrupt handler, it changes buffers and starts again

  6. #181
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    Merry Christmas to All

    Thanks Kurt. Still play with my generic functions for setting pin configs and triggers. Only seems to work for ADC_0 and trigger=0 trying to trace the bug down.

    Did test your SPI2 changes and they looked like it works for me considering I have a messed up clock pin for SPI2 - once in awhile it would display so looks like you could probably merge it with the master branch

  7. #182
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE

    Ok sorted out my coding issue with my trigger confs. I embedded it in your earlier DMA example as a independent test. If you want to check it out I am attaching.
    Attached Files Attached Files

  8. #183
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    Sounds great! Will play with it.

    But now probably need to play with our kids (Laik and Annie) Time for their daily walk.

    Plus so far they opened up one of their new toys (a larger chuck-it ball). Still have a few more new toys to get out...

  9. #184
    Senior Member+
    Join Date
    Jul 2013
    Posts
    280
    Hello @KurtE and @mjs513.

    The teensy4 branch for the ADc library is pretty much ready to merge into master (I'll do it tomorrow). The library works for all Teensys since 3.0, using a similar codebase.
    I have added both of you as collaborators so you have rights to merge pull requests. You're doing a great job with the DMA and frequency stuff, I'm looking forward to integrate some of it into the ADC library if you like (feel free to comment on the issues and create PRs).

  10. #185
    Senior Member+
    Join Date
    Jul 2013
    Posts
    280
    Quote Originally Posted by KurtE View Post
    @mjs513 - I agree that right now doing much on the ADCL_t4, may not be that productive for us... I will spend some time trying to see how to migrate some of our additions/examples over for him to see, and potentially integrate into library.

    Example his code has current code has none of the timed reads capability for T4.

    Currently he has two different timing read mechanisms...
    T3.2 use PGA
    T3.x use PDB
    TLC None
    T4 None

    But I have examples now using QTimer... The question will be to him, on add it? Is it some other different set of methods specific to T4?

    That is instead of specific functions like:
    Code:
        #if ADC_USE_PDB
    
        //! Start PDB triggering the ADC at the frequency
        /** Call startSingleRead or startSingleDifferential on the pin that you want to measure before calling this function.
        *   See the example adc_pdb.ino.
        *   \param freq is the frequency of the ADC conversion, it can't be lower that 1 Hz
        */
        void startPDB(uint32_t freq);
    
        //! Stop the PDB
        void stopPDB();
    
        //! Return the PDB's frequency
        uint32_t getPDBFrequency();
        #endif
    Could be more generic... like:
    Code:
    void startTimedReads(uint32_t freq);
    void stopTimedReads()
    uint32 getTimedReadsFrequency();
    (Note: PGA is the programmable gain amplifier, it has nothing to do with frequency).
    Indeed for the older Teensys I implemented some functions using the PDB, I'm open to add a the generic method you suggest so it can work with the new boards too.

  11. #186
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE

    Was thinking about something like this for a startTimer function:
    Code:
    // try to use some teensy core functions...
    // mainly out of pwm.c
    #ifdef USE_TIMED_READS
    extern "C" {
      extern void xbar_connect(unsigned int input, unsigned int output);
      extern void quadtimer_init(IMXRT_TMR_t *p);
      extern void quadtimerWrite(IMXRT_TMR_t *p, unsigned int submodule, uint16_t val);
      extern void quadtimerFrequency(IMXRT_TMR_t *p, unsigned int submodule, float frequency);
    }
    #endif
    
    void startTimer(uint8_t trigger, uint8_t timer, uint32_t freq)
    {
    	switch (trigger)
    	{
    		case 0:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG00);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG00);   // pit to adc_etc
    			}
    			break;
    		case 1:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG01);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG01);   // pit to adc_etc
    			}			break;
    		case 2:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG02);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG02);   // pit to adc_etc
    			}			break;
    		case 3:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG03);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG03);   // pit to adc_etc
    			}			break;
    		case 4:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG04);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG04);   // pit to adc_etc
    			}			break;
    		case 5:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG05);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG05);   // pit to adc_etc
    			}			break;
    		case 6:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG06);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG06);   // pit to adc_etc
    			}			break;
    		case 7:
    			if(timer == 1){
    				xbar_connect(XBARA1_IN_PIT_TRIGGER0, XBARA1_OUT_ADC_ETC_TRIG07);   // pit to adc_etc
    			} else {
    				xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG07);   // pit to adc_etc
    			}			break;
    		default:
    			break;
    	}
    
    	if(timer == 1){
    	  CCM_CCGR1 |= CCM_CCGR1_PIT(CCM_CCGR_ON);
    	  PIT_MCR = 0;
    
    	  IMXRT_PIT_CHANNELS[0].LDVAL = freq;
    	  IMXRT_PIT_CHANNELS[0].TCTRL = PIT_TCTRL_TEN;
    	} else {
    	  Serial.println("Try to init QTimer"); Serial.flush();
    	  quadtimer_init(&IMXRT_TMR4);
    	  quadtimerFrequency(&IMXRT_TMR4, 0, (float) freq);
    	  quadtimerWrite(&IMXRT_TMR4, 0, 5);
    
    	  Serial.println("After Qtimer init"); Serial.flush();
    	}
    }
    just don't want to do with extern ?

    EDIT: think need to break up into 2 functions - connectTimer and startTimer. Now that I posted its make me nervous. Since you

  12. #187
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    @mjs513, @pedvide - wondering... If there might be a few different cases here...

    Pit Timer - I was personally thinking about punting on this one. That is on T4 PIT translates to IntervalTimer. So hard coding to: XBARA1_IN_PIT_TRIGGER0 may easily be problematic.
    For example there are already at least one IntervalTimer example...

    Which I tried earlier. Personally if I used one like their example I would modify and remove interrupts for the Analog read completing, but instead would read the previous result on the IntervalTimer interrupt before I issued the new read...

    My initial code was having the startTimer check that if on T3.x would simply call through to the startPDB functions... Did not have the timer, again assumed in T4 that it would use a QTimer.

    Trigger: You played with this a lot more than I have. So I have no clue on how best to set this part up. That is I have not played with any of the restrictions... That is what happens if I set trigger 1 and Trigger 3, but no others? This may be fine..

    I was sort of thinking we might see if it made sense to try to aim for example to be close to the current example adc_pdb? or the like:
    Where you do something like:
    Code:
        ///// ADC0 ////
        adc->setAveraging(1); // set number of averages
        adc->setResolution(8); // set bits of resolution
        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->startSingleRead(readPin)
        adc->adc0->startPDB(freq)
    Replace startPDB with startTimer().

    then wondered for chained, it made sense to have a new function(s), that you would call instead of startSingleRead()
    maybe something like: startChainedRead(pin1, pin2, pin3, pin4); all but pin1 default to -1 ?
    Again I am just thinking off the top of my head.

    Might new new function like readChained that replaces readSingle()...

    Then question also may be, assume Timer is a QTimer.
    Now should we allow the user to do something like:
    Code:
    adc->adc0->startTimer(3000);
    adc->adc1->startTimer(2000);
    If so Would need to setup two different timers. I used QTIMER4_0 as no IO is exposed that uses this (So No PWM and no frequency stuff).
    4_1 and 4_2 can be used with pins 6 and 9, so maybe avoid, 4_3 is not on an IO pin exposed, so might be good choice for other.
    With my DMA version, I used one QTimer, but did setup to XBAR_connects
    Code:
      xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG10);   // pit to adc_etc
      xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG00);   // pit to adc_etc
    the TRIG10, is for ADC2(ADC_1)

    Again sorry just back from lunch, so this may all be gibberish.

    Thoughts?

  13. #188
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE - @pedvide

    Was planning on eventually testing with the new ADC lib as soon I worked out some of the functions with what I have that I know works first - easier to debug.

    Trigger: You played with this a lot more than I have. So I have no clue on how best to set this part up. That is I have not played with any of the restrictions... That is what happens if I set trigger 1 and Trigger 3, but no others? This may be fine..
    Don't think you can have multiple timers on a single ADC like ADC1 with 2 timers, or if its even possible with XBAR? On initialization of the ADC_ETC it takes the ADC channel and the trigger group and link and links the config together. You can select any trigger group you want of course. Doesn't have to go in order. If you want to play I am attaching my latest with those added functions I mentioned above. I did a quick test and it didn't work but maybe there is another way?

    then wondered for chained, it made sense to have a new function(s), that you would call instead of startSingleRead()
    maybe something like: startChainedRead(pin1, pin2, pin3, pin4); all but pin1 default to -1 ?
    Again I am just thinking off the top of my head.
    Not sure how that would work with interrupts unless, if an interrupt has occurred you test on the interrupt flag and then do the returns. Here is what I have:
    Code:
    void adcetc0_isr() {
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
      ADC_ETC_DONE0_1_IRQ |= 1 << trigger_adc;   // clear
      //val0 = ADC_ETC_TRIG0_RESULT_1_0 & 4095;
      adcValues[0] = ADC_ETC_GetADCConversionValue( trigger_adc, 0U ); /* Get trigger0 chain0 result. */
      adcValues[1] = ADC_ETC_GetADCConversionValue( trigger_adc, 1U ); /* Get trigger0 chain1 result. */
      adcValues[2] = ADC_ETC_GetADCConversionValue( trigger_adc, 2U );
      adcValues[3] = ADC_ETC_GetADCConversionValue( trigger_adc, 3U );
      asm("dsb");
    }
    Then question also may be, assume Timer is a QTimer.
    Now should we allow the user to do something like:
    Code:
    adc->adc0->startTimer(3000);
    adc->adc1->startTimer(2000);
    If so Would need to setup two different timers. I used QTIMER4_0 as no IO is exposed that uses this (So No PWM and no frequency stuff).
    4_1 and 4_2 can be used with pins 6 and 9, so maybe avoid, 4_3 is not on an IO pin exposed, so might be good choice for other.
    With my DMA version, I used one QTimer, but did setup to XBAR_connects
    Code:
    xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG10); // pit to adc_etc
    xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_ADC_ETC_TRIG00); // pit to adc_etc
    the TRIG10, is for ADC2(ADC_1)
    Yep you would need a timer for each ADC. That was why for the test just used PIT for one tmer and QTimer for the second timer in my connectTimer and startTimer functions. The timers actually get linked in the initialization of ADC_ETC.
    Attached Files Attached Files

  14. #189
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE - @pedvide
    I did a little modification to my last version of the triggered reads. Basically everything is setup with these lines:
    Code:
    int adc_0_pins[] = {14, 15, 16, 17};   //sets pins for chaining on adc0
    int adc_1_pins[] = {14, 15};    //sets pins for chaining on adc1
    uint8_t trigger_adc_0 = 0;      //for ADC_0 uses trigger 0, but in actuality can be any trig 0-3
    uint8_t trigger_adc_1 = 4;      //for ADC_1 uses trigger 4, but in actuality can be any trig 4-7
    
    uint8_t chain_len_0 = 4;        //chain length for ADC_0 (basically number of pins in adc_0_pins array
    uint8_t chain_len_1 = 2;        //chain length for ADC_1

    for the timers didn't get fancy:
    Code:
      //timer 1 = pit0, 2 = qtimer
      connectTimer(1, trigger_adc_0);
      connectTimer(2, trigger_adc_1);
    
      startTimer(1, 24 * 1000);   // 1 khz  1000 ADCs/sec
      //use QTIMER (timer2)
      startTimer(2, 3000.0);  // try at 20 hz for test...
    to link with adc_etc and define the trigger chains:
    Code:
     
      adc0_etc_ctrl_init(chain_len_0,         //chainLength_0, chainLength_1
                         adc_0_pins, //*adc_0_pinArray, *adc_1_pinArray
                         trigger_adc_0,          //trigger_adc_0, trigger_adc_1
                         false);     //bool DMA
      adc1_etc_ctrl_init(chain_len_1,         //chainLength_0, chainLength_1
                         adc_1_pins, //*adc_0_pinArray, *adc_1_pinArray
                         trigger_adc_1,          //trigger_adc_0, trigger_adc_1
                         false);     //bool DMA
      //  ADC_ETC_SetTriggerChainConfig(trigger#, channel Group#, pin1, pin2);
      ADC_ETC_SetTriggerChainConfig(ADC_0, trigger_adc_0, 0, adc_0_pins[0], adc_0_pins[1]);
      ADC_ETC_SetTriggerChainConfig(ADC_0, trigger_adc_0, 1, adc_0_pins[2], adc_0_pins[3]);
      ADC_ETC_SetTriggerChainConfig(ADC_1, trigger_adc_1, 0, adc_1_pins[0], adc_1_pins[1]);
    
      attachInterruptVector(IRQ_ADC_ETC0, adcetc0_isr);
    Probably could automate more but for a proof of concept.


    The interrupt is where the data is read:
    Code:
    void adcetc1_isr() {
      digitalWriteFast(LED_BUILTIN, !digitalReadFast(LED_BUILTIN));
      ADC_ETC_DONE0_1_IRQ |= 1 << trigger_adc_0;   // clear
      ADC_ETC_DONE0_1_IRQ |= 1 << trigger_adc_1;   // clear
      //val0 = ADC_ETC_TRIG0_RESULT_1_0 & 4095;
      for(uint8_t i=0; i < chain_len_0; i++) {
        adcValues_0[i] = ADC_ETC_GetADCConversionValue( trigger_adc_0, i ); /* Get trigger0 chain0 result. */
      }
      for(uint8_t i=0; i < chain_len_1; i++) {
        adcValues_1[i] = ADC_ETC_GetADCConversionValue( trigger_adc_1, i );
      }
    
      asm("dsb");
    }
    This would somehow have to modified to do readChained().




    BTW: All this is compatible with ADC library.
    Code:
    #include <ADC.h>
    .
    ADC *adc = new ADC(); // adc object
    .
      adc->setAveraging(8); // set number of averages
      adc->setResolution(12); // set bits of resolution
      adc->adc1->setResolution(8);
    The only thing don't know how to link to the ADC lib is the mappins2channel function.
    Attached Files Attached Files

  15. #190
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    Good Morning @mjs513 - Looks like you are making progress here. I downloaded and will try it out.

    First the easy stuff: Mapping from pins to channel.
    There are two tables in adc.cpp: example:
    Code:
    #elif defined(ADC_TEENSY_4)
    const uint8_t ADC::channel2sc1aADC1[]= { // new version, gives directly the sc1a number. 0x1F=31 deactivates the ADC.
        7, 8, 12, 11, 6, 5, 15, 0, 13, 14, 31, 31, 3, 4, // 0-13, we treat them as A0-A13
        7, 8, 12, 11, 6, 5, 15, 0, 13, 14, // 14-23 (A0-A9)
        31, 31, 3, 4 // A10, A11, A12, A13
    };
    #endif
    This table is passed to the module on the constructor:

    Code:
    ADC() : // awkward initialization  so there are no -Wreorder warnings
        #if ADC_DIFF_PAIRS > 0
        adc0_obj(0, channel2sc1aADC0, diff_table_ADC0, ADC0_START)
        #if ADC_NUM_ADCS>1
        , adc1_obj(1, channel2sc1aADC1, diff_table_ADC1, ADC1_START)
        #endif
        #else
        adc0_obj(0, channel2sc1aADC0, ADC0_START)
        #if ADC_NUM_ADCS>1
        , adc1_obj(1, channel2sc1aADC1, ADC1_START)
        #endif
        #endif
        {
        //ctor
    
        //digitalWriteFast(LED_BUILTIN, HIGH);
    }
    Which the constructor for the module stores away in the member variable: channel2sc1a

    There is a simple function to ask if the pin is valid, which most of the function use like:
    Code:
    int ADC_Module::analogRead(uint8_t pin) {
    
        //digitalWriteFast(LED_BUILTIN, HIGH);
    
        // check whether the pin is correct
        if(!checkPin(pin)) {
            fail_flag |= ADC_ERROR::WRONG_PIN;
            return ADC_ERROR_VALUE;
        }
    Then to get the actual channel, you just need to index that array like:
    Code:
        // translate pin number to SC1A number, that also contains MUX a or b info.
        const uint8_t sc1a_pin = channel2sc1a[pin];
    In our case I don't think there is any such MUX... stuff, so simply the channel number..


    Next up, will be interesting to muck with your example. More on this later, but was thinking about how to package.
    That is maybe try to setup that ADC_0 automatically uses Q4_0 and ADC_1 uses Q4_3 and see if it makes sense as something else to pass in constructor?
    Likewise I still need to better understand how these chains relate to ADC1 versus ADC2 (sorry for switching numbering), when it comes to ADC_ETC and channels.

    It will also be interesting to see how best to read chained reads in different cases. Example do we have a single read case, that waits for all to complete? Interrupt case, need to read more through your stuff here.
    of where the values stored in ADC_ETC...

    Then how this works with DMA?

    But maybe I need some more coffee first

  16. #191
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE
    Thanks have to absorb and then best way to incorporate.

    As to your other questions think if you dig into the code most of the answers are there. The trigger group is looks its kind of the key.

    First when you do the timer connections you are linking the timer to the timer group then when you initialize adc_etc you link the trigger group to the adc channel. Then you can configure the pin chains to the trigger group. Took a while for me to follow it through.

    Should be easy enough to change from the PIT timer to Q4_3 - all timer stuff is done is done in connectTimer for xbar linkage and timer config is in start timer

    As for DMA think I posted an a version of your DMA stuff using chains and my crazy functions.

    Ok - rambling here - need more coffee and close my eyes.

  17. #192
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE

    Made the changes to use the ADC Lib mapping functions and also changed my timer1. Am using Q4_3 instead of PIT0 and all seems to be working. Here is the updated sketch. Now more coffee.
    Attached Files Attached Files
    Last edited by mjs513; 12-28-2019 at 01:13 PM.

  18. #193
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    Sounds good, Will have to try it out!

  19. #194
    Senior Member+ mjs513's Avatar
    Join Date
    Jul 2014
    Location
    New York
    Posts
    4,601
    @KurtE
    Not sure how much more I can do on this at this point but, anyway, enjoy playing around with this version. The DMA version you already have.

  20. #195
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    @mjs513 @pedvide - Starting to have some luck with new APIs for T4 to startTimer, stopTimer.

    SO far I am only trying to get one trigger working per ADC... Using Qtimers...

    DMA was not working yesterday will debug next, but Got the interrupt on ADC completions working.
    I made a copy of the adc_pdb sketch and named it adc_timer, which I the got working. I extended the sketch, to have it do a "timed read", where I read into buffers 500 analog reads. When this completes it prints out data like how long it took...

    Example output, still printing out debug info...
    Code:
    Begin setup
    
    End setup
    
    Enter a command such as: s 3000<cr> to start doing something
    
    Start Timer with frequency 3000 Hz.
    
    
    *** ADC and ADC_ETC ***
    
    ADC1: HC0:90 HS:0 CFG:12440 GC:0 GS:2
    ADC2: HC0:90 HS:0 CFG:12440 GC:0 GS:2
    ADC_ETC: CTRL:20000011 DONE0_1:0 DONE2_ERR:0 DMA: 0
        TRIG[0] CTRL: 0 CHAIN_1_0:2017
        TRIG[1] CTRL: 0 CHAIN_1_0:0
        TRIG[2] CTRL: 0 CHAIN_1_0:0
        TRIG[3] CTRL: 0 CHAIN_1_0:0
        TRIG[4] CTRL: 0 CHAIN_1_0:2018
        TRIG[5] CTRL: 0 CHAIN_1_0:0
        TRIG[6] CTRL: 0 CHAIN_1_0:0
        TRIG[7] CTRL: 0 CHAIN_1_0:0
    Starting Timed read
    
    ADC:0 delta time:166 freq:3012 - min:67 max:189 avg:128 rms:42
    ADC:1 delta time:166 freq:3012 - min:84 max:172 avg:128 rms:30
    Code including example up on github: https://github.com/KurtE/ADC/tree/T4_Timer

  21. #196
    Senior Member+ KurtE's Avatar
    Join Date
    Jan 2014
    Posts
    6,097
    @mjs513 and @pedvide

    I pushed up some more changes to my branch https://github.com/KurtE/ADC/tree/T4_Timer

    Allow for only one buffer to be passed into my DMA buffer object, which sets up the code to only run the DMA operation once to fill the buffer. You can call a member function to have it run again...

    I pushed up the changes plus some of the example sketches.

  22. #197
    Quote Originally Posted by KurtE View Post
    Added in the startContinuous functions, need to test...
    Hello,

    I have converted a Teensy 3.2 to a Teensy 4.0 project. The showstopper in my project is startContinuous, and it seems to not be really implemented (at least in a compatible way) in the PJRC download of the Teensyduino library.

    I'd be happy to beta-test startContinuous, if you want to collaborate by PM -- and compare its performance/compatibility with my Teensy 3.2 (in swap back-and-fourth comparisions).

  23. #198
    Senior Member+ defragster's Avatar
    Join Date
    Feb 2015
    Posts
    10,610
    Quote Originally Posted by GDouglas View Post
    Hello,

    I have converted a Teensy 3.2 to a Teensy 4.0 project. The showstopper in my project is startContinuous, and it seems to not be really implemented in the PJRC download of the Teensyduino library.

    I'd be happy to beta-test startContinuous, if you want to collaborate by PM -- and compare its performance/compatibility with my Teensy 3.2 (in swap back-and-fourth comparisions).
    Was that with the latest just released TeensyDuino 1.49? If you can post a simple sketch that works for T_3.2 that fails on T_4.0 with TD 1.49 that would be the first step.

  24. #199
    Yes, I just installed the latest 1.4.9 and my project fails to invoke the adc0_isr at all on 4.0 using the ADC settings I configured, while it worked on all previous versions (3.2 and 3.6).

    I need to isolate only the offending code from the project, so that it's non-confusing to post. Keep tuned...

  25. #200
    Ok, in the process of packaging the sample, I found out why my code worked on Teensy 3.2 but not on Teensy 4.0

    1. I added a forgotten pinMode(0, INPUT);
    2. I changed adc->enableInterrupts(ADC_0) into adc->enableInterrupts(adc0_isr, ADC_0);

    Once I did these, the same code worked on both 3.2 and 4.0 .... However,

    New question:

    1. What's the max adcReadContinuous rate?
    It seems that analogReadContinuous throttles to approximately 330 KHz (during 600 Mhz CPU), no matter what I do to go faster -- trying to increase speeds seems to show a self-bottlenecking behaviour. At read sample 1, the ADC_HIGH_SPEED setting is almost identical to ADC_VERY_HIGH_SPEED, the former generating 130 KHz on T3.2 and 300 KHz on T4. I'm already using an op-amp setup and the data still even seems still usable at this rate, better than it was with the 3.2.

    2. Also, exact accurate read rate is extremely important, so is there a way to detect that the read rate is bottlenecking / deviating / out of spec?

    Interestingly, the signal-noise margin /seems/ better at 300 KHz on the new one than 130 KHz on the old 3.2. I would thought that the 12-bit of the 4.0 was slightly less accurate than the 13-bit of the 3.2 but at ultra high speeds, the 4.0 seems to be producing similar noise margins at over twice the sample rate. Currently using an op amp. I need to do more signal-to-noise ratio tests.

    (I wonder if there's a way to do 1 MHz.)

Posting Permissions

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