memtest-spi.py 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. #!/usr/bin/env python3
  2. #
  3. # memtest-spi.py
  4. #
  5. # Control software for testing the SPI PSRAM
  6. #
  7. # Copyright (C) 2020-2021 Sylvain Munaut <tnt@246tNt.com>
  8. # SPDX-License-Identifier: MIT
  9. #
  10. import binascii
  11. import random
  12. import sys
  13. from memtest import WishboneInterface, MemoryTester, HDMIOutput
  14. from memtest import QSPIController
  15. # ----------------------------------------------------------------------------
  16. # Main
  17. # ----------------------------------------------------------------------------
  18. def hexdump(x):
  19. return binascii.b2a_hex(x).decode('utf-8')
  20. def RAM_ADDR_CS(cs, addr):
  21. return (cs << 30) | addr
  22. def main(argv0, port='/dev/ttyUSB1', filename=None):
  23. # Connect to board
  24. wb = WishboneInterface(port)
  25. # Devices on the bus
  26. flash = QSPIController(wb, 0x00000, cs=0)
  27. psram = QSPIController(wb, 0x00000, cs=1)
  28. memtest = MemoryTester(wb, 0x10000)
  29. hdmi = HDMIOutput(wb, 0x20000)
  30. # Make sure to disable DMA
  31. hdmi.disable()
  32. wb.aux_csr(0)
  33. # Read chip IDs
  34. print("[+] ID read")
  35. print(" Flash: " + hexdump(flash.spi_xfer(b'\x9f', rx_len=3)))
  36. print(" PSRAM: " + hexdump(psram.spi_xfer(b'\x9f', dummy_len=3, rx_len=8)))
  37. # Enable PSRAM QPI
  38. psram.spi_xfer(b'\x35')
  39. # Manual page read/write test
  40. if True:
  41. print("[+] Manual page read/write test")
  42. # Write a random page
  43. data = bytes([random.randint(0,255) for i in range(256)])
  44. psram.qpi_xfer(b'\x02\x01\x00\x00', data)
  45. # Read it back
  46. rdata = psram.qpi_xfer(b'\xeb\x01\x00\x00', dummy_len=3, rx_len=256)
  47. # Results
  48. if data != rdata:
  49. print("[!] Failed")
  50. print(" Orig: " + hexdump(data))
  51. print(" Read: " + hexdump(rdata))
  52. print(" Diff: " + hexdump(bytes([a^b for a,b in zip(data,rdata) ])))
  53. else:
  54. print("[.] OK")
  55. # What mode ?
  56. if filename is None:
  57. # Run memtest on PSRAM
  58. print("[+] Testing PSRAM")
  59. good = memtest.run(RAM_ADDR_CS(1, 0), 1<<21)
  60. if good:
  61. print("[.] All good !")
  62. else:
  63. print("[!] Errors found !")
  64. # Disable QPI
  65. psram.qpi_xfer(b'\xf5')
  66. else:
  67. # Load data file
  68. print("[+] Uploading image data")
  69. img = open(filename, 'rb').read()
  70. img = bytearray([(a << 4) | b for a, b in zip(img[0::2], img[1::2])])
  71. memtest.load_data(RAM_ADDR_CS(1, 0), img)
  72. print("[+] Uploading palette")
  73. try:
  74. # Palette data from file
  75. def to_col(d):
  76. return (
  77. (((d[2] + 0x08) >> 4) << 8) |
  78. (((d[1] + 0x08) >> 4) << 4) |
  79. (((d[0] + 0x08) >> 4) << 0) |
  80. 0
  81. )
  82. with open(filename + '.pal', 'rb') as fh:
  83. pal = [to_col(fh.read(3)) for i in range(16)]
  84. for i in range(4*16):
  85. hdmi.pal_write(i, pal[i&15])
  86. except:
  87. # 1:1 palette
  88. for i in range(4*16):
  89. hdmi.pal_write(i, i&15)
  90. # Start DMA
  91. print("[+] Starting DMA")
  92. wb.aux_csr(1)
  93. hdmi.enable(RAM_ADDR_CS(1, 0), 64)
  94. # Done
  95. return 0
  96. if __name__ == '__main__':
  97. sys.exit(main(*sys.argv) or 0)