← PHYS 351Lecture 03 · LED control & timingReading notes →

Lecture 03: LED control & timing

1 / 38
PHYS 351 · Lecture 0301

Lecture 03

LED Control and Timing with the Raspberry Pi

Covers Lab 3
© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0302

Today, in one line

A GPIO pin is a voltage source that software can switch.

A very good switch. A mediocre clock.

When timing matters, move it out of the Python loop.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0303

What changed since last week

Labs 1–2: the hardware decided.

From Lab 3: software decides. One line of Python changes a voltage.

The catch: Linux plus Python is a poor timekeeper. Measuring how poor is half the lab.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0304

Where each task points

TaskYou doIdea
1–2boot, Python version, working directoryLinux guide
3turn on one LEDnumbering, resistor, set up / drive / clean up
4blue and green alternate every 2 s; push the rate; jitterloop period, scheduler jitter
5three LEDs in sequenceseveral pins, per-colour current
6RGB LED flashing three colourscommon cathode vs common anode
7PWM brightness; vary duty and frequency; scopeduty cycle, average voltage
8RGB breathingthree PWM channels, gamma
9copy work off, delete itthe Pis are shared
© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0305

The GPIO port

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0306

What a GPIO pin actually is

General-purpose: no fixed job. Input or output, your program decides.

As an output: push–pull. A 1 is 3.3 V, a 0 is 0 V.

Key idea

A 3.3 V source with a switch, not a current source. Straight into an LED is the Lab 1 mistake, inside a computer.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0307

Two numbering schemes for the same pins

BOARD

Physical position on the header, 1 to 40. Count with your finger.

BCM

The processor’s name, e.g. GPIO17. Gaps, not sequential. Used by datasheets and nearly all published code.

Rule for this course

BCM, declared on the first line: GPIO.setmode(GPIO.BCM). Reports say “BCM 17 (physical 11)”.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0308

The header

Raspberry Pi 40-pin header map distinguishing physical pin positions from BCM GPIO numbers and marking 3.3 V, 5 V, ground, I²C, UART, and SPI connections. Power pins are not GPIO inputs.

Pin 1 is the corner nearest the SD card.

Odd numbers down one row, even down the other.

Hardware PWM: BCM 12, 13, 18, 19.

Lab 3: 17, 27, 22 for LEDs; 18, 13, 19 for PWM.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0309

The numbers that protect the Pi

LimitValueMeaning for you
Output high3.3 Vevery calculation uses 3.3 V
Maximum input3.3 Vnot 5 V tolerant; 5 V kills the processor
One pin16 mAdesign LEDs for 5–10 mA
All pins together\sim50 mAthree LEDs at 8 mA fine; eight at 16 mA not
5 V header pinsdo not usenothing in Lab 3 needs them

There is no fuse between a pin and the processor.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0310

Find pins at the bench, without Python

pinout                 # labelled diagram of this board
pinctrl get 17         # function and level of BCM 17
pinctrl set 17 op dh   # drive BCM 17 high
pinctrl set 17 op dl   # ...and low again

LED dark? Run pinctrl set 17 op dh first.

Lights: the bug is in software. Still dark: the bug is in the circuit.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0311

Driving an LED

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0312

The circuit

Raspberry Pi LED connection using a 330-ohm series resistor between a GPIO signal and the LED, with the return connected to ground. Verify physical pin numbers against the pinout before wiring.

Pin \rightarrow resistor \rightarrow anode (long leg).

Cathode (short leg, flat rim) \rightarrow ground.

470 Ω\Upomega default; 330 Ω\Upomega also fine.

Backwards: no harm, just dark.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0313

Design from the current you want

ILED=VpinVFRR=VpinVFItargetI_{\text{LED}} = \frac{V_{\text{pin}} - V_F}{R}\qquad R = \frac{V_{\text{pin}} - V_F}{I_{\text{target}}}

Red, VF=2.0V_F = 2.0 V, 3.3 V pin:  470Ω2.8mA470\ohm \rightarrow 2.8\mA,  330Ω3.9mA330\ohm \rightarrow 3.9\mA.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0314

Forward voltage depends on colour

LEDVFV_FHeadroomII, 470 Ω\UpomegaII, 330 Ω\Upomega
Red1.8–2.0 V1.3–1.5 V2.8–3.2 mA3.9–4.5 mA
Yellow2.0–2.2 V1.1–1.3 V2.3–2.8 mA3.3–3.9 mA
Green2.0–2.4 V0.9–1.3 V1.9–2.8 mA2.7–3.9 mA
Blue2.7–3.0 V0.3–0.6 V0.6–1.3 mA0.9–1.8 mA

Same resistor, a factor of three in current. Nothing is wrong.

Measure VFV_F with the DMM diode test and tabulate it.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0315

Talking to the pins

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0316

Every GPIO program has three parts

1. Set up: numbering scheme, which pins are outputs.

2. Drive: HIGH or LOW, usually in a loop with delays.

3. Clean up: release the pins when the program ends.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0317

The RPi.GPIO vocabulary for Lab 3

CallWhat it does
import RPi.GPIO as GPIOthe conventional import
GPIO.setmode(GPIO.BCM)interpret numbers as BCM names
GPIO.setup(pin, GPIO.OUT)a pin, or a list of pins, becomes an output
GPIO.output(pin, GPIO.HIGH)3.3 V; GPIO.LOW is 0 V; lists work too
GPIO.cleanup()release every pin the script set up
GPIO.PWM(pin, freq)a PWM generator on an output pin
sleep(seconds)from time; a float; approximate

The whole vocabulary. What you build from it is the assignment.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0318

The one complete program: blink

import RPi.GPIO as GPIO
from time import sleep
GPIO.setmode(GPIO.BCM)             # 1. set up
GPIO.setup(17, GPIO.OUT)
try:
    for i in range(10):            # 2. drive
        GPIO.output(17, GPIO.HIGH); sleep(1.0)
        GPIO.output(17, GPIO.LOW);  sleep(0.5)
finally:
    GPIO.cleanup()                 # 3. clean up, even on Ctrl+C

range(1, 10) runs nine times, not ten.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0319

Task 4: work it out on paper first

  • How many pins? What does each setup line look like?
  • Per loop pass: how many output calls, in what order, so exactly one LED is lit?
  • Where do the sleep calls go? Predict the period before measuring it.
  • Put the delay in a named constant. Task 4d sweeps it.
© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0320

Timing

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0321

sleep() is not a clock

Tactual=tsleep,on+tsleep,off+toverheadT_{\text{actual}} = t_{\text{sleep,on}} + t_{\text{sleep,off}} + t_{\text{overhead}}

Overhead only ever adds. The measured period is always longer.

Roughly constant in absolute terms, so it matters more as you go faster:

2 ms on 1.5 s is 0.1 %. 2 ms on 1 ms is 200 %.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0322

What the scope shows

Ideal evenly spaced digital pulses compared with pulses from a Python timing loop. The period varies slightly from cycle to cycle; this spread is timing jitter.
In persistence mode the later edges smear into a band. Its width is the jitter.
© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0323

Where the extra time comes from

  • Linux is not real-time: the scheduler can pause you at any moment
  • sleep() guarantees a minimum, not an exact delay
  • every GPIO.output() is Python before it is hardware
  • garbage collection pauses, unpredictably
  • the desktop, the network, the SD card all steal CPU

Name them in your report. “The Pi is slow” is not an explanation.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0324

Measure jitter as a number

Scope: Period measurement, then Statistics on.

jitterpk–pk=TmaxTminjitterRMS=σT\text{jitter}_{\text{pk--pk}} = T_{\max} - T_{\min}\qquad \text{jitter}_{\text{RMS}} = \sigma_T

Infinite persistence, trigger on a rising edge: the most convincing screenshot.

Task 4 table: requested delay, expected ff, measured ff and TT, jitter pk–pk and RMS, jitter as % of TT.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0325

Reading a statistics box

Loop written for 1 kHz. Over 500 cycles: Tmean=1.213T_{\text{mean}} = 1.213 ms, Tmin=1.140T_{\min} = 1.140, Tmax=1.760T_{\max} = 1.760, σT=46μs\sigma_T = 46\us.

Period error and frequency error differ. RMS small, pk–pk large: the scheduler’s signature.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0326

Flicker fusion

Above roughly 50–90 Hz the LED stops flashing and looks dimmer.

The retina integrates over 10–20 ms and reports the average.

That is the bridge to PWM: switch faster than the eye, control the fraction.

Note where you stop seeing flicker; the scope still shows pulses.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0327

PWM

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0328

Pulse-width modulation

Three 3.3 V PWM waveforms with equal period and duty cycles of 20, 50, and 80 percent. Their ideal average voltages are 0.66, 1.65, and 2.64 V.

D=tonT×100%D = \frac{t_{\text{on}}}{T}\times 100\,\%
Vavg=DVhighV_{\text{avg}} = D\cdot V_{\text{high}}

Frequency and duty are independent controls.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0329

Software PWM calls

CallWhat it does
pwm = GPIO.PWM(pin, freq)PWM object on an output pin, freq in Hz
pwm.start(duty)begin; duty is a percentage, 0–100
pwm.ChangeDutyCycle(duty)frequency untouched
pwm.ChangeFrequency(freq)duty untouched
pwm.stop()call before GPIO.cleanup()
Units trap

ChangeDutyCycle(0.5) is 0.5 %, which looks like off. Half brightness is 50.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0330

Software PWM vs hardware PWM

GPIO.PWM() is always software: a thread toggles the pin, the scheduler can move every edge.

The Pi also has PWM peripherals on BCM 12, 13, 18, 19: a counter in silicon, no CPU per edge.

Task 7d: compare period statistics of your Task 4 loop and your PWM at the same frequency.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0331

Predict before you look: 1 kHz, 30 %

TT = ?   tont_{\text{on}} = ?   VavgV_{\text{avg}} = ?

Now 500 Hz at 30 %: what changes, what does not?

A DMM on DC volts across the pin reads VavgV_{\text{avg}}: a free cross-check.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0332

RGB LEDs

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0333

One package, three dies, four legs

TypeCommon legColour legsLogic
Common cathodegroundresistor, then a pinHIGH = on. Prefer this.
Common anode3v3resistor, then a pinLOW = on. All inverts.

Longest leg is the common. The DMM diode test finds the type and each colour.

One resistor per colour. Shared, red hogs the current.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0334

Breathing: why a linear ramp looks wrong

Linear and gamma-corrected LED brightness ramps. For the illustrated gamma of 2.2, a requested brightness of one half maps to approximately 22 percent duty cycle.

D=bγ,γ2.2D = b^{\,\gamma},\quad \gamma \approx 2.2

The eye is compressive.

Three PWM objects, a smooth b(t)b(t), one conversion line.

State the rule you used.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0335

Scope settings for Tasks 4 and 7

Probetip on the pin side of the resistor; ground clip on a header ground
Attenuation10×10\times, and tell the scope
CouplingDC. AC makes duty cycle meaningless
Triggeredge, rising, 1.65\approx 1.65 V
MeasurementsPeriod, Frequency, +Width, Duty, then Statistics on
Displayinfinite persistence for the jitter screenshot

Name screenshots so you still understand them next week.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0336

Destroys hardware / wastes your afternoon

Destroys hardware

5 V into a GPIO pin
LED with no resistor
power pin shorted to ground
rewiring with the Pi powered
a motor straight on a pin

Wastes your afternoon

BOARD/BCM mixed up
LED backwards
print() inside the timing loop
an old script still holding the pin
editing one file, running another

Before you leave: copy your work off, then delete it.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0337

Take away

A GPIO pin is a software-controlled 3.3 V switch with a hard 16 mA limit: every load needs a resistor, every big load needs a transistor.

A Python loop places an edge to within milliseconds, and that error is constant, so it becomes fatal as you go faster.

To control an average, switch faster than the load can follow and vary the duty cycle.

© Ran Yang, Ph.D.Advanced Instrumentation
PHYS 351 · Lecture 0338

Exit check

1. BCM name of physical pin 11?

2. Red LED, VF=1.9V_F = 1.9 V, 470 Ω\Upomega, 3.3 V pin: current?

3. 0.5 ms high, 0.5 ms low requested; scope reads 1.31 ms. Overhead? Frequency error?

4. 200 Hz at 35 %: period, on-time, average voltage?

© Ran Yang, Ph.D.Advanced Instrumentation

Use ← → to move, Home / End to jump, and F for fullscreen.

Figure descriptions

Slide 8 · The header

Raspberry Pi 40-pin header map distinguishing physical pin positions from BCM GPIO numbers and marking 3.3 V, 5 V, ground, I²C, UART, and SPI connections. Power pins are not GPIO inputs.

Slide 12 · The circuit

Raspberry Pi LED connection using a 330-ohm series resistor between a GPIO signal and the LED, with the return connected to ground. Verify physical pin numbers against the pinout before wiring.

Slide 22 · What the scope shows

Ideal evenly spaced digital pulses compared with pulses from a Python timing loop. The period varies slightly from cycle to cycle; this spread is timing jitter.

Slide 28 · Pulse-width modulation

Three 3.3 V PWM waveforms with equal period and duty cycles of 20, 50, and 80 percent. Their ideal average voltages are 0.66, 1.65, and 2.64 V.

Slide 34 · Breathing: why a linear ramp looks wrong

Linear and gamma-corrected LED brightness ramps. For the illustrated gamma of 2.2, a requested brightness of one half maps to approximately 22 percent duty cycle.