program-test-jig.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. # program the FLASH chip in the test jig
  2. # -*- coding: utf-8 -*-
  3. # COPYRIGHT: Openmoko Inc. 2009
  4. # LICENSE: GPL Version 2 or later
  5. # DESCRIPTION: Main board test
  6. # AUTHOR: Christopher Hall <hsw@openmoko.com>
  7. import Keithley
  8. import Agilent
  9. import RelayBoard
  10. import communication
  11. import process
  12. import sys
  13. import time
  14. if 'serial_number' in global_args:
  15. serial_number = global_args['serial_number']
  16. else:
  17. serial_number = 'No Serial Number'
  18. psu = None
  19. dvm = None
  20. relay = None
  21. RELAY_SERIAL = '/dev/USBrelay'
  22. CPU_SERIAL = '/dev/USBconsole'
  23. RELAY_VBATT = 1
  24. RELAY_RESET = 2
  25. RELAY_POWER_SWITCH = 3
  26. RELAY_RANDOM_KEY = 4
  27. RELAY_HISTORY_KEY = 5
  28. RELAY_SEARCH_KEY = 6
  29. RELAY_RXD = 7
  30. RELAY_TXD = 8
  31. RELAY_PROGRAM_FLASH = 9
  32. RELAY_1V8 = 10
  33. RELAY_3V = 11
  34. RELAY_LCD_V0 = 12
  35. RELAY_LCD_V1 = 13
  36. RELAY_LCD_V2 = 14
  37. RELAY_LCD_V3 = 15
  38. RELAY_LCD_V4 = 16
  39. # volts
  40. LCD_V0 = 21.0
  41. LCD_V0_DELTA = 0.1
  42. # power supply (volts, amps)
  43. SUPPLY_STANDARD_VOLTAGE = 3.0
  44. SUPPLY_CURRENT_LIMIT = 0.35
  45. # specify the voltages actual and +/- percentages
  46. # or minimum/maximum
  47. VOLTAGE_LIST = (
  48. # ("text", relay_name, required_value, percent_low, percent_high)
  49. # ("text", relay_name, None, minimum, maximum)
  50. ("1V8", RELAY_1V8, 1.8, -5.0, 5.0),
  51. ("3V ", RELAY_3V, None, 3.2, 3.4),
  52. ("V0 ", RELAY_LCD_V0, LCD_V0, -10.0, 10.0),
  53. ("V1 ", RELAY_LCD_V1, LCD_V0 * 14.0 / 15.0, -10.0, 10.0),
  54. ("V2 ", RELAY_LCD_V2, LCD_V0 * 13.0 / 15.0, -10.0, 10.0),
  55. ("V3 ", RELAY_LCD_V3, LCD_V0 * 2.0 / 15.0, -10.0, 10.0),
  56. ("V4 ", RELAY_LCD_V4, LCD_V0 * 1.0 / 15.0, -10.0, 10.0),
  57. )
  58. # amps
  59. MAXIMUM_LEAKAGE_CURRENT = 0.002
  60. MINIMUM_ON_CURRENT = 0.012
  61. MAXIMUM_ON_CURRENT = 0.150
  62. # seconds
  63. MINIMUM_ON_TIME = 0.01
  64. MAXIMUM_ON_TIME = 1.2
  65. MINIMUM_OFF_TIME = 1.7
  66. MAXIMUM_OFF_TIME = 4.0
  67. ON_OFF_DELTA = 0.01
  68. AVERAGING_DELAY = 0.02
  69. SETTLING_TIME = 0.25
  70. VOLTAGE_SAMPLE_TIME = 0.02
  71. VOLTAGE_SAMPLE_OFF = 0.01
  72. RESET_TIME = 0.5
  73. # 1/10 seconds
  74. ON_OFF_SCAN = int(5 / ON_OFF_DELTA)
  75. # function keys
  76. KEY_LIST = [
  77. ('Random', RELAY_RANDOM_KEY, '0x02'),
  78. ('History', RELAY_HISTORY_KEY, '0x04'),
  79. ('Search', RELAY_SEARCH_KEY, '0x01')
  80. ]
  81. def setUp():
  82. """Set up power supply and turn on
  83. Also put a message on the PSU LCD to warn operator"""
  84. global debug, psu, dvm, relay
  85. info('setUp: **initialising**')
  86. relay = RelayBoard.PIC16F873A(port = RELAY_SERIAL)
  87. dvm = Agilent.DMM34401A()
  88. dvm.setVoltageDC()
  89. psu = Keithley.PSU2303()
  90. psu.setCurrent(SUPPLY_CURRENT_LIMIT)
  91. psu.setVoltage(SUPPLY_STANDARD_VOLTAGE)
  92. psu.powerOff()
  93. if debug:
  94. psu.settings()
  95. psu.measure()
  96. psu.message('Test in progress Do NOT Touch ')
  97. relay.on(RELAY_VBATT)
  98. def tearDown():
  99. """Shutdown the power supply"""
  100. global debug, psu, dvm, relay
  101. relay.off(RELAY_VBATT)
  102. psu.powerOff()
  103. psu.setCurrent(0)
  104. psu.setVoltage(0)
  105. psu.messageOff()
  106. info('tearDown: **cleanup**')
  107. del psu
  108. psu = None
  109. del dvm
  110. dvm = None
  111. del relay
  112. relay = None
  113. def test001_leakage():
  114. """Make sure power is off and no leakage"""
  115. global debug, psu, dvm, relay
  116. relay.off(RELAY_POWER_SWITCH)
  117. time.sleep(RESET_TIME)
  118. psu.powerOn()
  119. time.sleep(SETTLING_TIME)
  120. if debug:
  121. psu.settings()
  122. psu.measure()
  123. i = psu.current
  124. info('Leakage current = %7.3f mA @ %5.1f V' % (1000 * i, psu.voltage))
  125. fail_if(abs(i) > MAXIMUM_LEAKAGE_CURRENT, "Leakage current %7.3f mA is too high" % (i * 1000))
  126. def test002_on():
  127. """Turn on power and wait for current to rise"""
  128. global debug, psu, dvm, relay
  129. relay.set(RELAY_PROGRAM_FLASH)
  130. relay.set(RELAY_POWER_SWITCH)
  131. relay.update()
  132. t = time.time()
  133. for i in range(ON_OFF_SCAN):
  134. if psu.current >= MINIMUM_ON_CURRENT:
  135. break
  136. time.sleep(ON_OFF_DELTA)
  137. t = time.time() - t
  138. relay.off(RELAY_POWER_SWITCH)
  139. time.sleep(SETTLING_TIME)
  140. info('On current = %7.3f mA @ %5.1f V' % (1000 * psu.current, psu.voltage))
  141. fail_unless(psu.current >= MINIMUM_ON_CURRENT, "Failed to Power On")
  142. fail_if(t < MINIMUM_ON_TIME, "On too short, %5.1f s < %5.1f" % (t, MINIMUM_ON_TIME))
  143. fail_if(t > MAXIMUM_ON_TIME, "On too long, %5.1f s > %5.1f" % (t, MAXIMUM_ON_TIME))
  144. def test003_check_current():
  145. """Monitor current to check if correct"""
  146. global debug, psu, dvm, relay
  147. averageCurrent = 0.0
  148. samples = 20
  149. for i in range(samples):
  150. if debug:
  151. psu.measure()
  152. time.sleep(AVERAGING_DELAY)
  153. i = psu.current
  154. averageCurrent = averageCurrent + i
  155. info('Supply current = %7.3f mA @ %5.1f V' % (1000 * i, psu.voltage))
  156. fail_unless(abs(i) > MINIMUM_ON_CURRENT, "Device failed to power up")
  157. fail_if(abs(i) > MAXIMUM_ON_CURRENT, "Device current too high")
  158. info('Average supply current = %7.3f mA @ %5.1f V' % (1000 * averageCurrent / samples, psu.voltage))
  159. def test004_measure_voltages():
  160. """Measure voltages"""
  161. global debug, psu, dvm, relay
  162. for item in VOLTAGE_LIST:
  163. v = item[0]
  164. r = item[1]
  165. if None == item[2]:
  166. min = item[3]
  167. max = item[4]
  168. else:
  169. min = item[2] * (100 + item[3]) / 100
  170. max = item[2] * (100 + item[4]) / 100
  171. relay.on(r)
  172. time.sleep(VOLTAGE_SAMPLE_TIME)
  173. actual = dvm.voltage
  174. info('%s = %7.3f V' % (v, actual))
  175. fail_if(actual < min, "Low Voltage %s = %7.3f < %7.3f" % (v, actual, min))
  176. fail_if(actual > max, "High Voltage %s = %7.3f > %7.3f" % (v, actual, max))
  177. relay.off(r)
  178. time.sleep(VOLTAGE_SAMPLE_OFF)
  179. def test005_power_off():
  180. """Check power off function"""
  181. global debug, psu, dvm, relay
  182. relay.clear(RELAY_PROGRAM_FLASH)
  183. relay.set(RELAY_POWER_SWITCH)
  184. relay.update()
  185. t = time.time()
  186. for i in range(ON_OFF_SCAN):
  187. if psu.current < MINIMUM_ON_CURRENT:
  188. break
  189. time.sleep(ON_OFF_DELTA)
  190. t = time.time() - t
  191. relay.off(RELAY_POWER_SWITCH)
  192. time.sleep(2)
  193. i = psu.current
  194. fail_unless(abs(i) < MAXIMUM_LEAKAGE_CURRENT, "Failed to power off , %7.3f mA" % (i * 1000))
  195. fail_if(t < MINIMUM_OFF_TIME, "Off too short, %5.1f s < %5.1f" % (t, MINIMUM_OFF_TIME))
  196. fail_if(t > MAXIMUM_OFF_TIME, "Off too long, %5.1f s > %5.1f" % (t, MAXIMUM_OFF_TIME))
  197. def test006_on():
  198. """Turn on power and wait for current to rise"""
  199. global debug, psu, dvm, relay
  200. test002_on()
  201. def test007_program_flash():
  202. """Program the boot loader into FLASH memory"""
  203. global debug, psu, dvm, relay
  204. relay.set(RELAY_RESET)
  205. relay.set(RELAY_PROGRAM_FLASH)
  206. relay.set(RELAY_RXD)
  207. relay.set(RELAY_TXD)
  208. relay.update()
  209. def callback(s):
  210. global debug, psu, dvm, relay
  211. i = psu.current
  212. info('Supply current = %7.3f mA' % (1000 * i))
  213. info(s.replace('\10', '')) # remove backspaces
  214. if 'Press Reset' == s.strip():
  215. relay.on(RELAY_RESET)
  216. time.sleep(RESET_TIME)
  217. relay.off(RELAY_RESET)
  218. p = process.Process(['make', 'flash-test-jig', 'BOOTLOADER_TTY=' + CPU_SERIAL,
  219. "SERIAL_NUMBER='" + serial_number + "'"], callback)
  220. rc = p.run()
  221. fail_unless(rc, 'Flashing failed')
  222. relay.off(RELAY_PROGRAM_FLASH)
  223. def test008_internal():
  224. """Run internal test program
  225. Memory Check
  226. Test three function keys
  227. Calibrate LCD contrast voltage
  228. Check software power off"""
  229. global debug, psu, dvm, relay
  230. p = communication.SerialPort(port = CPU_SERIAL)
  231. relay.on(RELAY_RESET)
  232. relay.clear(RELAY_PROGRAM_FLASH)
  233. relay.clear(RELAY_RANDOM_KEY)
  234. relay.clear(RELAY_HISTORY_KEY)
  235. relay.clear(RELAY_SEARCH_KEY)
  236. relay.set(RELAY_RXD)
  237. relay.set(RELAY_TXD)
  238. relay.update()
  239. time.sleep(RESET_TIME)
  240. relay.off(RELAY_RESET)
  241. fail_unless(p.waitFor('menu\?'), 'boot loader failed to start')
  242. p.send(' ')
  243. m_mem = p.waitFor('(.)\.\s+[mM]emory\s+[cC]heck')
  244. fail_unless(m_mem, 'Boot Loader missing Memory Check option')
  245. m_key = p.waitFor('(.)\.\s+[kK]ey\s+[tT]est')
  246. fail_unless(m_key, 'Boot Loader missing Key Test option')
  247. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  248. p.send(m_mem.group(1))
  249. m_mem = p.waitFor('[mM]emory:[^\]]+\]')
  250. fail_unless(m_mem, 'Memory Check did not respond')
  251. info(m_mem.group(0))
  252. m_mem = p.waitFor('(PASS|FAIL):\s+(.*)\n')
  253. fail_unless(m_mem, 'Memory Check did not respond')
  254. fail_unless('PASS' == m_mem.group(1), m_mem.group(2))
  255. info(m_mem.group(1) + ': ' + m_mem.group(2))
  256. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  257. p.send(m_key.group(1))
  258. for desc, r, k in KEY_LIST:
  259. relay.off(r)
  260. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  261. key = p.read(4)
  262. info('key (none) = %s' % key)
  263. fail_unless('0x00' == key, 'Invalid keys: wanted %s, got %s' % ('0x00', key))
  264. relay.on(r)
  265. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  266. key = p.read(4)
  267. i = psu.current
  268. info('Supply current = %7.3f mA' % (1000 * i))
  269. info('key (%s)[%s] = %s' % (desc, k, key))
  270. fail_unless(k == key, 'Invalid keys: wanted %s, got %s' % (k, key))
  271. relay.off(r)
  272. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  273. key = p.read(4)
  274. info('key (none) = %s' % key)
  275. fail_unless('0x00' == key, 'Invalid keys: wanted %s, got %s' % ('0x00', key))
  276. # exit key test and wait for prompt
  277. # contrast control should then be active
  278. p.send('\n')
  279. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  280. info('Calibrate LCD Voltages to %7.3f V +- %7.3f V' % (LCD_V0, LCD_V0_DELTA))
  281. relay.on(RELAY_LCD_V0)
  282. relay_decrease = RELAY_RANDOM_KEY
  283. relay_increase = RELAY_SEARCH_KEY
  284. relay_set = RELAY_HISTORY_KEY
  285. v0_max = LCD_V0 + LCD_V0_DELTA
  286. v0_min = LCD_V0 - LCD_V0_DELTA
  287. actual = 0
  288. for i in range(20):
  289. time.sleep(VOLTAGE_SAMPLE_TIME)
  290. actual = dvm.voltage
  291. #info('Contrast voltage = %7.3f V' % actual)
  292. if actual > v0_max:
  293. relay.set(relay_decrease)
  294. relay.off(relay_increase)
  295. elif actual < v0_min:
  296. relay.set(relay_increase)
  297. relay.off(relay_decrease)
  298. else:
  299. relay.set(relay_set)
  300. relay.clear(relay_increase)
  301. relay.off(relay_decrease)
  302. break
  303. relay.clear(relay_increase)
  304. relay.clear(relay_decrease)
  305. relay.off(RELAY_LCD_V0)
  306. time.sleep(VOLTAGE_SAMPLE_TIME)
  307. relay.off(relay_set)
  308. fail_if(actual > v0_max or actual < v0_min,
  309. 'LCD contrast voltage: %f7.3 out of range: %7.3f .. %7.3f' % (actual, v0_min, v0_max))
  310. info('Calibrate LCD Voltages Completed; New values are:')
  311. test004_measure_voltages()
  312. info('sending auto power off sequence')
  313. p.send('\n0\n')
  314. del p
  315. p = None
  316. for n in range(5):
  317. time.sleep(SETTLING_TIME)
  318. i = psu.current
  319. info('Supply current = %7.3f mA' % (1000 * i))
  320. if abs(i) < MAXIMUM_LEAKAGE_CURRENT:
  321. break
  322. fail_if(abs(i) > MAXIMUM_LEAKAGE_CURRENT, "Failed auto power off, current %7.3f mA is too high" % (i * 1000))
  323. #def test009_power_off():
  324. # """Check power off function"""
  325. # global debug, psu, dvm, relay
  326. # test005_power_off()