-- -------------------------------------------------------------------------- -- -- Wisp628 firmware -- -- (c) 2002, 2003 -- Van Ooijen Technische Informatica / Wouter van Ooijen -- -- see http://www.voti.nl/wisp628 -- -- version 1.08 -- support for 16F819 -- writing ID memory corrected -- baudrate switching changed -- bug in eeprom writing corrected -- -- version 1.07 -- read 8 bytes added -- 18F algorithms corrected -- general speedup -- -- version 1.06, 28-NOV-2002 -- another write timing bug corrected -- delays trimmed down (were ~ 20% too long) -- -- version 1.05, 26-NOV-2002 -- write timing bug corrected -- -- version 1.04, 21-NOV-2002 -- 12F eeprom write corrected (again?) -- Vpp rise delay enlarged to cope with cap on MCLR (MDM-1 devboard) -- -- version 1.03, 19-NOV-2002 -- baudrate switching -- jump supports 14-bit cores by repeated incrementing -- program delay can be specified -- uart error handling corrected -- -- version 1.02, 29-OCT-2002 -- 12Fxxx power pull-down using aux1 -- -- version 1.01, 22-OCT-2002 -- 'go' now floats clock and data -- -- version 1.00, 06-SEP-2002 -- first Jal 'release' version -- (previous versions coded in MPASM assembler) -- -- Permission to use this software is granted to everyone -- on the conditions outlined on the Wisp628 page at -- http://www.voti.nl/wisp628.html#legal -- -- -------------------------------------------------------------------------- -- -- ToDo list -- -- lazy write for old-style PICs -- -- -------------------------------------------------------------------------- include f628_20 include jdelay -- -------------------------------------------------------------------------- -- -- configuration fuses -- -- -------------------------------------------------------------------------- -- no code protection 11_11 -- don't care bit x -- no data protection 1 -- LVP disabled 0 -- brownout reset enabled 1 -- internal MCLR 0 -- power-up delay enabled 0 -- watchdog disabled 0 -- HS osc 0 10 pragma target fuses 0b_11_1111_0100_0010 -- -------------------------------------------------------------------------- -- -- I/O pins -- -- -------------------------------------------------------------------------- var volatile bit clock_pin is pin_a0 -- target RB6 var volatile bit reset_pin is pin_a1 -- var volatile bit dummy_1_pin is pin_a2 -- var volatile bit dummy_2_pin is pin_a3 -- var volatile bit dummy_3_pin is pin_a4 -- var volatile bit dummy_4_pin is pin_a5 -- var volatile bit pump_1_pin is pin_b0 -- var volatile bit async_in_pin is pin_b1 -- var volatile bit async_out_pin is pin_b2 -- var volatile bit pump_2_pin is pin_b3 -- var volatile bit aux_2_pin is pin_b4 -- var volatile bit data_pin is pin_b5 -- target RB7 var volatile bit aux_1_pin is pin_b6 -- short target Vcc var volatile bit pulldown_pin is pin_b7 -- target PGM var volatile bit clock_pin_direction is pin_a0_direction var volatile bit reset_pin_direction is pin_a1_direction var volatile bit dummy_1_pin_direction is pin_a2_direction var volatile bit dummy_2_pin_direction is pin_a3_direction var volatile bit dummy_3_pin_direction is pin_a4_direction var volatile bit dummy_4_pin_direction is pin_a5_direction var volatile bit pump_1_pin_direction is pin_b0_direction var volatile bit async_in_pin_direction is pin_b1_direction var volatile bit async_out_pin_direction is pin_b2_direction var volatile bit pump_2_pin_direction is pin_b3_direction var volatile bit aux_2_pin_direction is pin_b4_direction var volatile bit data_pin_direction is pin_b5_direction var volatile bit aux_1_pin_direction is pin_b6_direction var volatile bit pulldown_pin_direction is pin_b7_direction -- -------------------------------------------------------------------------- -- -- global data -- -- -------------------------------------------------------------------------- var byte received, cmd, response var byte d0, d1, d2, d3, d4, d5, d6, d7, d8, d9 var byte d10, d11, d12, d13, d14, d15, d16, d17, d18, d19, d20 var byte d_1 at d20 var byte d_2 at d19 var byte d_3 at d18 var byte d_4 at d17 var byte d_5 at d16 var byte d_6 at d15 -- -------------------------------------------------------------------------- -- -- programming algorithms -- -- All -- -- 0 no algorithm selected (error) -- 1 16c84 code/fuses, 14 bits, 10 ms -- 2 16c84 data eeprom, 8 bits, 10 ms -- 3 16f7x code/fuses, 14 bits, 1 ms -- 4 16f7x data eeprom, 8 bits, 1 ms (reserved) -- 5 16f87xA code/fuses, 14 bits, 1 ms -- 6 16f87xA data eeprom, 8 bits, 1 ms -- 7 16f819 code/fuses, 4 words, 1 ms -- 10 18f* code, single panel -- 11 18f* eeprom data -- 12 18f* configuration/fuses -- -- -------------------------------------------------------------------------- var byte algorithm = 0 var byte programming_delay var byte read_block_size -- -------------------------------------------------------------------------- -- -- misc -- -- -------------------------------------------------------------------------- function to_uppercase( byte in x ) return byte is if ( x >= "a" ) & ( x <= "z" ) then x = x + ( "A" - "a" ) end if return x end function function ascii_to_hex( byte in x ) return byte is const c1 = 0 - "A" const c2 = "9" + 1 - "A" const c3 = "A" - "0" assembler bank movfw x addlw c1 ; to get a carry for A..F skpnc ; got a carry? addlw c2 ; yes, add 9+1 .. F offset addlw c3 ; 'add' remaining offset for '0' bank movwf x end assembler return x end function function hex_to_ascii( byte in x ) return byte is const c1 = 0 - 0x0A const c2 = ( "A" - "9" ) - 1 const c3 = "0" + 0x0A assembler bank movfw x addlw c1 ; to get a carry for A..F skpnc ; got a carry? addlw c2 ; yes, add 9+1 .. F offset addlw c3 ; add remaining offset for '0' bank movwf x end assembler return x end function procedure shift( byte in n ) is for n loop d0 = d1 d1 = d2 d2 = d3 d3 = d4 d4 = d5 d5 = d6 d6 = d7 d7 = d8 d8 = d9 d9 = d10 d10 = d11 d11 = d12 d12 = d13 d13 = d14 d14 = d15 d15 = d16 d16 = d17 d17 = d18 d18 = d19 d19 = d20 end loop end procedure -- -------------------------------------------------------------------------- -- -- pump and reset -- -- -------------------------------------------------------------------------- var bit pump_enabled = false -- enable Vpp charge pump procedure pump_on is pump_1_pin_direction = output pump_2_pin_direction = output pump_enabled = true end procedure -- disable Vpp charge pump procedure pump_off is pump_1_pin_direction = input pump_2_pin_direction = input pump_enabled = false end procedure -- one charge pump cycle var bit pump_last_value procedure fast_pump_cycle is -- toggle both pump pins -- (no effect when the pins are inputs) pump_1_pin = pump_last_value pump_last_value = ! pump_last_value pump_2_pin = pump_last_value end procedure -- one charge pump cycle, call takes approximately 10 us procedure pump_cycle is -- toggle both pump pins -- (no effect when the pins are inputs) pump_1_pin = pump_last_value pump_last_value = ! pump_last_value pump_2_pin = pump_last_value -- procedure must take 10us total = 50 cycles @ 20 MHz -- 3 statements above takes 29 cycles, -- call-return takes 4, -- loop overhead another 3, -- so add 14 assembler nop nop nop nop nop nop nop nop nop nop nop nop nop nop end assembler end procedure -- wait N * 100 us, pump if enabled procedure target_wait_100us( byte in N = 1 ) is for N loop for 10 loop pump_cycle end loop end loop end procedure -- wait N * 1 ms, pump if enabled procedure target_wait_ms( byte in N = 1 ) is for N loop for 100 loop pump_cycle end loop end loop end procedure -- reset target, either to programming or run mode procedure target_reset is pulldown_pin = off pulldown_pin_direction = output aux_1_pin = on aux_1_pin_direction = output reset_pin = on target_wait_100us( 50 ) reset_pin = off target_wait_100us( 50 ) pulldown_pin_direction = input target_wait_100us( 50 ) aux_1_pin_direction = input target_wait_100us( 50 ) end procedure -- start programming the target, -- observe Vpp cap charge time when pump was not enabled procedure target_program_start is if pump_enabled then target_wait_ms( 10 ) else pump_on target_wait_ms( 200 ) end if reset_pin = on clock_pin = off data_pin = off clock_pin_direction = output data_pin_direction = output target_reset end procedure -- end programming the target, -- observe Vpp cap discharge time when pump was enabled procedure target_program_stop_and_reset is reset_pin = on if pump_enabled then pump_off target_wait_ms( 200 ) end if target_reset end procedure -- put target in run mode, -- disconnect the programming pins procedure target_run is reset_pin = on clock_pin_direction = input data_pin_direction = input target_program_stop_and_reset end procedure -- -------------------------------------------------------------------------- -- -- UART -- -- -------------------------------------------------------------------------- -- initialise the UART for 19k2 8N1 procedure uart_init( byte in divisor = 64 ) is bank_1 f877_txsta = 0b_0010_0100 -- asynch, 8 bit, transmit enable, high speed bank_0 asm movfw divisor bank_1 asm movwf f877_spbrg -- 64 == 19200 baud at 20 MHz (high speed) bank_0 f877_rcsta = 0b_1001_0000 -- receive enable, 8 bit async_in_pin_direction = input async_out_pin_direction = output end procedure -- disable UART -- set pin directions for bit-banged communication procedure uart_disable is async_in_pin_direction = input async_out_pin_direction = output async_out_pin = true bank_1 f877_txsta = 0b_0000_0000 -- disable, low speed f877_spbrg = 0 -- 300 baud at 20 MHz (low speed) bank_0 f877_rcsta = 0b_0000_0000 end procedure -- return whether the UART is idle (not sending a char) function uart_send_idle return bit is var byte _txsta bank_1 asm movfw f877_txsta bank_0 asm movwf _txsta var bit idle at _txsta : 1 return idle end function -- return whether the UART data register is empty (can accept a next char) function uart_buffer_empty return bit is var volatile bit _TXIF at 0x0C : 4 return _TXIF end function -- sent byte a the uart, -- but first wait for the data register to be empty procedure uart_send( byte in c ) is -- wait for buffer empty while ! uart_buffer_empty loop fast_pump_cycle end loop -- send the character var volatile byte txreg at 0x19 = c end procedure -- return whether a received character is available function uart_char_available return bit is var volatile byte _pir1 at 0x0C var volatile byte _rcsta at 0x18 var volatile bit char_available at _pir1 : 5 var volatile bit overrun at _rcsta : 1 var volatile bit framing_error at _rcsta : 2 overrun = false if framing_error then uart_init end if return char_available end function -- return the received character (if any, check uart_char_available first) function uart_received_char return byte is var volatile byte _rcreg at 0x1A return _rcreg end function -- -------------------------------------------------------------------------- -- -- programming primitives -- -- -------------------------------------------------------------------------- -- send the count lowest bits of data to the target (lowest first) procedure target_send( byte in data, byte in count ) is var bit data_bit at data : 0 data_pin_direction = output for count loop data_pin = data_bit clock_pin = on data = data >> 1 fast_pump_cycle clock_pin = off fast_pump_cycle end loop pump_cycle end procedure -- receive the count lowest bits from the target (lowest first) function target_receive( byte in count ) return byte is var byte data var bit data_bit at data : 7 data_pin_direction = input for count loop clock_pin = on fast_pump_cycle data = data >> 1 data_bit = data_pin clock_pin = off fast_pump_cycle end loop pump_cycle return data >> ( 8 - count ) end function function target_receive_ascii( byte in count ) return byte is return hex_to_ascii( target_receive( count ) & 0x0F ) end function -- 14-bit PICs: send a command procedure target_send_6( byte in d1 ) is target_send( d1, 6 ) end procedure -- 14-bit PICs: send data procedure target_send_14( byte in d1, byte in d2 ) is target_send( 0, 1 ) target_send( d2, 8 ) target_send( d1, 6 ) target_send( 0, 1 ) end procedure -- 14-bit PICs: send command and data procedure target_send_6_14( byte in cmd, byte in d1, byte in d2 ) is target_send( cmd, 6 ) target_send( 0, 1 ) target_send( d2, 8 ) target_send( d1, 6 ) target_send( 0, 1 ) end procedure -- 14-bit PICs: send command, receive data procedure target_send_6_receive_14( byte in cmd, byte out d1, byte out d2 ) is var byte dummy target_send( cmd, 6 ) dummy = target_receive( 1 ) d2 = target_receive( 8 ) d1 = target_receive( 6 ) dummy = target_receive( 1 ) end procedure -- 16-bit PICs: send command and data procedure target_send_20( byte in c, byte in a, byte in b ) is target_send( c, 4 ) target_send( b, 8 ) target_send( a, 8 ) end procedure -- 18-bit PICs: read a single byte, using command cmd function target_read_byte( byte in cmd ) return byte is target_send( cmd, 4 ) var byte dummy = target_receive( 8 ) return target_receive( 8 ) end function -- 16-bit PICs: programming, keep clock high for the prescribed time procedure target_program_pic18 is target_send( 0, 3 ) data_pin = off clock_pin = on target_wait_100us( programming_delay ) clock_pin = off pump_cycle target_send( 0, 16 ) end procedure -- -------------------------------------------------------------------------- -- -- 16-bit PIC address handling -- -- -------------------------------------------------------------------------- -- the current address var byte address_l, address_m, address_h procedure target_load_address is target_send_20( 0b_0000, 0x0E, address_h ) target_send_20( 0b_0000, 0x6E, 0xF8 ) target_send_20( 0b_0000, 0x0E, address_m ) target_send_20( 0b_0000, 0x6E, 0xF7 ) target_send_20( 0b_0000, 0x0E, address_l ) target_send_20( 0b_0000, 0x6E, 0xF6 ) end procedure -- add N to the current address procedure address_increment( byte in N ) is for N loop fast_pump_cycle address_l = address_l + 1 if address_l == 0 then address_m = address_m + 1 if address_m == 0 then address_h = address_h + 1 end if end if end loop -- for debugging only if false then uart_send( hex_to_ascii( address_l >> 4 )) uart_send( hex_to_ascii( address_l & 0x0F )) end if end procedure -- set current address and send it to the target procedure target_set_address( byte in a, byte in b, byte in c ) is address_h = a address_m = b address_l = c target_load_address end procedure -- -------------------------------------------------------------------------- -- -- programming details -- -- -------------------------------------------------------------------------- -- 16-bit PICs: set single-panel programming procedure single_panel is target_set_address( 0x3C, 0x00, 0x06 ) target_send_20( 0b_1100, 0x00, 0x00 ) end procedure procedure command_program is var byte default_delay response = cmd algorithm = 0 read_block_size = 1 programming_delay = d_3 + ( d_4 << 4 ) address_h = 0 address_m = 0 address_l = 0 -- program code (or ID locations) memory if d_1 == 0x0C then -- old 14-bit PICs, 10 ms if ( d_2 == 0 ) | ( d_2 == 5 ) then algorithm = 1 default_delay = 100 target_program_start if d_2 == 5 then read_block_size = 4 end if -- new 14-bit PICs (16f7x), one word, 1 ms elsif d_2 == 1 then algorithm = 3 default_delay = 10 target_program_start -- new 14-bit PICs (16f87xA), one word, 1 ms elsif d_2 == 2 then algorithm = 5 default_delay = 10 target_program_start -- 16-bit PICs, 1 ms elsif( d_2 == 3 ) | ( d_2 == 6 ) then algorithm = 10 default_delay = 10 target_program_start single_panel target_send_20( 0b_0000, 0x8E, 0xA6 ) target_send_20( 0b_0000, 0x9C, 0xA6 ) target_set_address( 0x00, 0x00, 0x00 ) if d_2 == 6 then read_block_size = 8 end if -- 12fxxx: re_use algorithm 1, 8 ms elsif d_2 == 4 then algorithm = 1 default_delay = 80 target_program_start -- 16f819: 4 words, 1ms elsif d_2 == 7 then algorithm = 7 default_delay = 10 target_program_start else response = "?" end if -- program eeprom data memory elsif d_1 == 0x0D then address_m = 0x21 -- 14-bit PICs, 10 ms if ( d_2 == 0 ) then algorithm = 2 default_delay = 100 target_program_start elsif ( d_2 == 1 ) then algorithm = 4 default_delay = 100 target_program_start elsif ( d_2 == 2 ) | ( d_2 == 7 ) then algorithm = 6 default_delay = 100 target_program_start -- 16-bit PICs elsif( d_2 == 3 ) | ( d_2 == 6 ) then algorithm = 11 default_delay = 10 target_program_start target_send_20( 0b_0000, 0x9E, 0xA6 ) target_send_20( 0b_0000, 0x9C, 0xA6 ) if d_2 == 6 then read_block_size = 8 end if -- 12fxxx: re-use algorithm 2 elsif d_2 == 4 then default_delay = 80 algorithm = 2 target_program_start else response = "?" end if -- program configuration (fuses) memory elsif d_1 == 0x0F then address_m = 0x20 -- 14-bit PICs if ( d_2 == 0 ) | ( d_2 == 1 ) | ( d_2 == 2 ) | ( d_2 == 4 ) | ( d_2 == 7 ) then algorithm = 1 target_program_start target_send_6( 0x00 ) target_send_14( 0x00, 0x00 ) default_delay = 100 if ( d_2 == 2 ) | ( d_2 == 7 ) then algorithm = 5 end if if ( d_2 == 1 ) then algorithm = 3 end if -- 16-bit PICs elsif( d_2 == 3 ) | ( d_2 == 6 ) then algorithm = 12 target_program_start single_panel target_send_20( 0b_0000, 0x8E, 0xA6 ) target_send_20( 0b_0000, 0x8C, 0xA6 ) target_set_address( 0x30, 0x00, 0x00 ) default_delay = 10 if d_2 == 6 then read_block_size = 8 end if else response = "?" end if -- erase chip elsif d_1 == 0x0E then -- old 14-bit PICs chip erase sequence if d_2 == 0 then target_program_start -- remove protection target_send_6( 0x00 ) target_send_14( 0x3F, 0xFF ) for 7 loop target_send_6( 0x06 ) end loop target_send_6( 0x01 ) target_send_6( 0x07 ) target_send_6( 0x08 ) target_wait_ms( 10 ) target_send_6( 0x01 ) target_send_6( 0x07 ) -- erase data target_reset target_send_6( 0x03 ) target_send_14( 0x00, 0xFF ) target_send_6( 0x08 ) target_wait_ms( 10 ) target_send_6( 0x0B ) target_send_6( 0x08 ) target_wait_ms( 10 ) -- new 14-bit PICs chip erase sequence (16f7x) elsif d_2 == 1 then target_program_start target_send_6( 0b_1001 ) target_wait_ms( 40 ) -- new 14-bit PICs chip erase sequence (16f87xA, 16f81x) elsif ( d_2 == 2 ) | ( d_2 == 7 ) then target_program_start -- select config memory to do full erase target_send_6( 0x00 ) target_send_14( 0x00, 0x00 ) target_send_6( 0b_11111 ) target_wait_ms( 5 ) -- new 14-bit PICs chip erase sequence (12f628/675, 16f630/676) elsif d_2 == 4 then target_program_start -- configuration target_send_6( 0b_0000 ) target_send_14( 0x3F, 0xFF ) -- for 0 loop -- target_send_6( 0x06 ) -- end loop -- target_send_6( 0b_1001 ) -- target_wait_ms( 10 ) -- code target_send_6( 0b_1001 ) target_wait_ms( 10 ) -- data target_send_6( 0b_1011 ) target_wait_ms( 10 ) -- 16-bit PICs elsif( d_2 == 3 ) then target_program_start -- 18FXX2 programming manual, p7 target_set_address( 0x3C, 0x00, 0x04 ) target_send_20( 0b_1100, 0x00, 0x80 ) target_send_20( 0b_0000, 0x00, 0x00 ) target_send(0b_0000, 4) target_wait_ms( 6 ) target_send(0, 16) else response = "?" end if else response = "?" end if if programming_delay == 0 then programming_delay = default_delay end if -- for debugging only if false then uart_send( hex_to_ascii( programming_delay >> 4 )) uart_send( hex_to_ascii( programming_delay & 0x0F )) end if -- also for debugging (for checking the delay timing) if false then aux_1_pin_direction = output forever loop aux_1_pin = on target_wait_100us( 1 ) aux_1_pin = off target_wait_100us( 2 ) aux_1_pin = on target_wait_100us( 4 ) aux_1_pin = off target_wait_100us( 8 ) end loop end if end procedure procedure command_increment is if algorithm < 10 then response = cmd target_send_6( 0x06 ) address_increment( 1 ) else response = "?" end if end procedure procedure command_read_14( byte in read_cmd ) is var byte dummy target_send_6( read_cmd ) dummy = target_receive( 1 ) d20 = target_receive_ascii( 4 ) d19 = target_receive_ascii( 4 ) d18 = target_receive_ascii( 4 ) d17 = target_receive_ascii( 2 ) dummy = target_receive( 1 ) end procedure procedure command_read is var byte adjust = 16 response = cmd if algorithm >= 10 then adjust = 18 end if for read_block_size loop -- 14-bit PICs code if ( algorithm == 1 ) | ( algorithm == 3 ) | ( algorithm == 5 ) | ( algorithm == 7 ) then command_read_14( 0x04 ) if read_block_size > 1 then command_increment end if shift( 4 ) adjust = adjust - 4 -- 14-bit PICs data elsif ( algorithm == 2 ) | ( algorithm == 4 ) | ( algorithm == 6 )then command_read_14( 0x05 ) d17 = "0" d18 = "0" shift( 4 ) adjust = adjust - 4 -- 16 bit core PICs (single byte) flash read elsif ( algorithm == 10 ) | ( algorithm == 12 ) then -- target_load_address -- wovo var byte d = target_read_byte( 0b_1001 ) d19 = hex_to_ascii( d >> 4 ) d20 = hex_to_ascii( d & 0x0F ) address_increment( 1 ) shift( 2 ) adjust = adjust - 2 -- 16 bit core PICs (single byte) data eeprom read elsif algorithm == 11 then -- PIC18FXX2 programming manual, p19 target_send_20( 0b_0000, 0x0E, address_l ) target_send_20( 0b_0000, 0x6E, 0xA9 ) target_send_20( 0b_0000, 0x80, 0xA6 ) target_send_20( 0b_0000, 0x50, 0xA8 ) target_send_20( 0b_0000, 0x6E, 0xF5 ) var byte d = target_read_byte( 0b_0010 ) d19 = hex_to_ascii( d >> 4 ) d20 = hex_to_ascii( d & 0x0F ) address_increment( 1 ) shift( 2 ) adjust = adjust - 2 else response = "?" end if end loop shift( adjust ) end procedure procedure command_write_14( byte in write_cmd, byte in read_cmd, byte in start_cmd, byte in stop_cmd ) is -- write target_send_6( write_cmd ) target_send( 0, 1 ) target_send( d_1, 4 ) target_send( d_2, 4 ) target_send( d_3, 4 ) target_send( d_4, 2 ) target_send( 0, 1 ) target_send_6( start_cmd ) target_wait_100us( programming_delay ) if stop_cmd != 0 then target_send_6( stop_cmd ) end if -- read back var byte dummy target_send_6( read_cmd ) dummy = target_receive( 1 ) d1 = target_receive( 4 ) d2 = target_receive( 4 ) d3 = target_receive( 4 ) d4 = target_receive( 2 ) dummy = target_receive( 1 ) -- check if algorithm == 1 then if ( d_3 != d3 ) | ( d_4 != d4 ) then response = "?" end if end if if ( d_2 != d2 ) | ( d_2 != d2 ) then response = "?" end if -- for debugging only if false then if response == "?" then uart_send( hex_to_ascii( d1 & 0x0F )) uart_send( hex_to_ascii( d2 & 0x0F )) uart_send( hex_to_ascii( d3 & 0x0F )) uart_send( hex_to_ascii( d4 & 0x0F )) end if end if end procedure procedure command_write is response = cmd -- old 14-bit PICs code/configuration if algorithm == 1 then command_write_14( 0x02, 0x04, 0x08, 0 ) elsif algorithm == 2 then command_write_14( 0x03, 0x05, 0x08, 0 ) elsif algorithm == 3 then command_write_14( 0x02, 0x04, 0x08, 0x0E ) elsif algorithm == 4 then -- 16f7x do not have a data eeprom... response = "?" elsif algorithm == 5 then command_write_14( 0x02, 0x04, 0b_11000, 0b_10111 ) elsif algorithm == 6 then command_write_14( 0x03, 0x05, 0b_11000, 0b_10111 ) elsif algorithm == 7 then var byte n = 4 while n > 0 loop n = n - 1 -- load target_send_6( 0b_00010 ) target_send( 0, 1 ) target_send( d8, 4 ) target_send( d7, 4 ) target_send( d6, 4 ) target_send( d5, 2 ) target_send( 0, 1 ) -- increment if n > 0 then target_send_6( 0b_00110 ) end if -- shift d5 = d9 d9 = d13 d13 = d17 d6 = d10 d10 = d14 d14 = d18 d7 = d11 d11 = d15 d15 = d19 d8 = d12 d12 = d16 d16 = d20 end loop -- program target_send_6( 0b_11000 ) target_wait_100us( programming_delay ) target_send_6( 0b_10111 ) -- increment target_send_6( 0b_00110 ) -- update current address address_increment( 4 ) -- 16 bit core PICs (single pane, 8 byte) flash write elsif algorithm == 10 then target_load_address target_send_20( 0b_1101, ( d7 << 4 ) + d8, ( d5 << 4 ) + d6 ) target_send_20( 0b_1101, ( d11 << 4 ) + d12, ( d9 << 4 ) + d10 ) target_send_20( 0b_1101, ( d15 << 4 ) + d16, ( d13 << 4 ) + d14 ) target_send_20( 0b_1111, ( d19 << 4 ) + d20, ( d17 << 4 ) + d18 ) target_program_pic18 address_increment( 8 ) -- 16 bit core PICs (single byte) data eeprom write elsif algorithm == 11 then -- PIC18FXX2 programming manual, p15 target_send_20( 0b_0000, 0x0E, address_l ) target_send_20( 0b_0000, 0x6E, 0xA9 ) target_send_20( 0b_0000, 0x0E, ( d_2 << 4 ) + d_1 ) target_send_20( 0b_0000, 0x6E, 0xA8 ) target_send_20( 0b_0000, 0x84, 0xA6 ) target_send_20( 0b_0000, 0x0E, 0x55 ) target_send_20( 0b_0000, 0x6E, 0xA7 ) target_send_20( 0b_0000, 0x0E, 0xAA ) target_send_20( 0b_0000, 0x6E, 0xA7 ) target_send_20( 0b_0000, 0x82, 0xA6 ) target_send_20( 0b_0000, 0x00, 0x00 ) target_send( 0b_0000, 4) target_wait_ms( 6 ) target_send( 0b_0000, 16) target_send_20( 0b_0000, 0x94, 0xA6 ) address_increment( 1 ) -- 16 bit core PICs (single byte) configuration fuses write elsif algorithm == 12 then target_load_address -- PIC18FXX2 programming manual, p17 -- note: duplicates data byte in LSB and MSB var byte d = ( d_2 << 4 ) + d_1 target_send_20( 0b_1111, d, d ) target_program_pic18 address_increment( 1 ) else response = "?" end if end procedure procedure command_lazy_write is command_write end procedure procedure command_jump is response = cmd if algorithm < 10 then while ( address_h != (( d_6 << 4 ) + d_5 )) | ( address_m != (( d_4 << 4 ) + d_3 )) | ( address_l != (( d_2 << 4 ) + d_1 )) loop command_increment end loop elsif ( algorithm == 10 ) | ( algorithm == 11 ) | ( algorithm == 12 ) then target_set_address( ( d_6 << 4 ) + d_5, ( d_4 << 4 ) + d_3, ( d_2 << 4 ) + d_1 ) else response = "?" end if end procedure -- -------------------------------------------------------------------------- -- -- passthrough -- -- -------------------------------------------------------------------------- procedure passthrough_start is uart_disable target_run end procedure procedure passthrough_b6t is var byte count1, count2 data_pin_direction = input clock_pin_direction = output forever loop clock_pin = ! async_in_pin async_out_pin = ! data_pin if async_in_pin == high then count2 = 0 end if count1 = count1 + 1 if count1 == 0 then count2 = count2 + 1 if count2 == 80 then return end if end if end loop end procedure procedure passthrough_b6i is var byte count1, count2 data_pin_direction = input clock_pin_direction = output forever loop clock_pin = async_in_pin async_out_pin = data_pin if async_in_pin == high then count2 = 0 end if count1 = count1 + 1 if count1 == 0 then count2 = count2 + 1 if count2 == 80 then return end if end if end loop end procedure procedure passthrough_auxt is var byte count1, count2 aux_1_pin_direction = output aux_2_pin_direction = input forever loop aux_1_pin = ! async_in_pin async_out_pin = ! aux_2_pin if async_in_pin == high then count2 = 0 end if count1 = count1 + 1 if count1 == 0 then count2 = count2 + 1 if count2 == 80 then return end if end if end loop end procedure procedure passthrough_auxi is var byte count1, count2 aux_1_pin_direction = output aux_2_pin_direction = input forever loop aux_1_pin = async_in_pin async_out_pin = aux_2_pin if async_in_pin == high then count2 = 0 end if count1 = count1 + 1 if count1 == 0 then count2 = count2 + 1 if count2 == 80 then return end if end if end loop end procedure procedure command_passthrough is if d_1 == 0 then passthrough_start passthrough_b6t elsif d_1 == 1 then passthrough_start passthrough_b6i elsif d_1 == 2 then passthrough_start passthrough_auxt elsif d_1 == 3 then passthrough_start passthrough_auxi elsif d_1 == 4 then uart_send( cmd ) -- wait for transmission to complete target_wait_ms( 20 ) if d_2 == 0 then uart_init( 129 ) return elsif d_2 == 1 then uart_init( 64 ) return elsif d_2 == 2 then uart_init( 32 ) return elsif d_2 == 3 then uart_init( 21 ) return elsif d_2 == 4 then uart_init( 10 ) return else response = "?" return end if else response = "?" return end if aux_1_pin_direction = input uart_init end procedure -- -------------------------------------------------------------------------- -- -- WBus commands: hello, name, query, version, burn, next -- -- -------------------------------------------------------------------------- procedure command_hello is response = cmd end procedure procedure command_name is response = cmd d1 = " " d2 = "W" d3 = "i" d4 = "s" d5 = "p" d6 = "6" d7 = "2" d8 = "8" d9 = " " end procedure procedure command_query is response = cmd end procedure procedure command_version is response = cmd -- current version is 1.09 d1 = " " d2 = "1" d3 = "." d4 = "0" d5 = "9" d6 = " " end procedure procedure command_next is response = d0 end procedure procedure command_go is target_program_stop_and_reset target_run response = cmd end procedure procedure command_unknown is response = "?" end procedure -- -------------------------------------------------------------------------- -- -- initialisation and main loop -- -- -------------------------------------------------------------------------- var volatile byte CMCON at 0x1F CMCON = 0x07 -- disable port a analog functions reset_pin = off -- disable reset clock_pin_direction = input reset_pin_direction = output dummy_1_pin_direction = output dummy_2_pin_direction = output dummy_3_pin_direction = output dummy_4_pin_direction = output pump_1_pin_direction = input pump_2_pin_direction = input aux_2_pin_direction = input data_pin_direction = input aux_1_pin_direction = input pulldown_pin_direction = input uart_init -- blink the pulldown to show that the programmer is alive -- pull only down, not up pulldown_pin = low pulldown_pin_direction = output for 2 loop pulldown_pin_direction = output delay_100ms pulldown_pin_direction = input delay_100ms end loop forever loop while ! uart_char_available loop fast_pump_cycle end loop received = uart_received_char & 0b0111_1111 cmd = to_uppercase( received ) response = "#" -- for debugging if cmd <= "F" then response = cmd elsif cmd == "G" then command_go elsif cmd == "H" then command_hello elsif cmd == "I" then command_increment elsif cmd == "J" then command_jump elsif cmd == "K" then command_unknown elsif cmd == "L" then command_lazy_write elsif cmd == "M" then command_jump elsif cmd == "N" then command_next elsif cmd == "P" then command_passthrough elsif cmd == "Q" then command_query elsif cmd == "R" then command_read elsif cmd == "S" then command_unknown elsif cmd == "T" then command_name elsif cmd == "V" then command_version elsif cmd == "W" then command_write elsif cmd == "X" then command_program else command_unknown end if shift( 1 ) d20 = ascii_to_hex( cmd ) uart_send( response ) end loop