Copy Link
Add to Bookmark
Report

PIC Challenge Handshake Sequence

xbox's profile picture
Published in 
xbox
 · 20 Feb 2024

written by anonymous, 23 June 2002

Four bytes are read from the PIC, each after 4 special commands are sent. The 4 bytes are then crunched and a two byte result is calculated. These two bytes are sent back to the PIC (aong with special commands), which will disable the CPU reset if they are correct. If the two bytes are incorrect, the CPU will reset. This process must be completed within the first 200ms after power on.

The commands 0x1C,0x1Dh,0x1Eh, and 0x1F are written to address 0x21 (0x20 | 0x01). After each one of these commands, a byte is read back. That byte is called res_1c, res_1d, etc, for "response to 1d" etc. For reasons that are not entirely clear, the address is ORed with a 1 in the sending routine, so that the real address used is 0x21, even though the calling routine sends in 0x20.

This program will take the four PIC bytes on the command line, in order, and return the two response bytes. It has been tested on several PIC outputs and is works correctly.

Here is a sample successful interchange captured on the i2c bus:

10 w: 1C 
10 r: 52 <-- $res_1C
10 w: 1D
10 r: 72 <-- $res_1D
10 w: 1E
10 r: EA <-- $res_1E
10 w: 1F
10 r: 46 <-- $res_1F
10 w: 20 40 <-- 20 $byte1
10 w: 21 7D <-- 21 $byte2
10 w: 01 00 <-- 01 00

E.g., running this program as follows:

$> i2c_crypt.pl 52 72 ea 46 
52 72 ea 46 --> 40 7d

The communications process is as follows (pseudo code):

WRITE COMMAND READ DATA

out 0x21 --> 0xC004 ; address 
out 0x1C --> 0xC008 ; command
in status_byte <-- 0xC000 ; read status
out status_byte --> 0xC000 ; write back status
out 0x0A --> 0xC002 ; control - tests an argument and can send 0x0B if a word command (0x0A = byte command)
; for this sequence the commands are always bytes (0x0A sent)
|---> in status_byte <-- 0xC000 ; read status again
|--- ( status_byte & 0x08 == 1) ; if status & 0x08 == 1 then loop reading status again (busy?)
( status_byte & 0x02 == 1) start over ; collision? go back to top and re-send address and data
( status_byte & 0x20 == 1) exit with error ; sets error code and exits
( status_byte & 0x04 == 1) exit with error ; sets error code and exits
( status_byte & 0x10 != 1) exit with error ; sets error code and exits
in data_word <-- 0xC006 ; read data byte, always a 16-bit read
if (byte command) data_word & 0x00FF; always read 16-bits but clears upper byte if a byte command

The above sequence is sent for commands 0x1C,0x1D,0x1E,0x1F. Each byte read is stored and then crunched per below algorithm. The program below will output two bytes from four bytes on the command line. These two bytes are sent with commands 0x20 and 0x21 followed by command 0x01 and 0x00 data which if correct will disable the CPU reset.The two bytes plus 0 are sent back to the PIC as follows:

WRITE COMMAND WRITE DATA

out 0x20 & 0xFE -->  0xC004 ; address; the lower bit of the address is clipped in this case 
out 0x20 --> 0xC008 ; command
out byte1 --> 0xC006 ; data
in status_byte <-- 0xC000; read status
out status_byte --> 0xC000; write status back
out 0x0A --> 0xC002 ; write 0x0A to control (0x0B if a word but not in this case)
|---> in status_byte <-- 0xC000 ; read status again
|--- ( status_byte & 0x08 == 1) ; if status & 0x08 == 1 then loop reading status again (busy?)
( status_byte & 0x02 == 1) start over ; collision? go back to top and re-send address and data
( status_byte & 0x20 == 1) exit with error ; sets error code and exits
( status_byte & 0x04 == 1) exit with error ; sets error code and exits
( status_byte & 0x10 != 1) exit with error ; sets error code and exits
exit no error

The above is repeated 0x21 and byte2, and 0x01 and data 0x00.
The crunching algorithm is illustrated below:

#!/usr/local/bin/perl 

$res_1c = hex(shift @ARGV) + 0;
$res_1d = hex(shift @ARGV) + 0;
$res_1e = hex(shift @ARGV) + 0;
$res_1f = hex(shift @ARGV) + 0;

printf ("%x %x %x %x ",$res_1c, $res_1d, $res_1e, $res_1f);

$t1 = ($res_1c << 2) ^ ($res_1d + hex('039')) ^ ($res_1e >> 2) ^ ($res_1f + hex('063'));

$t2 = ($res_1c + hex('0b')) ^ ($res_1d >> 2) ^ ($res_1e + hex('1b'));

$byte1 = hex('033');
$byte2 = hex('0ed');

for ( $i=0; $i < 4; $i++ ) {
$byte1 += $byte2 ^ $t1;
$byte2 += $byte1 ^ $t2;
}

$byte1 &= 255;
$byte2 &= 255;

printf ("--> %x %x\n",$byte1, $byte2);

The Perl source code which includes the documentation above is available below.

i2c_crypt.pl

#!/usr/local/bin/perl 
#
# PIC challenge handshake sequence
#----------------------------------------------------------------
# Four bytes are read from the PIC , each after 4 special commands
# are sent. The 4 bytes are then crunched and
# a two byte result is calculated. These two bytes are sent back
# to the PIC (aong with special commands), which will disable the CPU
# reset if they are correct. If the two bytes are incorrect,
# the CPU will reset. This process must be
# completed within the first 200ms after power on.
#
# the commands 0x1C,0x1Dh,0x1Eh, and 0x1F are written to address 0x21 (0x20 | 0x01). After each one of these commands,
# a byte is read back. That byte is called res_1c, res_1d, etc, for "response to 1d" etc.
# For reasons that are not entirely clear, the address is ORed with a 1 in the sending routine,
# so that the real address used is 0x21, even though the calling routine sends in 0x20.
# This program will take the four PIC bytes on the command line, in order, and return the two response
# bytes. It has been tested on several PIC outputs and is works correctly.
#
# Here is a sample successful interchange captured on the i2c bus:
#
# 10 w: 1C
# 10 r: 52 <-- $res_1C
# 10 w: 1D
# 10 r: 72 <-- $res_1D
# 10 w: 1E
# 10 r: EA <-- $res_1E
# 10 w: 1F
# 10 r: 46 <-- $res_1F
# 10 w: 20 40 <-- 20 $byte1
# 10 w: 21 7D <-- 21 $byte2
# 10 w: 01 00 <-- 01 00
#
#
# eg, running this program as follows:
#
# $> i2c_crypt.pl 52 72 ea 46
# 52 72 ea 46 --> 40 7d
#
# The communications process is as follows (pseudo code):
#
#-------------------------------
# WRITE COMMAND READ DATA
#-------------------------------
# out 0x21 --> 0xC004 ; address
# out 0x1C --> 0xC008 ; command
# in status_byte <-- 0xC000 ; read status
# out status_byte --> 0xC000 ; write back status
# out 0x0A --> 0xC002 ; control - tests an argument and can send 0x0B if a word command (0x0A = byte command)
# ; for this sequence the commands are always bytes (0x0A sent)
# |---> in status_byte <-- 0xC000 ; read status again
# |--- ( status_byte & 0x08 == 1) ; if status & 0x08 == 1 then loop reading status again (busy?)
# ( status_byte & 0x02 == 1) start over ; collision? go back to top and re-send address and data
# ( status_byte & 0x20 == 1) exit with error ; sets error code and exits
# ( status_byte & 0x04 == 1) exit with error ; sets error code and exits
# ( status_byte & 0x10 != 1) exit with error ; sets error code and exits
# in data_word <-- 0xC006 ; read data byte, always a 16-bit read
# if (byte command) data_word & 0x00FF; always read 16-bits but clears upper byte if a byte command
#------
#
# the above sequence is sent for commands 0x1C,0x1D,0x1E,0x1F
# each byte read is stored and then crunched per below algorithm
# The program below will output two bytes from four bytes on the command line.
# These two bytes are sent with commands 0x20 and 0x21 followed by command 0x01 and 0x00 data
# which if correct will disable the CPU reset.
#
# the two bytes plus 0 are sent back to the PIC as follows:
#--------------------------------------
# WRITE COMMAND WRITE DATA
#-------------------------------------
# out 0x20 & 0xFE --> 0xC004 ; address; the lower bit of the address is clipped in this case
# out 0x20 --> 0xC008 ; command
# out byte1 --> 0xC006 ; data
# in status_byte <-- 0xC000; read status
# out status_byte --> 0xC000; write status back
# out 0x0A --> 0xC002 ; write 0x0A to control (0x0B if a word but not in this case)
# |---> in status_byte <-- 0xC000 ; read status again
# |--- ( status_byte & 0x08 == 1) ; if status & 0x08 == 1 then loop reading status again (busy?)
# ( status_byte & 0x02 == 1) start over ; collision? go back to top and re-send address and data
# ( status_byte & 0x20 == 1) exit with error ; sets error code and exits
# ( status_byte & 0x04 == 1) exit with error ; sets error code and exits
# ( status_byte & 0x10 != 1) exit with error ; sets error code and exits
# exit no error
# ---------------------
# the above is repeated 0x21 and byte2, and 0x01 and data 0x00.
#
# The crunching algorithm is illustrated below:
#

$res_1c = hex(shift @ARGV) + 0;
$res_1d = hex(shift @ARGV) + 0;
$res_1e = hex(shift @ARGV) + 0;
$res_1f = hex(shift @ARGV) + 0;

printf ("%x %x %x %x ",$res_1c, $res_1d, $res_1e, $res_1f);

$t1 = ($res_1c << 2) ^ ($res_1d + hex('039')) ^ ($res_1e >> 2) ^ ($res_1f + hex('063'));

$t2 = ($res_1c + hex('0b')) ^ ($res_1d >> 2) ^ ($res_1e + hex('1b'));

$byte1 = hex('033');
$byte2 = hex('0ed');

for ( $i=0; $i < 4; $i++ ) {
$byte1 += $byte2 ^ $t1;
$byte2 += $byte1 ^ $t2;
}

$byte1 &= 255;
$byte2 &= 255;

printf ("--> %x %x\n",$byte1, $byte2);

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT