gnupic: Re: [gnupic] PICDEM FS USB and Linux tools


Previous by date: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Xiaofan Chen
Next by date: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Nicolas
Previous in thread: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Xiaofan Chen
Next in thread: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Nicolas

Subject: Re: [gnupic] PICDEM FS USB and Linux tools
From: "Xiaofan Chen" ####@####.####
Date: 22 Sep 2007 02:54:50 +0100
Message-Id: <a276da400709211854r51e53e41u2e0cb80d85a3aef8@mail.gmail.com>

On 9/21/07, Rick Bronson ####@####.#### wrote:
> Hi,
>
>   If someone wanted to use Linux tools for uploading a program via USB
> to the PICDEM board what are the suggested tools?  Two I've run across
> are:
>
> 1. picdem.pl (or picdem2.pl which is mentioned but I can't find it)
> 2. fsusb-0.1.11-2.tar.gz
>
>   picdem.pl seems to requre USB.pm, which I can't seem to find for
> debian.  Unless it's the one in Zaptel.
>

I have not used picdem.pl but I happen to have the archive posted
by Ben Dugan before. The author is Alessandro. I have not used it
since fsusb works fine for me.

USB.pm: is it this one?
http://search.cpan.org/~gwadej/Device-USB-0.21/lib/Device/USB.pm

picdem.pl: I notice that attachement does not with GNUPIC
archive. So I will try to posted it here. I tried to find it in
the thread I posted and found the post but the attachement was
gone.
http://www.linuxhacker.org/cgi-bin/ezmlm-cgi?1:aas:6514:laceapkmfbcildembmhb#b


#!/usr/bin/perl -w

use USB;
use IO::File;
#use Data::HexDump ();
#use Data::Dumper;

	use constant READ_VERSION	=> 0x00;
	use constant READ_FLASH		=> 0x01;
	use constant WRITE_FLASH	=> 0x02;
	use constant ERASE_FLASH	=> 0x03;
	use constant READ_EEDATA	=> 0x04;
	use constant WRITE_EEDATA	=> 0x05;
	use constant READ_CONFIG	=> 0x06;
	use constant WRITE_CONFIG	=> 0x07;
	use constant UPDATE_LED		=> 0x32;
	use constant RESET		=> 0xFF;

	my $commands = {

		'dump'		=> [ qw ( userid config eeprom program ) ],
		'erase'		=> [ qw ( userid eeprom program ) ],
		'compare'	=> 'file',
		'reset'		=> undef,
		'fill'		=> undef,
		'write'		=> 'file',
	};

	print "picdem.pl 0.4 - 20050329\n";
	print "Copyright (c) 2005 Tower Technologies, written by Alessandro Zummo,\n";
	print "licensed under the GPL. Feedback to
####@####.####

	# show usage when no args
	help() unless scalar @ARGV;

	# validate commands
	my @cmds = @ARGV;

	while (scalar @cmds)
	{
		my $cmd = shift @cmds;

		# check command
		help("Unknown command: $cmd\n")
			unless grep { $cmd eq $_ } keys %$commands;

		my $what = shift @cmds
			if defined $commands->{$cmd};

		# check command's option (if required)
		help(
			"Unknown option for $cmd: $what\n",
			"Valid options are: ",
			join(',', @{$commands->{$cmd}}), "\n"
		)
		if ref($commands->{$cmd}) eq 'ARRAY'
		and not grep { $what eq $_ } @{$commands->{$cmd}};

		help("Missing filename\n")
			if defined $commands->{$cmd}
			and $commands->{$cmd} eq 'file'
			and not defined $what;
	}

	# the real job

	# init USB

	USB::usb_init();
	USB::usb_find_busses();
	USB::usb_find_devices();

	# Search for 0x04D8/0x000B

	my $device = picdem_find(0x04D8, 0x00B);

	die "Couldn't find PICDEM FS USB\n"
		unless defined $device;

	print "PICDEM FS USB found\n";

	# open and setup
	my $handle = USB::usb_open($device);

	USB::usb_set_configuration($handle, 1);
	USB::usb_claim_interface($handle, 0);

	# led on
	picdem_update_led($handle, 4, 1);

	# banner
	my ($maj, $min) = picdem_version($handle);
	print "bootloader version $maj.$min\n\n";


	my $cmd = '';

	while (scalar @ARGV)
	{
		$cmd = shift;
		my $what = shift
			if defined $commands->{$cmd};

		job($handle, $cmd, $what);
	}

	# leds off, we have finished.

	if ($cmd ne 'reset')
	{
		picdem_update_led($handle, 3, 0);
		picdem_update_led($handle, 4, 0);
	}

	USB::usb_release_interface($handle, 0);
	USB::usb_close($handle);

	print "done.\n";

sub job
{
	my ($handle, $cmd, $what) = @_;

	# handle commands

	if ($cmd eq 'dump')
	{
		print "dumping $what\n";

		picdem_read_userid($handle)	if $what eq 'userid';
		picdem_read_config($handle)	if $what eq 'config';
		picdem_read_eeprom($handle)	if $what eq 'eeprom';
		picdem_read_flash($handle)	if $what eq 'program';
	}

	if ($cmd eq 'erase')
	{
		print "erasing $what\n";

		picdem_erase_eeprom($handle)	if $what eq 'eeprom';
		picdem_erase_flash($handle)	if $what eq 'program';
		picdem_erase_block($handle, 0x00200000, 1)
						if $what eq 'userid';
	}

	if ($cmd eq 'write')
	{
		my $data = load_inhx32($what);

		print "writing\n";
		picdem_write_flash($handle, $data);

		print "comparing\n";
		picdem_compare_flash($handle, $data);
	}

	picdem_compare_flash($handle, load_inhx32($what))
					if $cmd eq 'compare';

	picdem_reset($handle)		if $cmd eq 'reset';
	picdem_fill($handle)		if $cmd eq 'fill';
}

sub help
{
	print @_;

	print "\nUsage:\n\n";

	foreach (sort keys %$commands)
	{
		print "$_\t[", join(',', @{$commands->{$_}}), "]\n"
			if defined $commands->{$_} and ref($commands->{$_}) eq 'ARRAY';

		print "$_\t<inhx32 file name>\n"
			if defined $commands->{$_} and $commands->{$_} eq 'file';

		print "$_\n"
			if not defined $commands->{$_};
	}

	exit;
}


sub picdem_find
{
	my ($vid, $pid) = @_;

	my $bus = &USB::get_usb_busses();

	do
	{
		my $device = &USB::get_usb_devices($bus);

		do
		{
			my $desc = USB::get_usb_device_descriptor($device);	

			return $device
				if $desc->{'idVendor'} == $vid
				and $desc->{'idProduct'} == $pid;
		}
		while ($device = USB::get_usb_next_device($device));

	}
	while ($bus = USB::get_usb_next_bus($bus));

	return undef;
}



sub do_cmd
{
	my ($handle, $command, @data) = @_;

	my ($out, $len) = encode($command, @data);
	my $in = 0xFF x 64;

#	print ">>> $len\n";
#	dump_buffer($out);

	my $num = USB::usb_bulk_write($handle, 0x01, $out, $len, 300);

	die "usb_bulk_write: $!\n"
		if $num < 0;

	$num = USB::usb_bulk_read($handle, 0x81, $in, 64, 1000);

	die "usb_bulk_read: $!\n"
		if $num < 0;

#	print "<<< $num\n";
#	dump_buffer(substr($in, 0, $num));

	@data = unpack('C*', substr($in, 0, $num));

	return \@data;
}

sub encode
{
	my ($command, @data) = @_;

	my $raw = pack('C*', $command, @data);

	return ($raw, length($raw));
}
	
sub dump_buffer
{
	my ($buffer) = @_;

	my ($cmd, $len, $addr1, $addr2, $addr3, $data)  = unpack('C C C C C
a*', $buffer);

#	printf "CMD: %02x\n", $cmd;
#	printf "LEN: %02x\n", $len;

	print Data::HexDump::HexDump($buffer);

	print "\n";
}

sub picdem_version
{
	my ($handle) = @_;

	my $data = do_cmd($handle, READ_VERSION);	

	return ($data->[3], $data->[2]);
}

sub picdem_reset
{
	my ($handle) = @_;

	do_cmd($handle, RESET);
}

sub picdem_update_led
{
	my ($handle, $led, $status) = @_;

	my $data = do_cmd($handle, UPDATE_LED, $led, $status);
}

sub picdem_read_config
{
	my ($handle) = @_;

	my $cfg1 = do_cmd($handle, READ_CONFIG, 14, 0x00, 0x00, 0x30);
	my $cfg2 = do_cmd($handle, READ_CONFIG, 2, 0xFE, 0xFF, 0x3F);

	$cfg1 = join ' ', map { sprintf "%02X", $_ } splice @$cfg1, 5;

	print "\n";
	printf "300000: %s\n", $cfg1;
	printf "3000FE: %02X\n", $cfg2->[5];
	printf "3000FF: %02X\n", $cfg2->[6];
	print "\n";
}

sub picdem_read_userid
{
	my ($handle) = @_;

	my $uid = do_cmd($handle, READ_CONFIG, 8, 0x00, 0x00, 0x20);

	$uid = join ' ', map { sprintf "%02X", $_ } splice @$uid, 5;

	print "\n";
	print "200000: $uid\n";
	print "\n";
}

sub picdem_read_eeprom
{
	my ($handle) = @_;

	print "\n";

	for (my $i = 0; $i < 0xFF; $i += 16)
	{
		my $mem = do_cmd($handle, READ_EEDATA, 16, 0x00, 0x00, $i);

		$mem = join ' ', map { sprintf "%02X", $_ } splice @$mem, 5;

		printf "0000%02X: $mem\n", $i;
	}

	print "\n";
}

sub picdem_erase_eeprom
{
	my ($handle) = @_;

	for (my $i = 0; $i < 0xFF; $i += 16)
	{
		do_cmd($handle, WRITE_EEDATA, 16, 0x00, 0x00, $i, (0xFF) x 16);
	}
}

sub mkpicaddr
{
	my $addr = $_[0];

	return	(
		($addr & 0x0000FF),
		(($addr & 0x00FF00) >> 8),
		(($addr & 0xFF0000) >> 16),
	);
}


sub picdem_read_flash
{
	my ($handle) = @_;

	print "program:\n";

	for (my $i = 0; $i < 0x007FFF; $i += 16)
	{
		my @addr = mkpicaddr($i);

		my $mem = do_cmd($handle, READ_FLASH, 16, @addr);

		$mem = join ' ', map { sprintf "%02X", $_ } splice @$mem, 5;

		printf "%02X%02X%02X: $mem\n", $addr[2], $addr[1], $addr[0];
	}

	print "\n";
}

# erases $count 64-byte blocks starting @ $addr

sub picdem_erase_block
{
	my ($handle, $addr, $count) = @_;

	do_cmd($handle, ERASE_FLASH, $count, mkpicaddr($addr));
}

sub picdem_erase_flash
{
	my ($handle) = @_;

#	optimized but not working.. (??)
#	picdem_erase_block($handle, 0x00000800, 0xE0);
#	picdem_erase_block($handle, 0x00004000, 0xFF);

	for (my $i = 0x800; $i < 0x7FFF; $i += 64)
	{
		picdem_erase_block($handle, $i, 1);
	}
}

sub picdem_compare_flash
{
	my ($handle, $data) = @_;

	my $errors = 0;

	foreach my $addr (sort keys %{$data->{'addr'}})
	{
		next unless $addr >= 0x800;

		my @addr = mkpicaddr($addr);
		my @data = unpack('C*', $data->{'addr'}{$addr}{'data'});
		my $len = scalar @data;

		my $mem = do_cmd($handle, READ_FLASH, scalar @data, @addr);

		for (my $i = 0; $i < $len; $i++)
		{
			printf "mismatch #%d @ %08X: wanted %02X, read %02X\n",
				++$errors,
				$addr + $i,
				$data[$i],
				$mem->[5 + $i]
			if $data[$i] != $mem->[5 + $i];
		}
	}

	print "comparing succesful\n"
		unless $errors > 0;
}

sub picdem_write_flash
{
	my ($handle, $data) = @_;

	my $i = 0;

	foreach my $addr (sort keys %{$data->{'addr'}})
	{
		next unless $addr >= 0x800;

		my @addr = mkpicaddr($addr);
		my @data = unpack('C*', $data->{'addr'}{$addr}{'data'});

		my $len = scalar @data;

		die "picdem_write_flash: max 16 bytes\n"
			if $len > 16;

		# check data is at 16 bytes boundary

		if ($addr & 0x0000000F)
		{
			my $block = $addr & 0xFFFFFFF0;

			#printf "fixing boundary: %08X %08X %d\n", $addr, $block, $len;

			@data = ((0xFF) x ($addr - $block), @data);

			$len = scalar @data;
			$addr = $block;
		}

		# picdem seems to only accept 16 bytes packets. We extend
		# the packet with 0xFF. It will not hurt.
		push(@data, (0xFF) x (16 - $len))
			if $len < 16;

		#printf "programming %08X\n", $addr;

		do_cmd($handle, WRITE_FLASH,
			16,
			mkpicaddr($addr),
			@data
		);

		$i++;
	}

	print "programmed $i locations\n";
}

sub picdem_fill
{
	my ($handle) = @_;

	print "filling program memory with 0x55AA\n";

	for (my $i = 0x800; $i < 0x7FFF; $i += 16)
	{
		do_cmd($handle, WRITE_FLASH,
			16,
			mkpicaddr($i),
			((0x55, 0xAA) x 8)
		);
	}
}

sub load_inhx32
{
	my ($file) = @_;

	my $fh = new IO::File;

	$fh->open($file, '<:crlf')
		or die "Couldn't open $file: $!\n";

	print "loading $file\n";

	my $high = 0x0000;

	my %data = ();

	while (<$fh>)
	{
		next unless /^:([[:xdigit:]]{2})([[:xdigit:]]{4})([[:xdigit:]]{2})([[:xdigit:]]{0,}?)([[:xdigit:]]{2})$/;

		my ($count, $addr, $type, $data, $checksum) = ($1, $2, $3, $4, $5);

		last if $type == 0x01;	# EOF

		# Extended linear address record
		if ($type == 0x04)
		{
			die "Wrong address in type 0x04, must be 0x000, found $addr\n"
				unless $addr eq '0000';

			$high = (hex($data) << 16);
			next;
		}

		# Extended segment address record
		if ($type == 0x02)
		{
			die "Wrong address in type 0x02, must be 0x000, found $addr\n"
				unless $addr eq '0000';

			$high = (hex($data) << 4);
			next;
		}

		# Data record
		if ($type == 0x00)
		{
			$addr = $high || hex($addr);

#			printf "$count %08X $type $data $checksum\n", $addr;

			$data{'addr'}{$addr}{'data'} = pack('H*', $data);
			$data{'addr'}{$addr}{'length'} = length($data{'addr'}{$addr}{'data'});
			$data{'addr'}{$addr}{'checksum'} = pack('H', $checksum);

			next;
		}

		die "I'm not able to handle INHX32 record type $type\n";

	}

	$fh->close;

#	print Data::Dumper->Dump([\%data]);

	return \%data;
}

Previous by date: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Xiaofan Chen
Next by date: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Nicolas
Previous in thread: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Xiaofan Chen
Next in thread: 22 Sep 2007 02:54:50 +0100 Re: [gnupic] PICDEM FS USB and Linux tools, Nicolas


Powered by ezmlm-browse 0.20.