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

Thread: T4 Pin Drive Strength

  1. #1

    T4 Pin Drive Strength

    Hi all,

    I'm hoping to learn whether someone has already developed a function to set the drive strength, speed and other configurable parameters of Teensy digital pins (esp. T4.0 and 4.1)

    Something like setDriveStrength(Pin, Level)

    If not, is there a thread or resource explaining how to do it with lower level code, e.g.
    IOMUXC_SW_PAD_CTL_PAD_GPIO_AD_B1_10 = 0x8;

    I've found snippets scattered on various threads, but no central source of wisdom.

    Thanks!
    -J

  2. #2
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    Would this work for drive-strength?

    In file :: ...\hardware\teensy\avr\cores\teensy4\digital.c :: void pinMode(uint8_t pin, uint8_t mode)


    void pinMode(uint8_t pin, uint8_t mode)
    {
    const struct digital_pin_bitband_and_config_table_struct *p;

    if (pin >= CORE_NUM_DIGITAL) return;
    p = digital_pin_to_info_PGM + pin;

    if (mode == OUTPUT || mode == OUTPUT_OPENDRAIN)
    {
    *(p->reg + 1) |= p->mask; // TODO: atomic
    if (mode == OUTPUT) // Default
    {
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else if (mode == OUTPUT_1) // 400 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(1);
    }
    else if (mode == OUTPUT_2) // 200 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(2);
    }
    else if (mode == OUTPUT_3) // 132 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(3);
    }
    else if (mode == OUTPUT_4) // 104 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(4);
    }
    else if (mode == OUTPUT_5) // 83 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(5);
    }
    else if (mode == OUTPUT_6) // 70 ohm
    {
    *(p->pad) = IOMUXC_PAD_DSE(6);
    }
    else if (mode == OUTPUT_7) // 55 ohm - same as Default
    {
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else
    { // OUTPUT_OPENDRAIN
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_ODE;
    }
    }
    else
    {
    *(p->reg + 1) &= ~(p->mask); // TODO: atomic
    if (mode == INPUT)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else if (mode == INPUT_PULLUP)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
    }
    else if (mode == INPUT_PULLDOWN)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(0) | IOMUXC_PAD_HYS;
    }
    else
    { // INPUT_DISABLE
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_HYS;
    }
    }
    *(p->mux) = 5 | 0x10;
    }

  3. #3
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    And update core_pins.h to add the underscore OUTPUT_Xs

    ...

    #define HIGH 1
    #define LOW 0
    #define INPUT 0
    #define OUTPUT 1
    #define OUTPUT_1 1
    #define OUTPUT_2 1
    #define OUTPUT_3 1
    #define OUTPUT_4 1
    #define OUTPUT_5 1
    #define OUTPUT_6 1
    #define OUTPUT_7 1
    #define INPUT_PULLUP 2
    #define INPUT_PULLDOWN 3
    #define OUTPUT_OPENDRAIN 4
    #define INPUT_DISABLE 5
    #define LSBFIRST 0
    #define MSBFIRST 1
    #define _BV(n) (1<<(n))
    #define CHANGE 4
    #define FALLING 2
    #define RISING 3

    ...

    Which comples - now need to test to see if the output impedance does actually change.

  4. #4
    Senior Member
    Join Date
    Dec 2016
    Location
    Montreal, Canada
    Posts
    3,803
    they all equal 1, therefore only OUTPUT statement gets selected

  5. #5
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    Thanks tonton81 - need to put brain into gear

    Clunky, but it now works... with an updated .h file which I will post next

    void pinMode(uint8_t pin, uint8_t mode)
    {
    const struct digital_pin_bitband_and_config_table_struct *p;

    if (pin >= CORE_NUM_DIGITAL) return;
    p = digital_pin_to_info_PGM + pin;

    if (mode == OUTPUT_OPENDRAIN)
    {
    *(p->reg + 1) |= p->mask; // TODO: atomic
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_ODE; // OUTPUT_OPENDRAIN
    }
    else if (mode == OUTPUT)
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else if (mode == OUTPUT_1) // 400 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(1);
    }
    else if (mode == OUTPUT_2) // 200 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(2);
    }
    else if (mode == OUTPUT_3) // 132 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(3);
    }
    else if (mode == OUTPUT_4) // 104 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(4);
    }
    else if (mode == OUTPUT_5) // 83 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(5);
    }
    else if (mode == OUTPUT_6) // 70 ohm
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(6);
    }
    else if (mode == OUTPUT_7) // 55 ohm - same as Default
    {
    *(p->reg + 1) |= p->mask;
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else
    {
    *(p->reg + 1) &= ~(p->mask); // TODO: atomic
    if (mode == INPUT)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7);
    }
    else if (mode == INPUT_PULLUP)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
    }
    else if (mode == INPUT_PULLDOWN)
    {
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(0) | IOMUXC_PAD_HYS;
    }
    else
    { // INPUT_DISABLE
    *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_HYS;
    }
    }
    *(p->mux) = 5 | 0x10;
    }

  6. #6
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    Updated core_pins.h

    #define HIGH 1
    #define LOW 0
    #define INPUT 0
    #define OUTPUT 1
    #define OUTPUT_1 11
    #define OUTPUT_2 12
    #define OUTPUT_3 13
    #define OUTPUT_4 14
    #define OUTPUT_5 15
    #define OUTPUT_6 16
    #define OUTPUT_7 17
    #define INPUT_PULLUP 2
    #define INPUT_PULLDOWN 3
    #define OUTPUT_OPENDRAIN 4
    #define INPUT_DISABLE 5
    #define LSBFIRST 0
    #define MSBFIRST 1
    #define _BV(n) (1<<(n))
    #define CHANGE 4
    #define FALLING 2
    #define RISING 3

  7. #7
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    Posts
    24,247
    I tried it just now on a Teensy 4.0. The code needs a minor edit, since the first if condition doesn't allow OUTPUT_1 to OUTPUT_7. To be used within a normal program, the function needs a different name so it doesn't conflict with the original pinMode().

    I tested by connecting a 464 ohm resistor to GND and measuring the voltage for logic high. VCC was measured at 3.286. The drive strength does indeed change, though the impedance is lower (stronger drive) than NXP's documentation.

    Code:
               Ohms              Ohms
    Setting   Claimed  Voltage  Actual
    
    OUTPUT_1    400     2.588    125
    OUTPUT_2    200     2.915     59
    OUTPUT_4    104     3.107     27
    OUTPUT_7     55     3.177     16
    I tested only 1 board and only at room temperature. NXP's specs might be the worst case for all chips at max temperature?

    Here's the code in the form of a complete working program. To recreate this measurement, just connect a 470 ohm resistor across a voltmeter and measure each pin's actual voltage.

    Code:
    #define HIGH 1
    #define LOW 0
    #define INPUT 0
    #define OUTPUT 1
    #define OUTPUT_1 11
    #define OUTPUT_2 12
    #define OUTPUT_3 13
    #define OUTPUT_4 14
    #define OUTPUT_5 15
    #define OUTPUT_6 16
    #define OUTPUT_7 17
    #define INPUT_PULLUP 2
    #define INPUT_PULLDOWN 3
    #define OUTPUT_OPENDRAIN 4
    #define INPUT_DISABLE 5
    #define LSBFIRST 0
    #define MSBFIRST 1
    #define _BV(n) (1<<(n))
    #define CHANGE 4
    #define FALLING 2
    #define RISING 3
    
    void setup() {
      pinModeExt(2, OUTPUT_1);
      pinModeExt(3, OUTPUT_2);
      pinModeExt(4, OUTPUT_4);
      pinModeExt(5, OUTPUT_7);
      digitalWrite(2, HIGH);
      digitalWrite(3, HIGH);
      digitalWrite(4, HIGH);
      digitalWrite(5, HIGH);
    }
    
    void loop() {
      // put your main code here, to run repeatedly:
    
    }
    
    void pinModeExt(uint8_t pin, uint8_t mode)
    {
      const struct digital_pin_bitband_and_config_table_struct *p;
    
      if (pin >= CORE_NUM_DIGITAL) return;
      p = digital_pin_to_info_PGM + pin;
    
      if (mode == OUTPUT || mode == OUTPUT_OPENDRAIN || (mode >= OUTPUT_1 && mode <= OUTPUT_7))
      {
        *(p->reg + 1) |= p->mask; // TODO: atomic
        if (mode == OUTPUT) // Default
        {
          *(p->pad) = IOMUXC_PAD_DSE(7);
        }
        else if (mode == OUTPUT_1) // 400 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(1);
        }
        else if (mode == OUTPUT_2) // 200 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(2);
        }
        else if (mode == OUTPUT_3) // 132 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(3);
        }
        else if (mode == OUTPUT_4) // 104 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(4);
        }
        else if (mode == OUTPUT_5) // 83 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(5);
        }
        else if (mode == OUTPUT_6) // 70 ohm
        {
          *(p->pad) = IOMUXC_PAD_DSE(6);
        }
        else if (mode == OUTPUT_7) // 55 ohm - same as Default
        {
          *(p->pad) = IOMUXC_PAD_DSE(7);
        }
        else
        { // OUTPUT_OPENDRAIN
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_ODE;
        }
      }
      else
      {
        *(p->reg + 1) &= ~(p->mask); // TODO: atomic
        if (mode == INPUT)
        {
          *(p->pad) = IOMUXC_PAD_DSE(7);
        }
        else if (mode == INPUT_PULLUP)
        {
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
        }
        else if (mode == INPUT_PULLDOWN)
        {
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(0) | IOMUXC_PAD_HYS;
        }
        else
        { // INPUT_DISABLE
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_HYS;
        }
      }
      *(p->mux) = 5 | 0x10;
    }

  8. #8
    Member
    Join Date
    Apr 2021
    Location
    Finland
    Posts
    30
    Those 400, 200, 104, and 55 ohms seem to be for 1.8V setup, for the Rpu only?...
    Corresponding values for 3.3V nominal are 220, 110, 58 and 32... Still high..
    However, if looking at the "Data Sheet: Technical data" (the small pdf..), page 38, the AC-impedances (couldn't figure out what was the frequency of measurement), the corresponding values could be:
    157, 78, 39, and 23...
    (Though I can't see how that would match with anything declared in the datasheets for DC.. And the table a bit above talks about Rpu at 22k, 47k, 100k.. That is one very ambiguous datasheet combination. Different numbers thrown around with related terms, either without explanation or given explanation not matching the other sets of data.)
    Last edited by bugi74; 05-02-2021 at 09:01 PM.

  9. #9
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    Hi Paul,

    Awesome, thanks for the update.

    [QUOTE=PaulStoffregen;278409]I tried it just now on a Teensy 4.0. The code needs a minor edit, since the first if condition doesn't allow OUTPUT_1 to OUTPUT_7. To be used within a normal program, the function needs a different name so it doesn't conflict with the original pinMode().

  10. #10
    Junior Member
    Join Date
    Mar 2021
    Location
    West London, UK
    Posts
    9
    Alternately adding an extra parameter... although one has to specify something in the third position even for inputs

    Code:
    // See i.MX RT1060 Processor Reference Manual, Rev. 2, pages 385 to 399
    
    void pinModeExt(uint8_t pin, uint8_t mode, uint8_t strength)
      {
      const struct digital_pin_bitband_and_config_table_struct *p;
    
      if (pin >= CORE_NUM_DIGITAL) return;
      p = digital_pin_to_info_PGM + pin;
    
      if(mode == OUTPUT || mode == OUTPUT_OPENDRAIN)
        {
        *(p->reg + 1) |= p->mask; // TODO: atomic
        if (mode == OUTPUT) // Default
          {
          switch(strength)
            {
            case 1:
              *(p->pad) = IOMUXC_PAD_DSE(1);
              break;
            case 2:
              *(p->pad) = IOMUXC_PAD_DSE(2);
              break;
            case 3:
              *(p->pad) = IOMUXC_PAD_DSE(3);
              break;
            case 4:
              *(p->pad) = IOMUXC_PAD_DSE(4);
              break;
            case 5:
              *(p->pad) = IOMUXC_PAD_DSE(5);
              break;
            case 6:
              *(p->pad) = IOMUXC_PAD_DSE(6);
              break;
            case 7:
              *(p->pad) = IOMUXC_PAD_DSE(7);
              break;
            default:
              *(p->pad) = IOMUXC_PAD_DSE(7);
              break;
            }
          }
        else
          { // OUTPUT_OPENDRAIN
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_ODE;
          }
        }
      else
        {
        *(p->reg + 1) &= ~(p->mask); // TODO: atomic
        if (mode == INPUT)
          {
          *(p->pad) = IOMUXC_PAD_DSE(7);
          }
        else if (mode == INPUT_PULLUP)
          {
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(3) | IOMUXC_PAD_HYS;
          }
        else if (mode == INPUT_PULLDOWN)
          {
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_PKE | IOMUXC_PAD_PUE | IOMUXC_PAD_PUS(0) | IOMUXC_PAD_HYS;
          }
        else
          { // INPUT_DISABLE
          *(p->pad) = IOMUXC_PAD_DSE(7) | IOMUXC_PAD_HYS;
          }
        }
      *(p->mux) = 5 | 0x10;
      }

Posting Permissions

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