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

Thread: Teensy 3.5 - Using different voltage references for ADC and DAC

  1. #1

    Teensy 3.5 - Using different voltage references for ADC and DAC

    In my application I would like to use the
    - ADC based on a reference voltage of 3.3V
    - DAC based on a reference voltage of 1.2 V

    Using the core library (I guess) I only can select the (internal) reference voltage by the call to
    analogReference(1); // for 1.2V, or
    analogReference(0); // for 3.3V
    but as far as I understood this sets the reference voltages for ADC and DAC in the same way.

    The only solution I can imagine is to rewrite "analogWriteDAC0()" and to set the DAC reference voltage by
    DAC0_C0 = DAC_C0_DACEN; // 1.2V
    DAC0_C0 = DAC_C0_DACEN | DAC_C0_DACRFS; // 3.3V

    Is there any possibilty to set different values for DAC and ADC?

    Regards,
    Peter

  2. #2
    Would it be possible to use the ADC library from Pedvide to solve my problem above? It looks like that a call to adc->setReference() only sets the reference voltage for the ADC but does not influence the DAC settings (?). So my idea is to use the standard "analogReference(1)" for the DAC and "adc->setReference()" for the ADC.

    Code:
    // Configure DAC:
    analogWriteResolution(8);
    analogReference(1);  // Vref set to 1.2V 
    
    // configure ADCs:
    ADC *adc = new ADC();
    adc->setResolution(12,ADC_0);
    adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0);
    adc->setAveraging(32,ADC_0);
    Is this a feasible way? I guess I have to first setup the DAC followed by the ADC, because if I do it the other way around, the call to analogReference(1) would re-configure the ADC reference voltage as well (what I don't want).

  3. #3
    Senior Member
    Join Date
    Jul 2013
    Posts
    272
    I think that should work, but you need to switch on the VREF (I don't know if it's on by default) with
    VREF::start()

    VREF is included by the ADC library. You can stop it with
    VREF::stop()

  4. #4
    Thank you - I will try that.

    I think that should work, but you need to switch on the VREF (I don't know if it's on by default) with
    VREF::start()
    I try to understand the code in ADC_Module::setReference():

    - When I would like to use the internal 1.2V internal reference, I call "setReference" with the parameter REF_1V2, and then the 1.2V ist switched on as internal reference by an call to VREF::start().

    - When I use the parameter "REF_3V3", the internal reference voltage is switched off, and either the internal 3.3V is used (may be just an static internal pullup to Vcc) or an external voltage at pin Uref. And this makes no diffference within the code.

    If this is correct, I don't have to call VREF::start() or VREF::stop() manually in my code, but just only adc->setReference() with the right parameters.

    BTW, thank you very much for the library :-)

  5. #5
    Senior Member
    Join Date
    Jul 2013
    Posts
    272
    Yes and no.
    You need to invert the statements in #2. When you call adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0); it will stop the VREF, which is shared with the DAC. You can then call analogReference(1); because that will switch it on (it calls analog_init() which will switch it on) and set the core library analog to 1.2V. At that point the core library is at 1.2V and the ADC library a 3.3V.

    To avoid errors in the future, maybe it's better if you call VREF::start() after adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0); anyway, and add a comment explaining why. It's always risky to have instructions that depend on the order of execution in non-obvious ways.

  6. #6
    Senior Member
    Join Date
    Mar 2013
    Posts
    643
    My understanding was the DAC was fixed at 3.3V and could not be changed?

  7. #7
    As far as I understood, one set the Uref of the DAC with "analogReference(x)" ,where x is "1" for 1.2V and 0 for 3.3V.

    But currently I am completely confused about the interworking between the ADC and the DAC. Following the proposal of Pedvide in #5, I changed my code accordingly (and I fully agree with his proposal), but the results are somehow crazy: If I put 1V at the ADC input and use a resolution of 12bit (dec 4095), I got "810" as measured DAC output. So, 810/4095*3.3 should lead to a smaller input value of 0.65V, but hypothetically a Uref of 5V would lead to the real input value of 1V=810/4095*5V. Of course, 5V is nothing what can be applied to the Teensy as Uref, I know. As conclusion, I have to sort it out by using an easier test code. I am pretty sure that it's not related to the library.

  8. #8
    Senior Member
    Join Date
    Mar 2013
    Posts
    643
    Looking at post number 2 I would say try setting the ADC's first and then the DAC, it could be that the DAC settings are being overwritten.

  9. #9
    Senior Member
    Join Date
    Jul 2013
    Posts
    272
    PumpkinEater, please post your complete code. What are you connecting to the ADC pin? the DAC output?

  10. #10
    In principle (and simplified), the Teensy drives a signal generator (DDS AD9851) with some of the digital outputs to set its frequency (1-60 MHz). In an analog circuit the signal is processed and the resulting rectified DC signal is routed across an OP back to the ADC input of the Teensy. With this arangement I can measure the behaviour of the analog circuit relative to the frequency. As the output level of the signal generator decreases with increasing frequency, I put the Level(f)-values as calibration into the EEPROM and adjust the DDS level by this values each time when I measure via analogRead(). I achieve this by reading the stored calibration values, converting them by the DAC and use the analog output as a control signal for the DDS. In an earlier phase I only used the core libraries and everything seemed to work but the dynamic range of the ADC and DAC were not optimal. Therefore I am searching now for a way to use different Uref's for DAC and ADC (see #1).

    So as you might see, there are a lot of points which could be the reason for the issue. Therefore first of all, I will isolate the relevant code for ADC and DAC, and test them separately. If the problems still exists then, the problem might depend on the libraries. Otherwise (and more likely) it's related to my current large code or hardware. I will report about this hopefully after weekend.

  11. #11
    Senior Member
    Join Date
    Mar 2013
    Posts
    643
    So is there any reason you cant just use a voltage divider on the DAC output?
    And I would use an external Reference Voltage since the 3.3V is basically whatever the 3.3V rail is.

  12. #12
    I made some tests in the evening with a quite simple code, and hopefully solved the issue. In the following source code I have placed the line "analogReference(1);" alternatively before or after the settings for the ADC. In the first case, the ADC outputs "4095" for an analog input, which is pulled up to Vcc. And also the output level of the DAC is correct (measured 1.2V). In the second case the line "analogReference(1);" is placed after the ADC configuration, and now the ADC output delivers "1023" (which somehow looks like an accidentally changed resolution from 12 to 10 bit). Assuming that the reference voltage for the ADC was changed somehow, I also tried to set it again with "adc->setReference" at the last point, but without any impact.

    Code:
    #include <ADC.h>
    
    ADC *adc = new ADC();
    
    void setup()
    {
      pinMode(A8,INPUT_PULLUP);
      pinMode(A21,OUTPUT);
    
    //1  working if following line enabled -> ADC output "4095" (correct), DAC output 1.2V (correct)
      analogReference(1);  // 1: Vref set to 1.2V 
    
      adc->setResolution(12,ADC_0);
      adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0);
      adc->setAveraging(32,ADC_0);
    
      analogWriteResolution(8);
    
    //2  not working if following line enabled -> ADC output "1023" (wrong), DAC output 1.2V (correct)
    //  analogReference(1);  // 1: Vref set to 1.2V 
    
    //3 just a trial - does not fix the problem if //2 is enabled 
    adc->setReference(ADC_REFERENCE::REF_3V3,ADC_0);
    
      delay(2000);
      Serial.print("Max Value ADC_0: ");
      Serial.println(adc->getMaxValue(ADC_0));
    
    }
    
    void loop() {
      analogWrite(A21,255);
      int value = adc->analogRead(A8);
      Serial.println(value);
      delay(500);
    }

  13. #13
    Junior Member
    Join Date
    May 2018
    Posts
    1
    hey I have i2C 0-10v ADC which is connected with Teensy 3.5 (Pin 19(SCL) and Pin 18(SDA)) but teensy is operated on 3.3v and to read 0-10v reading connecting directly to I/o pins with ADC might destroy teensy board , What will be the best way to read analog signals easily ?

    Your suggestion will be helpful

Posting Permissions

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