Skip to content
Level 3 · AdvancedBuildPart 14 · page 3 of 6180 minSafety level B · Advanced home laboratoryScienceCraft££
180Minutes
16Sources
BSafety level

Safety level B, advanced home laboratory. Needs additional controls, experience and precautions beyond the standard darkroom: stronger ventilation, splash protection, careful handling of concentrated reagents or of energies such as UV and low-voltage electronics.

Build: The LED Light Source and Exposure Timer

To build and bench-prove the half of the sensitometer that makes and times the light: an LED on a heatsink, fed a constant current, switched by a logic-level MOSFET from a Raspberry Pi Pico, watched by a monitor photodiode, and driven by firmware that reports the interval it achieved rather than the one it was asked for.

Nothing here goes into a box. That is the next page. The reason for separating them is that a light source whose stability you have not measured is not worth putting in a box, and once it is in a box you cannot get a meter near it.

You finish this session holding three things: a working module, a serial log of ten identical exposures with their spread computed, and a warm-up curve of your own lamp. The third is the one that matters, because everything the design lesson promised about repeatability depends on a drift figure that nobody can quote for your device.

By the end of this session you should be able to:

  • wire a low-side MOSFET switch from a microcontroller pin, and say what each of the two gate resistors is for;
  • choose a drive current from the light the instrument actually needs rather than from the LED’s rating, and justify running far below maximum;
  • read the five numbers off an LED, a MOSFET and an ADC datasheet and say which of them your circuit depends on;
  • load and run MicroPython firmware on a Pico, read its serial output, and change the four settings that are meant to be changed;
  • explain why the exposure is a busy-wait rather than a timer callback on this port;
  • measure your own lamp’s warm-up drift and the repeatability of ten identical exposures, and express the second as a spread in log H;
  • diagnose the four failures that account for most of the trouble in this circuit: a lamp that will not light, a lamp that will not go out, a microcontroller that resets when the lamp switches, and a monitor reading that is noise.

Low-voltage electronics for the darkroom builder, in full. This page assumes Ohm’s law, the LED current-voltage curve, the low-side switch, the gate resistor and the pull-down, and the datasheet-reading table, and does not re-teach any of them.

Sensitometer design principles, for the two decisions this build implements without re-arguing: fixed direct current, no PWM during an exposure, and half a second as the design exposure.

A computer with a USB port and a serial terminal. Thonny is the usual choice and needs no setting up; any terminal that opens the Pico’s serial device will do.

Level B, and the page says so plainly because the course’s own classification rubric says so. Its Level B criteria name UV exposure units, high-brightness LED sources, or low-voltage electronics builds where a certified power supply provides isolation from the mains — which is this build in one clause. Level A is reserved for work done with purchased, certified equipment, and a module you have soldered yourself is not that.

The rubric’s Level B controls for electronics are the ones this page applies: certified, isolated low-voltage supplies, and no exposed mains conductors at any stage. Both hold by construction. The supply is a USB charger or power bank with its own approvals, nothing in the build exceeds 5 V, and no mains enclosure is opened. HSE’s guidance names limiting the supply voltage to the lowest that will do the job as one of the best ways of reducing the risk of injury, and notes that 230 V AC can kill and that the risk is worst in wet surroundings — which is the room this instrument will end up in.

What is not a hazard here, and why. This page handles no chemistry at all. There is no developer, no fixer, no silver salt, no acid, no solution of any kind, and therefore no splash risk, no glove-selection problem, no eye-irrigation requirement, no vapour, and no liquid waste stream. Saying so plainly matters, because the reflex after twelve parts of chemical safety is to import the whole apparatus of controls, and importing controls that do not apply wastes the attention the real hazards need. The only substances present are a few grams of solder alloy, its flux, and a little isopropanol for cleaning residue.

Nor is there a shock hazard in the ordinary sense. Five volts across dry skin drives a current far below anything a person can feel, and the reason is arithmetic rather than reassurance: skin resistance is measured in tens of kilohms and Ohm’s law does the rest. What five volts can do is deliver a great deal of current into a short circuit, which is a heating and fire question rather than a shock one, and it is why a bare lithium cell is not permitted anywhere in this course and a certified power bank is.

Burns, from the soldering iron and from fresh joints. The tip runs at about 350 °C and a joint stays at solder temperature for several seconds after the iron leaves. The iron returns to its stand every time it leaves your hand. If you are burned, the NHS instruction is cool running water for 20 minutes, as soon as possible; remove clothing and jewellery near the area but never anything stuck to it; and cover the cooled injury by laying cling film over it rather than wrapping. The course’s first aid page carries the general guidance.

Solder flux fume. HSE’s EH40 lists rosin-based solder flux fume, CAS 8050-09-7, at 0.05 mg/m³ over eight hours and 0.15 mg/m³ over fifteen minutes, annotated Sen — capable of causing occupational asthma. The controls are in the next two sections and they are proportionate: the fume rises, so the whole of your exposure comes from having your head in the plume.

Optical radiation from the emitter. A one-watt LED at arm’s length is a lamp; at 30 mm from an eye it is not. Risk groups under BS EN 62471 are assigned by measurement to a specific lamp system, and neither the maker nor this course has measured yours, so the course states no risk group for your LED. HSE’s guidance places exempt and Risk Group 1 LEDs among safe sources and Risk Group 2 LED systems among sources that are safe in normal use but can harm if placed extremely close to the eyes. The control that does not depend on knowing the group: never look into the unshielded emitter, point it away from your face while wiring, and run the bench tests at the lowest current that gives a usable monitor reading.

Heat from the LED and its heatsink. At a few hundred milliamps the star board and heatsink become hot enough to burn a finger held on them. Cree give the maximum junction temperature as 150 °C, and the solder point is not far below it.

Flying offcuts. Trimming component leads fires the cut end across the room. Cut with the offcut trapped between your fingers.

Trip and snag. A USB lead across a floor in a room worked in the dark is a hazard the darkroom inherits from this bench. Route and tape it now, not later.

Safety spectacles with side protection, worn for all soldering and all lead trimming. This is the one item that is not optional, and the reason is the offcuts rather than the solder.

Nothing else is specified, and the reason is stated rather than assumed. Gloves are not among the controls here: there is no chemical to keep off the skin, and a glove between your fingers and a 350 °C iron makes the handling worse rather than better by dulling the feedback that stops a burn. A respirator is not among them either — the flux-fume control is ventilation and head position, and HSE’s own hierarchy puts those above personal protection. The isopropanol used for cleaning residue is handled in millilitres and the control is its own label.

Wash your hands before eating. Even with lead-free solder, a bench is a bench.

Work at a bench with a window open and a small fan set to move air across the bench and away from your face — not blowing at the joint, which scatters the plume, but drawing it past you.

HSE’s HSG258 classes solder fume among fumes that rise, expand and mix with the room air, and its hierarchy puts eliminating, substituting and reducing the source ahead of extraction. Applied here, that means: solder for an hour rather than an afternoon, keep your head out of the rising plume, and make fewer joints by breadboarding first.

If you buy a bench-top fume extractor, buy it knowing what HSG258 says about them: some of the fan-and-filter units commonly used for solder fume control are ineffective, and a supplier should be able to show that a proposed system provides adequate control. Position it to capture the plume at the joint, a few centimetres away, rather than to stir the room from across the bench.

The bill of materials, with what each part is for and what may replace it. Nothing here is a proprietary kit and every line has a substitute.

Part Quantity What it does Substitutes and notes
White LED on a 20 mm aluminium star board, about 1 W 1 The source Any mid-power white emitter on a star. The Cree XP-E2 is the course’s worked datasheet example, not a mandate; whatever you buy, find its forward voltage at your current, its maximum current, its maximum junction temperature and its thermal resistance before you wire it
Heatsink, 20 to 40 mm, with thermal pad or adhesive 1 Holds the junction temperature still, which holds the light output still A 40 × 40 mm finned extrusion is ample. An offcut of 3 mm aluminium plate works. The thermal interface matters more than the fin area at these powers
Constant-current LED driver module, adjustable, 5 V input 1 Sets the current and holds it Or a series resistor, below. The course has not verified a specific module and names none; see the callout under Build stage 2 for the five numbers to check on its datasheet
Resistor, 47 Ω, 0.5 W, for the resistor-limited route 1 Sets about 50 mA from 5 V Only if you take the resistor route. Recompute it for your LED’s forward voltage
IRLZ44N logic-level N-channel MOSFET, TO-220 1 Carries the LED current, switched by a 3.3 V pin Any logic-level N-channel part whose datasheet quotes an on-resistance at 3.3 V of gate drive is a better choice than the IRLZ44N, which quotes 10, 5.0 and 4.0 V and nothing lower
Resistor, 330 Ω 1 Gate series resistor; limits the pin current to 10 mA while the gate capacitance charges 220 Ω to 1 kΩ all work. Below 220 Ω the pin is asked for more than its 12 mA drive setting
Resistor, 100 kΩ 1 Gate pull-down; holds the lamp off while the Pico is in reset or unplugged Not optional. This is the resistor that stops a lamp switching itself on inside a closed box
Resistor, 220 kΩ 1 Photodiode load; converts photocurrent to a voltage the ADC can read Chosen on the bench in stage 3. Start at 220 kΩ and change it until the reading sits near two-thirds of full scale
BPW34 silicon PIN photodiode 1 The monitor: watches the lamp during every exposure Optional but strongly recommended. An OPT101, which puts the photodiode and its amplifier on one die at 0.45 A/W at 650 nm, removes the load-resistor choice at higher cost
Raspberry Pi Pico, with headers 1 Times the exposure, reads the monitor, writes the log A Pico W works and its wireless is unused. An Arduino or ESP32 runs the same circuit with the pin numbers and the language changed
Momentary push button 1 Triggers an exposure Any normally-open switch to 0 V; the internal pull-up does the rest
Electrolytic capacitor, 470 µF, 10 V or more 1 Holds the 5 V rail up when the lamp switches on The cure for a Pico that resets on every exposure. Fit it at the driver, not at the Pico
Ceramic capacitor, 100 nF 2 Decoupling at the driver and at the photodiode Standard practice; cheap; fit them
Solderless breadboard, 400 or 830 points 1 The prototype, and a legitimate final form Everything in this list is through-hole for exactly this reason
Stripboard, 0.1 in pitch, about 50 × 80 mm 1 The soldered final form Optional. A breadboard taped down inside the enclosure measures just as well until something is knocked
Hook-up wire, 22 AWG solid and stranded a few metres Wiring Solid for the breadboard, stranded for anything that flexes
USB supply or power bank, 1 A or better, and a lead 1 Power, at the only voltage this course builds at A certified supply or a power bank. Never a bare lithium cell, never a bench supply of unknown provenance, never anything mains that has been opened
Heat-shrink sleeving, assorted a little Insulating and strain-relieving the LED leads Electrical tape is a poor second and unwraps when warm

The course’s firmware drives no display, and that is a decision rather than an omission. A small OLED is one more part, one more library and one more thing to fail in the dark, and the serial log is a better record than a screen because it can be pasted into the lab notebook. The enclosure page adds the one indicator the instrument actually needs, which is an LED you can see with the lid down.

Tool For Notes
Temperature-controlled soldering iron, fine tip Every joint About 350 °C, back in the stand every time
Lead-free solder, 0.7 mm Joints The flux-fume limit applies to leaded and lead-free alike
Side cutters, wire strippers, tweezers Preparation and trimming Spectacles on for the trimming
Helping hands or a small vice Holding the work The commonest cause of a burn is holding a hot board
Digital multimeter Everything Continuity, then voltage, then current. The single most useful tool on the bench
Computer with a serial terminal Loading and running the firmware Thonny needs no configuration; mpremote or any terminal works
Lux meter, or a phone app you have compared with one Recording the emitter’s output on the bench The planner carries a lux-meter line already
Second timepiece, with a seconds display The independent timing check A phone stopwatch is adequate at the 0.1 per cent level over 60 s
Isopropanol and a stiff brush Flux residue Small quantities; read its label

Cost band ££. The Pico and the LED are the two named parts; everything else is passive components and wire that cost less together than either of them. The one line that can double the total is the constant-current driver module, and the resistor route removes it entirely at a stated cost in stability.

This page quotes no prices, because it cannot verify a current one and because the laboratory planner does not yet carry a single electronics line. The planner records what it could not price rather than guessing, and the electronics for Parts XIV to XVII are on the list of things it is waiting on. What is durable, and is on this page instead, is the specification: the five numbers to check on any substitute part’s datasheet outlast any price.

Almost nothing in this session is consumed. The parts are capital: they go into an instrument that is meant to last for years and to be recalibrated rather than replaced. What is actually used up is a few grams of alloy and a little solvent.

Consumed This session Sourced price Cost this session
Lead-free solder, 0.7 mm about 2 g, or none if you stay on the breadboard None. The planner carries no electronics line
Heat-shrink sleeving about 100 mm None. The planner carries no electronics line
Isopropanol, for flux residue a few millilitres None. The planner prices isopropanol only in the darkroom quantities of Part II
Stripboard one 50 × 80 mm piece, or none None. The planner carries no electronics line

No row here carries a dated price, so no total is given and none should be inferred. Nothing on this list is free. A run of this session a second time — to build a spare module, or after a mistake — consumes the same four lines and nothing else, because every component is reusable and the two most expensive are socketed rather than soldered in.

Seven stages, about three hours. Stage 0 is not optional and stage 5 is the one people skip.

Stage 0 — Fill in the five numbers (30 minutes)

Section titled “Stage 0 — Fill in the five numbers (30 minutes)”

Before a single wire, open the datasheets for the LED and the MOSFET you actually bought and write these on the first page of the build record.

LED. Forward voltage at the current you intend; maximum DC forward current; maximum junction temperature; thermal resistance junction to solder point; temperature coefficient of forward voltage. For a white XP-E2 those are 2.84 to 3.1 V at 350 mA and 85 °C, 1500 mA, 150 °C, 5.8 °C/W and −1.5 mV/°C.

MOSFET. On-resistance at the gate voltage you will apply; gate threshold; input capacitance; maximum continuous drain current; gate-source voltage rating. For the IRLZ44N those are not quoted at 3.3 V — the datasheet gives 0.025 Ω at 5.0 V and 0.035 Ω at 4.0 V and stops — with a threshold of 1.0 to 2.0 V, 1700 pF, 47 A and ±16 V.

If your LED’s forward voltage is not 2.9 V, every resistor value below changes and you must recompute it. That is the point of the stage.

Stage 1 — The Pico and the button (20 minutes)

Section titled “Stage 1 — The Pico and the button (20 minutes)”

Push the Pico into the breadboard across the centre channel. Wire the button from GPIO14 to a ground rail, and join the Pico’s ground pin to that rail. Nothing else yet.

Load MicroPython on the board if it is new: hold BOOTSEL while plugging in the USB lead, and the Pico appears as a mass-storage device onto which the interpreter’s .uf2 file is dragged. Then, at the REPL:

from machine import Pin
b = Pin(14, Pin.IN, Pin.PULL_UP)
print(b.value()) # 1 with the button released
print(b.value()) # 0 while you hold it down

If it reads 0 with nothing pressed, the button is wired to the wrong rail or is not a normally-open type. Fix it here; a button that reads backwards is very confusing three stages later.

Stage 2 — The switch and first light (30 minutes)

Section titled “Stage 2 — The switch and first light (30 minutes)”

Wire the low-side switch exactly as the schematic shows. Build it with the LED disconnected first, check with the multimeter that GPIO15 high pulls the MOSFET’s drain to within a few tens of millivolts of ground and that GPIO15 low leaves it floating high, and only then connect the LED.

The complete module: switch, lamp, monitor and trigger

+5 V (USB)1CC element234DS5330 Ω100 kΩ6PicoGPIO15GPIO14GPIO26 / ADC0GPIO27 / ADC13V3 outBPW34780 V9
  1. +5 V rail, from USB only — certified supply or power bank; nothing mains, no bare cells
  2. Constant-current element — driver module set to the working current, or 47 Ω for the resistor route
  3. 470 µF and 100 nF at the driver — holds the rail up through the switching step; fit them here, not at the Pico
  4. LED on star board and heatsink — anode to the element, cathode to the MOSFET drain
  5. IRLZ44N, low side — source to 0 V; drain to the LED cathode
  6. 330 Ω gate series, 100 kΩ gate pull-down — 10 mA peak from the pin; gate defined when the Pico is not driving it
  7. BPW34 from 3V3 through 220 kΩ to 0 V — reverse biased; the ADC reads the voltage across the load resistor
  8. GPIO27 tied to 0 V — the converter reads its own offset on ADC1, as the Pico datasheet suggests
  9. Single ground junction — lamp current and logic meet once; a shared track is how a lamp resets a processor
Two things in this drawing are easy to get wrong and expensive to find later: the photodiode runs from 3V3 and not from the 5 V rail, because an ADC pin must not be taken above the 3.3 V supply; and the two capacitors belong at the driver, where the current step happens.

Breadboard layout, seen from above

+5 V0 V+5 V0 VABCDEFGHIJ151015202530central channelRaspberry Pi Pico, USB left, columns 1–2012345678910111213141516
  1. Pico, USB to the left, columns 1 to 20 — pins land in row C and row H; the 0.7 in row spacing means it straddles the channel with rows A-B and I-J free
  2. C1 to top + rail, C3 to top − rail — VBUS carries the 5 V rail and the lamp current runs back through the Pico's USB connector; keep the total under 400 mA
  3. C9 to top − rail — GPIO27, ADC1, tied to 0 V so the firmware can read the converter's own offset
  4. C5 to B23, C10 to B25 — 3V3 out to the photodiode cathode column; GPIO26 to the monitor junction column
  5. BPW34: cathode D23, anode D25 — reverse biased — cathode to 3V3, never to the 5 V rail, because an ADC pin must not exceed the 3.3 V supply
  6. 220 kΩ from E25 to E27; A27 to top − rail — the photodiode load. Change this value in stage 3 until the reading sits near two-thirds of full scale
  7. 100 nF from C25 to C27 — across the load resistor; quietens the monitor reading
  8. Button from J19 to J21; I21 to bottom − rail — GPIO14 with its internal pull-up, so a press reads 0
  9. 330 Ω from I20 to I24 — GPIO15 to the MOSFET gate column; 10 mA peak into the gate capacitance
  10. 100 kΩ from H24 to bottom − rail — gate pull-down; the lamp stays off while the Pico is in reset or unplugged
  11. IRLZ44N: gate J24, drain J25, source J26 — check the pinout against your own datasheet — TO-220 packages are not all in this order
  12. H26 to bottom − rail — MOSFET source to 0 V
  13. Constant-current element: bottom + rail to F29 — the driver module's output, or the 47 Ω resistor of the resistor route
  14. 470 µF and 100 nF, bottom + rail to bottom − rail at columns 27 and 28 — watch the electrolytic's polarity; these belong here, at the current step, not by the Pico
  15. Two jumpers at column 30 — top + rail to bottom + rail, top − rail to bottom − rail
  16. LED on flying leads: anode from column 29, cathode to column 25 — off the board with its heatsink; heat-shrink and a cable tie on both leads
The key is the wiring, hole by hole; the drawing is the map. Build it in the key's order and check continuity with a meter before the first power-up.

Check the whole board against the key with the meter on continuity before you plug the USB lead in. Three checks catch almost everything: the two rails are not connected to each other; the MOSFET’s gate and source are not connected to each other; and the photodiode’s cathode is on the 3V3 column and not the 5 V rail.

Then, at the REPL, with the LED connected and pointed away from your face:

from machine import Pin
import time
lamp = Pin(15, Pin.OUT, value=0)
lamp.value(1); time.sleep(1); lamp.value(0)

Stage 3 — The monitor, and choosing its load resistor (25 minutes)

Section titled “Stage 3 — The monitor, and choosing its load resistor (25 minutes)”

The BPW34 is wired reverse-biased from the Pico’s 3V3 output, not from the 5 V rail: an ADC input must not go above the 3.3 V supply by more than about 300 mV, because those pins carry a reverse diode to that rail. Cathode to 3V3, anode to the top of the load resistor, load resistor to 0 V, and the ADC reads the junction.

Sizing the load resistor is a two-line calculation and then a measurement. The datasheet gives a short-circuit current of 80 µA at 1000 lux under standard light A, so:

V = I_photo × R, with I_photo ≈ 80 nA per lux
Monitor voltage

At 100 lux on the sensor — a plausible figure a few centimetres off-axis from the emitter — that is 8 µA, and 220 kΩ gives 1.76 V, comfortably over half of the 3.3 V range. But the real figure depends entirely on where you put the sensor, so do this instead: fit 220 kΩ, switch the lamp on, read monitor.read_u16(), and change the resistor until the reading sits between about 20,000 and 45,000. Below that you are wasting resolution; above about 62,000 the reading saturates and can no longer detect an increase, which is the failure mode that hides a fault.

Position the sensor so it sees the emitter but not the film plane, and fix it permanently. A monitor that moves is a monitor that lies.

Save the listing below to the board as sensitometer.py. Then, at the REPL:

import sensitometer as s
s.selftest()

selftest prints the button state, the monitor reading dark and lit, and passes or fails on whether the lamp switches and the monitor is on scale. Do not go further until it passes.

This is the whole of it. It is published under the course’s content licence and was tested on MicroPython v1.24.1 for the RP2 port. Four settings near the top are meant to be changed and the rest is not: EXPOSURE_MS, WARM_UP_S, CADENCE_S and SETTLE_US all get their real values from stage 5, and the values in the listing are provisional starting points rather than measurements.

"""
sensitometer.py - Pure Silver, Part XIV: LED light source and exposure timer.
Target Raspberry Pi Pico (RP2040), MicroPython v1.24.1 for RPI_PICO.
Install copy to the board as sensitometer.py, then at the REPL:
import sensitometer as s
s.selftest()
Licence CC BY-SA 4.0, as the rest of this course's content.
Every routine prints comma-separated values, with '#' beginning any line that
is a comment, so a captured terminal session is already a data file.
"""
import machine
import math
import micropython
import sys
import time
micropython.alloc_emergency_exception_buf(100)
VERSION = "1.0"
# --- Wiring. Rewiring the board means changing these four numbers only. -----
PIN_GATE = 15 # -> 330 R -> IRLZ44N gate; 100k gate-to-source pull-down
PIN_BUTTON = 14 # -> button -> 0 V; internal pull-up, so pressed reads 0
PIN_MONITOR = 26 # ADC0 <- photodiode load resistor
PIN_ZERO = 27 # ADC1 <- tied to 0 V, read as the converter's own offset
# --- Settings the calibration experiment will replace with measured ones. ---
EXPOSURE_MS = 500 # the design exposure of Part XIV
WARM_UP_S = 600 # continuous run before the first exposure of a session
CADENCE_S = 30 # minimum interval between exposures, so each starts alike
SETTLE_US = 5000 # delay after switch-on before the monitor is sampled
MONITOR_N = 32 # ADC readings averaged into one monitor value
DEBOUNCE_MS = 250 # further button edges ignored for this long
GUARD_US = 60000 # below this exposure the monitor is not sampled at all
lamp = machine.Pin(PIN_GATE, machine.Pin.OUT, value=0)
button = machine.Pin(PIN_BUTTON, machine.Pin.IN, machine.Pin.PULL_UP)
monitor = machine.ADC(machine.Pin(PIN_MONITOR))
zero = machine.ADC(machine.Pin(PIN_ZERO))
try: # "LED" on current firmware, 25 on old
heartbeat = machine.Pin("LED", machine.Pin.OUT, value=0)
except (TypeError, ValueError):
heartbeat = machine.Pin(25, machine.Pin.OUT, value=0)
_count = 0
_press = False
_press_at = 0
COLUMNS = "n,kind,ticks_ms,requested_us,measured_us,monitor_mean,monitor_sd"
def _on_button(pin):
"""Soft-IRQ handler. Debounced in software: contacts bounce for milliseconds."""
global _press, _press_at
now = time.ticks_ms()
if time.ticks_diff(now, _press_at) < DEBOUNCE_MS:
return
_press_at = now
_press = True
button.irq(trigger=machine.Pin.IRQ_FALLING, handler=_on_button)
def mean(xs):
return sum(xs) / len(xs)
def sd(xs):
"""Sample standard deviation. Returns 0.0 for fewer than two values."""
n = len(xs)
if n < 2:
return 0.0
m = mean(xs)
return math.sqrt(sum((x - m) * (x - m) for x in xs) / (n - 1))
def off():
"""Everything dark. Call this if anything goes wrong."""
lamp.value(0)
heartbeat.value(0)
def header():
print("# Pure Silver sensitometer firmware v{}".format(VERSION))
print("# {}".format(sys.implementation))
print("# exposure {} ms, cadence {} s, monitor {} samples".format(
EXPOSURE_MS, CADENCE_S, MONITOR_N))
def read_monitor(n=MONITOR_N):
"""Mean and standard deviation of n monitor readings, offset-corrected.
The offset comes from a second ADC channel tied to 0 V, because the Pico's
converter has an inherent offset of tens of millivolts that varies from
chip to chip. read_u16 always returns 0 to 65535 whatever the real
resolution, so the bottom four bits here carry no information.
"""
offset = zero.read_u16()
xs = []
for _ in range(n):
xs.append(monitor.read_u16() - offset)
return mean(xs), sd(xs)
def expose(ms=EXPOSURE_MS):
"""Switch the lamp on for ms milliseconds. Return what actually happened.
Returns (requested_us, measured_us, monitor_mean, monitor_sd), with the two
monitor values set to -1.0 when the exposure was too short to sample.
The interval is busy-waited on the microsecond counter. That is deliberate:
machine.Timer on the RP2 port is a virtual timer whose callback can be
delayed by garbage collection, so the tightest thing available is a loop
that does nothing else. The loop can only end on an iteration, so the
measured interval always slightly exceeds the requested one, and the
routine reports the interval it achieved rather than the one it was asked
for.
"""
target = int(ms * 1000)
m_mean = -1.0
m_sd = -1.0
lamp.value(1)
start = time.ticks_us()
try:
if target >= GUARD_US:
time.sleep_us(SETTLE_US)
m_mean, m_sd = read_monitor()
while time.ticks_diff(time.ticks_us(), start) < target:
pass
finally:
lamp.value(0)
measured = time.ticks_diff(time.ticks_us(), start)
return target, measured, m_mean, m_sd
def _log(kind, target, measured, m_mean, m_sd):
global _count
_count += 1
print("{},{},{},{},{},{:.1f},{:.1f}".format(
_count, kind, time.ticks_ms(), target, measured, m_mean, m_sd))
def selftest():
"""Prove the wiring before anything is exposed. Nothing runs for long."""
header()
off()
print("# button reads {} (1 = released, 0 = pressed)".format(button.value()))
time.sleep_ms(200)
dark, dark_sd = read_monitor()
lamp.value(1)
time.sleep_ms(300)
lit, lit_sd = read_monitor()
off()
print("# monitor dark {:.1f} +/- {:.1f}".format(dark, dark_sd))
print("# monitor lit {:.1f} +/- {:.1f}".format(lit, lit_sd))
if lit - dark < 500:
print("# FAIL: the monitor barely sees the lamp.")
print("# Check the LED, the driver, the MOSFET gate and the photodiode polarity.")
elif lit > 62000:
print("# FAIL: the monitor is saturated and cannot detect a change.")
print("# Reduce its load resistor, or move it further from the emitter.")
else:
print("# PASS: the lamp switches and the monitor is on scale.")
return lit - dark
def warm_up(seconds=WARM_UP_S, interval=30):
"""Run the lamp continuously, logging the monitor, and print the curve.
This is the drift characterisation, not an operating step. Run it once,
plot monitor_mean against elapsed_s, and read off how long the assembly
takes to stop moving and by how much it moved. Set WARM_UP_S from your own
plot; the 600 s here is a provisional starting value, not a measurement.
"""
print("# warm_up: {} s continuous, monitor every {} s".format(seconds, interval))
print("elapsed_s,monitor_mean,monitor_sd")
lamp.value(1)
start = time.ticks_ms()
due = 0
try:
while True:
elapsed = time.ticks_diff(time.ticks_ms(), start) // 1000
if elapsed >= due:
m, s = read_monitor()
print("{},{:.1f},{:.1f}".format(elapsed, m, s))
due = due + interval
if elapsed >= seconds:
break
time.sleep_ms(100)
finally:
off()
print("# warm_up complete")
def repeat(n=10, ms=EXPOSURE_MS, cadence_s=CADENCE_S):
"""n identical exposures at a fixed cadence, with the statistics at the end.
This is the repeatability test, and the cadence is part of the result: with
the lamp off between exposures the LED cools, so strips made two minutes
apart are not the same measurement as strips made ten seconds apart. Fix
the cadence, record it, and quote it with the figure.
"""
print("# repeat: {} exposures of {} ms at a {} s cadence".format(n, ms, cadence_s))
print(COLUMNS)
times = []
lights = []
for i in range(n):
if i:
time.sleep(cadence_s)
record = expose(ms)
_log("repeat", *record)
times.append(record[1])
if record[2] >= 0:
lights.append(record[2])
t_mean = mean(times)
print("# measured_us mean {:.1f} sd {:.2f} ({:.4f} % of the mean)".format(
t_mean, sd(times), 100.0 * sd(times) / t_mean))
if len(lights) > 1:
l_mean = mean(lights)
l_sd = sd(lights)
print("# monitor mean {:.1f} sd {:.2f} ({:.3f} % of the mean)".format(
l_mean, l_sd, 100.0 * l_sd / l_mean))
print("# flux spread expressed as log H: {:.5f}".format(
math.log10(1.0 + l_sd / l_mean)))
return times, lights
def session(ms=EXPOSURE_MS, warm_s=WARM_UP_S, cadence_s=CADENCE_S):
"""Warm up, then make one exposure per button press, logging every one.
Runs until interrupted. Ctrl-C at the REPL leaves the lamp off, because
expose() switches it off in a finally clause.
"""
global _press
header()
if warm_s:
warm_up(warm_s)
print(COLUMNS)
last = time.ticks_ms()
_press = False
try:
while True:
if _press:
_press = False
wait = cadence_s * 1000 - time.ticks_diff(time.ticks_ms(), last)
if wait > 0:
print("# holding {} ms to keep the cadence".format(wait))
time.sleep_ms(wait)
heartbeat.value(1)
record = expose(ms)
heartbeat.value(0)
last = time.ticks_ms()
_log("exposure", *record)
time.sleep_ms(20)
finally:
off()

Three things in that listing repay a second reading. expose switches the lamp off inside a finally clause, so an interrupt at the REPL leaves the lamp dark rather than lit. The exposure interval is a busy-wait on ticks_us, because machine.Timer on this port is a virtual timer whose callback can be delayed by garbage collection, and the loop can only end on an iteration, so the measured interval always slightly exceeds the requested one — which is why the routine reports the interval it achieved. And read_monitor subtracts a reading from a second ADC channel tied to 0 V, which is the Pico datasheet’s own suggestion for dealing with a converter whose reference is filtered from a switching regulator and whose offset of some tens of millivolts varies from chip to chip.

Stage 5 — Characterise the lamp (40 minutes)

Section titled “Stage 5 — Characterise the lamp (40 minutes)”

This is the stage that turns a circuit into an instrument, and it is the one that gets skipped.

s.warm_up(1800, 30) # 30 minutes continuous, a monitor reading every 30 s
s.repeat(10, 500, 30) # ten 500 ms exposures at a 30 s cadence

Capture both to a file. The first is your drift curve and the second is your repeatability, and neither exists for your device anywhere else.

One exposure, end to end

Lamp
offon: settle 5 mson: exposing, 500 msoff
Monitor
32 ADC reads
Log
one CSV line
The settle delay exists because a driver's output takes time to reach its set current, and the monitor must not be read during that transient. Five milliseconds is a starting value; stage 5 tells you what yours needs.

Stage 6 — Commit it to metal, or do not (45 minutes)

Section titled “Stage 6 — Commit it to metal, or do not (45 minutes)”

If the breadboard works and will live inside the enclosure on double-sided tape, it will measure exactly as well as a soldered board until something is knocked. Many readers should stop here.

If you solder: lay the stripboard out to match the breadboard, cut the tracks under the Pico’s two rows of pins and between the MOSFET’s three legs, and solder in this order — links first, then resistors, then the capacitors, then the MOSFET, then the Pico’s headers last. Check continuity with the multimeter before the first power-up, and check specifically that the MOSFET’s gate and source are not shorted, which is the failure a cut-track mistake produces.

The LED and its heatsink stay off the board, on flying leads, because they belong at the bottom of the enclosure and the board does not.

Stage 7 — Strain relief and labelling (10 minutes)

Section titled “Stage 7 — Strain relief and labelling (10 minutes)”

Every wire that leaves the board gets a cable tie or a blob of hot-melt adhesive within 20 mm of its joint, so that a pull lands on the tie and not on the solder. The LED’s two leads get heat-shrink and a tie. Label the board with the date, the drive current, the load resistor value and the firmware version, in permanent marker, on the board itself — not on a note that will be lost. The instrument certificate the calibration experiment writes will refer to these, and a module whose current nobody recorded has to be characterised again from the beginning.

Three tests, in this order, and all three produce numbers that go on the instrument certificate the calibration experiment later in this part writes. The tables below are blank on purpose. The course has not built and measured this module, and printing a plausible drift figure would be inventing a measurement — which is the one thing this course does not do. Fill them in from your own bench.

Test 1 — Exposure time, against an independent clock

Section titled “Test 1 — Exposure time, against an independent clock”

The firmware’s own measured_us is honest but self-referential: it is the same counter that timed the exposure. One check from outside is needed, and one is enough.

import sensitometer as s
s.expose(60000) # sixty seconds; start a stopwatch on the same breath

A minute timed by hand is good to about a tenth of a second, or 0.17 per cent — thirty times looser than the crystal’s own ±65 ppm and about six times tighter than the one per cent the instrument needs. If the two agree, the whole timing chain is proved and you need never test it again.

Requested Firmware’s measured_us Independent clock Difference
60 s check 60.000 s
Repeat, next session 60.000 s

Test 2 — Flux stability over thirty minutes

Section titled “Test 2 — Flux stability over thirty minutes”
s.warm_up(1800, 30)

Plot monitor_mean against elapsed_s. What you are looking for is not a number but a shape: a rise or fall that flattens, and the time at which it flattens. Read three things off it.

Quantity How to read it Your figure
Total excursion, first reading to last (max − min) ÷ mean, as a percentage
Time to settle within 0.5 per cent of the final value from the plot
Residual drift after settling, per 10 minutes slope of the flat part
Residual drift expressed in log H log₁₀(1 + fractional drift)

The middle row is your warm-up rule and it replaces the provisional value in the firmware. If your lamp settles in four minutes, WARM_UP_S = 600 is wasting six minutes of every session; if it takes twenty, the provisional value is dangerously short.

Test 3 — Repeatability of ten identical exposures

Section titled “Test 3 — Repeatability of ten identical exposures”
s.repeat(10, 500, 30)

The firmware computes the statistics for you and prints the flux spread in log H, which is the form the error budget wants.

Quantity Firmware output Your figure
Mean measured interval measured_us mean
Timing spread, as a percentage of the mean sd line
Mean monitor reading monitor mean
Flux spread, as a percentage of the mean sd line
Flux spread in log H flux spread expressed as log H

Then run it again at a different cadence — ten seconds instead of thirty — and record both. If the two differ, the cadence is part of your operating procedure and must be written on the certificate. The next section says why it might.

Every exposure is a thermal event as well as an optical one.

At 350 mA and about 2.9 V the LED is dissipating roughly a watt, almost all of it as heat. Cree’s thermal resistance from junction to solder point is 5.8 °C/W for a white part, so the junction sits about 6 °C above its own solder point whenever it is running — and it gets there fast, because the die and the slug beneath it have very little heat capacity. The heatsink, by contrast, has a great deal, and warms over tens of seconds to minutes.

That split is the whole of the behaviour you are about to measure, and it has a consequence worth stating before you see it. In a half-second exposure the junction reaches its excess over the heatsink almost immediately and then stops moving. What changes from exposure to exposure is not the junction’s excess but the heatsink’s own temperature, which depends on how long ago the last exposure was. That is why repeat takes a cadence argument and why it is part of the result rather than a convenience. Note what the course is doing here: Cree publish the thermal resistance, and that is a datasheet fact; the time constants are not published for any assembly, which is precisely why this is a measurement and not a calculation.

Two optical consequences follow the thermal one. Flux droops as the junction warms — Cree plot relative flux against junction temperature from 25 °C to 150 °C, and this course reads the axes of that chart and not its ordinates, because a value taken off a printed graph is a guess with a decimal point on it. And the spectrum shifts, because a phosphor white LED is a blue emitter under a phosphor and the two do not respond to temperature identically; Cree publish a chart of relative chromaticity against current and temperature, whose existence is the evidence that the mixture moves.

Constant-current drive removes the runaway that constant-voltage drive would add on top of all this, but it does not remove the droop: the current is held, the temperature still rises, and the light still falls. What removes most of the droop is the same starting temperature every time, which is what the cadence buys, and what accounts for the rest is the monitor, which turns the residue into a number you can put in the budget instead of an unknown you have to bound.

What you see Likely cause What to do
LED does not light at all LED reversed, or the driver’s output open, or the MOSFET not switching Meter first, guess second. With GPIO15 high, measure gate to source: it should read about 3.3 V. Then measure drain to source: a few tens of millivolts means the MOSFET is on and the fault is upstream. Then measure across the LED
LED is permanently on and the pin does nothing Drain and source swapped, or the MOSFET is not a logic-level part, or the body diode is conducting Check the pinout against the datasheet — TO-220 packages are not all the same order. If the gate is at 0 V and the LED still lights, the device is in backwards and its body diode is passing the current
LED lights dimly and the MOSFET gets hot The gate is not being driven hard enough to bring the device fully on Measure the gate voltage while it is on. If it is well below 3.3 V, the gate resistor is too large or the pin is loaded. If it is at 3.3 V and the drain still sits at a volt or more, your MOSFET is not logic-level: replace it with one whose datasheet quotes on-resistance at 3.3 V
The Pico resets every time the lamp switches on Supply sag: the current step drops the 5 V rail through the resistance of the wiring, and the board browns out Fit the 470 µF across the rail at the driver. Shorten and thicken the supply wires. Join grounds at one point rather than along a shared track. If it persists, power the lamp from a second USB supply, joining only the grounds
Monitor reading jumps about by thousands of counts Mains-frequency light falling on the photodiode, or a floating ADC pin, or a ground loop Shield the sensor from room light — it should see the emitter and nothing else. Check GPIO27 really is at 0 V. Increase MONITOR_N. The RP2 documentation warns that an unconfigured ADC pin sinks about 60 µA after a hard reset, which produces exactly this
Monitor sits near 65535 whatever the lamp does Saturated: the load resistor is too large, or the sensor is too close Reduce the load resistor, or move the sensor further from the emitter or off-axis. Saturation is dangerous because it hides an increase and looks like perfect stability
Monitor reads a few hundred with the lamp on The photodiode is reversed, or the load resistor is far too small Cathode goes to 3V3, anode to the load resistor. Reversed, it is a forward-biased diode and reads a fixed voltage that does not follow the lamp
One button press gives three exposures Contact bounce outrunning the debounce window Increase DEBOUNCE_MS to 400. If it persists, the button is worn: a hardware 100 nF across its contacts helps and does not replace the software
Measured interval far longer than requested Something else is running: a print inside the loop, an interrupt firing, or garbage collection Nothing may run during the busy-wait. Check you have not added a print or a monitor read inside the while loop. Call gc.collect() before the exposure, not during it
Nothing appears on the serial port The board is in BOOTSEL mode, or the wrong device is open, or MicroPython is not installed Unplug, replug without holding BOOTSEL. If it enumerates as a mass-storage device, the interpreter is not installed
Ten exposures show a steady downward trend in the monitor The assembly is still warming, and you did not warm it up Run warm_up first and read your own settling time off the curve. This is the fault the whole of test 2 exists to find
  1. Your LED measures 2.65 V forward at 50 mA rather than the 2.72 V assumed on this page, and you are taking the resistor route from a 5.0 V rail. Recompute the resistor, its dissipation, and the percentage change in current that a 1 per cent supply wobble now produces. Say whether the change in forward voltage made the supply sensitivity better or worse, and why.
  2. The firmware reports measured_us of 500 312, 500 287 and 500 305 for three requested 500 ms exposures. Express the spread as a fraction of the exposure and in log H, and say whether it belongs in the error budget or can be ignored. Then explain why the offset of about 300 µs is not an error at all.
  3. selftest prints a lit reading of 63 800 and a dark reading of 640. It reports a pass. Why is that pass misleading, what will the module do wrong that will not be obvious for weeks, and what is the fix?
  4. Your warm-up curve falls by 4 per cent over the first eight minutes and is then flat. Convert the 4 per cent to log H, compare it with the 0.02 log H uniformity target from the design lesson, and say what warm-up rule you would write. Then say what would change if the fall were 0.4 per cent instead.
  5. A friend wires the MOSFET on the high side — between the 5 V rail and the LED anode, with the LED cathode to ground — using the same IRLZ44N and the same 3.3 V pin. Explain why the lamp will either not light or light dimly, in terms of the gate-to-source voltage rather than in terms of convention.
  6. The driver module you bought says nothing about open-circuit operation. Give the two wirings that are then available, say what each one asks the driver to do at the moment of switching, and say which measurement in stage 5 would reveal a driver that is unhappy with the choice you made.

Measure the intermittency effect on your own monitor, and then on film. The design lesson forbids PWM during an exposure on the strength of Sheppard and Mees’s 1907 sector-wheel measurement, and says plainly that the critical frequency for a modern emulsion is not published anywhere the course has read. You can attack the second half of that. Drive the lamp with machine.PWM, whose duty_u16 sets the duty cycle as a ratio of the value you give it to 65535, so half duty is duty_u16(32768); take 100 Hz, 1 kHz and 10 kHz in turn and confirm on the monitor that the mean is the same at all three — it should be, since the photodiode integrates. Then expose three strips of film for the same total time at the three frequencies plus one at fixed current at half the current, and develop all four together. If the four strips differ, you have measured the intermittency effect with equipment you built.

Find your cadence dependence. Run repeat(10, 500, 10) and repeat(10, 500, 120) on the same afternoon. Plot the monitor reading against exposure number for both. A rising or falling trend at the short cadence and a flat line at the long one is the heatsink’s thermal time constant showing itself, and the crossover tells you the shortest cadence the instrument may be operated at.

Compare the two current-setting routes head to head. Build both, and run each from a good regulated supply and then from a cheap USB charger under load — a phone charging from the same port is a realistic disturbance. The prediction from the arithmetic in stage 2 is a 2.1 per cent current change per 1 per cent supply change for the resistor and something far smaller for the driver. Measuring it turns a specification into your own number.

Build the green variant. A green emitter is the design lesson’s documented alternative: better matched to a lux meter, more stable in spectrum, and measuring a green speed rather than a panchromatic one. Build a second LED assembly, keep everything else identical, and expose the same film through both. The offset between the two curves is your own measurement of what the illuminant is worth — and it is a number nobody can look up for you.

Sources for this page

16 cited · checked 2026-09-05

  1. 01Raspberry Pi Pico Datasheet: An RP2040-based microcontroller boardRaspberry Pi Ltd§ Section 4.2, general purpose IO - GPIO powered from the on-board 3.3 V rail and fixed at 3.3 V, GPIO0 to GPIO22 digital only, GPIO26 to 28 ADC-capable, and the reverse diode to the 3.3 V rail that limits the input voltage on those pins; section 4.3, using the ADC - the reference filtered from the switching regulator through 201 ohms into 2.2 microfarads, the inherent offset of about 30 mV varying chip to chip, and the recommendation to tie a second channel to ground as an offset measurement; section 2.3 and the pin descriptions - VBUS 5 V plus or minus 10 per cent, VSYS 1.8 to 5.5 V, and the 3V3 pin load kept below 300 mA; section 3.1, current tablesdatasheets.raspberrypi.com/pico/pico-datasheet.pdftier 1, primary2026-09-05
  2. 02RP2040 Datasheet: A microcontroller by Raspberry PiRaspberry Pi Ltd§ Section 5.5.3.5, interpreting GPIO output voltage specifications - the 2, 4, 8 and 12 mA drive strengths are not hard limits, and the limits on the total current sourced and sunk by the IO bank; section 2.16.1.1, recommended crystalsdatasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdftier 1, primary2026-09-05
  3. 03IRLZ44NPbF HEXFET Power MOSFET, data sheet PD-94831International Rectifier, now Infineon Technologies, 2003§ Electrical Characteristics at TJ = 25 C - gate threshold voltage 1.0 to 2.0 V at VDS = VGS and ID = 250 microamps; on-resistance 0.022 ohm at 10 V, 0.025 ohm at 5.0 V and 0.035 ohm at 4.0 V of gate drive, with no figure at 3.3 V; input capacitance 1700 pF; Absolute Maximum Ratings - 55 V drain-source, 47 A continuous drain current at 25 C case, gate-source plus or minus 16 V, junction-to-ambient thermal resistance 62 C/Winfineon.com/dgdl/Infineon-IRLZ44N-DataSheet-v01_01-EN.pdftier 1, primary2026-09-05
  4. 04XLamp XP-E2 LEDs, product family data sheet CLD-DS56 rev 25BCree LED§ Characteristics - forward voltage 2.84 V minimum to 3.1 V maximum for white at 350 mA and 85 C and 3.12 V at 1000 mA; maximum DC forward current 1500 mA for white; maximum junction temperature 150 C; thermal resistance junction to solder point 5.8 C/W for white; temperature coefficient of voltage -1.5 mV/C for white; Relative Flux vs. Current, whose axes run to 1500 mA against a flux axis drawn to 300 per cent; and the absence of any switching or rise-time figure in the documentdownloads.cree-led.com/files/ds/x/XLamp-XPE2.pdftier 1, primary2026-09-05
  5. 05BPW 34 silicon PIN photodiode, data sheet version 1.5ams-OSRAM AG, 2020§ Characteristics at 25 C - short-circuit current 80 microamps at 1000 lux under standard light A, spectral sensitivity 80 nA/lx, wavelength of maximum sensitivity 920 nm, spectral range 420 to 1120 nm, radiant sensitive area 7.02 square millimetres, half angle 60 degrees, dark current 2 nA typical and 30 nA maximum, rise and fall times 0.02 microseconds; Maximum Ratings - reverse voltage 32 V, total power dissipation 150 mWlook.ams-osram.com/m/65d547088a09187c/original/BPW-34.pdftier 1, primary2026-09-05
  6. 06OPT101 monolithic photodiode and single-supply transimpedance amplifier, data sheet SBBS002Texas Instruments Incorporated§ Features and Electrical Characteristics - responsivity 0.45 A/W at 650 nm and 0.45 V per microwatt at the internal feedback resistor, with the photodiode and its transimpedance amplifier on one dieti.com/lit/ds/symlink/opt101.pdftier 1, primary2026-09-05
  7. 07Quick reference for the RP2, MicroPython documentationDamien P. George, Paul Sokolovsky and contributors§ Timers - the RP2040 system timer provides a global microsecond timebase but only the software timer is available; ADC - four 12-bit SAR channels on GP26 to GP29, standard range 0 to 3.3 V, read_u16 across that range, and the note that after a hard reset an unconfigured pin sinks about 60 microamps and can give wrong readings; Pins and GPIO - internal pull-up on an inputdocs.micropython.org/en/latest/rp2/quickref.htmltier 1, primary2026-09-05
  8. 08class Timer, control hardware timers, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ Timer Types - most ports support hardware timers except Zephyr and RP2, which support only virtual timers, and soft-interrupt callbacks are prone to garbage-collection jitterdocs.micropython.org/en/latest/library/machine.Timer.htmltier 1, primary2026-09-05
  9. 09time, time related functions, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ time.ticks_us and time.ticks_diff - counters from an arbitrary reference that wrap at an unexposed value, on which only ticks_diff and ticks_add are valid; time.sleep_us, documented as delaying for at least the requested intervaldocs.micropython.org/en/latest/library/time.htmltier 1, primary2026-09-05
  10. 10class ADC, analog to digital conversion, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ ADC.read_u16 - one reading returned as an integer from 0 to 65535 scaled across the input range, whatever the converter's real resolutiondocs.micropython.org/en/latest/library/machine.ADC.htmltier 1, primary2026-09-05
  11. 11class PWM, pulse width modulation, MicroPython library documentationDamien P. George, Paul Sokolovsky and contributors§ Constructor and methods - freq in hertz, duty_u16 setting the duty cycle as the ratio of the given value to 65535, and duty_ns setting the pulse width directly; and the note that on the rp2 port there are eight independent PWM blocks each with two outputs and a 16-bit counter, so setting the frequency of one object may affect another sharing the same generatordocs.micropython.org/en/latest/library/machine.PWM.htmltier 1, primary2026-09-05
  12. 12EH40/2005 Workplace exposure limits, containing the list of workplace exposure limits for use with COSHHHealth and Safety Executive, 2005§ Table 1 - rosin-based solder flux fume, CAS 8050-09-7, 0.05 mg/m3 over eight hours and 0.15 mg/m3 over fifteen minutes, annotated Sen; Annotations - Sen means capable of causing occupational asthmahse.gov.uk/pubns/priced/eh40.pdftier 1, primary2026-09-05
  13. 13Controlling airborne contaminants at work: A guide to local exhaust ventilation (LEV), HSG258Health and Safety Executive, 2011§ The list of controls that come before extraction, and paragraph 93, that some bench-mounted fan and filter units commonly used for solder fume control are ineffective and that a supplier should show the proposed system provides adequate controlhse.gov.uk/pubns/priced/hsg258.pdftier 1, primary2026-09-05
  14. 14Guidance for Employers on the Control of Artificial Optical Radiation at Work Regulations 2010Health and Safety Executive, 2010§ List 1 and the intermediate list - exempt and Risk Group 1 lamps and lamp systems including LEDs among safe sources, and Risk Group 2 lamps and LED systems among the sources that are safe under normal conditions but can cause harm if placed extremely close to the eyes; and the supplier's duty under section 6 of the Health and Safety at Work etc Act 1974 to provide information for safe useaber.ac.uk/en/media/departmental/healthsafetyenvironment/employers-aor.pdftier 1, primary2026-09-05
  15. 15Electrical safety and you: A brief guide, INDG231(rev1)Health and Safety Executive, 2012§ Reducing the risk, Reduce the voltage - limit the supply voltage to the lowest needed to get the job done; What are the hazards - 230 volts AC can kill, and the risk is greatest in wet surroundingshse.gov.uk/pubns/indg231.pdftier 1, primary2026-09-05
  16. 16Burns and scalds: TreatmentNational Health Service, 2026§ Treatment - cool running water for 20 minutes as soon as possible, remove clothing and jewellery near the burn but nothing stuck to it, cover with cling film laid over rather than wrapped, and the routes to 111 and to accident and emergencynhs.uk/conditions/burns-and-scalds/treatmenttier 1, primary2026-09-05

Formulas, hazard statements, historical dates and process descriptions on this page were checked against the sources above on the date shown. Safety data changes: obtain the current safety data sheet for the product you actually buy before you open it.