PIC 16F628 Microcontroller Programmer
This project describes how to build a simple programmer for the PIC 16F628 single-chip microcontroller. This should be considered a "hobby grade" programmer as it does not use a variable Vcc and uses the "Low Voltage Programming Algorithm." The 16F628 can be configured (through programmable fuses) to disable the low voltage Programming mode. Once disabled, a high voltage programmer is required to re-enable the low voltage programming mode.
The programmer hardware consists of an 18 pin socket for the 16F628 and a 14 pin header for connecting to the
SBC2's onboard 65C22. Please note that this can be adapted for use with any 65C22. The 16F628 uses
4 pins for serial programming (in addition to Vcc and Gnd):
16F628 (DIP18) SBC2 65C22 (DIP40)
Port Pin Function Description J1 PIN PORT RB6 12 clk shift clock 3 2 PA0 RB7 13 data data in/out 4 3 PA1 RB4 10 prg program mode 9 8 PA6 RA5 4 CLR clear/run mode 10 9 PA7
This programmer should also work for other processors in the PIC family (with some modifications).
Here is the programmer schematic:
Programming the 16F628 is done by placing the part into RESET and PRG mode, then applying serial commands and data to the data pin while clocking the clk pin.
There are commands to read and write program memory, EEPROM memory, and the configuration area. Since the MPLABS Development tools create an Intel-Hex formatted output file, I decided to incorporate a modified version of Ross Archer's "Intel Hex Downloader" which allows for seemless operation.
Here is the source code for the programmer:
;======================================================================= ; | ; SSSSSSS BBBBBB CCCCCC 222222 | ; S S B B C C 2 2 | ; SS B B C 2 | ; SSSS BBBBBBB C ======== 2 | ; SS B B C 2 | ; S S B B C C 2 | ; SSSSSSS BBBBBBB CCCCCCC 22222222 | ; | ;======================================================================= ; ;//****************************************************************// ;// Routine to program a PIC16F628 using 4 lines from a 65C22 VIA // ;// By Daryl Rictor (c) Dec 19, 2003 http://65c02.tripod.com/ // ;//****************************************************************// ; ; This program was tested and ran from my SBC-2 board running at ; 2MHz. Any 65c02-based computer with a 6522 VIA should be able ; to use this code. ; ; VIA - PIC connections ; ; VIA Function PIC ;------------------- ; PA0 CLK -> RB6 ; PA1 DATA -> RB7 ; PA6 PGM -> RB4 ; PA7 MCLR -> RA5 ; ; *** This is a hobby-grade programmer using the LV programming algorithm. ; ;********************************************************************* ; Memory map ;********************************************************************* ; This program resided in RAM from $0800 to $0F76 ; ; Program Data is loaded from $1000 - $1FFF (14 bits, w/0 in bit 14 & 15, lo, hi)) ; EEPROM data is loaded from $2000 - $207F (8 bits) ; ID and configuration words are loaded from $2100-2109 (14 bits w/0 in bits 14 & 15) ; PIC ADDR - PC ADDR ; $2000 <- $2100,$2101 ID word 0 (lo, hi) ; $2001 <- $2102,$2103 ID word 1 (lo, hi) ; $2002 <- $2104,$2105 ID word 2 (lo, hi) ; $2003 <- $2106,$2107 ID word 3 (lo, hi) ; $2007 <- $2108,$2109 Configuration Word (lo, hi) ; ;During compare operations, these addresses are used to store the data read from the PIC ; Program Data is stored at $3000 - $3FFF (14 bits, w/0 in bit 14 & 15, lo, hi)) ; EEPROM data is stored at $4000 - $407F (8 bits) ; ID and configuration words are stored at $4100-4109 (14 bits w/0 in bits 14 & 15) ; PIC ADDR - PC ADDR ; $2000 -> $4100,$4101 ID word 0 (lo, hi) ; $2001 -> $4102,$4103 ID word 1 (lo, hi) ; $2002 -> $4104,$4105 ID word 2 (lo, hi) ; $2003 -> $4106,$4107 ID word 3 (lo, hi) ; $2007 -> $4108,$4109 Configuration Word (lo, hi) ; ;*********************************************************************** ; MENU OPTIONS ; ; 1 - Erase Program Memory ; 2 - Write Program Memory ; 3 - Compare Program Memory (read back stored in $3000-$3FFF) ; 4 - Erase EEPROM Data ; 5 - Write EEPROM Data ; 6 - Compare EEPROM Data (read back stored in $4000-$407F) ; 7 - Write Configuration Data ; 8 - Compare Configuration Data (read back stored in $4100-$410F) ; 9 - Reset memory protection and erase PIC ; L - Do Intel Hex download (offset to $1000) ; Q - Quit ;//**************************************************************** ; CONSTANTS ;//**************************************************************** LDCONF = $00 ; Load Configuration Command LDPM = $02 ; Load Data for Program Memory Command LDDM = $03 ; Load Data for Data Memory Command INCADD = $06 ; Increment Program Counter Command RDPM = $04 ; Read Program Memory Command RDDM = $05 ; Read Data memory Command BPOC = $18 ; Begin Program Only Cycle Command BEPC = $08 ; begin Erase & Program Cycle Command BEPM = $09 ; Bulk Erase Program Memory Command BEDM = $0B ; Bulk Erase Data Memeory Command BES1 = $01 ; Bulk Erase Setup #1 Command BES2 = $07 ; Bulk Erase Setup #2 Command OUTP = $FF ; Set all 8 bits as outputs (65C22) INP = $00 ; set all 8 bits as inputs (65C22) ;//**************************************************************** ; SBC-2 VIA address Map ;//**************************************************************** Via1DDRA = $7F53 ; Data Direction Register Via1PRA = $7F51 ; Port A Data Register CLK = $01 ; Port A - clock pin DATA = $02 ; Port A - data pin PGM = $40 ; Port A - program pin MCLR = $80 ; Port A - /MCLR pin ;//**************************************************************** ; Zero Page Variables ;//**************************************************************** memptr = $30 ; 2 byte memory pointer shift = $32 ; 2 byte temp shift word spsav = $ee ; sav SP (restores stack on exit) ; needed by abort code in HEX upload cmd ;//**************************************************************** ; init code ;//**************************************************************** *= $0800 ; beginning of code tsx stx spsav ; save the stack pointer lda #OUTP sta Via1DDRA ; set all pins as outputs jsr SetMCLR ; set PIC in RESET mode ;//**************************************************************** ; Main Program ;//**************************************************************** main ldx #$00 ; set display pointer prtmenu lda menudat,x beq getcmd jsr output ; print then command menu inx bra prtmenu getcmd jsr input ; wait for a keypress cmp #"Q" ; is it Q? bne getc1 jsr SetMCLR ; ensure pic is reset rts ; exit program getc1 cmp #"1" ; is it 1? bne getc2 jsr epm ; erase program memory bra main getc2 cmp #"2" ; is it 2? bne getc3 jsr wpm ; write program memory bra main getc3 cmp #"3" ; is it 3? bne getc4 jsr cpm ; compare program memory bra main getc4 cmp #"4" ; is it 4? bne getc5 jsr eem ; erase data memory (EEPROM) bra main getc5 cmp #"5" ; is it 5? bne getc6 jsr wem ; write data memory (EEPROM) bra main getc6 cmp #"6" ; is it 6? bne getc7 jsr cem ; compare data memory (EEPROM) bra main getc7 cmp #"7" ; is it 7? bne getc8 jsr wcd ; write Configuration data bra main getc8 cmp #"8" ; is it 8? bne getc9 jsr ccd ; compare Configuration data bra main getc9 cmp #"9" ; is it 9? bne getcL ; jsr unp ; remove code protection and erase PIC bra main getcL cmp #"L" ; is it L? bne getcmd ; no, not valid key jsr HexDnLd ; Do Intel Hex download bra main ;//**************************************************************** ; Erase Program Memory ;//**************************************************************** epm jsr SetPRG ; set PRG mode ldy #$3F ; hi data word ldx #$FF ; low data word lda #LDPM ; Load Data for PM cmd jsr sendcmd ; send it jsr senddata ; send data word lda #BEPM ; bulk erase PM cmd jsr sendcmd ; send it lda #BPOC ; begin Program only cmd jsr sendcmd ; send it lda #10 ; jsr delay_ms ; wait 10 ms for erase to be done jsr SetMCLR ; Reset PIC rts ; done ;//**************************************************************** ; Write Program Memory ;//**************************************************************** wpm lda #$00 ; sta memptr ; init mem pointer lda #$10 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set PRG mode wpm1 lda (memptr) ; get data byte (lo half of word) pha ; save it tax ; save lo byte jsr incptr ; advance pointer lda (memptr) ; get data byte (hi half of word) pha ; save it tay ; save hi byte jsr incptr ; advance pointer lda #LDPM ; Load Data for PM cmd jsr sendcmd ; send it jsr senddata ; send data word lda #BPOC ; begin Program only cmd jsr sendcmd ; send it lda #10 ; 10ms max prog cycle jsr delay_ms ; wait 6 ms for erase to be done lda #RDPM ; jsr sendcmd ; read data from PM cmd jsr readdata ; read back PM values are returned as yyxx pla ; get hi byte cmp shift+1 ; compare with hi byte read back beq wpm2 ; match? jsr Hierr ; no! -write fail error, stop pla ; clean stack rts wpm2 pla ; yes restore lo byte cmp shift ; compare with lo byte read back beq wpm3 ; match? jsr Loerr ; no! write fail error, stop rts wpm3 lda memptr ; yes get pointer low byte cmp #$00 ; is it 0? bne wpm4 ; no, inc PIC PC lda memptr+1 ; get pointer hi byte cmp #$20 ; is hi page = $20xx beq wpm5 ; yes, we're done wpm4 lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word bra wpm1 ; prog next word wpm5 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; Compare Program Memory ;//**************************************************************** cpm lda #$00 ; sta memptr ; init mem pointer lda #$30 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set program mode cpm1 lda #RDPM ; jsr sendcmd ; read data from PM cmd jsr readdata ; read back PM values into shift variable lda shift ; sta (memptr) ; jsr incptr ; lda shift+1 ; sta (memptr) ; jsr incptr ; cpm3 lda memptr ; yes get pointer low byte cmp #$00 ; is it 0? bne cpm4 ; no, inc PIC PC lda memptr+1 ; get pointer hi byte cmp #$40 ; is hi page = $40xx beq cpm5 ; yes, we're done cpm4 lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word bra cpm1 ; prog next word cpm5 lda #$00 ; sta memptr ; init mem pointer to PIC mem table sta shift ; init shift to Desired mem table lda #$30 ; sta memptr+1 ; lda #$10 ; sta shift+1 ; ldy #$00 ; cpm6 lda (memptr) ; get PIC data cmp (shift),y ; is equal to ourt data? beq cpm7 ; yes, do next lda memptr ; no - print error tax lda memptr+1 ; and #$0F ; mask hi bits jsr print2byte ; if mismatched then print error lda #":" ; jsr output ; format is: lda (memptr) ; jsr print1byte ; AAAA:DD-CClda #"-" ; jsr output ; where AAAA is the byte address lda (shift) ; DD is the PIC memory value jsr print1byte ; CC is the expected value jsr print_cr ; cpm7 jsr incptr ; inc mem pointers inc shift ; bne cpm8 ; inc shift+1 ; cpm8 lda memptr ; cmp #$00 ; is equal to 0? bne cpm6 ; no, get next lda memptr+1 ; cmp #$40 ; top of table? bne cpm6 ; no, get next cpm9 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; Erase EEPROM Memory ;//**************************************************************** eem jsr SetPRG ; set PRG mode ldy #$3F ; hi data word ldx #$FF ; low data word lda #LDDM ; Load Data for DM cmd jsr sendcmd ; send it jsr senddata ; send data word lda #BEDM ; bulk erase DM cmd jsr sendcmd ; send it lda #BPOC ; begin Program only cmd jsr sendcmd ; send it lda #10 ; jsr delay_ms ; wait 6 ms for erase to be done jsr SetMCLR ; Reset PIC rts ; done ;//**************************************************************** ; Write EEPROM Memory ;//**************************************************************** wem lda #$00 ; sta memptr ; init mem pointer lda #$20 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set PRG mode wem1 lda (memptr) ; get data byte (lo half of word) pha ; save it tax ; save lo byte ldy #$00 ; hi byte is $00 inc memptr ; advance pointer lda #"." ; visual status jsr output ; send to SBC output port lda #LDDM ; Load Data for DM cmd jsr sendcmd ; send it jsr senddata ; send data word lda #BPOC ; begin Program only cmd jsr sendcmd ; send it lda #10 ; 8ms max programming time jsr delay_ms ; wait 6 ms for erase to be done lda #RDDM ; jsr sendcmd ; read data from DM cmd jsr readdata ; read back PM values are returned as yyxx pla ; get hi byte cmp shift ; compare with lo byte read back beq wem3 ; match? jsr Loerr ; no! write fail error, stop rts wem3 lda memptr ; yes get pointer low byte cmp #$80 ; is it 0? beq wem5 ; yes, we're done wem4 lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word bra wem1 ; prog next word wem5 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; Compare EEPROM Memory ;//**************************************************************** cem lda #$00 ; sta memptr ; init mem pointer lda #$40 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set PRG mode cem1 lda #RDDM ; jsr sendcmd ; read data from DM cmd jsr readdata ; read back DM values into shift variable lda shift ; sta (memptr) ; inc memptr ; lda #"." ; visual status jsr output ; send to SBC output port cem3 lda memptr ; yes get pointer low byte cmp #$80 ; is it 80? beq cem5 ; yes, we're done cem4 lda #$06 ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word bra cem1 ; prog next word cem5 jsr print_cr ; lda #$00 ; sta memptr ; init mem pointer to PIC mem table sta shift ; init shift to Desired mem table lda #$40 ; sta memptr+1 ; lda #$20 ; sta shift+1 ; ldy #$00 ; cem6 lda (memptr) ; get PIC data cmp (shift),y ; is equal to ourt data? beq cem7 ; yes, do next lda memptr ; no - print error tax ; sav lo byte lda #$00 ; hi byte=0 jsr print2byte ; if mismatched then print error lda #":" ; jsr output ; format is: lda (memptr) ; jsr print1byte ; AAAA:DD-CC lda #"-" ; jsr output ; where AAAA is the byte address lda (shift) ; DD is the PIC memory value jsr print1byte ; CC is the expected value jsr print_cr ; cem7 inc memptr ; inc mem pointers inc shift ; cem8 lda memptr ; cmp #$80 ; is equal to 80? bne cem6 ; no, get next cem9 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; Write Configuration Words ;//**************************************************************** wcd lda #$00 ; sta memptr ; init mem pointer lda #$21 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set PRG mode ldy #$00 ; init data word to $0000 ldx #$00 ; lda #LDCONF ; Load Configuration cmd jsr sendcmd ; send it jsr senddata ; send data=0000 wcd1 lda (memptr) ; get data byte (lo half of word) pha ; save it tax ; save lo byte wcd11 jsr incptr ; advance pointer lda (memptr) ; get data byte (hi half of word) pha ; save it tay ; save hi byte jsr incptr ; advance pointer lda #"." ; visual status jsr output ; send to SBC output port lda #LDPM ; Load Data for PM cmd jsr sendcmd ; send it jsr senddata ; send data word lda #BPOC ; begin Program only cmd jsr sendcmd ; send it lda #10 ; jsr delay_ms ; wait 10ms for erase to be done lda #RDPM ; jsr sendcmd ; read data from PM cmd jsr readdata ; read back PM values are returned as yyxx pla ; get hi byte cmp shift+1 ; compare with hi byte read back beq wcd2 ; match? jsr Hierr ; no! -write fail error, stop pla ; clear stack rts wcd2 pla ; yes restore lo byte cmp shift ; compare with lo byte read back beq wcd3 ; match? jsr Loerr ; no! write fail error, stop rts wcd3 lda memptr ; yes get pointer low byte cmp #$08 ; is it < 8? bpl wcd4 ; yes, inc PIC PC lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word bra wcd1 ; prog next word wcd4 bne wcd5 ; if not 8, then we're done lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda (memptr) ; get data byte (lo half of config word) ora #$80 ; ensure LV programming is always enabled!!! pha ; save it tax ; save lo byte bra wcd11 ; get hi byte & write the configuration word wcd5 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; Compare Configuration Words ;//**************************************************************** ccd lda #$00 ; sta memptr ; init mem pointer lda #$41 ; to start of ram table sta memptr+1 ; jsr SetPRG ; set PRG mode LDY #$00 ; init data word to $0000 LDX #$00 ; lda #LDCONF ; Load Configuration cmd jsr sendcmd ; send it jsr senddata ; data=0000 ccd1 lda #RDPM ; jsr sendcmd ; read data from PM cmd jsr readdata ; read back PM values into shift variable lda shift ; sta (memptr) ; save lo byte inc memptr ; lda shift+1 ; sta (memptr) ; save hi byte inc memptr ; lda #"." ; visual status jsr output ; send to SBC output port lda memptr ; yes get pointer low byte cmp #$08 ; is it >=8? bpl ccd4 ; yes, get config word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word jmp ccd1 ; read next word ccd4 bne ccd5 ; <>8 means were done lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to next word lda #INCADD ; no, INC PC command jsr sendcmd ; inc PIC's PC to conguration word jmp ccd1 ; read it ccd5 jsr print_cr ; send to SBC output port lda #$00 ; sta memptr ; init mem pointer to PIC mem table sta shift ; init shift to Desired mem table lda #$41 ; sta memptr+1 ; lda #$21 ; sta shift+1 ; ldy #$00 ; ccd6 lda (memptr) ; get PIC data cmp (shift),y ; is equal to ourt data? beq ccd7 ; yes, do next lda memptr ; no - print error tax ; save lo byte lda #$00 ; set high byte to 0 jsr print2byte ; if mismatched then print error lda #":" ; jsr output ; format is: lda (memptr) ; jsr print1byte ; AAAA:DD-CC lda #"-" ; jsr output ; where AAAA is the byte address lda (shift) ; DD is the PIC memory value jsr print1byte ; CC is the expected value jsr print_cr ; ccd7 inc memptr ; inc mem pointers inc shift ; ccd8 lda memptr ; cmp #$0A ; is equal to A? bne ccd6 ; no, get next ccd9 jsr SetMCLR ; done, Reset PIC rts ; done ;//**************************************************************** ; unp - Unprotect and erase the PIC ;//**************************************************************** unp jsr SetPRG ; set PRG mode ldx #$00 ; low data word ldy #$00 ; hi data word lda #LDCONF ; Load Configuration cmd w/$0 jsr sendcmd ; send it jsr senddata ; send data word=0000 lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #INCADD ; Inc PC cmd jsr sendcmd ; send it lda #BES1 ; Bulk Erase setup 1 cmd jsr sendcmd ; send it lda #BES2 ; Bulk Erase setup 2 cmd jsr sendcmd ; send it lda #BEPC ; begin Erase/Program cmd jsr sendcmd ; send it lda #20 ; 14ms max wait time jsr delay_ms ; wait 14 ms for erase to be done lda #BES1 ; Bulk Erase setup 1 cmd jsr sendcmd ; send it lda #BES2 ; Bulk Erase setup 2 cmd jsr sendcmd ; send it jsr SetMCLR ; Reset PIC rts ;################################################################### ; ; Subroutines ; ;################################################################### ;//**************************************************************** ; sendcmd - send a programming command to the PIC ;//**************************************************************** sendcmd sta shift ; save cmd phx ; save x reg ldx #06 ; number of command bits sendcmdlp lsr shift ; get lsb of cmd bcc sendcmd1 ; is it 0? lda #$F3 ; no, set data=1, clk=1 .byte $2c ; bit abs opcode (skip cmd) sendcmd1 lda #$F1 ; yes, set data=0, clk=1 sta Via1PRA ; Raise clk and #$FE ; mask out clk bit sta Via1PRA ; drop clk dex ; done all 6 yet bne sendcmdlp ; no, do next lda #$F0 ; yes sta Via1PRA ; drop data & clk plx ; restore x reg rts ;//**************************************************************** ; senddata - send a data word to the PIC from YYXX ; YYXX = 14 bits, right aligned (00yyyyyy xxxxxxxx) ; sent centered ( 0yyyyyyx xxxxxxx0) ;//**************************************************************** senddata phx ; save x phy ; save y stx shift ; save lo byte tya ; get hi byte and #$3F ; force 14 bits only sta shift+1 ; save hi byte ldx #16 ; # of bits bra senddata1 ; first bit is always 0 senddatalp lsr shift+1 ; adds 0's to top end ror shift ; 15th & 16th shift will send 0's bcc senddata1 ; lda #$F3 ; set data=1, clk=1 .byte $2c ; bit abs opcode senddata1 lda #$F1 ; set data=0, clk=1 sta Via1PRA ; Raise clk and #$FE ; sta Via1PRA ; drop clk dex ; done all 16 yet bne senddatalp ; no, do next lda #$F0 ; yes sta Via1PRA ; drop data & clk ply ; restore y plx ; restore x rts ;//**************************************************************** ; readdata - read a 16 bit data word from the PIC into shift vairable ; 14 bits, right aligned (00yyyyyy xxxxxxxx) ;//**************************************************************** readdata lda #$F1 ; sta Via1PRA ; raise clk ldx #$FD ; bit 1 now input lda #$F0 ; sta Via1PRA ; lower clk stx Via1DDRA ; set DDRA stz shift ; stz shift+1 ; zero variable ldx #14 ; # of data bits readdatalp lda #$F1 ; sta Via1PRA ; raise clk nop ; wait for valid data lda Via1PRA ; read data port and #$02 ; mask data pin clc ; clr carry adc #$FF ; set carry if data bit = 1 ror shift+1 ; shift carry bit into storage ror shift ; shift second byte lda #$F0 ; sta Via1PRA ; lower clk dex ; done all 14 yet bne readdatalp ; no, do next nop ; lda #$F1 ; sta Via1PRA ; raise clk lda #$FF ; bit 1 now output again sta Via1DDRA ; set DDRA lda #$F0 ; sta Via1PRA ; lower clk lsr shift+1 ; shift carry bit into storage ror shift ; shift second byte lsr shift+1 ; shift carry bit into storage ror shift ; shift second byte rts ;//**************************************************************** ; incptr - increment the memory pointer ;//**************************************************************** incptr inc memptr ; inc low byte bne incptr2 ; if not zero, done inc memptr+1 ; if if zero, inc hi byte incptr1 lda #"." ; visual status jsr output ; send to SBC output port lda #$60 ; page $60xx cmp memptr+1 ; compare with hi byte bpl incptr2 ; if below $60xx, done brk ; memptr too high - error, stop incptr2 rts ; done ;//**************************************************************** ; delay_ms - delay milliseconds in A reg ;//**************************************************************** delay_ms phx ; phy ; 1MHz clk = $01C0 delayms1 ldy #$02 ; 2MHz clk = $0288 ldx #$88 ; 4MHz clk = $0416 delayms2 dex ; 8MHz clk = $0734 bne delayms2 ; 10MHz clk = $08C3 dey ; 14MHz clk = $0BE0 bne delayms2 dec bne delayms1 ply plx rts ;//**************************************************************** ; Compare Error on High Byte ;//**************************************************************** HiErr jsr SetMCLR ; reset the PIC jsr print_cr ; new line lda memptr+1 ldx memptr jsr print2byte ; print SBC address pointer ldx #$00 herr lda herrtxt,x beq herr1 jsr output inx bra herr herr1 rts herrtxt .byte " - Hi Byte Write Error!", $0d, $0a, $00 ;//**************************************************************** ; Compare Error on LO Byte ;//**************************************************************** LoErr jsr SetMCLR ; reset the PIC jsr print_cr ; new line lda memptr+1 ldx memptr ; *** adj 2 bytes backward jsr print2byte ; print SBC address pointer ldx #$00 Lerr lda Lerrtxt,x beq Lerr1 jsr output inx bra Lerr Lerr1 rts Lerrtxt .byte " - Lo Byte Write Error!", $0d, $0a, $00 ;//**************************************************************** ; SetMCLR - Set the PIC into RESET mode ;//**************************************************************** SetMCLR lda #$00 sta Via1PRA ; set PIC into RESET mode lda #$80 ; raise MCLR sta Via1PRA ; set PIC into RUN mode lda #$01 ; 1ms jsr delay_ms ; pause lda #$00 ; lower MCLR sta Via1PRA ; set PIC into RESET mode rts ;//**************************************************************** ; SetPGM - Set the PIC into PROGRAM mode ;//**************************************************************** SetPRG lda #$F0 sta Via1PRA ; set PIC into PROGRAM mode ldx #$04 setpgm1 dex bne setpgm1 ; delay 5uS rts ;//**************************************************************** ; Menudat - Programming Menu text ;//**************************************************************** menudat .byte $0d, $0a .byte "Program Memory", $0d, $0a .byte " 1 - Erase", $0d, $0a .byte " 2 - Write", $0d, $0a .byte " 3 - Compare", $0d, $0a .byte "EEPROM Data", $0d, $0a .byte " 4 - Erase", $0d, $0a .byte " 5 - Write", $0d, $0a .byte " 6 - Compare", $0d, $0a .byte "Configuration Data", $0d, $0a .byte " 7 - Write", $0d, $0a .byte " 8 - Compare", $0d, $0a .byte " 9 - Unprotect & Erase PIC", $0d, $0a .byte "(L)oad Intel Hex File", $0d, $0a .byte "(Q)uit Program", $0d, $0a, $0d, $0a, $00 ;//**************************************************************** ; Jump Table into the SBC Monitor's Jump Table (v5.0 and above) ;//**************************************************************** output jmp $e824 ; send to SBC output port input jmp $e821 ; wait for chr from SBC input port scan jmp $e81e ; get chr from SBC input port (no wait) print_cr jmp $e803 ; print CR-LF to SBC output port print2sp jmp $e809 ; print 2 spaces print1sp jmp $e806 ; print 1 space print1byte jmp $e812 ; print one byte (AA) to SBC output port print2byte jmp $e815 ; print one word (AAXX) to SBC output port ;//**************************************************************** ; END ;//**************************************************************** ;//**************************************************************** ; Ross Archer's Intel Hex downloader added to allow direct import ; of the *.hex file generated by the MPLAB assembler. ;//**************************************************************** ; add an Intel-Hex Downloader to get program code for target PIC ; I'm using Ross Archer's code, with slight modifications to use ; some of the SBC's commands. ; ; zero page variables (Its ok to stomp on the monitor's zp vars) ; ; reclen = $39 ; record length in bytes chksum = $3A ; record checksum accumulator start_lo = $3b start_hi = $3c rectype = $3d dlfail = $3e ; flag for upload failure temp = $3f ; save hex value strptr = $40 strptrh = $41 ; temporary string pointer (not preserved across calls) ; ; tables and constants ; CR = 13 LF = 10 ESC = 27 ; ESC to exit HexDnLd jsr print_cr lda #0 sta dlfail ;Start by assuming no D/L failure HdwRecs jsr GetSer ; Wait for start of record mark ':' cmp #":" bne HdwRecs ; not found yet ; Start of record marker has been found IHex jsr GetHex ; Get the record length sta reclen ; save it sta chksum ; and save first byte of checksum jsr GetHex ; Get the high part of start address sta start_hi clc adc chksum ; Add in the checksum sta chksum ; jsr GetHex ; Get the low part of the start address sta start_lo clc adc chksum sta chksum clc lda #$10 adc start_hi sta start_hi ; adjust storage base jsr GetHex ; Get the record type sta rectype ; & save it clc adc chksum sta chksum lda rectype bne HdEr1 ; end-of-record ldx reclen ; number of data bytes to write to memory ldy #0 ; start offset at 0 HdLp1 jsr GetHex ; Get the first/next/last data byte sta (start_lo),y ; Save it to RAM clc adc chksum sta chksum ; iny ; update data pointer dex ; decrement count bne HdLp1 jsr GetHex ; get the checksum clc adc chksum bne HdDlF1 ; If failed, report it ; Another successful record has been processed lda #"#" ; Character indicating record OK = '#' jsr output jmp HdwRecs ; get next record HdDlF1 lda #"F" ; Character indicating record failure = 'F' sta dlfail ; upload failed if non-zero jsr output jmp HdwRecs ; wait for next record start HdEr1 cmp #1 ; Check for end-of-record type beq HdEr2 cmp #4 beq HdwRecs ; skip this type (configuration data word???) lda #>MsgUnknownRecType ldx # upload has failed jsr Print1Byte ; print it jsr print_cr jmp HdwRecs ; We've reached the end-of-record record HdEr2 jsr GetHex ; get the checksum clc adc chksum ; Add previous checksum accumulator value beq HdEr3 ; checksum = 0 means we're OK! lda #>MsgBadRecChksum ldx # MsgUploadFail ldx # MsgUploadOK ldx # 255 PrintStrAXX1 pla tay rts ; ; Checksum messages ; MsgUnknownRecType .byte CR,LF,CR,LF .byte "Unknown record type $" .byte 0 ; null-terminate every string MsgBadRecChksum .byte CR,LF,CR,LF .byte "Bad record checksum!" .byte 0 ; Null-terminate MsgUploadFail .byte CR,LF,CR,LF .byte "Upload Failed",CR,LF .byte "Aborting!" .byte 0 ; null-terminate every string or crash'n'burn MsgUploadOK .byte CR,LF,CR,LF .byte "Upload Successful!" .byte 0 ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ; END OF PROGRAM ;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%