123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 |
- """
- # TOP2049 Open Source programming suite
- #
- # Microchip8 common - basic file for 8bit PIC MCU
- #
- # Copyright (c) 2012 Pavel Stemberk <stemberk@gmail.com>
- #
- # This program is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation; either version 2 of the License, or
- # (at your option) any later version.
- #
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public License along
- # with this program; if not, write to the Free Software Foundation, Inc.,
- # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- """
- from libtoprammer.chip import *
- import math
- class Chip_Microchip8_common(Chip):
- CMD_LOAD_DATA_FOR_PGM = 0x02
- CMD_LOAD_DATA_FOR_DM = 0x03
- CMD_READ_DATA_FROM_PGM = 0x04
- CMD_READ_DATA_FROM_DM = 0x05
- CMD_INCREMENT_ADDRESS = 0x06
- CMD_BULK_ERASE_PGM = 0x09
- CMD_BULK_ERASE_DM = 0x0B
-
- PCMDBIT_4BITINSTR = 0
- PCMDBIT_SENDDATA = 1
- PCMDBIT_READDATA = 2
-
- STAT_BUSY = 0x01
- STAT_SDIO = 0x02
- # EEPROM access: default off, if exists override it
- hasEEPROM = False
- # Signature bytes access: default on, if doesn't exist, override it
- hasSigBytes = True
- # default delays - can be overridden
- delayTdly5 = 0.00000015
- delayTdis = 0.0001
- delayTprog = 0.001
- delayTdly = 0.000001
- delayTera = 0.01
- nLatches = 1
- @classmethod
- def getSupportFlags(cls):
- flags = super(Chip_Microchip8_common, cls).getSupportFlags()
- if not cls.hasEEPROM:
- flags &= ~(Chip.SUPPORT_EEPROMREAD |\
- Chip.SUPPORT_EEPROMWRITE)
- if not cls.hasSigBytes:
- flags &= ~Chip.SUPPORT_SIGREAD
- return flags
- def __init__(self,
- chipPackage, chipPinVCC, chipPinsVPP, chipPinGND,
- signature,
- flashPageSize, flashPages,
- eepromPageSize, eepromPages,
- fuseBytes
- ):
- Chip.__init__(self,
- chipPackage=chipPackage,
- chipPinVCC=chipPinVCC,
- chipPinsVPP=chipPinsVPP,
- chipPinGND=chipPinGND)
- self.signature = signature
- self.flashPageSize = flashPageSize # Flash page size, in words
- self.flashPages = flashPages # Nr of flash pages
- self.eepromPageSize = eepromPageSize # EEPROM page size, in bytes
- self.eepromPages = eepromPages # Nr of EEPROM pages
- self.fuseBytes = fuseBytes # Nr of fuse bytes
- self.PC = 0
- self.isInPmMode = False
- def erase(self):
- if(hasattr(self, 'osccalAddr')):
- self.__erase(keepOSCCAL=True)
- else:
- self.__erase(keepOSCCAL=False)
-
- def __erase(self, keepConfigWord=False, keepUserIDLocation=False, keepOSCCAL=False, keepEEPROM=False):
- OSCCAL = 0xfff
- self.exitPM()
- self.enterPM()
- if(keepOSCCAL):
- self.progressMeterInit("Reading OSCCAL)", 0)
- self.setPC(self.osccalAddr)
- self.sendReadFlashInstr()
- self.top.cmdDelay(self.delayTdly)
- self.readSDOBufferLow()
- self.readSDOBufferHigh()
- OSCCAL = self.top.cmdReadBufferReg16()
- self.progressMeterFinish()
- if(hasattr(self, 'osccalBackupAddr') and OSCCAL == 0xfff):
- self.progressMeterInit("OSCCAL value lost, restoring from backup location ...", 0)
- print("OSCCAL value lost, restoring from backup location ...")
- self.setPC(self.osccalBackupAddr - self.osccalAddr)
- self.sendReadFlashInstr()
- self.top.cmdDelay(self.delayTdly)
- self.readSDOBufferLow()
- self.readSDOBufferHigh()
- OSCCAL = self.top.cmdReadBufferReg16()
- self.progressMeterFinish()
- # print ("osccal: %x\n" % OSCCAL)
- if(keepConfigWord):
- self.progressMeterInit("Reading ConfigWord for backup", 0)
- CW = self.getConfigWord()
- self.progressMeterFinish()
- # erase User ID Location and backup osccal Tooo
- # erase User ID Location and backup osccal Tooo
- if(not keepUserIDLocation):
- self.enterConfigArea()
- self.setPC(self.userIDLocationAddr)
- self.progressMeterInit("Erasing chip", 0)
- self.bulkErasePGM()
- self.progressMeterFinish()
- #OSCCAL=0x3454
- #OSCCAL=0x0C10
- if(keepOSCCAL and OSCCAL != 0xfff):
- self.exitPM()
- self.enterPM()
- self.progressMeterInit("Writing osccal, value %x" % OSCCAL, 0)
- print("Writing osccal, value %x" % OSCCAL)
- self.setPC(self.osccalAddr)
- self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, OSCCAL)
- self.top.cmdDelay(self.delayTdly)
- self.sendWriteFlashInstr()
- self.progressMeterFinish()
- if(keepConfigWord):
- self.progressMeterInit("Writing ConfigWord, value %x" % CW, 0)
- self.writeConfigWord(CW)
- self.progressMeterFinish()
- if((not keepEEPROM) and self.hasEEPROM):
- self.progressMeterInit("Erasing EEPROM", 0)
- self.bulkEraseDM()
- self.progressMeterFinish()
- self.exitPM()
- def bulkErasePGM(self):
- self.sendCommand(0, 0, 0, self.CMD_BULK_ERASE_PGM)
- self.top.cmdDelay(self.delayTera) # Tera
-
- def bulkEraseDM(self):
- self.sendCommand(0, 0, 0, self.CMD_BULK_ERASE_DM)
- self.top.cmdDelay(self.delayTera) # Tera
-
- def readProgmem(self):
- nrWords = self.flashPages * self.flashPageSize
- image = b""
- self.enterPM()
- self.setPC(0)
- self.progressMeterInit("Reading flash", nrWords)
- bufferedBytes = 0
- for word in range(0, nrWords):
- self.sendReadFlashInstr()
- # self.top.cmdDelay(0.00002) #20us wait - inconsistent data if skipped
- self.top.cmdDelay(self.delayTdly)
-
- self.readSDOBufferLow()
- bufferedBytes += 1
- self.readSDOBufferHigh()
- bufferedBytes += 1
- if bufferedBytes == self.top.getBufferRegSize():
- image += self.top.cmdReadBufferReg(bufferedBytes)
- self.progressMeter(word)
- bufferedBytes = 0
- self.incrementPC(1)
- image += self.top.cmdReadBufferReg(bufferedBytes)
- self.progressMeterFinish()
- # self.exitPM()
- return image
-
- def readEEPROM(self):
- nrWords = self.eepromPages * self.eepromPageSize
- image = b""
- self.enterPM()
- self.progressMeterInit("Reading eeprom", nrWords)
- bufferedBytes = 0
- for word in range(0, nrWords):
- self.sendReadEEPROMInstr()
- self.top.cmdDelay(self.delayTdly) # 20us wait - inconsistent data if skipped
- self.readSDOBufferLow()
- bufferedBytes += 1
- if bufferedBytes == self.top.getBufferRegSize():
- image += self.top.cmdReadBufferReg(bufferedBytes)
- self.progressMeter(word)
- bufferedBytes = 0
- self.incrementPC(1)
- image += self.top.cmdReadBufferReg(bufferedBytes)
- self.progressMeterFinish()
- # self.exitPM()
- return image
- def writeEEPROM(self, image):
- nrWords = self.eepromPages * self.eepromPageSize
- if len(image) > nrWords:
- self.throwError("Invalid flash image size %d (expected <=%d)" % len(image))
- self.enterPM()
- self.progressMeterInit("Writing eeprom", nrWords)
- bufferedBytes = 0
- for addr in range(0, len(image)):
- self.progressMeter(addr)
- byte = byte2int(image[addr])
- if byte != 0xff:
- self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_DM, byte)
- self.top.cmdDelay(self.delayTdly)
- self.sendWriteFlashInstrDM()
- self.incrementPC(1)
- self.progressMeterFinish()
- # self.exitPM()
- def writeProgmem(self, image):
- nrWords = self.flashPages * self.flashPageSize
- if len(image) > nrWords * 2 or len(image) % 2 != 0:
- self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" % \
- (len(image), nrWords * 2))
- self.progressMeterInit("Writing flash", len(image) // 2)
- self.enterPM()
- self.setPC(0)
- latCnt=1;
- writeCurrentLatches=False
- for wordAddr in range(0, len(image) // 2):
- self.progressMeter(wordAddr)
- # do not swap following two lines
- WD = (byte2int(image[wordAddr * 2 + 1]) << 8) | byte2int(image[wordAddr * 2 + 0])
- if(WD != (byte2int(self.defaultWord[1]) << 8) + byte2int(self.defaultWord[0])):
- self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, WD)
- self.top.cmdDelay(self.delayTdly)
- writeCurrentLatches=True
- if(latCnt == self.nLatches):
- if(writeCurrentLatches):
- self.sendWriteFlashInstr()
- latCnt=0
- writeCurrentLatches=False
- latCnt+=1
- self.incrementPC(1)
- if(latCnt>1):
- self.sendWriteFlashInstr()
- self.progressMeterFinish()
- # self.exitPM()
- def readFuse(self):
- self.enterPM()
- fuses = []
- self.progressMeterInit("Reading fuses (configuration word)", 0)
- for CW in self.getConfigWord():
- fuses.append(int2byte(CW & 0x00ff))
- fuses.append(int2byte((CW >> 8) & 0x00ff))
- self.progressMeterFinish()
- return b"".join(fuses)
-
- def readUserIdLocation(self):
- self.enterPM()
- self.enterConfigArea()
- self.setPC(self.userIDLocationAddr)
- self.progressMeterInit("Reading User ID Location", 0)
- for i in range(0, self.userIDLocationSize):
- self.sendReadFlashInstr()
- self.top.hostDelay(self.delayTdly)
- self.readSDOBufferLow()
- self.readSDOBufferHigh()
- self.incrementPC(1)
- # self.exitPM()
- self.progressMeterFinish()
- return self.top.cmdReadBufferReg()[0:2 * self.userIDLocationSize]
-
- def writeUserIdLocation(self, image):
- if len(image) > self.userIDLocationSize * 2 or len(image) % 2 != 0:
- self.throwError("Invalid flash image size %d (expected <=%d and word aligned)" % \
- (len(image), self.userIDLocationSize * 2))
- self.enterPM()
- self.enterConfigArea()
- self.setPC(self.userIDLocationAddr)
- self.progressMeterInit("Writing User ID Location", (len(image) // 2) - 1)
- for word in range(0, (len(image) // 2)):
- self.progressMeter(word)
- # do not swap following two lines
- WD = (byte2int(image[word * 2 + 1]) << 8) | byte2int(image[word * 2 + 0])
- if(WD != (byte2int(self.defaultWord[1]) << 8) + byte2int(self.defaultWord[0])):
- self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, WD)
- self.sendWriteFlashInstr()
- self.incrementPC(1)
- self.top.hostDelay(self.delayTdly)
- self.sendWriteFlashInstr()
- self.progressMeterFinish()
- # self.exitPM()
-
- def getConfigWordSize(self):
- return self.fuseBytes // 2
- def getConfigWord(self):
- self.enterPM()
- self.enterConfigArea()
- self.setPC(self.configWordAddr)
- retVal = []
- for i in range(0, self.getConfigWordSize()):
- self.sendReadFlashInstr()
- self.top.cmdDelay(self.delayTdly)
- self.readSDOBufferLow()
- self.readSDOBufferHigh()
- self.incrementPC(1)
- retVal.append(self.top.cmdReadBufferReg16())
- return retVal
- def writeFuse(self, image):
- if len(image) != 2 * self.getConfigWordSize():
- self.throwError("Invalid Fuses image size %d (expected %d)" % \
- (len(image), 2 * self.getConfigWordSize()))
- self.progressMeterInit("Writing fuses", 0)
- # print "image1:%x,,%x,,%x" % (byte2int(image[0]),byte2int(image[1]),byte2int(image[1])<<8)
- CW = []
- for tBytes in zip(image[::2], image[1::2]):
- CW.append((byte2int(tBytes[1]) << 8) | byte2int(tBytes[0]))
- self.writeConfigWord(CW)
- self.progressMeterFinish()
-
- def writeConfigWord(self, listConfigWord16):
- # Externally timed writes are not supported
- # for Configuration and Calibration bits. Any
- # externally timed write to the Configuration
- # or Calibration Word will have no effect on
- # the targeted word.
- self.enterPM()
- self.enterConfigArea()
- self.setPC(self.configWordAddr)
- for configWord16 in listConfigWord16:
- # print "write CW {:x}".format(configWord16)
- self.send6bitWriteInstruction(self.CMD_LOAD_DATA_FOR_PGM, configWord16)
- self.top.cmdDelay(self.delayTdly)
- self.sendWriteFlashInstrCW()
- self.incrementPC(1)
- self.top.flushCommands()
-
-
- def enterPM(self):
- if self.isInPmMode and self.isInsideProgramMemoryArea:
- self.resetPC()
- return
- self.PC = self.initPcValue
- self.isInsideProgramMemoryArea = True
- "Enter HV programming mode. Vdd first entry mode"
- self.applyVCC(False)
- self.applyVPP(False)
- self.applyGND(False)
- self.setPins(0, 0)
- self.top.cmdSetVCCVoltage(self.voltageVDD)
- self.top.cmdSetVPPVoltage(self.voltageVPP)
- # self.top.cmdEnableZifPullups(True)
- self.applyGND(True)
-
- self.applyVPP(True)
- self.top.cmdDelay(0.000250)
-
-
- self.applyVCC(True)
- # self.top.cmdEnableZifPullups(True)
-
- # self.top.cmdDelay(0.000005) #least 5us is required to reach Vdd first entry PM
- self.setTopProgrammerDelays()
- self.isInPmMode = True
- def checkSignature(self):
- signature = self.readSignature()
- if signature != self.signature:
- msg = "Unexpected device signature. " + \
- "Want %02X%02X%02X, but got %02X%02X%02X" % \
- (byte2int(self.signature[0]), byte2int(self.signature[1]),
- byte2int(self.signature[2]),
- byte2int(signature[0]), byte2int(signature[1]),
- byte2int(signature[2]))
- if self.top.getForceLevel() >= 1:
- self.printWarning(msg)
- else:
- self.throwError(msg)
- def exitPM(self):
- "Exit HV programming mode. Vdd last exit mode"
- self.top.flushCommands()
- self.setPins(0, 0)
- self.applyVPP(False)
- self.applyGND(False)
- self.top.hostDelay(self.delayTdly)
- self.applyVCC(False)
- self.isInPmMode = False
- def sendReadFlashInstr(self):
- '''
- '''
- self.sendCommand(0, 0, 1, self.CMD_READ_DATA_FROM_PGM)
- def sendWriteFlashInstr(self):
- '''
- to be overriden
- '''
- pass
-
- def sendReadEEPROMInstr(self):
- '''
- '''
- self.sendCommand(0, 0, 1, self.CMD_READ_DATA_FROM_DM)
- def send6bitReadInstruction(self, pInstruction):
- def incBbAndCheckFillImage():
- self.BufferedBytes += 1
- if self.BufferedBytes == self.top.getBufferRegSize():
- self.flushBufferToImage()
- # self.sendCommand(1,0,1,pInstruction)
- self.sendCommand(0, 0, 1, pInstruction)
- # self.busyWait()
- self.readSDOBufferHigh()
- incBbAndCheckFillImage()
-
- def send6bitWriteInstruction(self, pInstruction, pDataPayload):
- # self.busyWait()
- self.setSDI(pDataPayload)
- # print("sending {:x}\n".format(pDataPayload))
- self.sendCommand(0, 1, 0, pInstruction)
- self.top.flushCommands()
- def setSDI(self, sdi):
- '''
- set 14 bit sdi value
- '''
- self.top.cmdFPGAWrite(0x13, sdi & 0xFF)
- self.top.cmdFPGAWrite(0x14, (sdi >> 8) & 0x3F)
- def sendCommand(self, bit4bitInstr=0, bitSendData=0, bitReadData=0, cmd4bit=0):
- '''
- `define CMDBIT_4BITINSTR 0
- `define CMDBIT_SENDDATA 1
- `define CMDBIT_READDATA 2
- '''
- command = (cmd4bit & 0x1F) << 3
- if bit4bitInstr:
- command |= 2 ** self.PCMDBIT_4BITINSTR
- if bitSendData:
- command |= 2 ** self.PCMDBIT_SENDDATA
- if bitReadData:
- command |= 2 ** self.PCMDBIT_READDATA
- # print("cmd sending {:x}\n".format(command))
- self.top.cmdFPGAWrite(0x12, command)
-
- def setTopProgrammerDelays(self):
- #print("tdel5:{:d}".format(int(math.ceil(self.delayTdly5 / 42e-9))))
- #print("tdly:{:d}".format(int(math.ceil(self.delayTdly / 42e-9))))
- self.top.cmdFPGAWrite(0x10, int(math.ceil(self.delayTdly5 / 42e-9)))
- self.top.cmdFPGAWrite(0x11, int(math.ceil(self.delayTdly / 42e-9)))
- # def runCommandSync(self, command):
- # self.loadCommand(command)
- # self.busyWait()
- def resetPC(self):
- '''can be overriden'''
- self.setPC(self.initPcValue)
-
- def setPC(self, address):
- '''to be overriden'''
- pass
- def incrementPC(self, count):
- '''to be overriden'''
- pass
-
- def enterConfigArea(self, wordLatched=0):
- '''to be overriden'''
- pass
- def setPins(self, ICSPCLK=0, SDIOVALUE=0, SDIODRIVEN=1):
- '''
- setPins
- '''
- data = 0
- if ICSPCLK:
- data |= 1
- if SDIODRIVEN:
- data |= 2
- if SDIOVALUE:
- data |= 4
- self.top.cmdFPGAWrite(0x15, data)
- def getStatusFlags(self):
- '''
- '''
- self.top.cmdFPGARead(0x12)
- stat = self.top.cmdReadBufferReg()
- return byte2int(stat[0])
- def readSDOBufferHigh(self):
- self.top.cmdFPGARead(0x10)
-
- def readSDOBufferLow(self):
- self.top.cmdFPGARead(0x13)
-
- def rawSDIOState(self):
- return bool(self.getStatusFlags() & self.STAT_SDIO)
- def busy(self):
- return bool(self.getStatusFlags() & self.STAT_BUSY)
- # def busyWait(self):
- # for i in range(0, 100):
- # if not self.busy():
- # return
- # self.top.hostDelay(0.01)
- # self.throwError("Timeout in busywait.")
- # def waitHighSDIO(self):
- # for i in range(0, 100):
- # if self.rawSDOState():
- # return
- # self.top.hostDelay(0.01)
- # self.throwError("Timeout waiting for SDO.")
|