Test Types & Methods

Spécification de test fonctionnel PCBA

Apprenez à construire une spécification de test fonctionnel pour la production de PCBA, à mapper les nets du schéma aux mesures avec des limites dérivées.

JJulien Buteau
intermediate10 min de lecture14 mars 2026

Une spécification de test fonctionnel définit chaque mesure que votre carte doit réussir avant son expédition. Elle associe les nets du schéma aux points de test physiques, fixe les limites de réussite/échec à partir des fiches techniques, et devient le contrat entre la conception matérielle et le test de production. Ce guide vous montre comment construire ce document et le transformer en phases OpenHTF exécutables suivies dans TofuPilot.

Qu'est-ce qu'une spécification de test fonctionnel

Une spécification de test fonctionnel est un tableau structuré qui répond à trois questions pour chaque signal de votre carte :

  1. Que mesurez-vous ? (nom du net, point de test, type de mesure)
  2. Quelle est la valeur attendue ? (nominale d'après le schéma ou la fiche technique)
  3. Quelle est la plage acceptable ? (limites min/max avec tolérance)

Ce n'est pas un script de test. C'est la source de vérité qui pilote le script de test.

Associer les nets du schéma aux points de test

Commencez par votre schéma et exportez une liste de nets. Pour chaque net portant un signal testable, identifiez le point d'accès physique sur la carte.

Nom du netPoint de testType de signalNominalNotes
VCC_3V3TP1Tension DC3,3 VSortie LDO
VCC_5V0TP2Tension DC5,0 VUSB VBUS
XTAL_OUTTP3Fréquence12 MHzOscillateur à quartz
I2C_SDATP4Niveau haut3,3 VPull-up vers VCC_3V3
VBATTP5Tension DC3,7 VNominal Li-ion
LED_PWMTP6Rapport cyclique50%État firmware par défaut

Règles pour choisir les points de test :

  • Préférer les vias de test dédiés aux pads de composants
  • Inclure un TP de référence de masse près de chaque cluster de mesure
  • Numéroter les points de test dans l'ordre physique pour réduire la complexité du câblage de la fixation

Définir les limites à partir des fiches techniques

Les limites proviennent de deux sources : les fiches techniques des composants et les marges au niveau système. Tracez chaque limite vers un document et un élément de ligne.

Régulateurs de tension

Pour un LDO comme le TLV1117-3.3, la fiche technique spécifie :

  • Précision de la tension de sortie : +/-1% sur la plage de température
  • Régulation en ligne : 0,2% typique
  • Régulation en charge : 0,4% typique

À 3,3 V nominal avec +/-1% de précision plus 0,4% de régulation en charge :

NetNominalMinMaxSource
VCC_3V33,300 V3,234 V3,366 VTLV1117-3.3 DS, Tableau 6.6

Oscillateurs à quartz

Un quartz de 12 MHz avec une tolérance de +/-20 ppm à 25°C :

  • 20 ppm de 12 MHz = 240 Hz
NetNominalMinMaxSource
XTAL_OUT12 000 000 Hz11 999 760 Hz12 000 240 HzABM8 DS, spéc. ppm

Signaux logiques

Utilisez les seuils VIH et VIL du composant, pas 50% de VCC.

NetTypeMinMaxSource
I2C_SDA (haut)V_OH2,97 V3,63 VSpéc. GPIO, 0,9VCC à 1,1VCC
I2C_SCL (bas)V_OL0 V0,33 VSpéc. GPIO, V_OL max 0,1*VCC

Structure du document de spécification de test

Stockez la spécification sous forme de tableau versionné. Une ligne par mesure.

IDPoint de testNetNom de phaseType de mesureNominalMinMaxUnitéRéf. fiche technique
M01TP1VCC_3V3power_railsTension DC3,3003,2343,366VTLV1117-3.3 DS Tableau 6.6
M02TP2VCC_5V0power_railsTension DC5,0004,7505,250VSpéc. USB 2.0 section 7.2.1
M03TP3XTAL_OUTclock_checkFréquence120000001199976012000240HzABM8 DS spéc. ppm
M04TP4I2C_SDAi2c_busTension DC3,3002,9703,630VSpéc. GPIO MCU
M05TP5VBATbattery_voltageTension DC3,7003,0004,200VSpéc. cellule Li-ion
M06TP6LED_PWMled_driverRapport cyclique50,045,055,0%Exigence firmware

Conservez ce tableau dans un CSV ou un tableur sous contrôle de version aux côtés du firmware. Tagguez chaque révision de spécification à la révision matérielle correspondante.

Traduire la spécification en phases OpenHTF

Chaque phase correspond à un bloc fonctionnel de la spécification. Les mesures au sein d'une phase correspondent aux lignes individuelles par ID.

tests/pcba_functional_test.py
import openhtf as htf
from openhtf.util import units
from tofupilot.openhtf import TofuPilot

from plugs.dmm import DmmPlug
from plugs.counter import FrequencyCounterPlug


@htf.plug(dmm=DmmPlug)
@htf.measures(
    htf.Measurement("vcc_3v3_voltage")
    .in_range(minimum=3.234, maximum=3.366)
    .with_units(units.VOLT)
    .doc("M01 : VCC_3V3 au TP1, TLV1117-3.3 DS Tableau 6.6"),
    htf.Measurement("vcc_5v0_voltage")
    .in_range(minimum=4.750, maximum=5.250)
    .with_units(units.VOLT)
    .doc("M02 : VCC_5V0 au TP2, spéc. USB 2.0 7.2.1"),
)
def power_rails(test, dmm):
    test.measurements.vcc_3v3_voltage = dmm.measure_dc_voltage(channel=1)
    test.measurements.vcc_5v0_voltage = dmm.measure_dc_voltage(channel=2)


@htf.plug(counter=FrequencyCounterPlug)
@htf.measures(
    htf.Measurement("xtal_frequency")
    .in_range(minimum=11_999_760, maximum=12_000_240)
    .with_units(units.HERTZ)
    .doc("M03 : XTAL_OUT au TP3, ABM8 DS spéc. ppm"),
)
def clock_check(test, counter):
    test.measurements.xtal_frequency = counter.measure_frequency(channel=1)


@htf.plug(dmm=DmmPlug)
@htf.measures(
    htf.Measurement("i2c_sda_high_voltage")
    .in_range(minimum=2.970, maximum=3.630)
    .with_units(units.VOLT)
    .doc("M04 : I2C_SDA au TP4, spéc. GPIO MCU"),
)
def i2c_bus(test, dmm):
    test.measurements.i2c_sda_high_voltage = dmm.measure_dc_voltage(channel=3)


@htf.plug(dmm=DmmPlug)
@htf.measures(
    htf.Measurement("vbat_voltage")
    .in_range(minimum=3.000, maximum=4.200)
    .with_units(units.VOLT)
    .doc("M05 : VBAT au TP5, spéc. cellule Li-ion"),
)
def battery_voltage(test, dmm):
    test.measurements.vbat_voltage = dmm.measure_dc_voltage(channel=4)


@htf.plug(counter=FrequencyCounterPlug)
@htf.measures(
    htf.Measurement("led_pwm_duty_cycle")
    .in_range(minimum=45.0, maximum=55.0)
    .doc("M06 : LED_PWM au TP6, exigence firmware"),
)
def led_driver(test, counter):
    test.measurements.led_pwm_duty_cycle = counter.measure_duty_cycle(channel=2)


def main():
    test = htf.Test(
        power_rails,
        clock_check,
        i2c_bus,
        battery_voltage,
        led_driver,
        test_name="PCBA Functional Test",
    )

    with TofuPilot(test):
        test.execute(test_start=lambda: input("Entrez le numéro de série du DUT : "))


if __name__ == "__main__":
    main()

La chaîne .doc() sur chaque mesure la relie à l'ID de la spécification, rendant la sortie du test auto-auditable. Quand une mesure échoue dans TofuPilot, vous pouvez la tracer directement jusqu'à la ligne de la fiche technique qui a défini la limite.

Suivi de la couverture de la spécification dans TofuPilot

Après votre première exécution, croisez le tableau de spécification avec la liste des mesures TofuPilot :

ID Spéc.Nom de la mesureStatut TofuPilot
M01vcc_3v3_voltageprésent
M02vcc_5v0_voltageprésent
M03xtal_frequencyprésent
M04i2c_sda_high_voltageprésent
M05vbat_voltageprésent
M06led_pwm_duty_cycleprésent

Une mesure qui n'échoue jamais sur des centaines d'unités peut indiquer des limites trop larges. Examinez la distribution dans l'analytique des mesures de TofuPilot et resserrez les limites si l'histogramme montre toutes les valeurs regroupées loin des bords.

Mise à jour des limites

Quand la révision matérielle B change le LDO, mettez à jour le tableau de spécification et le code ensemble :

tests/pcba_functional_test.py
from openhtf.util import units

# AP2112K-3.3 : Précision Vout +/-1,5%, régulation en charge 0,3%
# Min : 3,300 * (1 - 0,015 - 0,003) = 3,2406
# Max : 3,300 * (1 + 0,015 + 0,003) = 3,3594
htf.Measurement("vcc_3v3_voltage")
    .in_range(minimum=3.2406, maximum=3.3594)
    .with_units(units.VOLT)
    .doc("M01 : VCC_3V3 au TP1, AP2112K-3.3 DS rév. B"),

Committez la mise à jour du tableau de spécification et la modification du code dans le même commit pour que la piste d'audit reste intacte.

Plus de guides

Mettez ce guide en pratique