microchip8_18_common.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. """
  2. # TOP2049 Open Source programming suite
  3. #
  4. # Microchip8_18_common - basic file for 8bit PIC18 MCU
  5. #
  6. # Copyright (c) 2013 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. class Chip_Microchip8_18_common(Chip):
  24. STAT_BUSY = 0x01
  25. STAT_SDIO = 0x02
  26. PCMDBIT_4BITINSTR = 0
  27. PCMDBIT_SENDDATA = 1
  28. PCMDBIT_READDATA = 2
  29. PCMDBIT_KEEPCLKHIGH = 7
  30. CMD_CORE_INSTRUCTION = 0x0
  31. CMD_SHIFT_OUT_TABLAT = 0x2
  32. CMD_TR = 0x8
  33. CMD_TRI = 0x9
  34. CMD_TRD = 0xA
  35. CMD_ITR = 0xB
  36. CMD_TW = 0xC
  37. CMD_TWII = 0xD
  38. CMD_TWDD = 0xE
  39. CMD_TW_START_PROG = 0xF
  40. # EEPROM access: default on, if does not exist override it
  41. hasEEPROM = True
  42. # default delays - can be overridden
  43. delayP2A = 400e-9 # Serial clock low time
  44. delayP5 = 2.2e-6 # Delay between 4-bit command and command operand
  45. delayP5A = 2.2e-6 # Delay between 4-bit command operand and next 4-bit command
  46. delayP6 = 2.2e-6 # Delay between last SCK fall of command byte to first SCK rise of read data word
  47. delayP9 = 1e-3 # SCK High time (minimum programming time)
  48. delayP10 = 30e-6 # SCK Low time after programming (high-voltage discharge time)
  49. delayP11 = 0.01 # Delay to allow self-timed data write or bulk erase to occur
  50. delayP12 = 0.000002 # Input data hold time from nMCLR/Vpp rise
  51. delayP13 = 0.0000001 # Vdd rise setup time to nMCLR/Vpp rise
  52. delayP14 = 0.00000001 # Data out Valid from SCK rise
  53. delayP15 = 0.000002 # PGM rise setup time to nMCLR/Vpp rise
  54. userIDLocationSize = 8
  55. userIDLocationAddr = 0x200000
  56. deviceIDAddr = 0x3FFFFE
  57. configWordAddr = 0x300000
  58. deviceIDLength = 2
  59. voltageVDD = 5
  60. voltageVPP = 12
  61. def __init__(self,
  62. chipPackage, chipPinVCC, chipPinsVPP, chipPinGND,
  63. signature,
  64. flashPageSize, flashPages,
  65. eepromPageSize, eepromPages,
  66. fuseBytes
  67. ):
  68. Chip.__init__(self,
  69. chipPackage=chipPackage,
  70. chipPinVCC=chipPinVCC,
  71. chipPinsVPP=chipPinsVPP,
  72. chipPinGND=chipPinGND)
  73. self.signature = signature
  74. self.flashPageSize = flashPageSize # Flash page size, in words
  75. self.flashPages = flashPages # Nr of flash pages
  76. self.eepromPageSize = eepromPageSize # EEPROM page size, in bytes
  77. self.eepromPages = eepromPages # Nr of EEPROM pages
  78. self.fuseBytes = fuseBytes # Nr of fuse bytes
  79. self.isInPmMode = False
  80. self.BufferedBytes = 0
  81. self.Image = b""
  82. def getIHexInterpreter(self):
  83. inter = IHexInterpreter()
  84. inter.progmemRanges = [ AddressRange(0, self.flashPageSize) ]
  85. inter.fuseRanges = [ AddressRange(self.configWordAddr,
  86. self.configWordAddr + self.fuseBytes) ]
  87. inter.uilRanges = [ AddressRange(self.userIDLocationAddr,
  88. self.userIDLocationAddr + self.userIDLocationSize) ]
  89. return inter
  90. def enterPM(self, force=False):
  91. if self.isInPmMode and not force:
  92. return
  93. "Enter HV programming mode. Vdd first entry mode"
  94. self.applyVCC(False)
  95. self.applyVPP(False)
  96. self.applyGND(False)
  97. self.setPins(0, 0)
  98. self.top.cmdSetVCCVoltage(self.voltageVDD)
  99. self.top.cmdSetVPPVoltage(self.voltageVPP)
  100. self.applyGND(True)
  101. self.applyVCC(True)
  102. self.top.hostDelay(10 * self.delayP13)
  103. self.applyVPP(True)
  104. self.top.hostDelay(102 * self.delayP12)
  105. self.setTopProgrammerDelays()
  106. self.isInPmMode = True
  107. def readUserIdLocation(self):
  108. return self.readSequentialBlock(self.userIDLocationAddr, self.userIDLocationSize, "Reading User ID Locations")
  109. def readFuse(self):
  110. return self.readSequentialBlock(self.configWordAddr, self.fuseBytes, "Reading Config Words")
  111. def readSignature(self):
  112. return self.readSequentialBlock(self.deviceIDAddr, self.deviceIDLength, "Reading Signature")
  113. def readProgmem(self):
  114. nrBytes = self.flashPages * self.flashPageSize
  115. return self.readSequentialBlock(0, nrBytes, "Reading flash")
  116. def readSequentialBlock(self, startAddr, nBytes, infoText):
  117. self.enterPM()
  118. self.progressMeterInit(infoText, nBytes)
  119. self.BufferedBytes = 0
  120. self.Image = b""
  121. self.executeCode(self.getCodeAddrToTBLPTR(startAddr))
  122. for byteAddr in range(0, nBytes):
  123. self.send4bitReadInstruction(self.CMD_TRI)
  124. self.progressMeter(byteAddr)
  125. self.progressMeterFinish()
  126. self.flushBufferToImage()
  127. return self.Image
  128. def writeSequentialBlock(self, startAddr, image, size, infoText):
  129. if len(image) > size:
  130. self.throwError("Invalid flash image size %d (expected <=%d)" % \
  131. (len(image), self.userIDLocationSize))
  132. self.enterPM()
  133. self.executeCode((0x8EA6, 0x9CA6))
  134. self.progressMeterInit(infoText, len(image) // 8)
  135. for blockAddr in range(0, len(image), self.writeBufferSize):
  136. #print("addr:{:x}".format(startAddr+blockAddr))
  137. self.executeCode(self.getCodeAddrToTBLPTR(startAddr+blockAddr))
  138. #for code in self.getCodeAddrToTBLPTR(startAddr+blockAddr):
  139. # print("({:x}, ".format(code))
  140. print(")\n")
  141. self.writeNbytes(image[blockAddr:], self.writeBufferSize)
  142. #self.executeCode((0x0, 0x0))
  143. self.progressMeter(blockAddr)
  144. self.progressMeterFinish()
  145. def readEEPROM(self):
  146. nrBytes = self.eepromPages * self.eepromPageSize
  147. self.enterPM()
  148. self.progressMeterInit("Reading EEPROM", nrBytes)
  149. self.BufferedBytes = 0
  150. self.Image = b""
  151. self.executeCode((0x9EA6, 0x9CA6))
  152. for byteAddr in range(0, nrBytes):
  153. # print("set addr to {:x}\n".format(byteAddr))
  154. self.setEEPROMAddr(byteAddr)
  155. self.executeCode((0x80A6, 0x50A8, 0x6EF5))
  156. self.send4bitReadInstruction(self.CMD_SHIFT_OUT_TABLAT)
  157. self.progressMeter(byteAddr)
  158. self.progressMeterFinish()
  159. self.flushBufferToImage()
  160. return self.Image
  161. def writeEEPROM(self, image):
  162. nrBytes = self.eepromPages * self.eepromPageSize
  163. if len(image) > nrBytes:
  164. self.throwError("Invalid flash image size {:d} (expected <={:d})".format(len(image), nrBytes))
  165. self.enterPM()
  166. self.progressMeterInit("Writing eeprom", len(image))
  167. self.executeCode((0x9EA6, 0x9CA6))
  168. for addr in range(0, len(image)):
  169. self.progressMeter(addr)
  170. #print("writing {:x} value to addr {:x}\n".format(byte2int(image[addr]), addr))
  171. self.setEEPROMAddr(addr)
  172. self.executeCode((0x0E00 | (byte2int(image[addr]) & 0xFF), 0x6EA8))
  173. self.executeCode((0x84A6, 0x0E55, 0x6EA7, 0x0EAA, 0x6EA7))
  174. self.executeCode((0x82A6, 0x0, 0x0))
  175. self.top.hostDelay(self.delayP11 + self.delayP10)
  176. self.executeCode((0x94A6,))
  177. self.progressMeterFinish()
  178. def writeNbytes(self, image, N):
  179. if N % 2:
  180. self.throwError("N should be even, not %d" % N)
  181. isEmpty = True
  182. #N = (pN, len(image))[len(image) < pN]
  183. for idx in range(0, N):
  184. if idx == len(image):
  185. image += b'\xFF'
  186. elif byte2int(image[idx]) != 0xFF:
  187. isEmpty = False
  188. if(not isEmpty):
  189. for wordAddr in range(0, N-2, 2):
  190. self.send4bitWriteInstruction(self.CMD_TWII, byte2int(image[wordAddr]) | (byte2int(image[wordAddr + 1]) << 8))
  191. self.send4bitWriteInstruction(self.CMD_TW_START_PROG, byte2int(image[N-2]) | (byte2int(image[N-1]) << 8))
  192. self.top.cmdFPGAWrite(0x12, 0x81)
  193. self.top.hostDelay(self.delayP9)
  194. self.setPins(0)
  195. self.top.cmdDelay(self.delayP10)
  196. for i in range(0,4):
  197. self.sendCommand(1)
  198. def writeUserIdLocation(self, image):
  199. self.writeSequentialBlock(self.userIDLocationAddr, image, self.userIDLocationSize, "Writing User ID Locations")
  200. def checkSignature(self):
  201. signature = self.readSignature()
  202. if signature != self.signature:
  203. msg = "Unexpected device signature. " + \
  204. "Want %02X%02X%02X, but got %02X%02X%02X" % \
  205. (byte2int(self.signature[0]), byte2int(self.signature[1]),
  206. byte2int(self.signature[2]),
  207. byte2int(signature[0]), byte2int(signature[1]),
  208. byte2int(signature[2]))
  209. if self.top.getForceLevel() >= 1:
  210. self.printWarning(msg)
  211. else:
  212. self.throwError(msg)
  213. def writeProgmem(self, image):
  214. nrBytes = self.flashPages * self.flashPageSize
  215. if len(image) > nrBytes:
  216. self.throwError("Invalid flash image size %d (expected <=%d)" % \
  217. (len(image), nrBytes))
  218. self.writeSequentialBlock(0, image, nrBytes, "Writing flash")
  219. def writeFuse(self, image):
  220. self.enterPM()
  221. if len(image) > self.fuseBytes:
  222. self.throwError("Invalid Fuses image size %d (expected less than %d)" % \
  223. (len(image), self.fuseBytes))
  224. self.executeCode((0x8EA6, 0x8CA6, 0xEF00, 0xF800))
  225. for fuseAddr in range(0,len(image)):
  226. self.executeCode(self.getCodeAddrToTBLPTR(self.configWordAddr+fuseAddr))
  227. if(fuseAddr & 0x01):
  228. byte = byte2int(image[fuseAddr]) << 8
  229. else:
  230. byte = byte2int(image[fuseAddr])
  231. self.send4bitWriteInstruction(self.CMD_TW_START_PROG, byte)
  232. self.top.cmdFPGAWrite(0x12, 0x81)
  233. #self.setPins(1)
  234. self.top.hostDelay(self.delayP9)
  235. self.setPins(0)
  236. self.top.cmdDelay(self.delayP10)
  237. for i in range(0,4):
  238. self.sendCommand(1)
  239. #self.executeCode((0x2AF6,))
  240. self.writeSequentialBlock(self.configWordAddr, image, self.fuseBytes, "Writing fuses")
  241. self.progressMeterInit("Writing fuses", 0)
  242. def exitPM(self):
  243. "Exit programming mode. Vdd last exit mode"
  244. self.top.flushCommands()
  245. self.setPins(0, 0)
  246. self.applyVPP(False)
  247. self.applyVCC(False)
  248. self.applyGND(False)
  249. self.isInPmMode = False
  250. # ready for 18F below
  251. def send4bitReadInstruction(self, pInstruction):
  252. def incBbAndCheckFillImage():
  253. self.BufferedBytes += 1
  254. if self.BufferedBytes == self.top.getBufferRegSize():
  255. self.flushBufferToImage()
  256. # self.sendCommand(1,0,1,pInstruction)
  257. self.sendCommand(1, 0, 1, pInstruction)
  258. # self.busyWait()
  259. self.readSDOBufferHigh()
  260. incBbAndCheckFillImage()
  261. def send4bitWriteInstruction(self, pInstruction, pDataPayload):
  262. # self.busyWait()
  263. self.setSDI(pDataPayload)
  264. #print("sending {:x}\n".format(pDataPayload))
  265. self.sendCommand(1, 1, 0, pInstruction)
  266. self.top.flushCommands()
  267. def sendCommand(self, bit4bitInstr=1, bitSendData=0, bitReadData=0, cmd4bit=0, bitKeepClkHigh=0):
  268. '''
  269. `define CMDBIT_4BITINSTR 0
  270. `define CMDBIT_SENDDATA 1
  271. `define CMDBIT_READDATA 2
  272. `define CMDBIT_KEEPCLKHIGH 7
  273. '''
  274. command = (cmd4bit & 0x0F) << 3
  275. if bit4bitInstr:
  276. command |= 2 ** self.PCMDBIT_4BITINSTR
  277. if bitSendData:
  278. command |= 2 ** self.PCMDBIT_SENDDATA
  279. if bitReadData:
  280. command |= 2 ** self.PCMDBIT_READDATA
  281. if bitKeepClkHigh:
  282. command |= 2 ** self.PCMDBIT_KEEPCLKHIGH
  283. # print("cmd sending {:x}\n".format(command))
  284. self.top.cmdFPGAWrite(0x12, command)
  285. if(bitSendData or bitReadData):
  286. self.top.cmdDelay(2 * 20 * 2 * self.delayP2A)
  287. else:
  288. self.top.cmdDelay(2 * 4 * 2 * self.delayP2A)
  289. def setTopProgrammerDelays(self):
  290. #print("tdel5:{:d}".format(int(math.ceil(self.delayP2A / 42e-9))))
  291. #print("tdly:{:d}".format(int(math.ceil(self.delayP5 / 42e-9))))
  292. self.top.cmdFPGAWrite(0x10, int(math.ceil(self.delayP2A / 42e-9)))
  293. self.top.cmdFPGAWrite(0x11, int(math.ceil(self.delayP5 / 42e-9)))
  294. def setSDI8(self, sdi):
  295. self.top.cmdFPGAWrite(0x16, sdi & 0xFF)
  296. def setSDI(self, sdi):
  297. '''
  298. 16 -set 16 bit sdi value
  299. '''
  300. for addr in (0x16, 0x17):
  301. self.top.cmdFPGAWrite(addr, sdi & 0xFF)
  302. sdi = sdi >> 8
  303. def flushBufferToImage(self):
  304. # print ("storing {:d} bytes to image".format(self.BufferedBytes))
  305. if self.BufferedBytes > 0:
  306. self.Image += self.top.cmdReadBufferReg(self.BufferedBytes)
  307. self.BufferedBytes = 0
  308. def sendInstruction(self, instr):
  309. self.setSDI(instr)
  310. self.sendCommand(1, 1) # send 4 times positive edge
  311. # self.top.flushCommands()
  312. def executeCode(self, code):
  313. for instr in code:
  314. self.sendInstruction(instr)
  315. def setPins(self, ICSPCLK=0, SDIOVALUE=0, SDIODRIVEN=1):
  316. '''
  317. 16 - setPins
  318. '''
  319. data = 0
  320. if ICSPCLK:
  321. data |= 1
  322. if SDIODRIVEN:
  323. data |= 2
  324. if SDIOVALUE:
  325. data |= 4
  326. self.top.cmdFPGAWrite(0x15, data)
  327. def getStatusFlags(self):
  328. '''
  329. [0] - BUSY
  330. [1] - SDO
  331. '''
  332. self.flushBufferToImage()
  333. self.top.cmdFPGARead(0x12)
  334. stat = self.top.cmdReadBufferReg()
  335. return byte2int(stat[0])
  336. def readSDOBufferHigh(self):
  337. self.top.cmdFPGARead(0x14)
  338. def readSDOBufferLow(self):
  339. self.top.cmdFPGARead(0x15)
  340. def rawSDIOState(self):
  341. return bool(self.getStatusFlags() & self.STAT_SDIO)
  342. def isBusy(self):
  343. return bool(self.getStatusFlags() & self.STAT_BUSY)
  344. def busyWait(self):
  345. for i in range(0, 100):
  346. if not self.isBusy():
  347. return
  348. self.top.hostDelay(0.000001)
  349. self.throwError("Timeout in busywait.")
  350. def getCodeAddrToTBLPTR(self, addr):
  351. ub = (addr >> 16) & 0xFF
  352. hb = (addr >> 8) & 0xFF
  353. lb = addr & 0xFF
  354. return ((0x0E00 | ub), 0x6EF8, (0x0E00 | hb), 0x6EF7, (0x0E00 | lb), 0x6EF6)