Improved flash memory programming method; increased speed by a factor of 3.
authorscottlivingston <scottlivingston@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sat, 24 Apr 2010 23:45:31 +0000 (23:45 +0000)
committerscottlivingston <scottlivingston@12e2690d-a6be-4b82-a7b7-67c4a43b65c8>
Sat, 24 Apr 2010 23:45:31 +0000 (23:45 +0000)
For example, for a dsPIC33F program that has a text segment
of 2347 instructions,
the old method requires about 126 seconds to program the MCU,
whereas the new method requires only 42 seconds.

This has been tested with dsPIC33FJ128GP710 and dsPIC33FJ128GP708 chips
using a GoodFET30 board.

Additionally, an extra and unnecessary "goto 0x200" instruction was removed
from several locations of the PIC programmer code (client and firmware app).

git-svn-id: https://svn.code.sf.net/p/goodfet/code/trunk@464 12e2690d-a6be-4b82-a7b7-67c4a43b65c8

client/goodfet.pic
firmware/apps/pic/dspic33f.c

index 5158912..4250635 100755 (executable)
@@ -80,6 +80,13 @@ def readreg( reg_num ):
     client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] ) # NOP (pump clock)
     return readVISI()
 
+def writereg( reg_num, word ):
+    """Write 16-bit word to a working register (i.e., W0, W1, ..., W15)."""
+    instr = 0x200000 + ((word&0xffff)<<4) + (reg_num&0xf)
+    client.writecmd( PICAPP, 0x82, 3, [instr & 0xff,
+                                       (instr >> 8) & 0xff,
+                                       (instr >> 16) & 0xff] )
+
 def readVISI():
     """Read VISI register; assumes ICSP session already started."""
     data = client.writecmd( PICAPP, 0x83, 0 )
@@ -96,6 +103,11 @@ def readNVMCON():
     runlist( rd_nvmcon_li )
     return readVISI()
 
+def resetPC():
+    """Reset program counter during an active ISCP session."""
+    runlist( [0x040200,   # GOTO 0x0200
+              0x000000] )
+
 def startICSP():
     #print "Starting dsPIC33F/PIC24H ICSP session..."
     data = client.writecmd( PICAPP, 0x84, 0 )
@@ -201,8 +213,7 @@ if sys.argv[1] == "devid": #0x81
 
 elif sys.argv[1] == "config": # Dump configuration registers
     prep_cmd_li = [0x040200, # GOTO 0x0200
-                   0x040200, # GOTO 0x0200
-                   0x000000, # NOP
+                   0x000000, #
                    0x200F80, # MOV #0x00F8, W0
                    0x880190, # MOV W0, TBLPAG
                    0xEB0300, # CLR W6
@@ -225,11 +236,11 @@ elif sys.argv[1] == "config": # Dump configuration registers
         result = readVISI()
         addr = 0xF80000+k*2
         if cfg_table.has_key( addr ):
-            print "0x%06X (%s): 0x%04X" % ( addr,
+            print "0x%06X (%s): 0x%02X" % ( addr,
                                             cfg_table[addr].ljust(cfg_table["width"]),
                                             result )
         else:
-            print "0x%06X: 0x%04X" % ( addr, result )
+            print "0x%06X: 0x%02X" % ( addr, result )
 
     stopICSP()
 
@@ -243,87 +254,117 @@ elif sys.argv[1] == "program":
     except IOError:
         print "Error while attempting to read from %s" % sys.argv[2]
         exit(-1)
+    ph_addrs = proghex.addresses()
+
+    # Load starting program memory address
+    wr_pm64_li_setaddr = [0x040200, # GOTO 0x0200
+                          0x000000, #
+                          0x24001A, # MOV $0x4001, W10
+                          0x883B0A, # MOV W10, NVMCON
+                          0x200000, # + ((addr>>12)&0xff0),  # MOV #addr<23:16>, W0
+                          0x880190, # MOV W0, TBLPAG
+                          0x200007] # + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
+
+    # Load 4 instructions into write latches
+    wr_pm64_li_wrlat = [0xEB0300, # CLR W6
+                        0x000000, # NOP
+                        0xBB0BB6, # TBLWTL [W6++], [W7]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBBDBB6, # TBLWTH.B [W6++], [W7++]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBBEBB6, # TBLWTH.B [W6++], [++W7]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBB1BB6, # TBLWTL [W6++], [W7++]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBB0BB6, # TBLWTL [W6++], [W7]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBBDBB6, # TBLWTH.B [W6++], [W7++]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBBEBB6, # TBLWTH.B [W6++], [++W7]
+                        0x000000, # NOP
+                        0x000000, # NOP
+                        0xBB1BB6, # TBLWTL [W6++], [W7++]
+                        0x000000, # NOP
+                        0x000000] # NOP
 
-    wr_pm_li = [0x040200, # GOTO 0x0200
-                0x040200, # GOTO 0x0200
-                0x000000, # NOP
-
-                0x24003A, # MOV $0x4003, W10
-                0x883B0A, # MOV W10, NVMCON
-                
-                0x200000,# + ((addr>>12)&0xff0),  # MOV #addr<23:16>, W0
-                0x880190, # MOV W0, TBLPAG
-                0x200007,# + ((addr&0xffff)<<4), # MOV #addr<15:0>, W7
-
-                # Here we load the instruction into registers W0:W1
-                0x200000,# + ((new_words[0]&0xffff)<<4),
-                0x200001,# + ((new_words[1]&0xffff)<<4),
-
-                0xEB0300, # CLR W6
-                0x000000, # NOP
-                0xBB0BB6, # TBLWTL [W6++], [W7]
-                0x000000, # NOP
-                0x000000, # NOP
-                0xBBDBB6, # TBLWTH.B [W6++], [W7++]
-                0x000000, # NOP
-                0x000000, # NOP
-
-                0xA8E761, # BSET NVMCON, #WR
-                0x000000, # NOP
-                0x000000, # NOP
-                0x000000, # NOP
-                0x000000] # NOP
-
+    wr_pm64_li_wr = [0xA8E761, # BSET NVMCON, #WR
+                     0x000000, # NOP
+                     0x000000, # NOP
+                     0x000000, # NOP
+                     0x000000] # NOP
+    
     startICSP()
-
-    for addr in proghex.addresses():
-        # Ignore non-aligned steps
-        if addr % 4 != 0:
-            continue
-
-        # Configuration registers must be treated separately
-        if (addr>>1) >= 0xf80000 and (addr>>1) <= 0xf80017:
-            wr_cfg_li = [0x040200, # GOTO 0x0200
-                         0x040200, # GOTO 0x0200
-                         0x000000, # NOP
-                         0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
-                         0x24000A, # MOV #0x4000, W10
-                         0x883B0A, # MOV W10, NVMCON
-                         0x200F80, # MOV #0xF8, W0
-                         0x880190, # MOV W0, TBLPAG
-                         0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
-                         0xBB0B80, # TBLWTL W0, [W7]
-                         0x000000, # NOP
-                         0x000000, # NOP
-                         0xA8E761, # BSET NVMCON, #WR
-                         0x000000, # NOP
-                         0x000000, # NOP
-                         0x000000, # NOP
-                         0x000000] # NOP
-            runlist( wr_cfg_li )
+    
+    for last_code_addr in reversed(ph_addrs):
+        if (last_code_addr>>1) < 0xf80000:
+            last_row_addr = (last_code_addr>>1) & 0xffff80
+            break
+    for addr in range((ph_addrs[0]>>1)&0xffff80,last_code_addr+2,128):
+        # Prevent crossing addresses where upper byte
+        # (i.e., address<23:16>) changes.
+        #if addr+126 > 0xffff:
+        #    stop_addr = addr | 0xffff
+        #else:
+        #    stop_addr = addr+126
+
+        runlist( wr_pm64_li_setaddr[:4]
+                 + [0x200000 + ((addr>>12)&0xff0),
+                    wr_pm64_li_setaddr[5],
+                    0x200007 + ((addr&0xffff)<<4)] )
+                 
+        instr_list = [0,0,0,0]
+        for mid_addr in range(addr,addr+126,8):
+            for offset in range(4):
+                if (mid_addr+offset*2)<<1 not in ph_addrs:
+                    instr_list[offset] = 0xffffff
+                else:
+                    instr_list[offset] = proghex[(mid_addr+offset*2)<<1]
+                    instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+1] << 8
+                    instr_list[offset] |= proghex[((mid_addr+offset*2)<<1)+2] << 16
+            packed_instr_list = instr2words( instr_list )
+            runlist( [0x200000 + ((packed_instr_list[0]&0xffff)<<4),
+                      0x200001 + ((packed_instr_list[1]&0xffff)<<4),
+                      0x200002 + ((packed_instr_list[2]&0xffff)<<4),
+                      0x200003 + ((packed_instr_list[3]&0xffff)<<4),
+                      0x200004 + ((packed_instr_list[4]&0xffff)<<4),
+                      0x200005 + ((packed_instr_list[5]&0xffff)<<4)]
+                     + wr_pm64_li_wrlat )
+        
+        runlist( wr_pm64_li_wr )
+        status = readNVMCON()
+        while status & 0x8000:
+            client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
             status = readNVMCON()
-            while status & 0x8000:
-                client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
-                status = readNVMCON()
-            continue
-
-        # Build instruction from 3 separate bytes
-        instr = proghex[addr]
-        instr |= proghex[addr+1] << 8
-        instr |= proghex[addr+2] << 16
-
-        # Change HEX file address to actual program memory address
-        addr_pm = addr >> 1
 
-        # Program this instruction word
-        addr_highb_cmd  = 0x200000 + ((addr_pm>>12)&0xff0)
-        addr_loww_cmd   = 0x200007 + ((addr_pm&0xffff)<<4)
-        instr_loww_cmd  = 0x200000 + ((instr&0xffff)<<4)
-        instr_highb_cmd = 0x200001 + ((instr>>12)&0xff0)
-        runlist( wr_pm_li[:5] + [addr_highb_cmd] + [wr_pm_li[6]]
-                 + [addr_loww_cmd,
-                    instr_loww_cmd, instr_highb_cmd]
-                 + wr_pm_li[10:] )
+    # Configuration registers must be treated separately
+    for addr in ph_addrs[ph_addrs.index(last_code_addr):]:
+        if addr%4 != 0:
+            continue
+        if (addr>>1) > 0xf80017:
+            break
+        wr_cfg_li = [0x040200, # GOTO 0x0200
+                     0x000000, #
+                     0x200007 + ((addr<<3)&0xffff0), # MOV #addr<15:0>, W7
+                     0x24000A, # MOV #0x4000, W10
+                     0x883B0A, # MOV W10, NVMCON
+                     0x200F80, # MOV #0xF8, W0
+                     0x880190, # MOV W0, TBLPAG
+                     0x200000 + ((proghex[addr]&0x00ff)<<4), # MOV #new_val<7:0>, W0
+                     0xBB0B80, # TBLWTL W0, [W7]
+                     0x000000, # NOP
+                     0x000000, # NOP
+                     0xA8E761, # BSET NVMCON, #WR
+                     0x000000, # NOP
+                     0x000000, # NOP
+                     0x000000, # NOP
+                     0x000000] # NOP
+        runlist( wr_cfg_li )
         status = readNVMCON()
         while status & 0x8000:
             client.writecmd( PICAPP, 0x82, 3, [0x00,0x00,0x00] )
@@ -344,8 +385,7 @@ elif sys.argv[1] == "verify":
         exit(-1)
 
     readpm_cmd_li = [0x040200, # GOTO 0x0200
-                     0x040200, # GOTO 0x0200
-                     0x000000, # NOP
+                     0x000000, #
                      0x200000, # MOV #addr_pm<23:16>, W0
                      0x880190, # MOV W0, TBLPAG
                      0x200006, # MOV #addr_pm<15:0>, W6
@@ -384,9 +424,9 @@ elif sys.argv[1] == "verify":
         # Change HEX file address to actual program memory address
         addr_pm = addr >> 1
         
-        runlist( readpm_cmd_li[:3] + [readpm_cmd_li[3]+((addr_pm&0xff0000)>>12)]
-                 + [readpm_cmd_li[4]] + [readpm_cmd_li[5]+((addr_pm&0xffff)<<4)]
-                 + readpm_cmd_li[6:] )
+        runlist( readpm_cmd_li[:2] + [readpm_cmd_li[2]+((addr_pm&0xff0000)>>12)]
+                 + [readpm_cmd_li[3]] + [readpm_cmd_li[4]+((addr_pm&0xffff)<<4)]
+                 + readpm_cmd_li[5:] )
         loww = readreg(0)  # Read W0, which has lower 16 bits
         highb = readreg(1) # Read W1, which has high 8 bits
         result = (highb<<16) | loww
@@ -416,8 +456,7 @@ elif sys.argv[1] == "write":
     #new_words = instr2words( new_instr_li )
         
     wr_pm_li = [0x040200, # GOTO 0x0200
-                0x040200, # GOTO 0x0200
-                0x000000, # NOP
+                0x000000, #
 
                 0x24003A, # MOV $0x4003, W10
                 0x883B0A, # MOV W10, NVMCON
@@ -496,8 +535,7 @@ elif sys.argv[1] == "write_config":
         reg_addr = cfg_table.keys()[cfg_table.values().index(sys.argv[2])]
     
     wr_cfg_li = [0x040200, # GOTO 0x0200
-                 0x040200, # GOTO 0x0200
-                 0x000000, # NOP
+                 0x000000, #
                  0x200007 + ((reg_addr&0xffff)<<4), # MOV #addr<15:0>, W7
                  0x24000A, # MOV #0x4000, W10
                  0x883B0A, # MOV W10, NVMCON
@@ -530,8 +568,7 @@ elif sys.argv[1] == "read": # Read an address of program memory
     addr = int(float.fromhex(sys.argv[2]))
 
     readpm_cmd_li = [0x040200,                         # GOTO 0x0200
-                     0x040200,                         # GOTO 0x0200
-                     0x000000,                         # NOP
+                     0x000000,                         #
                      0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
                      0x880190,                         # MOV W0, TBLPAG
                      0x200006+((addr & 0xffff)<<4),    # MOV #addr<15:0>, W6
@@ -660,8 +697,7 @@ elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
 
     if addr is None: # Bulk erase (all of program memory)
         erase_cmd_li = [0x040200, # GOTO 0x0200
-                        0x040200, # GOTO 0x0200
-                        0x000000, # NOP
+                        0x000000, #
                         0x2404FA, # MOV $0x404F, W10
                         0x883B0A, # MOV W10, NVMCON
                         0xA8E761, # BSET NVMCON, #WR
@@ -672,8 +708,7 @@ elif sys.argv[1] == "erase": # Bulk (all program memory) or page erase
     else: # Page erase
         print "Erasing page of 0x%06X" % addr
         erase_cmd_li = [0x040200, # GOTO 0x0200
-                        0x040200, # GOTO 0x0200
-                        0x000000, # NOP
+                        0x000000, #
                         0x24042A, # MOV $0x4042, W10
                         0x883B0A, # MOV W10, NVMCON
                         0x200000+((addr & 0xff0000)>>12), # MOV #addr<23:16>, W0
index b2534b0..bc02e39 100644 (file)
@@ -228,7 +228,6 @@ unsigned int pic33f_getid()
 
        // Read application ID.
        pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
-       pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
        pic33f_six( 0x00, 0x0000 ); // nop
        pic33f_six( 0x20, 0x0800 ); // mov #0x80, W0
        pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG