Teensy 4.0 which pins for which ADC

Status
Not open for further replies.
@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();
 
@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 :)
 
@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...
 

Attachments

  • T4_ADC_DMA_RMS-191224a.zip
    5.2 KB · Views: 66
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/Teensy4_DMA_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
 
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 :)
 
@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.
 

Attachments

  • T4_ADC_DMA_QTIMER_RMS_BOTH.zip
    6.4 KB · Views: 61
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...
 
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).
 
@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.
 
@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
 
@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?
 
@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.
 

Attachments

  • ADCLpitxbaradcV5-191226a.zip
    4.3 KB · Views: 52
@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.
 

Attachments

  • ADCLpitxbaradcV6-191227c.zip
    4.2 KB · Views: 51
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
    [COLOR="#FF0000"]adc0_obj(0, channel2sc1aADC0, ADC0_START)[/COLOR]
    #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
 
@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.
 
@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.
 

Attachments

  • ADCLpitxbaradcV7-191228a.zip
    3.9 KB · Views: 56
Last edited:
@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.
 
@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
 
@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.
 
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).
 
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.
 
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...
 
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.)
 
Status
Not open for further replies.
Back
Top