Skip to content

Commit 85a4587

Browse files
ladyadaladyada
andcommitted
Add GP8403 QT production tester
Co-authored-by: Limor Fried <ladyada@users.noreply.github.com>
1 parent 2bc2e85 commit 85a4587

2 files changed

Lines changed: 216 additions & 0 deletions

File tree

Lines changed: 209 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,209 @@
1+
/*
2+
* GP8403 QT Production Tester
3+
*
4+
* Runs automatically on the GP8403 QT Tester with an Arduino Uno. Verifies
5+
* the boosted 12 V rail, all eight I2C addresses, and both outputs in the 5 V
6+
* and 10 V ranges. Press the tester reset button to test the next board.
7+
*/
8+
9+
#include <Adafruit_GP8403.h>
10+
11+
const uint16_t ADDRESS_0_PIN = 5;
12+
const uint16_t ADDRESS_1_PIN = 4;
13+
const uint16_t ADDRESS_2_PIN = 3;
14+
const uint16_t PASS_LED_PIN = 12;
15+
const uint16_t SPEAKER_PIN = 11;
16+
const uint16_t VOUT0_ADC_PIN = A1;
17+
const uint16_t VOUT1_ADC_PIN = A2;
18+
const uint16_t BOOST_ADC_PIN = A3;
19+
20+
const uint8_t ADC_SAMPLES = 32;
21+
const float BOOST_EXPECTED_VOLTS = 12.0;
22+
const float BOOST_TOLERANCE_VOLTS = 1.0;
23+
24+
Adafruit_GP8403 gp8403;
25+
26+
void setup() {
27+
Serial.begin(115200);
28+
Serial.println(F("GP8403 QT production tester"));
29+
30+
pinMode(PASS_LED_PIN, OUTPUT);
31+
digitalWrite(PASS_LED_PIN, LOW);
32+
pinMode(SPEAKER_PIN, OUTPUT);
33+
noTone(SPEAKER_PIN);
34+
35+
pinMode(ADDRESS_0_PIN, OUTPUT);
36+
pinMode(ADDRESS_1_PIN, OUTPUT);
37+
pinMode(ADDRESS_2_PIN, OUTPUT);
38+
setAddressPins(0);
39+
delay(10);
40+
41+
float boostVolts = readBoostVolts();
42+
Serial.print(F("Boost rail="));
43+
Serial.print(boostVolts, 3);
44+
Serial.println(F(" V"));
45+
if (abs(boostVolts - BOOST_EXPECTED_VOLTS) > BOOST_TOLERANCE_VOLTS) {
46+
clearOutputsAndHalt(F("QT_TESTER FAIL: 12 V boost rail"));
47+
}
48+
Serial.println(F("12 V boost rail succeeded"));
49+
Serial.println();
50+
51+
for (uint8_t addressOffset = 0; addressOffset < 8; addressOffset++) {
52+
setAddressPins(addressOffset);
53+
delay(1);
54+
55+
uint8_t address = GP8403_DEFAULT_ADDRESS + addressOffset;
56+
if (!gp8403.begin(address)) {
57+
clearOutputsAndHalt(F("QT_TESTER FAIL: I2C address"));
58+
}
59+
Serial.print(F("I2C address 0x"));
60+
Serial.print(address, HEX);
61+
Serial.println(F(" succeeded"));
62+
}
63+
Serial.println();
64+
65+
setAddressPins(0);
66+
if (!gp8403.begin()) {
67+
clearOutputsAndHalt(F("QT_TESTER FAIL: restore default address"));
68+
}
69+
Serial.println(F("Default address restored"));
70+
Serial.println();
71+
72+
if (!gp8403.setVoltages(1.0, 4.0)) {
73+
clearOutputsAndHalt(F("QT_TESTER FAIL: set 1 V / 4 V"));
74+
}
75+
Serial.println(F("Set 1 V / 4 V succeeded"));
76+
77+
delay(10);
78+
float vout0Volts = readOutputVolts(VOUT0_ADC_PIN);
79+
float vout1Volts = readOutputVolts(VOUT1_ADC_PIN);
80+
printOutputVoltages(vout0Volts, vout1Volts);
81+
if (abs(vout0Volts - 1.0) > 0.25 || abs(vout1Volts - 4.0) > 0.25) {
82+
clearOutputsAndHalt(F("QT_TESTER FAIL: 1 V / 4 V readings"));
83+
}
84+
Serial.println(F("1 V / 4 V readings succeeded"));
85+
86+
if (!gp8403.setVoltages(0.0, 0.0)) {
87+
clearOutputsAndHalt(F("QT_TESTER FAIL: clear 1 V / 4 V"));
88+
}
89+
Serial.println(F("Clear 1 V / 4 V succeeded"));
90+
Serial.println();
91+
92+
if (!gp8403.setOutputRange(GP8403_RANGE_10V)) {
93+
clearOutputsAndHalt(F("QT_TESTER FAIL: select 10 V range"));
94+
}
95+
Serial.println(F("10 V range selection succeeded"));
96+
97+
if (!gp8403.setVoltages(2.5, 7.5)) {
98+
clearOutputsAndHalt(F("QT_TESTER FAIL: set 2.5 V / 7.5 V"));
99+
}
100+
Serial.println(F("Set 2.5 V / 7.5 V succeeded"));
101+
102+
delay(10);
103+
vout0Volts = readOutputVolts(VOUT0_ADC_PIN);
104+
vout1Volts = readOutputVolts(VOUT1_ADC_PIN);
105+
printOutputVoltages(vout0Volts, vout1Volts);
106+
if (abs(vout0Volts - 2.5) > 0.35 || abs(vout1Volts - 7.5) > 0.35) {
107+
clearOutputsAndHalt(F("QT_TESTER FAIL: 2.5 V / 7.5 V readings"));
108+
}
109+
Serial.println(F("2.5 V / 7.5 V readings succeeded"));
110+
111+
if (!gp8403.setVoltages(0.0, 0.0)) {
112+
clearOutputsAndHalt(F("QT_TESTER FAIL: clear 2.5 V / 7.5 V"));
113+
}
114+
Serial.println(F("Clear 2.5 V / 7.5 V succeeded"));
115+
Serial.println();
116+
117+
if (!gp8403.setVoltages(9.0, 9.0)) {
118+
clearOutputsAndHalt(F("QT_TESTER FAIL: set 9 V"));
119+
}
120+
Serial.println(F("Set 9 V succeeded"));
121+
122+
delay(10);
123+
vout0Volts = readOutputVolts(VOUT0_ADC_PIN);
124+
vout1Volts = readOutputVolts(VOUT1_ADC_PIN);
125+
printOutputVoltages(vout0Volts, vout1Volts);
126+
if (abs(vout0Volts - 9.0) > 0.5 || abs(vout1Volts - 9.0) > 0.5) {
127+
clearOutputsAndHalt(F("QT_TESTER FAIL: 9 V readings"));
128+
}
129+
Serial.println(F("9 V readings succeeded"));
130+
131+
if (!gp8403.setOutputRange(GP8403_RANGE_5V)) {
132+
clearOutputsAndHalt(F("QT_TESTER FAIL: restore 5 V range"));
133+
}
134+
Serial.println(F("5 V range restore succeeded"));
135+
Serial.println();
136+
137+
passAndHalt(F("QT_TESTER PASS"));
138+
}
139+
140+
void loop() {}
141+
142+
void setAddressPins(uint8_t addressOffset) {
143+
digitalWrite(ADDRESS_0_PIN, bitRead(addressOffset, 0));
144+
digitalWrite(ADDRESS_1_PIN, bitRead(addressOffset, 1));
145+
digitalWrite(ADDRESS_2_PIN, bitRead(addressOffset, 2));
146+
}
147+
148+
uint16_t readADC(uint16_t pin, uint8_t samples) {
149+
uint32_t total = 0;
150+
for (uint8_t i = 0; i < samples; i++) {
151+
total += analogRead(pin);
152+
}
153+
return total / samples;
154+
}
155+
156+
float readOutputVolts(uint16_t pin) {
157+
// The 2:1 divider maps 0-1023 ADC counts to 0-10 V at the output.
158+
return map(readADC(pin, ADC_SAMPLES), 0, 1023, 0, 10000) / 1000.0;
159+
}
160+
161+
float readBoostVolts() {
162+
// The 11:1 divider maps 0-1023 ADC counts to 0-55 V at the boost rail.
163+
return map(readADC(BOOST_ADC_PIN, ADC_SAMPLES), 0, 1023, 0, 55000) / 1000.0;
164+
}
165+
166+
void printOutputVoltages(float vout0Volts, float vout1Volts) {
167+
Serial.print(F("VOUT0="));
168+
Serial.print(vout0Volts, 3);
169+
Serial.print(F(" V VOUT1="));
170+
Serial.print(vout1Volts, 3);
171+
Serial.println(F(" V"));
172+
}
173+
174+
void resetOutputs() {
175+
setAddressPins(0);
176+
if (!gp8403.begin()) {
177+
Serial.println(F("QT_TESTER FAIL: reset begin"));
178+
return;
179+
}
180+
if (!gp8403.setVoltages(0.0, 0.0)) {
181+
Serial.println(F("QT_TESTER FAIL: reset outputs"));
182+
}
183+
}
184+
185+
void clearOutputsAndHalt(const __FlashStringHelper *message) {
186+
Serial.println();
187+
Serial.println(message);
188+
resetOutputs();
189+
digitalWrite(PASS_LED_PIN, LOW);
190+
tone(SPEAKER_PIN, 220, 1000);
191+
192+
while (true) {
193+
delay(1000);
194+
}
195+
}
196+
197+
void passAndHalt(const __FlashStringHelper *message) {
198+
resetOutputs();
199+
Serial.println(message);
200+
Serial.println(F("Press reset to test the next board"));
201+
digitalWrite(PASS_LED_PIN, HIGH);
202+
tone(SPEAKER_PIN, 880, 100);
203+
delay(150);
204+
tone(SPEAKER_PIN, 1320, 250);
205+
206+
while (true) {
207+
delay(1000);
208+
}
209+
}

hw_tests/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,10 @@ three-boot sequence:
1515
1. Send `S` to save 1 V / 2 V, then remove and restore all power.
1616
2. Send `Z` to verify 1 V / 2 V and save zero, then power cycle again.
1717
3. Send `V` to verify that zero was restored.
18+
19+
`04_qt_tester` is the automatic production test for the GP8403 QT Tester PCB
20+
and an Arduino Uno. The fixture drives the DUT address pins from D5, D4, and D3;
21+
measures VOUT0 and VOUT1 on A1 and A2 through equal 10 kOhm dividers; measures
22+
the boosted 12 V rail on A3 through a 10 kOhm / 1 kOhm divider; drives the green
23+
pass LED from D12; and drives the buzzer from D11. Press the tester reset button
24+
to test the next board. This test intentionally does not write NVM.

0 commit comments

Comments
 (0)