attinyspc_common.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # Atmel Tiny small pin count
  5. #
  6. # Copyright (c) 2010 Michael Buesch <m@bues.ch>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation; either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License along
  19. # with this program; if not, write to the Free Software Foundation, Inc.,
  20. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. """
  22. from libtoprammer.chip import *
  23. class Chip_AtTinySPC_common(Chip):
  24. PROGCMD_SENDINSTR = 1 # Send an instruction to the chip
  25. STAT_BUSY = 0x01 # Programmer is running a command
  26. STAT_SDO = 0x02 # Raw SDO pin state
  27. def __init__(self,
  28. chipPackage,
  29. chipPinVCC,
  30. chipPinsVPP,
  31. chipPinGND,
  32. signature,
  33. flashPageSize,
  34. flashPages,
  35. eepromPageSize,
  36. eepromPages,
  37. nrFuseBits,
  38. nrLockBits):
  39. Chip.__init__(self,
  40. chipPackage=chipPackage,
  41. chipPinVCC=chipPinVCC,
  42. chipPinsVPP=chipPinsVPP,
  43. chipPinGND=chipPinGND)
  44. self.signature = signature
  45. self.flashPageSize = flashPageSize
  46. self.flashPages = flashPages
  47. self.eepromPageSize = eepromPageSize
  48. self.eepromPages = eepromPages
  49. self.nrFuseBits = nrFuseBits
  50. self.nrLockBits = nrLockBits
  51. def readSignature(self):
  52. self.__enterPM()
  53. self.progressMeterInit("Reading signature", 0)
  54. signature = self.__readSignature()
  55. self.progressMeterFinish()
  56. return signature
  57. def erase(self):
  58. self.__enterPM()
  59. self.progressMeterInit("Erasing chip", 0)
  60. self.__sendInstr(SDI=0x80, SII=0x4C)
  61. self.__sendInstr(SDI=0x00, SII=0x64)
  62. self.__sendInstr(SDI=0x00, SII=0x6C)
  63. self.__waitHighSDO()
  64. self.__sendNOP()
  65. self.progressMeterFinish()
  66. def readProgmem(self):
  67. nrWords = self.flashPages * self.flashPageSize
  68. image = b""
  69. self.__enterPM()
  70. self.progressMeterInit("Reading flash", nrWords)
  71. self.__sendReadFlashInstr()
  72. currentHigh = -1
  73. bufferedBytes = 0
  74. for word in range(0, nrWords):
  75. self.progressMeter(word)
  76. low = word & 0xFF
  77. high = (word >> 8) & 0xFF
  78. self.__sendInstr(SDI=low, SII=0x0C)
  79. if high != currentHigh:
  80. self.__sendInstr(SDI=high, SII=0x1C)
  81. currentHigh = high
  82. self.__sendInstr(SDI=0x00, SII=0x68)
  83. self.__sendInstr(SDI=0x00, SII=0x6C)
  84. self.__readSDOBufferHigh()
  85. bufferedBytes += 1
  86. self.__sendInstr(SDI=0x00, SII=0x78)
  87. self.__sendInstr(SDI=0x00, SII=0x7C)
  88. self.__readSDOBufferHigh()
  89. bufferedBytes += 1
  90. if bufferedBytes == self.top.getBufferRegSize():
  91. image += self.top.cmdReadBufferReg(bufferedBytes)
  92. bufferedBytes = 0
  93. image += self.top.cmdReadBufferReg(bufferedBytes)
  94. self.progressMeterFinish()
  95. return image
  96. def writeProgmem(self, image):
  97. nrWords = self.flashPages * self.flashPageSize
  98. if len(image) > nrWords * 2 or len(image) % 2 != 0:
  99. self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" %\
  100. (len(image), nrWords * 2))
  101. self.__enterPM()
  102. self.progressMeterInit("Writing flash", len(image) // 2)
  103. self.__sendWriteFlashInstr()
  104. currentHigh = -1
  105. for word in range(0, len(image) // 2):
  106. self.progressMeter(word)
  107. low = word & 0xFF
  108. high = (word >> 8) & 0xFF
  109. self.__sendInstr(SDI=low, SII=0x0C)
  110. self.__sendInstr(SDI=byte2int(image[word * 2 + 0]), SII=0x2C)
  111. self.__sendInstr(SDI=byte2int(image[word * 2 + 1]), SII=0x3C)
  112. self.__sendInstr(SDI=0x00, SII=0x7D)
  113. self.__sendInstr(SDI=0x00, SII=0x7C)
  114. if ((word + 1) % self.flashPageSize == 0) or word == len(image) // 2 - 1:
  115. if currentHigh != high:
  116. self.__sendInstr(SDI=high, SII=0x1C)
  117. currentHigh = high
  118. self.__sendInstr(SDI=0x00, SII=0x64)
  119. self.__sendInstr(SDI=0x00, SII=0x6C)
  120. self.__waitHighSDO()
  121. self.__sendNOP()
  122. self.progressMeterFinish()
  123. def readEEPROM(self):
  124. nrBytes = self.eepromPages * self.eepromPageSize
  125. image = b""
  126. self.__enterPM()
  127. self.progressMeterInit("Reading EEPROM", nrBytes)
  128. self.__sendReadEEPROMInstr()
  129. currentPage = -1
  130. bufferedBytes = 0
  131. for i in range(0, nrBytes):
  132. self.progressMeter(i)
  133. low = i & 0xFF
  134. high = (i >> 8) & 0xFF
  135. self.__sendInstr(SDI=low, SII=0x0C)
  136. if currentPage != high:
  137. self.__sendInstr(SDI=high, SII=0x1C)
  138. currentPage = high
  139. self.__sendInstr(SDI=0x00, SII=0x68)
  140. self.__sendInstr(SDI=0x00, SII=0x6C)
  141. self.__readSDOBufferHigh()
  142. bufferedBytes += 1
  143. if bufferedBytes == self.top.getBufferRegSize():
  144. image += self.top.cmdReadBufferReg(bufferedBytes)
  145. bufferedBytes = 0
  146. image += self.top.cmdReadBufferReg(bufferedBytes)
  147. self.progressMeterFinish()
  148. return image
  149. def writeEEPROM(self, image):
  150. nrBytes = self.eepromPages * self.eepromPageSize
  151. if len(image) > nrBytes:
  152. self.throwError("Invalid EEPROM image size %d (expected <=%d)" %\
  153. (len(image), nrBytes))
  154. self.__enterPM()
  155. self.progressMeterInit("Writing EEPROM", len(image))
  156. self.__sendWriteEEPROMInstr()
  157. for i in range(0, len(image)):
  158. self.progressMeter(i)
  159. low = i & 0xFF
  160. high = (i >> 8) & 0xFF
  161. self.__sendInstr(SDI=low, SII=0x0C)
  162. self.__sendInstr(SDI=high, SII=0x1C)
  163. self.__sendInstr(SDI=byte2int(image[i]), SII=0x2C)
  164. self.__sendInstr(SDI=0x00, SII=0x6D)
  165. self.__sendInstr(SDI=0x00, SII=0x64)
  166. self.__sendInstr(SDI=0x00, SII=0x6C)
  167. self.__waitHighSDO()
  168. self.__sendNOP()
  169. self.progressMeterFinish()
  170. def readFuse(self):
  171. usedBitsMask = (1 << self.nrFuseBits) - 1
  172. unusedBitsMask = usedBitsMask ^ 0xFFFFFF
  173. fuses = []
  174. self.__enterPM()
  175. self.progressMeterInit("Reading fuses", 0)
  176. self.__sendInstr(SDI=0x04, SII=0x4C)
  177. self.__sendInstr(SDI=0x00, SII=0x68)
  178. self.__sendInstr(SDI=0x00, SII=0x6C)
  179. self.__readSDOBufferHigh()
  180. fuses.append(int2byte(self.top.cmdReadBufferReg8() |
  181. ((unusedBitsMask >> 0) & 0xFF)))
  182. if self.nrFuseBits > 8:
  183. self.__sendInstr(SDI=0x04, SII=0x4C)
  184. self.__sendInstr(SDI=0x00, SII=0x7A)
  185. self.__sendInstr(SDI=0x00, SII=0x7E)
  186. self.__readSDOBufferHigh()
  187. fuses.append(int2byte(self.top.cmdReadBufferReg8() |
  188. ((unusedBitsMask >> 8) & 0xFF)))
  189. if self.nrFuseBits > 16:
  190. self.__sendInstr(SDI=0x04, SII=0x4C)
  191. self.__sendInstr(SDI=0x00, SII=0x6A)
  192. self.__sendInstr(SDI=0x00, SII=0x6E)
  193. self.__readSDOBufferHigh()
  194. fuses.append(int2byte(self.top.cmdReadBufferReg8() |
  195. ((unusedBitsMask >> 16) & 0xFF)))
  196. self.progressMeterFinish()
  197. return b"".join(fuses)
  198. def writeFuse(self, image):
  199. if len(image) != roundup(self.nrFuseBits, 8) // 8:
  200. self.throwError("Invalid Fuses image size %d (expected %d)" %\
  201. (len(image), roundup(self.nrFuseBits, 8) // 8))
  202. usedBitsMask = (1 << self.nrFuseBits) - 1
  203. self.__enterPM()
  204. self.progressMeterInit("Writing fuses", 0)
  205. self.__sendInstr(SDI=0x40, SII=0x4C)
  206. self.__sendInstr(SDI=(image[0] & (usedBitsMask >> 0)), SII=0x2C)
  207. self.__sendInstr(SDI=0x00, SII=0x64)
  208. self.__sendInstr(SDI=0x00, SII=0x6C)
  209. self.__waitHighSDO()
  210. if self.nrFuseBits > 8:
  211. self.__sendInstr(SDI=0x40, SII=0x4C)
  212. self.__sendInstr(SDI=(image[1] & (usedBitsMask >> 8)), SII=0x2C)
  213. self.__sendInstr(SDI=0x00, SII=0x74)
  214. self.__sendInstr(SDI=0x00, SII=0x7C)
  215. self.__waitHighSDO()
  216. if self.nrFuseBits > 16:
  217. self.__sendInstr(SDI=0x40, SII=0x4C)
  218. self.__sendInstr(SDI=(image[2] & (usedBitsMask >> 16)), SII=0x2C)
  219. self.__sendInstr(SDI=0x00, SII=0x66)
  220. self.__sendInstr(SDI=0x00, SII=0x6E)
  221. self.__waitHighSDO()
  222. self.progressMeterFinish()
  223. def readLockbits(self):
  224. usedBitsMask = (1 << self.nrLockBits) - 1
  225. unusedBitsMask = usedBitsMask ^ 0xFF
  226. self.__enterPM()
  227. self.progressMeterInit("Reading lockbits", 0)
  228. self.__sendInstr(SDI=0x04, SII=0x4C)
  229. self.__sendInstr(SDI=0x00, SII=0x78)
  230. self.__sendInstr(SDI=0x00, SII=0x7C)
  231. self.__readSDOBufferHigh()
  232. lockbits = int2byte(self.top.cmdReadBufferReg8() | unusedBitsMask)
  233. self.progressMeterFinish()
  234. return lockbits
  235. def writeLockbits(self, image):
  236. if len(image) != roundup(self.nrLockBits, 8) // 8:
  237. self.throwError("Invalid Lockbits image size %d (expected %d)" %\
  238. (len(image), roundup(self.nrLockBits, 8) // 8))
  239. usedBitsMask = (1 << self.nrLockBits) - 1
  240. self.__enterPM()
  241. self.progressMeterInit("Writing lockbits", 0)
  242. self.__sendInstr(SDI=0x20, SII=0x4C)
  243. self.__sendInstr(SDI=(byte2int(image[0]) & usedBitsMask), SII=0x2C)
  244. self.__sendInstr(SDI=0x00, SII=0x64)
  245. self.__sendInstr(SDI=0x00, SII=0x6C)
  246. self.__waitHighSDO()
  247. self.progressMeterFinish()
  248. def __readSignature(self):
  249. self.__sendInstr(SDI=0x08, SII=0x4C)
  250. for i in range(0, 3):
  251. self.__sendInstr(SDI=i, SII=0x0C)
  252. self.__sendInstr(SDI=0x00, SII=0x68)
  253. self.__sendInstr(SDI=0x00, SII=0x6C)
  254. self.__readSDOBufferHigh()
  255. return self.top.cmdReadBufferReg()[0:3]
  256. def __enterPM(self):
  257. "Enter HV programming mode."
  258. self.applyVCC(False)
  259. self.applyVPP(False)
  260. self.applyGND(False)
  261. self.top.cmdSetVCCVoltage(5)
  262. self.top.cmdSetVPPVoltage(0)
  263. self.top.cmdSetVPPVoltage(12)
  264. self.applyGND(True)
  265. self.applyVCC(True)
  266. self.__setPins(SCI=0, SDO_en=0, RST_en=1, RST=0)
  267. for i in range(0, 6):
  268. self.__setPins(SCI=0, SDO_en=0, RST_en=1, RST=0)
  269. self.__setPins(SCI=1, SDO_en=0, RST_en=1, RST=0)
  270. self.__setPins(SCI=0, SDO_en=1, SDO=0, RST_en=1, RST=0)
  271. self.top.hostDelay(0.001)
  272. self.__setPins(SDO_en=1, SDO=0, RST_en=0)
  273. self.applyVPP(True)
  274. self.top.hostDelay(0.001)
  275. self.__setPins(SDO_en=0)
  276. self.top.hostDelay(0.01)
  277. signature = self.__readSignature()
  278. if signature != self.signature:
  279. msg = "Unexpected device signature. " +\
  280. "Want %02X%02X%02X, but got %02X%02X%02X" % \
  281. (byte2int(self.signature[0]), byte2int(self.signature[1]),
  282. byte2int(self.signature[2]),
  283. byte2int(signature[0]), byte2int(signature[1]),
  284. byte2int(signature[2]))
  285. if self.top.getForceLevel() >= 1:
  286. self.printWarning(msg)
  287. else:
  288. self.throwError(msg)
  289. def __sendReadEEPROMInstr(self):
  290. self.__sendInstr(SDI=0x03, SII=0x4C)
  291. def __sendWriteEEPROMInstr(self):
  292. self.__sendInstr(SDI=0x11, SII=0x4C)
  293. def __sendReadFlashInstr(self):
  294. self.__sendInstr(SDI=0x02, SII=0x4C)
  295. def __sendWriteFlashInstr(self):
  296. self.__sendInstr(SDI=0x10, SII=0x4C)
  297. def __sendNOP(self):
  298. self.__sendInstr(SDI=0x00, SII=0x4C)
  299. def __sendInstr(self, SDI, SII):
  300. self.__setSDI(SDI)
  301. self.__setSII(SII)
  302. self.__loadCommand(self.PROGCMD_SENDINSTR)
  303. # We do not poll the busy flag, because that would result
  304. # in a significant slowdown. We delay long enough for the
  305. # command to finish execution, instead.
  306. self.top.hostDelay(0.001)
  307. def __setSDI(self, sdi):
  308. self.top.cmdFPGAWrite(0x13, sdi & 0xFF)
  309. def __setSII(self, sii):
  310. self.top.cmdFPGAWrite(0x14, sii & 0xFF)
  311. def __loadCommand(self, command):
  312. self.top.cmdFPGAWrite(0x12, command & 0xFF)
  313. def __runCommandSync(self, command):
  314. self.__loadCommand(command)
  315. self.__busyWait()
  316. def __setPins(self, SCI=0, SDO_en=0, SDO=0, RST_en=0, RST=0):
  317. data = 0
  318. if SCI:
  319. data |= 1
  320. if SDO_en:
  321. data |= 2
  322. if SDO:
  323. data |= 4
  324. if RST_en:
  325. data |= 8
  326. if RST:
  327. data |= 16
  328. self.top.cmdFPGAWrite(0x15, data)
  329. def __getStatusFlags(self):
  330. self.top.cmdFPGARead(0x12)
  331. stat = self.top.cmdReadBufferReg()
  332. return byte2int(stat[0])
  333. def __readSDOBufferHigh(self):
  334. self.top.cmdFPGARead(0x10)
  335. def __rawSDOState(self):
  336. return bool(self.__getStatusFlags() & self.STAT_SDO)
  337. def __busy(self):
  338. return bool(self.__getStatusFlags() & self.STAT_BUSY)
  339. def __busyWait(self):
  340. for i in range(0, 100):
  341. if not self.__busy():
  342. return
  343. self.top.hostDelay(0.01)
  344. self.throwError("Timeout in busywait.")
  345. def __waitHighSDO(self):
  346. for i in range(0, 100):
  347. if self.__rawSDOState():
  348. return
  349. self.top.hostDelay(0.01)
  350. self.throwError("Timeout waiting for SDO.")