microchip8_common.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # Microchip8 common - basic file for 8bit PIC MCU
  5. #
  6. # Copyright (c) 2012 Pavel Stemberk <stemberk@gmail.com>
  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. import math
  24. class Chip_Microchip8_common(Chip):
  25. CMD_LOAD_DATA_FOR_PGM = 0x02
  26. CMD_LOAD_DATA_FOR_DM = 0x03
  27. CMD_READ_DATA_FROM_PGM = 0x04
  28. CMD_READ_DATA_FROM_DM = 0x05
  29. CMD_INCREMENT_ADDRESS = 0x06
  30. CMD_BULK_ERASE_PGM = 0x09
  31. CMD_BULK_ERASE_DM = 0x0B
  32. PCMDBIT_4BITINSTR = 0
  33. PCMDBIT_SENDDATA = 1
  34. PCMDBIT_READDATA = 2
  35. STAT_BUSY = 0x01
  36. STAT_SDIO = 0x02
  37. # EEPROM access: default off, if exists override it
  38. hasEEPROM = False
  39. # Signature bytes access: default on, if doesn't exist, override it
  40. hasSigBytes = True
  41. # default delays - can be overridden
  42. delayTdly5 = 0.00000015
  43. delayTdis = 0.0001
  44. delayTprog = 0.001
  45. delayTdly = 0.000001
  46. delayTera = 0.01
  47. nLatches = 1
  48. @classmethod
  49. def getSupportFlags(cls):
  50. flags = super(Chip_Microchip8_common, cls).getSupportFlags()
  51. if not cls.hasEEPROM:
  52. flags &= ~(Chip.SUPPORT_EEPROMREAD |\
  53. Chip.SUPPORT_EEPROMWRITE)
  54. if not cls.hasSigBytes:
  55. flags &= ~Chip.SUPPORT_SIGREAD
  56. return flags
  57. def __init__(self,
  58. chipPackage, chipPinVCC, chipPinsVPP, chipPinGND,
  59. signature,
  60. flashPageSize, flashPages,
  61. eepromPageSize, eepromPages,
  62. fuseBytes
  63. ):
  64. Chip.__init__(self,
  65. chipPackage=chipPackage,
  66. chipPinVCC=chipPinVCC,
  67. chipPinsVPP=chipPinsVPP,
  68. chipPinGND=chipPinGND)
  69. self.signature = signature
  70. self.flashPageSize = flashPageSize # Flash page size, in words
  71. self.flashPages = flashPages # Nr of flash pages
  72. self.eepromPageSize = eepromPageSize # EEPROM page size, in bytes
  73. self.eepromPages = eepromPages # Nr of EEPROM pages
  74. self.fuseBytes = fuseBytes # Nr of fuse bytes
  75. self.PC = 0
  76. self.isInPmMode = False
  77. def erase(self):
  78. if(hasattr(self, 'osccalAddr')):
  79. self.__erase(keepOSCCAL=True)
  80. else:
  81. self.__erase(keepOSCCAL=False)
  82. def __erase(self, keepConfigWord=False, keepUserIDLocation=False, keepOSCCAL=False, keepEEPROM=False):
  83. OSCCAL = 0xfff
  84. self.exitPM()
  85. self.enterPM()
  86. if(keepOSCCAL):
  87. self.progressMeterInit("Reading OSCCAL)", 0)
  88. self.setPC(self.osccalAddr)
  89. self.sendReadFlashInstr()
  90. self.top.cmdDelay(self.delayTdly)
  91. self.readSDOBufferLow()
  92. self.readSDOBufferHigh()
  93. OSCCAL = self.top.cmdReadBufferReg16()
  94. self.progressMeterFinish()
  95. if(hasattr(self, 'osccalBackupAddr') and OSCCAL == 0xfff):
  96. self.progressMeterInit("OSCCAL value lost, restoring from backup location ...", 0)
  97. print("OSCCAL value lost, restoring from backup location ...")
  98. self.setPC(self.osccalBackupAddr - self.osccalAddr)
  99. self.sendReadFlashInstr()
  100. self.top.cmdDelay(self.delayTdly)
  101. self.readSDOBufferLow()
  102. self.readSDOBufferHigh()
  103. OSCCAL = self.top.cmdReadBufferReg16()
  104. self.progressMeterFinish()
  105. # print ("osccal: %x\n" % OSCCAL)
  106. if(keepConfigWord):
  107. self.progressMeterInit("Reading ConfigWord for backup", 0)
  108. CW = self.getConfigWord()
  109. self.progressMeterFinish()
  110. # erase User ID Location and backup osccal Tooo
  111. # erase User ID Location and backup osccal Tooo
  112. if(not keepUserIDLocation):
  113. self.enterConfigArea()
  114. self.setPC(self.userIDLocationAddr)
  115. self.progressMeterInit("Erasing chip", 0)
  116. self.bulkErasePGM()
  117. self.progressMeterFinish()
  118. #OSCCAL=0x3454
  119. #OSCCAL=0x0C10
  120. if(keepOSCCAL and OSCCAL != 0xfff):
  121. self.exitPM()
  122. self.enterPM()
  123. self.progressMeterInit("Writing osccal, value %x" % OSCCAL, 0)
  124. print("Writing osccal, value %x" % OSCCAL)
  125. self.setPC(self.osccalAddr)
  126. self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, OSCCAL)
  127. self.top.cmdDelay(self.delayTdly)
  128. self.sendWriteFlashInstr()
  129. self.progressMeterFinish()
  130. if(keepConfigWord):
  131. self.progressMeterInit("Writing ConfigWord, value %x" % CW, 0)
  132. self.writeConfigWord(CW)
  133. self.progressMeterFinish()
  134. if((not keepEEPROM) and self.hasEEPROM):
  135. self.progressMeterInit("Erasing EEPROM", 0)
  136. self.bulkEraseDM()
  137. self.progressMeterFinish()
  138. self.exitPM()
  139. def bulkErasePGM(self):
  140. self.sendCommand(0, 0, 0, self.CMD_BULK_ERASE_PGM)
  141. self.top.cmdDelay(self.delayTera) # Tera
  142. def bulkEraseDM(self):
  143. self.sendCommand(0, 0, 0, self.CMD_BULK_ERASE_DM)
  144. self.top.cmdDelay(self.delayTera) # Tera
  145. def readProgmem(self):
  146. nrWords = self.flashPages * self.flashPageSize
  147. image = b""
  148. self.enterPM()
  149. self.setPC(0)
  150. self.progressMeterInit("Reading flash", nrWords)
  151. bufferedBytes = 0
  152. for word in range(0, nrWords):
  153. self.sendReadFlashInstr()
  154. # self.top.cmdDelay(0.00002) #20us wait - inconsistent data if skipped
  155. self.top.cmdDelay(self.delayTdly)
  156. self.readSDOBufferLow()
  157. bufferedBytes += 1
  158. self.readSDOBufferHigh()
  159. bufferedBytes += 1
  160. if bufferedBytes == self.top.getBufferRegSize():
  161. image += self.top.cmdReadBufferReg(bufferedBytes)
  162. self.progressMeter(word)
  163. bufferedBytes = 0
  164. self.incrementPC(1)
  165. image += self.top.cmdReadBufferReg(bufferedBytes)
  166. self.progressMeterFinish()
  167. # self.exitPM()
  168. return image
  169. def readEEPROM(self):
  170. nrWords = self.eepromPages * self.eepromPageSize
  171. image = b""
  172. self.enterPM()
  173. self.progressMeterInit("Reading eeprom", nrWords)
  174. bufferedBytes = 0
  175. for word in range(0, nrWords):
  176. self.sendReadEEPROMInstr()
  177. self.top.cmdDelay(self.delayTdly) # 20us wait - inconsistent data if skipped
  178. self.readSDOBufferLow()
  179. bufferedBytes += 1
  180. if bufferedBytes == self.top.getBufferRegSize():
  181. image += self.top.cmdReadBufferReg(bufferedBytes)
  182. self.progressMeter(word)
  183. bufferedBytes = 0
  184. self.incrementPC(1)
  185. image += self.top.cmdReadBufferReg(bufferedBytes)
  186. self.progressMeterFinish()
  187. # self.exitPM()
  188. return image
  189. def writeEEPROM(self, image):
  190. nrWords = self.eepromPages * self.eepromPageSize
  191. if len(image) > nrWords:
  192. self.throwError("Invalid flash image size %d (expected <=%d)" % len(image))
  193. self.enterPM()
  194. self.progressMeterInit("Writing eeprom", nrWords)
  195. bufferedBytes = 0
  196. for addr in range(0, len(image)):
  197. self.progressMeter(addr)
  198. byte = byte2int(image[addr])
  199. if byte != 0xff:
  200. self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_DM, byte)
  201. self.top.cmdDelay(self.delayTdly)
  202. self.sendWriteFlashInstrDM()
  203. self.incrementPC(1)
  204. self.progressMeterFinish()
  205. # self.exitPM()
  206. def writeProgmem(self, image):
  207. nrWords = self.flashPages * self.flashPageSize
  208. if len(image) > nrWords * 2 or len(image) % 2 != 0:
  209. self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" % \
  210. (len(image), nrWords * 2))
  211. self.progressMeterInit("Writing flash", len(image) // 2)
  212. self.enterPM()
  213. self.setPC(0)
  214. latCnt=1;
  215. writeCurrentLatches=False
  216. for wordAddr in range(0, len(image) // 2):
  217. self.progressMeter(wordAddr)
  218. # do not swap following two lines
  219. WD = (byte2int(image[wordAddr * 2 + 1]) << 8) | byte2int(image[wordAddr * 2 + 0])
  220. if(WD != (byte2int(self.defaultWord[1]) << 8) + byte2int(self.defaultWord[0])):
  221. self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, WD)
  222. self.top.cmdDelay(self.delayTdly)
  223. writeCurrentLatches=True
  224. if(latCnt == self.nLatches):
  225. if(writeCurrentLatches):
  226. self.sendWriteFlashInstr()
  227. latCnt=0
  228. writeCurrentLatches=False
  229. latCnt+=1
  230. self.incrementPC(1)
  231. if(latCnt>1):
  232. self.sendWriteFlashInstr()
  233. self.progressMeterFinish()
  234. # self.exitPM()
  235. def readFuse(self):
  236. self.enterPM()
  237. fuses = []
  238. self.progressMeterInit("Reading fuses (configuration word)", 0)
  239. for CW in self.getConfigWord():
  240. fuses.append(int2byte(CW & 0x00ff))
  241. fuses.append(int2byte((CW >> 8) & 0x00ff))
  242. self.progressMeterFinish()
  243. return b"".join(fuses)
  244. def readUserIdLocation(self):
  245. self.enterPM()
  246. self.enterConfigArea()
  247. self.setPC(self.userIDLocationAddr)
  248. self.progressMeterInit("Reading User ID Location", 0)
  249. for i in range(0, self.userIDLocationSize):
  250. self.sendReadFlashInstr()
  251. self.top.hostDelay(self.delayTdly)
  252. self.readSDOBufferLow()
  253. self.readSDOBufferHigh()
  254. self.incrementPC(1)
  255. # self.exitPM()
  256. self.progressMeterFinish()
  257. return self.top.cmdReadBufferReg()[0:2 * self.userIDLocationSize]
  258. def writeUserIdLocation(self, image):
  259. if len(image) > self.userIDLocationSize * 2 or len(image) % 2 != 0:
  260. self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" % \
  261. (len(image), self.userIDLocationSize * 2))
  262. self.enterPM()
  263. self.enterConfigArea()
  264. self.setPC(self.userIDLocationAddr)
  265. self.progressMeterInit("Writing User ID Location", (len(image) // 2) - 1)
  266. for word in range(0, (len(image) // 2)):
  267. self.progressMeter(word)
  268. # do not swap following two lines
  269. WD = (byte2int(image[word * 2 + 1]) << 8) | byte2int(image[word * 2 + 0])
  270. if(WD != (byte2int(self.defaultWord[1]) << 8) + byte2int(self.defaultWord[0])):
  271. self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, WD)
  272. self.sendWriteFlashInstr()
  273. self.incrementPC(1)
  274. self.top.hostDelay(self.delayTdly)
  275. self.sendWriteFlashInstr()
  276. self.progressMeterFinish()
  277. # self.exitPM()
  278. def getConfigWordSize(self):
  279. return self.fuseBytes // 2
  280. def getConfigWord(self):
  281. self.enterPM()
  282. self.enterConfigArea()
  283. self.setPC(self.configWordAddr)
  284. retVal = []
  285. for i in range(0, self.getConfigWordSize()):
  286. self.sendReadFlashInstr()
  287. self.top.cmdDelay(self.delayTdly)
  288. self.readSDOBufferLow()
  289. self.readSDOBufferHigh()
  290. self.incrementPC(1)
  291. retVal.append(self.top.cmdReadBufferReg16())
  292. return retVal
  293. def writeFuse(self, image):
  294. if len(image) != 2 * self.getConfigWordSize():
  295. self.throwError("Invalid Fuses image size %d (expected %d)" % \
  296. (len(image), 2 * self.getConfigWordSize()))
  297. self.progressMeterInit("Writing fuses", 0)
  298. # print "image1:%x,,%x,,%x" % (byte2int(image[0]),byte2int(image[1]),byte2int(image[1])<<8)
  299. CW = []
  300. for tBytes in zip(image[::2], image[1::2]):
  301. CW.append((byte2int(tBytes[1]) << 8) | byte2int(tBytes[0]))
  302. self.writeConfigWord(CW)
  303. self.progressMeterFinish()
  304. def writeConfigWord(self, listConfigWord16):
  305. # Externally timed writes are not supported
  306. # for Configuration and Calibration bits. Any
  307. # externally timed write to the Configuration
  308. # or Calibration Word will have no effect on
  309. # the targeted word.
  310. self.enterPM()
  311. self.enterConfigArea()
  312. self.setPC(self.configWordAddr)
  313. for configWord16 in listConfigWord16:
  314. # print "write CW {:x}".format(configWord16)
  315. self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, configWord16)
  316. self.top.cmdDelay(self.delayTdly)
  317. self.sendWriteFlashInstrCW()
  318. self.incrementPC(1)
  319. self.top.flushCommands()
  320. def enterPM(self):
  321. if self.isInPmMode and self.isInsideProgramMemoryArea:
  322. self.resetPC()
  323. return
  324. self.PC = self.initPcValue
  325. self.isInsideProgramMemoryArea = True
  326. "Enter HV programming mode. Vdd first entry mode"
  327. self.applyVCC(False)
  328. self.applyVPP(False)
  329. self.applyGND(False)
  330. self.setPins(0, 0)
  331. self.top.cmdSetVCCVoltage(self.voltageVDD)
  332. self.top.cmdSetVPPVoltage(self.voltageVPP)
  333. # self.top.cmdEnableZifPullups(True)
  334. self.applyGND(True)
  335. self.applyVPP(True)
  336. self.top.cmdDelay(0.000250)
  337. self.applyVCC(True)
  338. # self.top.cmdEnableZifPullups(True)
  339. # self.top.cmdDelay(0.000005) #least 5us is required to reach Vdd first entry PM
  340. self.setTopProgrammerDelays()
  341. self.isInPmMode = True
  342. def checkSignature(self):
  343. signature = self.readSignature()
  344. if signature != self.signature:
  345. msg = "Unexpected device signature. " + \
  346. "Want %02X%02X%02X, but got %02X%02X%02X" % \
  347. (byte2int(self.signature[0]), byte2int(self.signature[1]),
  348. byte2int(self.signature[2]),
  349. byte2int(signature[0]), byte2int(signature[1]),
  350. byte2int(signature[2]))
  351. if self.top.getForceLevel() >= 1:
  352. self.printWarning(msg)
  353. else:
  354. self.throwError(msg)
  355. def exitPM(self):
  356. "Exit HV programming mode. Vdd last exit mode"
  357. self.top.flushCommands()
  358. self.setPins(0, 0)
  359. self.applyVPP(False)
  360. self.applyGND(False)
  361. self.top.hostDelay(self.delayTdly)
  362. self.applyVCC(False)
  363. self.isInPmMode = False
  364. def sendReadFlashInstr(self):
  365. '''
  366. '''
  367. self.sendCommand(0, 0, 1, self.CMD_READ_DATA_FROM_PGM)
  368. def sendWriteFlashInstr(self):
  369. '''
  370. to be overriden
  371. '''
  372. pass
  373. def sendReadEEPROMInstr(self):
  374. '''
  375. '''
  376. self.sendCommand(0, 0, 1, self.CMD_READ_DATA_FROM_DM)
  377. def send6bitReadInstruction(self, pInstruction):
  378. def incBbAndCheckFillImage():
  379. self.BufferedBytes += 1
  380. if self.BufferedBytes == self.top.getBufferRegSize():
  381. self.flushBufferToImage()
  382. # self.sendCommand(1,0,1,pInstruction)
  383. self.sendCommand(0, 0, 1, pInstruction)
  384. # self.busyWait()
  385. self.readSDOBufferHigh()
  386. incBbAndCheckFillImage()
  387. def send6bitWriteInstruction(self, pInstruction, pDataPayload):
  388. # self.busyWait()
  389. self.setSDI(pDataPayload)
  390. # print("sending {:x}\n".format(pDataPayload))
  391. self.sendCommand(0, 1, 0, pInstruction)
  392. self.top.flushCommands()
  393. def setSDI(self, sdi):
  394. '''
  395. set 14 bit sdi value
  396. '''
  397. self.top.cmdFPGAWrite(0x13, sdi & 0xFF)
  398. self.top.cmdFPGAWrite(0x14, (sdi >> 8) & 0x3F)
  399. def sendCommand(self, bit4bitInstr=0, bitSendData=0, bitReadData=0, cmd4bit=0):
  400. '''
  401. `define CMDBIT_4BITINSTR 0
  402. `define CMDBIT_SENDDATA 1
  403. `define CMDBIT_READDATA 2
  404. '''
  405. command = (cmd4bit & 0x1F) << 3
  406. if bit4bitInstr:
  407. command |= 2 ** self.PCMDBIT_4BITINSTR
  408. if bitSendData:
  409. command |= 2 ** self.PCMDBIT_SENDDATA
  410. if bitReadData:
  411. command |= 2 ** self.PCMDBIT_READDATA
  412. # print("cmd sending {:x}\n".format(command))
  413. self.top.cmdFPGAWrite(0x12, command)
  414. def setTopProgrammerDelays(self):
  415. #print("tdel5:{:d}".format(int(math.ceil(self.delayTdly5 / 42e-9))))
  416. #print("tdly:{:d}".format(int(math.ceil(self.delayTdly / 42e-9))))
  417. self.top.cmdFPGAWrite(0x10, int(math.ceil(self.delayTdly5 / 42e-9)))
  418. self.top.cmdFPGAWrite(0x11, int(math.ceil(self.delayTdly / 42e-9)))
  419. # def runCommandSync(self, command):
  420. # self.loadCommand(command)
  421. # self.busyWait()
  422. def resetPC(self):
  423. '''can be overriden'''
  424. self.setPC(self.initPcValue)
  425. def setPC(self, address):
  426. '''to be overriden'''
  427. pass
  428. def incrementPC(self, count):
  429. '''to be overriden'''
  430. pass
  431. def enterConfigArea(self, wordLatched=0):
  432. '''to be overriden'''
  433. pass
  434. def setPins(self, ICSPCLK=0, SDIOVALUE=0, SDIODRIVEN=1):
  435. '''
  436. setPins
  437. '''
  438. data = 0
  439. if ICSPCLK:
  440. data |= 1
  441. if SDIODRIVEN:
  442. data |= 2
  443. if SDIOVALUE:
  444. data |= 4
  445. self.top.cmdFPGAWrite(0x15, data)
  446. def getStatusFlags(self):
  447. '''
  448. '''
  449. self.top.cmdFPGARead(0x12)
  450. stat = self.top.cmdReadBufferReg()
  451. return byte2int(stat[0])
  452. def readSDOBufferHigh(self):
  453. self.top.cmdFPGARead(0x10)
  454. def readSDOBufferLow(self):
  455. self.top.cmdFPGARead(0x13)
  456. def rawSDIOState(self):
  457. return bool(self.getStatusFlags() & self.STAT_SDIO)
  458. def busy(self):
  459. return bool(self.getStatusFlags() & self.STAT_BUSY)
  460. # def busyWait(self):
  461. # for i in range(0, 100):
  462. # if not self.busy():
  463. # return
  464. # self.top.hostDelay(0.01)
  465. # self.throwError("Timeout in busywait.")
  466. # def waitHighSDIO(self):
  467. # for i in range(0, 100):
  468. # if self.rawSDOState():
  469. # return
  470. # self.top.hostDelay(0.01)
  471. # self.throwError("Timeout waiting for SDO.")