The MCUXpresso Config Tool will happily generate a pin_mux.c for every pin on the board in
about four clicks. On my Control Unit mainboard it did exactly that, and it set every
USDHC1 pin — CMD, CLK, DATA0-3, card detect — to 100K Pull Down.
That is wrong in two separate ways at once. The SD specification requires CMD and DAT to read high when undriven during card identification, so a pull-down can break enumeration outright. And the card-detect net already had a 10 kΩ external pull-up on the schematic, which the internal pull-down was now fighting.
The tool is not broken. It just does not know about my external resistors or my protocol. Nobody had told it, and I had not checked.
In this article I show what each pad-control field does, how to derive its value from the schematic and the protocol spec, and a cheat sheet you can run through before you hit Generate.
flowchart TD
A["For each routed pin"] --> B{"Driven by exactly<br>one fixed source?"}
B -->|yes| C["Pull/Keeper = Disabled"]
B -->|no| D{"External pull resistor<br>already on the net?"}
D -->|yes| E["Pull/Keeper = Disabled<br>don't fight it"]
D -->|no| F{"Protocol requires a<br>defined idle level?"}
F -->|yes| G["Pull, PUS matches<br>the required level"]
F -->|no| H{"Bidirectional bus,<br>always driven by someone?"}
H -->|yes| I["Keeper"]
H -->|no| C
The decision I should have walked for each pin before generating anything.
TL;DR
Step 1 — Know what each field does
Hysteresis (HYS)
Enables a Schmitt-trigger input buffer instead of a plain comparator.
- What it is for: rejecting slow, noisy, or bouncy transitions on an input so the pin does not chatter or false-trigger.
- Enable for: mechanical switches and buttons, open-drain shared lines, any input with a slow or noisy edge (long trace, RC-filtered line).
- Leave disabled for: clean, fast, actively-driven digital signals. It buys nothing there.
Pull Up/Down Config (PUS)
Selects the value of the internal pull resistor — typically 100K Pull Down, 47K Pull Up,
100K Pull Up, 22K Pull Up on the RT1062.
Only matters if Pull/Keeper is set to Pull and enabled. It picks the rest state of a pin that can be undriven — tri-stated, open-drain, or a true input with no other bias.
Pull/Keeper Select + Enable (PUE / PKE)
This is the field people mix up most.
- Pull enabled: the pad actively biases the line toward the configured rail through a real resistor. It will source or sink current to hold that level even with nothing else driving.
- Keeper enabled: the pad only latches the last driven logic level with a very weak feedback loop. It does not pull toward a fixed rail — it prevents the line drifting between drive events, and it will not fight an active driver on either side.
- Disabled: the pin floats completely when undriven. Fine for a pin that is always actively driven by exactly one side, such as a clock output.
Rule of thumb
Drive Strength (DSE)
Sets the pad’s output impedance, expressed as a fraction of a reference impedance — R0, about
260 Ω at 3.3 V nominal on RT1062 pads. A lower divisor (R0/7) means a stronger driver, lower
output impedance, more current, sharper edges.
- Stronger drive is needed for longer traces, higher capacitive load, or multiple parallel receivers, to keep edges clean at the far end.
- Stronger drive on a short, lightly-loaded trace mostly adds ringing, overshoot and EMI — no timing benefit.
- Match it to what is actually on the schematic: trace length, number of loads, whether there is series termination.
Slew Rate (SRE: Fast/Slow)
Controls how fast the output transitions between logic levels, independently of drive strength.
- Fast: sharper edges, needed to meet setup/hold timing at higher clock and data rates.
- Slow: softer edges, reduces overshoot, ringing and EMI. Prefer it whenever the timing budget allows.
Faster is not automatically better. It is a timing-margin-versus-EMI trade.
Open Drain Enable (ODE)
Forces the output stage to open-drain — only pulls low, never actively drives high — regardless of what the peripheral logic thinks it is doing.
- Needed for genuine wired-AND buses (classic I²C SCL/SDA) or when the schematic shows an external pull-up doing the high side on purpose.
- Do not enable it on push-pull peripheral signals (SPI, most USDHC lines in normal push-pull mode) — you will break the high level entirely.
Speed (pad frequency class)
A coarser frequency-class setting some RT1062 pads expose alongside SRE, e.g. fast(150MHz).
Pick the class that comfortably covers your actual signal frequency, not the fastest available
by default — the fastest class trades more EMI and overshoot for margin you may not need.
Step 2 — Derive the values from the schematic
For every pin, walk this sequence before touching the config tool:
- Read the direction and role off the schematic. Input, output, or bidirectional? Actively driven by exactly one side, or can it be undriven or tri-stated?
- Look for an external resistor already on the net. If the schematic already has a discrete pull to a rail, that resistor wins electrically — the internal pad setting should be disabled, or at most a consistent, weaker bias in the same direction. Never fight an external resistor with an opposing internal pull.
- Check the protocol spec for the peripheral, not just the schematic. Some interfaces have required pull directions during specific phases — SD command/identification mode requires pull-ups — even if nothing on the schematic looks like it needs one.
- Estimate trace length and loading to pick drive strength. Short on-board trace to one load → moderate. Longer trace, connector, multiple loads → stronger.
- Match slew rate and speed class to the frequency you will actually run, not the peripheral’s theoretical maximum. Leave margin by picking slow unless timing demands fast.
- Set hysteresis only where the input can be slow-edged or noisy.
Step 3 — Worked example: the microSD interface
The facts from the SD-card sheet:
SD-A_CMD,SD-A_CLKandSD-A_DATA[0:3]go directly from the RT1062 USDHC1 pads to the microSD socket — short, single-load, on-board traces.SD-A_nCD(card detect) has an external 10 kΩ pull-up to 3V3MEM already on the schematic; the card shorts it to ground when inserted.SD-A_nRSTdrives a transistor that gates the SD card’s power switch. It is a GPIO push-pull output, not a bus signal.
| Pin | Direction | Pull/Keeper | Drive | Slew | Why |
|---|---|---|---|---|---|
| CLK | Output (host-driven) | Disabled | R0/6 | Slow (Fast only for SD High-Speed 50 MHz) | Always actively driven by the host — a pull just adds load; a short trace does not need max drive |
| CMD, DATA0-3 | Bidirectional (open-drain during identification, push-pull after) | Pull, PUS = 47K/100K Pull-Up | R0/6 | Slow (Fast for High-Speed) | The SD spec requires these to read high when undriven during card identification; a pull-down here can break enumeration |
| CD (card detect) | Input | Disabled — the external 10 k already owns the line | n/a | n/a | An internal pull-down directly opposes the external pull-up; let the schematic’s resistor do its job |
| RESET | Output (drives the power-switch transistor) | Pull-Down (idle-safe: card held powered-off before GPIO init) | Low/default | Slow | Push-pull GPIO output — the pull setting only matters before the GPIO driver takes over at boot |
The bug this article exists for
100K Pull Down. That contradicts the SD spec, which wants CMD and DAT high when
idle, and it fights the external 10 kΩ pull-up on card detect. Always eyeball the
bulk-generated defaults against the schematic: the config tool does not know about your
external resistors or your protocol requirements.Step 4 — Run the cheat sheet before generating
| Question | Answer |
|---|---|
| Pin is always driven by exactly one fixed source (e.g. a clock output)? | Pull/Keeper → Disabled |
| Pin can float or be undriven, and the protocol or circuit needs a defined idle level? | Pull/Keeper → Pull, PUS direction matching the required idle level |
| Bidirectional bus line, always driven by someone, just needs to not float during turnaround? | Pull/Keeper → Keeper |
| Schematic already has a discrete pull resistor on this net? | Internal pull → Disabled (do not fight it) |
| Protocol spec requires a specific pull direction (SD CMD/DAT, I²C)? | Follow the spec even if the schematic shows nothing — pull-up for SD/I²C-style lines |
| Signal is a true wired-AND bus (I²C, shared open-drain line)? | Open Drain = ON, plus external pull-up |
| Signal is a push-pull peripheral output (SPI, USDHC normal mode)? | Open Drain = OFF |
| Long trace, multiple loads, or a connector in the path? | Higher drive strength (lower R0/N divisor) |
| Short on-board trace, single load? | Moderate drive strength (R0/6) — do not over-drive |
| High-frequency or tight-timing signal? | Fast slew rate, matched speed class |
| Lower-speed or noise-sensitive signal with timing margin available? | Slow slew rate — free reduction in ringing and EMI |
| Input from a mechanical switch or slow/noisy source? | Hysteresis = Enabled |
| Clean, fast, actively-driven digital signal? | Hysteresis = Disabled (no benefit) |
Summary
The pad-control fields are not style choices — three of them (pull direction, open-drain, and to a lesser extent drive strength) can stop a peripheral working at all. The config tool generates defaults from the pin function, not from your board, so its output is a starting point rather than an answer.
What works now: the SD card enumerates reliably with pull-ups on CMD/DAT and the internal pull
disabled on card detect. What I would do differently: walk the decision tree at the top of
this article before the first pin_mux.c generation, not after the card failed to mount.
Related
- Adding a microSD card active object with QP/C and USDHC1 — the driver that sits on top of these pins
- FlexSPI + QSPI NOR on the i.MX RT1062 — the other high-speed interface on the same silicon
💬 Questions, corrections, or your own war story with IOMUXC defaults? Leave a comment below — I read and answer all of them.
💬 Discussion
Questions, corrections, or war stories from your own board? Leave a comment below — I read and answer all of them. (Sign-in with GitHub.)