test_SAMO_V2_COB.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. # test main board
  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. MAXIMUM_SUSPEND_CURRENT = 0.02
  61. MINIMUM_ON_CURRENT = 0.012
  62. MAXIMUM_ON_CURRENT = 0.150
  63. # seconds
  64. MINIMUM_ON_TIME = 0.01
  65. MAXIMUM_ON_TIME = 1.2
  66. MINIMUM_OFF_TIME = 1.7
  67. MAXIMUM_OFF_TIME = 4.0
  68. ON_OFF_DELTA = 0.01
  69. AVERAGING_DELAY = 0.02
  70. SETTLING_TIME = 0.25
  71. VOLTAGE_SAMPLE_TIME = 0.02
  72. VOLTAGE_SAMPLE_OFF = 0.01
  73. RESET_TIME = 0.5
  74. # 1/10 seconds
  75. ON_OFF_SCAN = int(5 / ON_OFF_DELTA)
  76. # function keys
  77. KEY_LIST = [
  78. ('Random', RELAY_RANDOM_KEY, '0x02'),
  79. ('History', RELAY_HISTORY_KEY, '0x04'),
  80. ('Search', RELAY_SEARCH_KEY, '0x01')
  81. ]
  82. def setUp():
  83. """Set up power supply and turn on
  84. Also put a message on the PSU LCD to warn operator"""
  85. global debug, psu, dvm, relay
  86. info('setUp: **initialising**')
  87. relay = RelayBoard.PIC16F873A(port = RELAY_SERIAL)
  88. dvm = Agilent.DMM34401A()
  89. dvm.setVoltageDC()
  90. psu = Keithley.PSU2303()
  91. psu.setCurrent(SUPPLY_CURRENT_LIMIT)
  92. psu.setVoltage(SUPPLY_STANDARD_VOLTAGE)
  93. psu.powerOff()
  94. if debug:
  95. psu.settings()
  96. psu.measure()
  97. psu.message('Test in progress Do NOT Touch ')
  98. relay.on(RELAY_VBATT)
  99. def tearDown():
  100. """Shutdown the power supply"""
  101. global debug, psu, dvm, relay
  102. relay.off(RELAY_VBATT)
  103. psu.powerOff()
  104. psu.setCurrent(0)
  105. psu.setVoltage(0)
  106. psu.messageOff()
  107. info('tearDown: **cleanup**')
  108. del psu
  109. psu = None
  110. del dvm
  111. dvm = None
  112. del relay
  113. relay = None
  114. def test001_leakage():
  115. """Make sure power is off and no leakage"""
  116. global debug, psu, dvm, relay
  117. relay.off(RELAY_POWER_SWITCH)
  118. time.sleep(RESET_TIME)
  119. psu.powerOn()
  120. time.sleep(SETTLING_TIME)
  121. if debug:
  122. psu.settings()
  123. psu.measure()
  124. i = psu.current
  125. info('Leakage current = %7.3f mA @ %5.1f V' % (1000 * i, psu.voltage))
  126. fail_if(abs(i) > MAXIMUM_LEAKAGE_CURRENT, "Leakage current %7.3f mA is too high" % (i * 1000))
  127. def test002_on():
  128. """Turn on power and wait for current to rise"""
  129. global debug, psu, dvm, relay
  130. relay.set(RELAY_PROGRAM_FLASH)
  131. relay.set(RELAY_POWER_SWITCH)
  132. relay.update()
  133. t = time.time()
  134. for i in range(ON_OFF_SCAN):
  135. if psu.current >= MINIMUM_ON_CURRENT:
  136. break
  137. time.sleep(ON_OFF_DELTA)
  138. t = time.time() - t
  139. relay.off(RELAY_POWER_SWITCH)
  140. time.sleep(SETTLING_TIME)
  141. info('On current = %7.3f mA @ %5.1f V' % (1000 * psu.current, psu.voltage))
  142. fail_unless(psu.current >= MINIMUM_ON_CURRENT, "Failed to Power On")
  143. fail_if(t < MINIMUM_ON_TIME, "On too short, %5.1f s < %5.1f" % (t, MINIMUM_ON_TIME))
  144. fail_if(t > MAXIMUM_ON_TIME, "On too long, %5.1f s > %5.1f" % (t, MAXIMUM_ON_TIME))
  145. def test003_check_current():
  146. """Monitor current to check if correct"""
  147. global debug, psu, dvm, relay
  148. averageCurrent = 0.0
  149. samples = 20
  150. for i in range(samples):
  151. if debug:
  152. psu.measure()
  153. time.sleep(AVERAGING_DELAY)
  154. i = psu.current
  155. averageCurrent = averageCurrent + i
  156. info('Supply current = %7.3f mA @ %5.1f V' % (1000 * i, psu.voltage))
  157. fail_unless(abs(i) > MINIMUM_ON_CURRENT, "Device failed to power up")
  158. fail_if(abs(i) > MAXIMUM_ON_CURRENT, "Device current too high")
  159. info('Average supply current = %7.3f mA @ %5.1f V' % (1000 * averageCurrent / samples, psu.voltage))
  160. def test004_measure_voltages():
  161. """Measure voltages"""
  162. global debug, psu, dvm, relay
  163. for item in VOLTAGE_LIST:
  164. v = item[0]
  165. r = item[1]
  166. if None == item[2]:
  167. min = item[3]
  168. max = item[4]
  169. else:
  170. min = item[2] * (100 + item[3]) / 100
  171. max = item[2] * (100 + item[4]) / 100
  172. relay.on(r)
  173. time.sleep(VOLTAGE_SAMPLE_TIME)
  174. actual = dvm.voltage
  175. info('%s = %7.3f V' % (v, actual))
  176. fail_if(actual < min, "Low Voltage %s = %7.3f < %7.3f" % (v, actual, min))
  177. fail_if(actual > max, "High Voltage %s = %7.3f > %7.3f" % (v, actual, max))
  178. relay.off(r)
  179. time.sleep(VOLTAGE_SAMPLE_OFF)
  180. def test005_power_off():
  181. """Check power off function"""
  182. global debug, psu, dvm, relay
  183. relay.clear(RELAY_PROGRAM_FLASH)
  184. relay.set(RELAY_POWER_SWITCH)
  185. relay.update()
  186. t = time.time()
  187. for i in range(ON_OFF_SCAN):
  188. if psu.current < MINIMUM_ON_CURRENT:
  189. break
  190. time.sleep(ON_OFF_DELTA)
  191. t = time.time() - t
  192. relay.off(RELAY_POWER_SWITCH)
  193. time.sleep(2)
  194. i = psu.current
  195. fail_unless(abs(i) < MAXIMUM_LEAKAGE_CURRENT, "Failed to power off , %7.3f mA" % (i * 1000))
  196. fail_if(t < MINIMUM_OFF_TIME, "Off too short, %5.1f s < %5.1f" % (t, MINIMUM_OFF_TIME))
  197. fail_if(t > MAXIMUM_OFF_TIME, "Off too long, %5.1f s > %5.1f" % (t, MAXIMUM_OFF_TIME))
  198. def test006_on():
  199. """Turn on power and wait for current to rise"""
  200. global debug, psu, dvm, relay
  201. test002_on()
  202. def DISABLE_test007_program_flash():
  203. """Program the boot loader into FLASH memory"""
  204. global debug, psu, dvm, relay
  205. p = communication.SerialPort(port = CPU_SERIAL)
  206. relay.on(RELAY_RESET)
  207. relay.clear(RELAY_PROGRAM_FLASH)
  208. relay.clear(RELAY_RANDOM_KEY)
  209. relay.clear(RELAY_HISTORY_KEY)
  210. relay.clear(RELAY_SEARCH_KEY)
  211. relay.set(RELAY_RXD)
  212. relay.set(RELAY_TXD)
  213. relay.update()
  214. time.sleep(RESET_TIME)
  215. relay.off(RELAY_RESET)
  216. fail_unless(p.waitFor('menu\?'), 'Boot Loader failed to start')
  217. p.send(' ')
  218. m_flash = p.waitFor('(.)\.\s+[fF][lL][aA][sS][hH]\s+[mM][bB][rR]')
  219. fail_unless(m_flash, 'Boot Loader missing FLASH MBR option')
  220. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  221. p.send(m_flash.group(1))
  222. m_flash = p.waitFor('(PASS|FAIL):\s+FLASH\s+MBR', 90)
  223. fail_unless(m_flash, 'FLASH MBR did not respond')
  224. fail_unless('PASS' == m_flash.group(1), 'FLASH MBR')
  225. info('Flash programming sucessful')
  226. def test008_internal():
  227. """Run internal test program
  228. Memory Check
  229. Test three function keys
  230. Calibrate LCD contrast voltage
  231. Check software power off"""
  232. global debug, psu, dvm, relay
  233. p = communication.SerialPort(port = CPU_SERIAL)
  234. relay.on(RELAY_RESET)
  235. relay.clear(RELAY_PROGRAM_FLASH)
  236. relay.clear(RELAY_RANDOM_KEY)
  237. relay.clear(RELAY_HISTORY_KEY)
  238. relay.clear(RELAY_SEARCH_KEY)
  239. relay.set(RELAY_RXD)
  240. relay.set(RELAY_TXD)
  241. relay.update()
  242. time.sleep(RESET_TIME)
  243. relay.off(RELAY_RESET)
  244. fail_unless(p.waitFor('menu\?'), 'boot loader failed to start')
  245. p.send(' ')
  246. m_mem = p.waitFor('(.)\.\s+[mM]emory\s+[cC]heck')
  247. fail_unless(m_mem, 'Boot Loader missing Memory Check option')
  248. m_key = p.waitFor('(.)\.\s+[kK]ey\s+[tT]est')
  249. fail_unless(m_key, 'Boot Loader missing Key Test option')
  250. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  251. p.send(m_mem.group(1))
  252. m_mem = p.waitFor('[mM]emory:[^\]]+\]')
  253. fail_unless(m_mem, 'Memory Check did not respond')
  254. info(m_mem.group(0))
  255. m_mem = p.waitFor('(PASS|FAIL):\s+(.*)\n')
  256. fail_unless(m_mem, 'Memory Check did not respond')
  257. fail_unless('PASS' == m_mem.group(1), m_mem.group(2))
  258. info(m_mem.group(1) + ': ' + m_mem.group(2))
  259. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  260. p.send(m_key.group(1))
  261. for desc, r, k in KEY_LIST:
  262. relay.off(r)
  263. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  264. key = p.read(4)
  265. info('key (none) = %s' % key)
  266. fail_unless('0x00' == key, 'Invalid keys: wanted %s, got %s' % ('0x00', key))
  267. relay.on(r)
  268. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  269. key = p.read(4)
  270. i = psu.current
  271. info('Supply current = %7.3f mA' % (1000 * i))
  272. info('key (%s)[%s] = %s' % (desc, k, key))
  273. fail_unless(k == key, 'Invalid keys: wanted %s, got %s' % (k, key))
  274. relay.off(r)
  275. fail_unless(p.waitFor('keys = '), 'Key Test did not respond')
  276. key = p.read(4)
  277. info('key (none) = %s' % key)
  278. fail_unless('0x00' == key, 'Invalid keys: wanted %s, got %s' % ('0x00', key))
  279. # exit key test and wait for prompt
  280. # contrast control should then be active
  281. p.send('\n')
  282. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  283. info('Calibrate LCD Voltages to %7.3f V +- %7.3f V' % (LCD_V0, LCD_V0_DELTA))
  284. relay.on(RELAY_LCD_V0)
  285. relay_increase = RELAY_RANDOM_KEY
  286. relay_decrease = RELAY_SEARCH_KEY
  287. relay_set = RELAY_HISTORY_KEY
  288. v0_max = LCD_V0 + LCD_V0_DELTA
  289. v0_min = LCD_V0 - LCD_V0_DELTA
  290. actual = 0
  291. for i in range(50):
  292. time.sleep(VOLTAGE_SAMPLE_TIME)
  293. actual = dvm.voltage
  294. if actual > v0_max:
  295. relay.set(relay_decrease)
  296. relay.off(relay_increase)
  297. elif actual < v0_min:
  298. relay.set(relay_increase)
  299. relay.off(relay_decrease)
  300. else:
  301. relay.clear(relay_set) # *** Do _NOT_ Save to FLASH
  302. relay.clear(relay_increase)
  303. relay.off(relay_decrease)
  304. break
  305. relay.clear(relay_increase)
  306. relay.clear(relay_decrease)
  307. relay.off(RELAY_LCD_V0)
  308. time.sleep(VOLTAGE_SAMPLE_TIME)
  309. relay.off(relay_set)
  310. fail_if(actual > v0_max or actual < v0_min,
  311. 'LCD contrast voltage: %f7.3 out of range: %7.3f .. %7.3f' % (actual, v0_min, v0_max))
  312. info('Calibrate LCD Voltages Completed; New values are:')
  313. test004_measure_voltages()
  314. info('sending auto power off sequence')
  315. p.send('\n0\n')
  316. del p
  317. p = None
  318. for n in range(5):
  319. time.sleep(SETTLING_TIME)
  320. i = psu.current
  321. info('Supply current = %7.3f mA' % (1000 * i))
  322. if abs(i) < MAXIMUM_LEAKAGE_CURRENT:
  323. break
  324. fail_if(abs(i) > MAXIMUM_LEAKAGE_CURRENT, "Failed auto power off, current %7.3f mA is too high" % (i * 1000))
  325. def test009_on():
  326. """Turn on power and wait for current to rise"""
  327. global debug, psu, dvm, relay
  328. test002_on()
  329. def test010_boot_sd_card():
  330. """Boot the test program from the SD Card"""
  331. global debug, psu, dvm, relay
  332. p = communication.SerialPort(port = CPU_SERIAL)
  333. relay.on(RELAY_RESET)
  334. relay.clear(RELAY_PROGRAM_FLASH)
  335. relay.clear(RELAY_RANDOM_KEY)
  336. relay.clear(RELAY_HISTORY_KEY)
  337. relay.clear(RELAY_SEARCH_KEY)
  338. relay.set(RELAY_RXD)
  339. relay.set(RELAY_TXD)
  340. relay.update()
  341. time.sleep(RESET_TIME)
  342. relay.off(RELAY_RESET)
  343. fail_unless(p.waitFor('menu\?'), 'boot loader failed to start')
  344. p.send(' ')
  345. m_boot = p.waitFor('(.)\.\s+[bB]oot\s+[tT]est\s+[pP]rogram')
  346. fail_unless(m_boot, 'Boot Loader missing Boot Test Program option')
  347. fail_unless(p.waitFor('[sS]election:'), 'Boot Loader menu prompt failed')
  348. p.send(m_boot.group(1))
  349. info('Starting the test program')
  350. fail_unless(p.waitFor('\*START-TEST\*'), 'Test failed to load')
  351. request_action('Touch the CTP')
  352. while True:
  353. m_boot = p.waitFor('(\*SUSPEND\*|(PASS|FAIL):\s+(.*)(\r|\n))', 600)
  354. fail_unless(m_boot, 'Test program failed to respond')
  355. if m_boot.group(1) == '*SUSPEND*':
  356. break
  357. fail_unless('PASS' == m_boot.group(2), m_boot.group(3))
  358. info(m_boot.group(2) + ': ' + m_boot.group(3))
  359. samples = 20
  360. total = 0
  361. for j in range(samples):
  362. i = psu.current
  363. total = total + i
  364. info('suspend current = %7.3f mA @ %5.1f V' %
  365. (1000 * i, psu.voltage))
  366. time.sleep(0.1)
  367. info('average suspend current = %7.3f mA @ %5.1f V' %
  368. (1000 * total / samples, psu.voltage))
  369. if abs(i) > MAXIMUM_SUSPEND_CURRENT:
  370. p.send('N')
  371. else:
  372. p.send('Y')
  373. m_boot = p.waitFor('(PASS|FAIL):\s+(.*)\n', 60)
  374. fail_unless(m_boot, 'Suspend check failed to respond')
  375. fail_unless('PASS' == m_boot.group(1), m_boot.group(2))
  376. info(m_boot.group(1) + ': ' + m_boot.group(2))
  377. fail_unless(p.waitFor('\*END-TEST\*'), 'End Test timed out')
  378. def test011_power_off():
  379. """Check power off function"""
  380. global debug, psu, dvm, relay
  381. test005_power_off()