Teensy 4.1 - Internal Equivalent Schematic of Digital I/O Pins

Hello,

I am making a teensy4.1 capacitance meter running the adc at 12 bits. My code is posted below for one of my two code snippets, the one below is for small capacitors which is simply being charged and discharged via two analog pins.

I am in need of the 4.1's internal I/O pin equivalent schematic. I am unsure about how to interpret this for the teensy in contrast to the Arduino. In the ATMEGA user manual, there is an equivalent schematic with resistance values. For me to be able to charge and measure the capacitor, I need the internal pull up resistance and also the internal capacitance of the chip (which, I calculated by using a capacitor I measured with a keithly for its real value, placed it in my circuit, and did the math to solve for the unknown capacitance - image attached of this arithmetic).

Below is my code, please notice the const float r_pullup var I need to be accurate for this to work. Let me know if there are any ways you think I can improve the accuracy if you may - The measurement is accurate at some capcitances but for others it isnt (e.g. 22pf measures at 23.6 pf, 68pf measures at 50pf...). Thanks in advance!


Code:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ADC.h>

// Pin definitions for Teensy 4.1
const int OUT_PIN = 16; // Analog pin A2 on Teensy 4.1
const int IN_PIN = 14;  // Analog pin A0 on Teensy 4.1

LiquidCrystal_I2C lcd(0x27, 20, 4); // LCD address and dimensions

const float IN_STRAY_CAP_TO_GND = 14.59; // Adjusted value for your setup
const float IN_CAP_TO_GND = IN_STRAY_CAP_TO_GND;
const float R_PULLUP = 22000.0; // Pull-up resistor value in Ohms
const int MAX_ADC_VALUE = 4095; // Teensy 4.1 ADC max value for 12-bit resolution

ADC *adc = new ADC(); // Create an ADC object

void setup() {
  pinMode(OUT_PIN, OUTPUT);
  pinMode(IN_PIN, OUTPUT);
  lcd.init();
  lcd.backlight();

  // Set up ADC
  adc->adc0->setAveraging(16); // Set number of averages
  adc->adc0->setResolution(12); // Set resolution to 12 bits
  adc->adc0->setConversionSpeed(ADC_CONVERSION_SPEED::HIGH_SPEED); // Set conversion speed
  adc->adc0->setSamplingSpeed(ADC_SAMPLING_SPEED::HIGH_SPEED); // Set sampling speed
}

void loop() {
  pinMode(IN_PIN, INPUT);
  digitalWrite(OUT_PIN, HIGH);
  int val = adc->adc0->analogRead(IN_PIN);
  digitalWrite(OUT_PIN, LOW);

  lcd.setCursor(0, 0);
  lcd.print("ADC Value: ");
  lcd.print(val);

  if (val < (MAX_ADC_VALUE * 0.9)) { // Adjust threshold if needed
    pinMode(IN_PIN, OUTPUT);

    float capacitance = (float)val * IN_CAP_TO_GND / (float)(MAX_ADC_VALUE - val);

    lcd.setCursor(0, 1);
    if (capacitance > 1000.0) {
      lcd.print(capacitance / 1000.0, 3);
      lcd.print(" nF");
    } else {
      lcd.print(capacitance, 3);
      lcd.print(" pF");
    }
  } else {
    pinMode(IN_PIN, OUTPUT);
    delay(1);
    pinMode(OUT_PIN, INPUT_PULLUP);
    unsigned long u1 = micros();
    unsigned long t;
    int digVal;

    do {
      digVal = digitalRead(OUT_PIN);
      unsigned long u2 = micros();
      t = u2 > u1 ? u2 - u1 : u1 - u2;
    } while ((digVal < 1) && (t < 400000UL)); // Ensure correct type for UL

    pinMode(OUT_PIN, INPUT);
    val = adc->adc0->analogRead(OUT_PIN);
    digitalWrite(IN_PIN, HIGH);
    int dischargeTime = (int)(t / 1000UL) * 5; // Ensure correct type for UL
    delay(dischargeTime);
    pinMode(OUT_PIN, OUTPUT);
    digitalWrite(OUT_PIN, LOW);
    digitalWrite(IN_PIN, LOW);

    float capacitance = -(float)t / R_PULLUP / log(1.0 - (float)val / (float)MAX_ADC_VALUE);

    lcd.setCursor(0, 1);
    if (capacitance > 1e6) {
      lcd.print(capacitance / 1e6, 3);
      lcd.print(" uF");
    } else if (capacitance > 1000.0) {
      lcd.print(capacitance / 1000.0, 3);
      lcd.print(" nF");
    } else {
      lcd.print(capacitance, 3);
      lcd.print(" pF");
    }
  }

  while (micros() % 1000 != 0);
}
 

Attachments

  • unknowncapmath.png
    unknowncapmath.png
    15.9 KB · Views: 55
I assume you downloaded the IMXRT reference manual as well as the datasheet from the Teensy 4.1 product page?


My guess is that if the information is not contained in these documents, you may need to contact NXP maybe needing an NDA or the like. But that is just guessing.

For example if you at the RM at

11.7.190 SW_PAD_CTL_PAD_GPIO_AD_B1_07 SW PAD Control
Register
(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07)

There are several settings for the pad you are using for output...

Not sure if there are enough hints there for you or not.

Likewise your input pin. You might for example try pinMode(IN_PIN, INPUT_DISABLE);
before analogRead and see if that helps

EDIT: Is this more or less a duplicate of your other thread? Best to keep related things in one place.
 
I assume you downloaded the IMXRT reference manual as well as the datasheet from the Teensy 4.1 product page?


My guess is that if the information is not contained in these documents, you may need to contact NXP maybe needing an NDA or the like. But that is just guessing.

For example if you at the RM at

11.7.190 SW_PAD_CTL_PAD_GPIO_AD_B1_07 SW PAD Control
Register
(IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_07)

There are several settings for the pad you are using for output...

Not sure if there are enough hints there for you or not.

Likewise your input pin. You might for example try pinMode(IN_PIN, INPUT_DISABLE);
before analogRead and see if that helps

EDIT: Is this more or less a duplicate of your other thread? Best to keep related things in one place.
Thanks for the reference, I note in the RT1060 Processor Reference Manual that there seems to be three options... Other threads have suggested this too.

47k, 100k, or 22k. Ive used all options on pin 14 (A0) to see if my math will display the correct capacitance values and no dice.

I realized this thread may be better to post in with code and a shot of the equations im trying to use. But, I hope I can keep the other thread up so I can refer back to it.

Playing with input pin now to see if this solves my issue, thanks for the rec.
 
As mentioned in the other thread: use a different (digital) pin to drive a known-value resistor connected to the input pin, rather than rely on the input pull-up.
 
Back
Top