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 :
- Que mesurez-vous ? (nom du net, point de test, type de mesure)
- Quelle est la valeur attendue ? (nominale d'après le schéma ou la fiche technique)
- 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 net | Point de test | Type de signal | Nominal | Notes |
|---|---|---|---|---|
| VCC_3V3 | TP1 | Tension DC | 3,3 V | Sortie LDO |
| VCC_5V0 | TP2 | Tension DC | 5,0 V | USB VBUS |
| XTAL_OUT | TP3 | Fréquence | 12 MHz | Oscillateur à quartz |
| I2C_SDA | TP4 | Niveau haut | 3,3 V | Pull-up vers VCC_3V3 |
| VBAT | TP5 | Tension DC | 3,7 V | Nominal Li-ion |
| LED_PWM | TP6 | Rapport cyclique | 50% | É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 :
| Net | Nominal | Min | Max | Source |
|---|---|---|---|---|
| VCC_3V3 | 3,300 V | 3,234 V | 3,366 V | TLV1117-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
| Net | Nominal | Min | Max | Source |
|---|---|---|---|---|
| XTAL_OUT | 12 000 000 Hz | 11 999 760 Hz | 12 000 240 Hz | ABM8 DS, spéc. ppm |
Signaux logiques
Utilisez les seuils VIH et VIL du composant, pas 50% de VCC.
| Net | Type | Min | Max | Source |
|---|---|---|---|---|
| I2C_SDA (haut) | V_OH | 2,97 V | 3,63 V | Spéc. GPIO, 0,9VCC à 1,1VCC |
| I2C_SCL (bas) | V_OL | 0 V | 0,33 V | Spé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.
| ID | Point de test | Net | Nom de phase | Type de mesure | Nominal | Min | Max | Unité | Réf. fiche technique |
|---|---|---|---|---|---|---|---|---|---|
| M01 | TP1 | VCC_3V3 | power_rails | Tension DC | 3,300 | 3,234 | 3,366 | V | TLV1117-3.3 DS Tableau 6.6 |
| M02 | TP2 | VCC_5V0 | power_rails | Tension DC | 5,000 | 4,750 | 5,250 | V | Spéc. USB 2.0 section 7.2.1 |
| M03 | TP3 | XTAL_OUT | clock_check | Fréquence | 12000000 | 11999760 | 12000240 | Hz | ABM8 DS spéc. ppm |
| M04 | TP4 | I2C_SDA | i2c_bus | Tension DC | 3,300 | 2,970 | 3,630 | V | Spéc. GPIO MCU |
| M05 | TP5 | VBAT | battery_voltage | Tension DC | 3,700 | 3,000 | 4,200 | V | Spéc. cellule Li-ion |
| M06 | TP6 | LED_PWM | led_driver | Rapport cyclique | 50,0 | 45,0 | 55,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.
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 mesure | Statut TofuPilot |
|---|---|---|
| M01 | vcc_3v3_voltage | présent |
| M02 | vcc_5v0_voltage | présent |
| M03 | xtal_frequency | présent |
| M04 | i2c_sda_high_voltage | présent |
| M05 | vbat_voltage | présent |
| M06 | led_pwm_duty_cycle | pré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 :
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.