ucl 2.0 # Copyright (c) 2006 by Wayne C. Gramlich. # All rights reserved. # This is a boot loader that resides in high memory for # loading programs into low memory. #library $pic16f767 library $pic16f876 library clock20mhz library $uart configure wrt=on # Port and pin definitions: # Port definitions: package pdip pin 1 = mclr pin 2 = ra0_unused pin 3 = ra1_unused pin 4 = ra2_unused pin 5 = ra3_unused pin 6 = ra4_unused pin 7 = ra5_unused pin 8 = ground pin 9 = osc1 pin 10 = osc2 pin 11 = rc0_unused pin 12 = rc1_unused pin 13 = rc2_unused pin 14 = rc3_unused pin 15 = rc4_unused pin 16 = rc5_unused pin 17 = tx pin 18 = rx pin 19 = ground2 pin 20 = power_supply pin 21 = rb0_unused pin 22 = rb1_unused pin 23 = rb2_unused pin 24 = rb3_unused pin 25 = rb4_unused pin 26 = rb5_unused pin 27 = rb6_unused pin 28 = rb7_unused global module_address byte global rx9d bit global id_index byte global address_high byte global address_low byte global count byte global index byte origin 0 procedure main arguments_none returns_nothing local byte_high byte local byte_low byte local command byte local transmit bit local result byte local mode byte module_address := 28 # Warm up the UART: $trisc@7 := $true $trisc@6 := $true $txsta := 0 $tx9 := $true #$tx9 := $false $txen := $true $brgh := $true $rcsta := 0 $spen := $true $rx9 := $true #$rx9 := $false $cren := $true #$adden := $true $adden := $false # Baud rate = 625000 @ 20MHz. $spbrg := 1 mode := 0 id_index := 0 #loop_forever # call $uart_byte_put(command) # loop_exactly 100 # delay 500 # do_nothing # command := command + 1 #loop_forever # command := $uart_byte_get() # call $uart_byte_put(command + 1) # call $uart_byte_get() loop_forever transmit := $false rx9d := $false while !$rcif do_nothing if $rx9d rx9d := $true command := $rcreg if rx9d # We have an address bit: if command = module_address # We have a match: $adden := $false result := 0x5a transmit := $true else # We need to disable non-address reception: $adden := $true mode := 0 else # We have a command: switch mode case 0 # Basic instruction decoding: switch command >> 6 case 0 # 00xx xxxx: switch (command >> 3) & 7 case_maximum 7 case 0 #: 0000 0xxx: switch command & 7 case_maximum 7 case 0 #: 0000 0000 (Set Memory Address): mode := 1 case 1 #: 0000 0001 (Read Program Memory): mode := 3 case 2 #: 0000 0010 (Set Program Memory): mode := 4 case 3 #: 0000 0013 (Execute): $pclath := address_high $pcl := address_low case 3 # 11xx xxxx: switch (command >> 3) & 7 case 7 # 1111 1xxx: switch command & 7 case 4 # 1111 1100 (Address_Set) case 5 # 1111 1101 (Id_Next) transmit := $true result := 0 if id_index < id.size result := id[id_index] id_index := id_index + 1 #result := id_index case 6 # 1111 1110 (Id_Start) id_index := 0 result := 0 transmit := $true case 7 # 1111 1111 (Deselect): result := 0 transmit := $true $adden := $true case 1 # Read Program Memory: Get high address: mode := 2 address_high := command case 2 # Read Program Memory: Get high address: mode := 0 address_low := command result := 0x5b transmit := $true case 3 # Read Program Memory: Get count: mode := 0 count := command # Pump the program memory data back: loop_exactly count $eeadrh := address_high $eeadr := address_low # Read the word: $eepgd := $true $rd := $true # The next two instructions are *ignored*: assemble nop nop # Ship the results back: call $uart_byte_put($eedath) call $uart_byte_get() call $uart_byte_put($eedata) call $uart_byte_get() address_low := address_low + 1 if $z address_high := address_high + 1 result := 0x5c transmit := $true case 4 # Set Program Memory; Get {byte_high}: mode := 5 byte_high := command case 5 # Set Program Memory; Get {byte_low}: mode := 0 byte_low := command # Fry it in: $eedath := byte_high $eedata := byte_low $eeadrh := address_high $eeadr := address_low # Remember to get the WRT bit in the configuration # word set -- "configure wrt=on" # Write the word: $eepgd := $true $wren := $true $eecon2 := 0x55 $eecon2 := 0xaa $wr := $true # The next two instructions are *ignored*: assemble nop nop $wren := $true # Now read it back: # Read the word: $eepgd := $true $rd := $true # The next two instructions are *ignored*: assemble nop nop # Send the result code back: result := 0x5f if $eedath != byte_high result := 0x5e if $eedata != byte_low result := 0x5d transmit := $true # Bump the address: address_low := address_low + 1 if $z address_high := address_high + 1 if transmit transmit := $true # Send the result byte: call $uart_byte_put(result) # Dispose of echoed command in buffer: call $uart_byte_get() string id = "\16,0,28,1,3,14\Controller28-A\7\Gramson"