A binary counter can turn a fast clock into several slower clocks without repeated software toggles. But its outputs do not all change at once. Build a twelve-stage SN74HC4040 divider, observe two slow outputs, and use a small event model to discover why reading several counter bits during a transition can produce a number that was never a stable count.
This exact circuit and target adapter have not been physically built or executed on the Pico. Division and event-order plots are calculated, not measured. Host checks execute the supplied model and mock the actual adapter; they do not establish electrical timing.
The Texas Instruments SN74HC4040N is an asynchronous twelve-stage binary counter. Asynchronous here describes its ripple architecture: a change propagates through successive internal stages instead of updating every output from a single shared internal clock edge. A HIGH-to-LOW transition at CLK advances the count. A HIGH level at CLR clears every output asynchronously, without waiting for a clock edge.
QA is the first stage and divides by two; QH is the eighth and divides by 256; QL is the twelfth and divides by 4096. Each stage represents a binary weight, but those outputs are useful as separate frequency divisions as well as an encoded count. This lesson deliberately separates those two uses. A single divided output can be a useful signal while an unqualified sample of the entire changing word is unreliable.
Use TI SN74HC4040N in the N sixteen-pin plastic dual in-line package (PDIP), an original Raspberry Pi Pico running MicroPython 1.26.0, a 100 nF ceramic bypass capacitor, two 1 kΩ series resistors, two 10 kΩ bias resistors and two red light-emitting diodes (LEDs), each with a 4.7 kΩ resistor. Use ordinary small resistors rated 0.125 W or more. Ω means ohm, kΩ one thousand ohms, nF nanofarad, V volt and Hz cycles per second.
The Pico's Universal Serial Bus (USB) connection powers its regulated 3.3 V rail, which powers this counter. GP denotes a general-purpose pin; GPIO means general-purpose input/output. The chosen clock and clear signals are 3.3 V, sharing the same ground and supply domain. The HC device's recommended supply range is 2–6 V; an absolute maximum is not an operating target. Do not use a 5 V-powered counter output directly on a Pico input.
| Signal | SN74HC4040N pin | Experiment connection |
|---|---|---|
| VCC / GND | 16 /8 | Pico 3V3 physical 36 / ground physical 23; 100 nF directly 16–8 |
| CLK | 10 | GP16 physical 21 through 1 kΩ; 10 kΩ pulldown on chip side |
| CLR | 11 | GP17 physical 22 through 1 kΩ; 10 kΩ pullup to 3.3 V on chip side |
| QA,QB,QC,QD,QE,QF | 9,7,6,5,3,2 | Leave open; optional high-impedance probe on QA |
| QG,QH,QI,QJ,QK,QL | 4,13,12,14,15,1 | QH and QL each feed their own 4.7 kΩ and red LED to ground; others open |
Read the top-view notch and pin-one drawing. This is not a left-to-right sequential output pinout. Unused outputs may stay open; never ground an unused output as if it were an unused input. The only logic inputs are CLK and CLR, and both are deliberately biased to known idle states.

Wire with power disconnected and fit the 100 nF bypass close to pins 16 and 8. The pullup on CLR defaults the counter to clear, while the pulldown on CLK defaults its input LOW. Series resistors limit brief contention and connection mistakes; they are not permission to connect unrelated voltage domains. Verify the clear voltage under drive: its 1 kΩ/10 kΩ divider gives about 0.30 V when driven LOW and about 3.0 V for CLK when driven HIGH. These are intended rail-relative logic states; the datasheet's threshold tables at specified supply points are not a measured 3.3 V noise-margin guarantee.
The LED loads are deliberately small. Even assuming zero LED drop, 3.3/4700 ≈ 0.70 mA bounds each output's resistive load in this fixture. A typical red forward drop would reduce that current, but brightness and output HIGH voltage must be checked on real hardware. These indicators show slow toggling; they do not verify a nanosecond propagation specification. Keep optional scope or logic-analyzer grounds on the common low-voltage return.
For an ideal input frequency f, output stage n has frequency f/2ⁿ, with QA at n=1. The program requests 1024 Hz, so QA would be 512 Hz, QH 4 Hz and QL 0.25 Hz. QL's complete period is four seconds, not two: it spends approximately two seconds HIGH and two LOW. The adapter runs for eight seconds after a short clear hold, giving time to observe approximately two QL cycles if the actual clock and startup behave as intended.
A reported pulse-width modulation (PWM) frequency is the controller driver's configured result, not an external frequency measurement. Check it with an instrument if a quantitative division experiment is intended. Record actual input and output periods in the blank worksheet. Compare ratios even when the source differs slightly from the requested frequency.

The model starts with count unknown because software has not yet applied clear. CLR HIGH establishes zero; a subsequent falling clock edge increments a known count. It wraps modulo 4096. Inputs must be exact integer bits; strings, floats and booleans are rejected to expose accidental test-fixture misuse. The separate ripple helper returns ordered intermediate binary words, not their physical durations.
The actual Pico adapter configures clear HIGH and holds CLK LOW as an ordinary GPIO for 50 ms. It then releases clear and waits a further 1 ms with CLK still LOW before enabling PWM. This deliberate recovery interval avoids releasing asynchronous clear beside an already running falling clock edge. It checks the driver's reported frequency for a plausible 1000–1050 Hz configuration and emits an explicit unmeasured status. In cleanup it first attempts to assert clear, then deinitializes PWM and drives CLK LOW as an ordinary GPIO. Every cleanup action is attempted even if an earlier one fails. A failed cleanup is reported as unverified; the code cannot promise the circuit's physical state after a hardware or power fault.
Download the complete MicroPython adapter and host model.
"""SN74HC4040N: ideal edge/ripple model and optional Pico clock adapter.
Model event ordering is synthetic, not a predicted nanosecond timing sequence.
"""
def bit(value):
if type(value) is not int or value not in (0, 1):
raise ValueError("logic input must be integer zero or one")
return value
def ripple_states(before):
if type(before) is not int or not 0 <= before < 4096:
raise ValueError("12-bit count required")
states = []; value = before
for index in range(12):
value ^= 1 << index
states.append(value)
if value & (1 << index):
break
return states
class Counter:
def __init__(self):
self.count = None; self.last_clock = None
def step(self, clock, clear):
bit(clock); bit(clear)
if clear:
self.count = 0
elif self.last_clock == 1 and clock == 0 and self.count is not None:
self.count = (self.count + 1) & 4095
self.last_clock = clock
return self.count
def run(Pin, PWM, sleep_ms, emit=print):
clear = clock = pwm = None
try:
clear = Pin(17, Pin.OUT, value=1)
clock = Pin(16, Pin.OUT, value=0)
sleep_ms(50)
clear.value(0)
sleep_ms(1) # Recovery interval with CLK held LOW before its first edge.
pwm = PWM(clock, freq=1024, duty_u16=32768)
hz = pwm.freq()
if type(hz) is not int or not 1000 <= hz <= 1050:
raise ValueError("unexpected driver-reported clock")
emit({"commanded_hz": hz, "counter_measured": False})
sleep_ms(8000)
finally:
failures = []
actions = []
if clear is not None:
actions.append(("clear_high", lambda: clear.value(1)))
if pwm is not None:
actions.append(("clock_deinit", pwm.deinit))
if clock is not None:
actions.append(("clock_low", lambda: clock.init(Pin.OUT, value=0)))
for name, action in actions:
try:
action()
except Exception as error:
failures.append((name, type(error).__name__))
if failures:
emit({"cleanup": "UNVERIFIED", "failures": failures})
if __name__ == "__main__":
from machine import Pin, PWM
from time import sleep_ms
run(Pin, PWM, sleep_ms)
Host checks cover all 4096 ripple chains, wraparound, clear priority, wrong types and actual adapter cleanup under injected failures. They verify event-order logic and programming decisions, not the real chip's transition delays, clock edge quality, LED visibility or physical reset behavior. A clock disconnected while clear is LOW can also leave the current count retained; no clock does not automatically mean zero.
If a multi-bit word can be wrong during a transition, must every divided output be discarded?
No. A single stage still provides its documented frequency division when clocked within specifications. The problem is interpreting several differently delayed stages as one instantaneous settled number. Choose the observation and receiving circuit for the actual task rather than calling every use of a ripple counter equivalent.
TI SCLS160E, March 2022 gives the exact pinout, falling-edge advance, asynchronous clear and operating/timing limits. The current TI documentation was checked October 20, 2026; no separate applicable errata surfaced, which is not proof of absence. The original Pico datasheet and MicroPython 1.26 PWM application programming interface (API), support the adapter. Continue with the electronics course.