Forum Rule: Always post complete source code & details to reproduce any issue!
Page 15 of 17 FirstFirst ... 5 13 14 15 16 17 LastLast
Results 351 to 375 of 420

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

  1. #351
    Member randomrichard's Avatar
    Join Date
    Feb 2015
    Location
    UK
    Posts
    35
    Quote Originally Posted by GDouglas View Post
    Hello Pedvide,

    I discovered a possible quirk with the ADC library's setAveraging() function.

    adc->setAveraging(1); -- works as expected
    adc->setAveraging(2); -- behaves like adc->setAveraging(4)
    adc->setAveraging(4); -- works as expected (1/4th rate)
    adc->setAveraging(8); -- works as expected (1/8th rate)
    adc->setAveraging(16); -- works as expected (1/16th rate)
    Hi G Douglas
    I have experimented with "setAveraging(x) on my T3.6 and found that it makes an x-fold average of each x number of lines of data then puts that average value on all of the lines to which it applies - not useful - it produces a staircase of identical values and an x-fold reduction in lines. Instead, and taking advantage of the T3.6's memory I collected over 8-times more lines of data with setAveraging(1) than required then did an 8-fold average using this code: Click image for larger version. 

Name:	av.JPG 
Views:	197 
Size:	49.4 KB 
ID:	10740. This works to increase the effective resolution of the signal - more like real 16 bit data, although it also produces an x = 8 fold reduction in lines per second.

  2. #352
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    If im reading the library right there is no setting for "adc->setAveraging(2);" so most likely it reverts to 4. The allowed values are 1, 4, 8, 16, 32.

    @randomrichard, what it does is read the ADC channel multiple times in a row and then average those values using the internal ADC hardware.
    Try setting your averages to 8 and your ADC resolution(s) to 16, then remove your averaging math. The result should be roughly the same.

    Another thought randomrichard is to bitshift instead of divide, division is very slow even on the Teensy.
    Last edited by Donziboy2; 06-06-2017 at 10:41 AM.

  3. #353
    Junior Member
    Join Date
    Aug 2015
    Posts
    11

    what to include in adc_module.h on teensy 3.6

    I notice RingBuffer.h implies modifying this line as follows:
    Code:
    // include new and delete
    //#include <Arduino.h>
    In RingBuffer.h, should I use kinetis.h instead?
    And ADC_module.h shows
    Code:
    #include <Arduino.h>
    If I'm using a teensy 3.6 which is a Kinetis microcontroller from Freescale, do I still use the Arduino header? Is this header for the IDE or the hardware?
    The Arduino.h says its for the SDK, but it also looks like it is specific for an AVR core.

    Thanks if you can explain.

  4. #354
    Senior Member+ Frank B's Avatar
    Join Date
    Apr 2014
    Location
    Germany NRW
    Posts
    5,679
    Hi Pedro,

    firts, thank you for this great library!

    There is a little problem with the documentation. When trying to open Documentation.html, it tries to open "file:///C:/Arduino/hardware/teensy/avr/libraries/ADC/doxygen/html/a_d_c__r_e_a_d_m_e.html" - which does not work.

  5. #355
    Junior Member
    Join Date
    Sep 2017
    Posts
    1
    It seems that the Teensy 3.6 CPU only provides 1 differential channel pair. This sucks.

    The Teensy 3.5, however, seems to provide several differential channel pairs, especially it offers at least one for both ADC0 and ADC1, separately.
    According to https://www.nxp.com/docs/en/referenc...4M120SF5RM.pdf, page 245, the following pins can be used for differential measurements:
    J1, J2
    K1, K2
    L1, L2
    M1, M2 <-- this is also available on Teensy 3.6

    Looking at the code, it seems that Teensy 3.5 and 3.6 are treated equally, meaning the library currently does not support analogSyncReadDifferential() on Teensy 3.5.
    Is the ADC library still being updated? The last commit is more than 6 months old and there are several open issues..

  6. #356
    Senior Member
    Join Date
    Apr 2017
    Posts
    187
    Thanks for taking the time to do this. Sorry for my very basic question, but what will the results of using this library do? Faster analog read, more accurate analog read, less power consumption, other?

  7. #357
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    Before I break things: I'd like to measure the supply voltage, which won't work without some fixed reference.

    Can I do a conversion from ADC_INTERNAL_SOURCE::VREF_OUT (10-bit result for 3.3 V supply would be approximately 372) and calculate the supply voltage from there? Like so:
    Code:
    value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT);
    float v_bat = value*1.2/adc->getMaxValue(ADC_0);

  8. #358
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    I think what you need is.

    Code:
    value = adc->analogRead(VREF_OUT);
    float v_bat = value / adc->getMaxValue(ADC_0);
    v_bat = 1.2 / v_bat;
    Keep in mind the internal reference is not super accurate.

  9. #359
    Senior Member
    Join Date
    Dec 2014
    Posts
    262
    First: You cannot put a voltage higher than 3.3V into an analog in, so there is that. (I e, no hooking batteries straight to the analog in pin!)
    Second: The VREF uses specific hardware to make sure the voltage is always at the fixed value, no matter what the input voltage is. It's like a voltage regulator. Trying to make assumptions about other voltages (such as 3.3V) based on the reference is not going to work well.
    Third: The 3.3V voltage on the Teensy is also generated by a regulator, with low drop-out. As long as the input is about 3.6V or higher, it will generate 3.3V. Thus, you won't be able to tell much about the main battery in (USB or VBat) by looking at the 3.3V rail. Again, it's a stabilized regulator, so it's not expected to fluctuate much at all.

    If you want to measure the supply voltage, the most straight-forward way is to create a resistive divider, and buffer it with a 100 nF capacitor. You can make the resistive divider quite high impedance to avoid draining the source, as long as you don't read it too often. The parallel capacitor will make sure the ADC sees a representative voltage.
    This example uses a 604K upper resistor and 100K lower resistor, for a drain at 12V in of 17 microamps. The time constant for 604k*0.1uF is about 60 milliseconds, so if I read this no more often than every 500 milliseconds (half a second) it should be quite stable. If you're OK reading even more slowly, you can probably go to megaohms of resistance, although you start becoming susceptible to pick-up EMI noise at some point.
    (FWIW, the circuit below generates 3.3V in to the analog input when the battery voltage is 3.3V*(704/100) or about 23.2V, so it's safe up to about 5S LiPo input. If you want to push it all the way to "absolute max" (which I think is 3.6V in the data sheet) you'll see 25.3 Volts so 6S probably won't kill it. If your actual battery is lower voltage, you can increase the lower resistor to gain resolution and lower leakage.)

    Finally, if you want to measure the voltage, I suggest calling analogReadRes(12) to get a better resolution measurement.

    Click image for larger version. 

Name:	teensy-vref.png 
Views:	67 
Size:	5.5 KB 
ID:	11560
    Last edited by jwatte; 09-18-2017 at 03:44 PM.

  10. #360
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    Not quite. I want to run the teensy off a battery with not more than 3.6 V, probably without the regulator in between. So the controller's supply voltage is not known as it would usually be. That's why I want to compare it with a known reference, hence my question.

  11. #361
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Quote Originally Posted by jwatte View Post
    SNIP
    The time constant is much faster then you think. The formula for the series resistors connected to a capacitor is Rtot = (R1 * R2) / (R1 + R2), not just R1.

    So for a 604K/100K divider the total resistance is around 86.5K. Making your time constant about 8.65mS with a 0.1uF capacitor.

  12. #362
    Senior Member
    Join Date
    Dec 2014
    Posts
    262
    So the controller's supply voltage is not known
    I see. At that point, you can still use a resistive divider, but use the 1.2V reference instead of the 3.3V reference.
    Thus, use analogReference(INTERNAL1V1) and divide the input voltage at least 3:1.

    Rtot = (R1 * R2) / (R1 + R2), not just R1.
    ...
    So for a 604K/100K divider the total resistance is around 86.5K.
    For trying to get the capacitor down to ground, I can see how the time constant could go to "parallel resistors" resistance. Thanks!

    Anyway, that just means you get a more settled reading at 500 ms. The main point is to have a big enough capacitor to feed the ADC input when it actually samples, while having high through resistance to reduce current consumption.

  13. #363
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Quote Originally Posted by jwatte View Post
    I see. At that point, you can still use a resistive divider, but use the 1.2V reference instead of the 3.3V reference.
    Thus, use analogReference(INTERNAL1V1) and divide the input voltage at least 3:1.
    I think what he is doing should be fine as long as he avoids going over Vmax for the IC, he is using the internal 1.2V reference to determine what the actual voltage is on the Teensy since the ADC defaults to the 3.3V rail or whatever voltage it actually is if he is directly feeding the 3.3V pin. His idea does not require any external parts and allows him to adjust for the variation in voltage on the 3.3V rail.


    Quote Originally Posted by jwatte View Post
    Anyway, that just means you get a more settled reading at 500 ms. The main point is to have a big enough capacitor to feed the ADC input when it actually samples, while having high through resistance to reduce current consumption.
    The difference between a 10n and 100n capacitor is about 800uV (value of 1 at 12bit resolution) when sampled by the Teensy regardless of how much time you allow to charge back up. And the difference between the ideal value for the 604k/100K divider and what the Teensy will see is about 20mV all the way down to about 15-20mS per sample.
    Last edited by Donziboy2; 09-18-2017 at 08:51 PM.

  14. #364
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    @jwatte: I don't want to use the internal reference as reference for the ADC. You're right in that I'd have to scale down the supply voltage then. My plan was different: VDD (battery voltage) is used as ADC reference (as it is by default). Then I measure the internal reference voltage when it is an input to the ADC, so I can extrapolate VDD from there.

  15. #365
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    So I picked a board and ran the following:
    Code:
    #include <ADC.h>
    
    ADC* adc = new ADC();
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      int value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT);
      float voltage = 1.2/value*adc->getMaxValue(ADC_0);
      Serial.print("value = ");Serial.print(value);
      Serial.print(" ^= ");Serial.println(voltage);
      delay(1000);
    }
    And I got this output:

    Code:
    value = 349 ^= 3.52
    value = 344 ^= 3.57
    value = 340 ^= 3.61
    value = 335 ^= 3.66
    value = 331 ^= 3.71
    value = 327 ^= 3.75
    value = 322 ^= 3.81
    value = 318 ^= 3.86
    value = 314 ^= 3.91
    value = 309 ^= 3.97
    value = 305 ^= 4.02
    The ADC value is monotonically falling, so the calculated VDD is rising. That's definitely something I didn't expect...

    ADC library downloaded 20170918 (just now)
    Teensy 3.6
    teensyduino 1.39 release
    arduino 1.8.4
    arduino build system reports that it is using the correct library

  16. #366
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    @christoph

    try breaking
    Code:
    float voltage = 1.2/value*adc->getMaxValue(ADC_0);
    into 2 operations. Or try the example I posted earlier.

    Also is
    Code:
    int value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT);
    even valid? I don't recognize that as a command for reading adc's, only setting the reference.....

  17. #367
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    Same effect when breaking it into two operations.

    The usage of analogRead is mentioned in the first post of this thread, in section "Other conversion sources". This usage is also in the datasheet, ADC chapter, register ADCx_SC1n[4..0] (ADCH), bandgap input.

    Edit: now as I had a closer look at the datasheet it seems that bandgap input is *not* the same as the 1.2 V reference - so I'm unsure if what I want is feasible. The bandgap has 3% tolerance (0.97 V ... 1.03 V).
    Last edited by christoph; 09-19-2017 at 06:41 AM.

  18. #368
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    It seems that for the teensy 3.6, VREF_OUT can only be measured with the second adc on channel 18 (chapter "ADC1 connections/Channel Assignment"). I'll try that later today when I'm back home.

    Edit: for all chips:

    • Teensy 3.2 (MK20DX51VLH7)
      • ADC0: VREF_OUT on channel AD22
      • ADC1: VREF_OUT on channel AD18
    • Teensy 3.5 (MK64FX512VMD12)
      • ADC0: VREF_OUT not available for ADC0 in 144-pin package
      • ADC1: VREF_OUT on channel AD18
    • Teensy 3.6 (MK66FX1M0VMD18)
      • ADC0: VREF_OUT not available for ADC0
      • ADC1: VREF_OUT on channel AD18

    So what all chips have in common is that VREF_OUT can be measured on ADC1::AD18

    The solution would then be (if I'm right):
    Code:
    #include <ADC.h>
    
    ADC* adc = new ADC();
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      int value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT, ADC_1); // explicitly select ADC1, same in next row
      float voltage = 1.2/value*adc->getMaxValue(ADC_1);
      Serial.print("value = ");Serial.print(value);
      Serial.print(" ^= ");Serial.println(voltage);
      delay(1000);
    }
    Anyone fancy trying? I don't have hardware at hand. No external parts or wires needed, just a blank Teensy 3.2/3.5/3.6.
    Last edited by christoph; 09-19-2017 at 09:04 AM.

  19. #369
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    Problem persists, this is the code I've tried:
    Code:
    #include <ADC.h>
    
    ADC* adc;
    
    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
      adc = new ADC();
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
      int value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT, ADC_1);
      if (value == ADC_ERROR_VALUE)
      {
        Serial.println("error");
      }
      float voltage = 1.2/value*adc->getMaxValue(ADC_1);
      Serial.print("value = ");Serial.print(value);
      Serial.print(" ^= ");Serial.println(voltage);
      delay(1000);
    }
    Output:
    Code:
    value = 366 ^= 3.35
    value = 362 ^= 3.39
    value = 358 ^= 3.43
    value = 353 ^= 3.48
    ...
    So what I had in mind is either not possible, or I'm doing it wrong. Another reason might be some error in the library since reading from the internal reference might have been tested with somewhat low priority. I don't know.

  20. #370
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891

    Success (apparently)!

    I think I fixed it:
    • enable VREF_OUT and low-power buffer
    • wait for VREF_OUT to stabilize


    Code:
    #include <ADC.h>
    
    ADC* adc;
    
    void setup() {
      Serial.begin(9600);
      adc = new ADC();
      // enable VREF_OUT and wait for it to stabilize
      VREF_TRM |= VREF_TRM_CHOPEN;
      VREF_SC = VREF_SC_VREFEN | VREF_SC_REGEN | VREF_SC_ICOMPEN | VREF_SC_MODE_LV(2);
      while(!(VREF_SC & VREF_SC_VREFST))
      {    
      }
    }
    
    void loop() {
      int value = adc->analogRead(ADC_INTERNAL_SOURCE::VREF_OUT, ADC_1);
      if (value == ADC_ERROR_VALUE)
      {
        Serial.println("error");
      }
      float voltage = 1.2/value*(adc->getMaxValue(ADC_1));
      Serial.print("value = ");Serial.print(value);
      Serial.print(" ^= ");Serial.println(voltage);
      delay(1000);
    }
    Output:
    Code:
    value = 370 ^= 3.32
    value = 370 ^= 3.32
    value = 370 ^= 3.32
    value = 370 ^= 3.32
    value = 370 ^= 3.32
    value = 370 ^= 3.32
    So when I change from USB power to battery power, I should be able to measure VDD with this.

    I'm still playing with different VREF_SC_MODE_LV settings. VREF_SC_MODE_LV(1) or VREF_SC_MODE_LV(2) should both work, while VREF_SC_MODE_LV(0) puts the reference into standby.
    Last edited by christoph; 09-20-2017 at 10:48 AM. Reason: removed VREF_SC_MODE_LV stuff info which might be wrong

  21. #371
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Awesome, I might barrow some of that, its nice to have a second reference to insure your voltage is not way out of whack.

  22. #372
    Senior Member
    Join Date
    Sep 2013
    Location
    Hamburg, Germany
    Posts
    891
    Well if it's really way out of whack the chip will probable release magic smoke, wouldn't it?

  23. #373
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    @Pedvide, hope your doing ok.

    Been poking around the library, mainly looking at speeds and such and noticed some inconsistency's vs the ADC Code Paul provides for the Teensy. Here is the Breakdown table for FBus to ADCK. For both the stock analog.c and ADC_Module.h
    108Mhz has some math issues and 36Mhz seems to be missing 4.5Mhz.

    Click image for larger version. 

Name:	FBus to ADCK.JPG 
Views:	73 
Size:	143.3 KB 
ID:	11629


    On another note I was playing around and created a small lookup table for selecting resistor values for a divider. The values indicated are safe to use with or without an external capacitor on the divider. Although you may have noise issues without the capacitor.


    Just set the Time Constant to the value you want and using the table provided(values are calculated sample time for the ADC), insert the sample time your after and it will highlight all values that are safe to use. The pictures show the usable values for a Time constant of 7 and a 250nS sample time(24Mhz @ Very High Speed). You can change RADIN and CADIN if you want, both are set to worst case single ended read.
    Click image for larger version. 

Name:	ADC Lookup pg1.jpg 
Views:	79 
Size:	164.4 KB 
ID:	11630
    Click image for larger version. 

Name:	ADC Lookup pg2.JPG 
Views:	68 
Size:	168.2 KB 
ID:	11631
    Click image for larger version. 

Name:	ADC Time Constant Losses.JPG 
Views:	58 
Size:	68.7 KB 
ID:	11632

    Link to the Excel file on my Google Drive.

  24. #374
    Senior Member
    Join Date
    Mar 2013
    Posts
    651
    Quote Originally Posted by christoph View Post
    Well if it's really way out of whack the chip will probable release magic smoke, wouldn't it?
    Well its nice to know if your reference is shifting outside spec, ya know so your electric Gocart does not go all Maximum Overdrive on ya.

  25. #375
    Senior Member ninja2's Avatar
    Join Date
    Aug 2016
    Location
    Adelaide, Australia
    Posts
    151
    @christoph I have a simple question on bit naming convention. This topic is detailed in the K66 Freescale reference manual section 42.3 but if I search (the manual) for any of the bit terms you use (say VREF_SC_REGEN) they are not found. But I can find VREF_SC[REGEN] and similar for others like VREF_SC[CHOPEN] ...

    What is the convention for bit naming and is it explained anywhere ? And is this just a Freescale convention, or industry wide?

    Code:
    VREF_TRM |= VREF_TRM_CHOPEN;
    VREF_SC = VREF_SC_VREFEN | VREF_SC_REGEN | VREF_SC_ICOMPEN | VREF_SC_MODE_LV(2);
    TIA
    Last edited by ninja2; 10-01-2017 at 04:02 AM.

Posting Permissions

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