diff -u picprog-1.7/hexfile.cc picprog-1.7-slow-test/hexfile.cc --- picprog-1.7/hexfile.cc 2004-04-29 06:08:48.000000000 +0200 +++ picprog-1.7-slow-test/hexfile.cc 2005-08-03 04:09:26.000000000 +0200 @@ -909,7 +909,7 @@ } { - picport pic (port); + picport pic (port, NULL); // As PIC18 parts never have prog_preserved, it does not have to // be tested here. @@ -1291,7 +1291,7 @@ } { - picport pic (port); + picport pic (port, NULL); int e; if (0 == deviceinfo [dev].prog_size) { @@ -1386,7 +1386,7 @@ { if (-1 == d) { // Read version information off the chip at address 0x2006 - picport pic (port); + picport pic (port, NULL); pic.command (picport::load_conf, 0); for (int i = 0; i < 6; ++i) pic.command (picport::inc_addr); diff -u picprog-1.7/main.cc picprog-1.7-slow-test/main.cc --- picprog-1.7/main.cc 2004-04-29 06:41:25.000000000 +0200 +++ picprog-1.7-slow-test/main.cc 2005-08-15 12:23:14.000809818 +0200 @@ -36,12 +36,13 @@ #include "hexfile.h" #include "program.h" +#include "picport.h" using namespace std; program prog; -char short_opts [] = "d:p:i:o:c:qh?"; +char short_opts [] = "d:p:i:o:c:qsh?"; int main (int argc, char **argv) @@ -61,6 +62,10 @@ int opt_burn = 0; int opt_calibration = 0; + int opt_testvpp = 0; + int opt_testrb6 = 0; + int opt_testrb7 = 0; + // Auto ident (-1) is the default, or if that fails, first device (0) int opt_device = -1; @@ -81,6 +86,10 @@ {"erase", no_argument, &opt_erase, 1}, {"burn", no_argument, &opt_burn, 1}, {"force-calibration", no_argument, &opt_calibration, 1}, + {"slow", no_argument, NULL, 's'}, + {"test-vpp", no_argument, &opt_testvpp, 1}, + {"test-rb6", no_argument, &opt_testrb6, 1}, + {"test-rb7", no_argument, &opt_testrb7, 1}, {0, 0, 0, 0} }; @@ -113,6 +122,12 @@ case 'q': opt_quiet = 1; break; + case 's': + // Add extra delays for capacity added by very long cable + picport::t_edge = 10; // 10 us + picport::t_on = 200000; // 200 ms + picport::t_off = 700000; // 700 ms - I'm not kidding ! + break; default: // -? -h --help unknown flag opt_usage = 1; } @@ -149,8 +164,8 @@ if (opt_warranty || opt_copying || opt_usage) return EX_OK; - if (!opt_input && !opt_output && !opt_erase) { - cerr << "Please specify either input or output hexfile or --erase option." + if (!opt_input && !opt_output && !opt_erase && !opt_testvpp && !opt_testrb6 && !opt_testrb7) { + cerr << "Please specify either input or output hexfile, --erase or --test* option." << endl; prog.usage (long_opts, short_opts); } @@ -160,6 +175,25 @@ prog.usage (long_opts, short_opts); } + if ((opt_testvpp || opt_testrb6 || opt_testrb7) && (opt_input || opt_erase || opt_output)) { + cerr << "Can't do hardware testing while burning, reading or erasing." << endl; + prog.usage (long_opts, short_opts); + } + + /* Hardware testing */ + if ((opt_testvpp || opt_testrb6 || opt_testrb7)) { + bool testing[3]; + char input[100]; + testing[picport::TEST_VPP] = opt_testvpp; + testing[picport::TEST_RB6] = opt_testrb6; + testing[picport::TEST_RB7] = opt_testrb7; + + picport port(opt_port, testing); + cout << endl << "Enabled outputs:" << (opt_testvpp?" VPP":"") << (opt_testrb6?" RB6":"") << (opt_testrb7?" RB7":"") << endl; + cout << "Press enter to quit."; + cin.getline(input, 100); /* Is there a nicer way to do this in cpp? */ + } + // if both input and output files are specified, first program the device // and then read it. diff -u picprog-1.7/picport.cc picprog-1.7-slow-test/picport.cc --- picprog-1.7/picport.cc 2004-04-29 06:08:10.000000000 +0200 +++ picprog-1.7-slow-test/picport.cc 2005-08-03 04:19:54.000000000 +0200 @@ -54,6 +54,11 @@ unsigned int picport::tsc_1000ns = 0; int picport::use_nanosleep = -1; +// Extra delays for long cables, in us +int picport::t_on = 0; +int picport::t_off = 0; +int picport::t_edge = 0; + void picport::set_clock_data (int rts, int dtr) { @@ -75,7 +80,7 @@ } } -picport::picport (const char *tty) +picport::picport (const char *tty, bool* testing) : addr (0), debug_on (0), W(0) { portname = new char [strlen (tty) + 1]; @@ -102,7 +107,7 @@ // Before first call to set_clock_data, read the modem status. ioctl (fd, TIOCMGET, &modembits); set_clock_data (0, 0); - usleep (50); + usleep (50+t_edge); // Check the CTS. If it is up, even when we just lowered DTR, // we probably are not talking to a JDM type programmer. int i; @@ -192,21 +197,43 @@ cout << "CPU clock speed: " << tsc_1000ns << " MHz" << endl; } #endif - - if (0 > ioctl (fd, TIOCSBRK, 0)) { - int e = errno; + + if (testing) { + set_vpp(testing[TEST_VPP]); + set_clock_data(testing[TEST_RB6], testing[TEST_RB7]); + } else { + set_vpp (1); + } + usleep (10+t_off); +} + +/* + * Sets Vpp on or off (value is non-zero or zero resp.). + */ +void +picport::set_vpp (int value) +{ + /* Setting the break bit sends a stream of zeroes, meaning a continuous + * stream of high voltage on TxD */ + if (value) { + if (0 > ioctl (fd, TIOCSBRK, 0)) { + /* Hmm, failed. Maybe driver doesn't support it... */ + int e = errno; + /* Clear the bit before quitting */ + ioctl (fd, TIOCCBRK, 0); + tcsetattr (fd, TCSANOW, &saved); + cerr << "Unable to start break (== Vpp/MCLR on programmer) on tty " << portname << ":" << strerror (e) << endl; + exit (EX_IOERR); + } + } else { ioctl (fd, TIOCCBRK, 0); - tcsetattr (fd, TCSANOW, &saved); - cerr << "Unable to start break on tty " << tty << ":" << strerror (e) << endl; - exit (EX_IOERR); } - usleep (10); } picport::~picport () { - ioctl (fd, TIOCCBRK, 0); - usleep (1); + set_vpp(0); + usleep (1+t_off); tcsetattr (fd, TCSANOW, &saved); close (fd); delete [] portname; @@ -216,15 +243,15 @@ { set_clock_data (0, 0); ioctl (fd, TIOCCBRK, 0); - usleep (50); + usleep (50+t_off); ioctl (fd, TIOCSBRK, 0); - usleep (10); + usleep (10+t_on); addr = 0; } void picport::delay (long ns) { - if (1 == use_nanosleep) { + if (1 == use_nanosleep && !t_edge) { timespec ts = {ns / 1000000000, ns % 1000000000}, ts2; while (nanosleep (&ts, &ts2) && EINTR == errno) ts = ts2; @@ -232,7 +259,7 @@ } #ifdef RDTSC_WORKS - if (tsc_1000ns > 1) { + if (tsc_1000ns > 1 && !t_edge) { unsigned long a1, d1, a2, d2; asm volatile("rdtsc":"=a" (a1), "=d" (d1)); d2 = d1; @@ -259,10 +286,10 @@ volatile int i; gettimeofday (&tv1, 0); tv2.tv_sec = tv1.tv_sec; - tv2.tv_usec = 0xffffffff & (tv1.tv_usec + 1 + (ns + 999)/1000); + tv2.tv_usec = 0xffffffff & (tv1.tv_usec + 1 + (ns + 999)/1000+t_edge); if (tv2.tv_usec < tv1.tv_usec) tv2.tv_sec++; - for (i = 0; i < 10000; i++) { + for (i = 0; i < 10000 || t_edge; i++) { gettimeofday (&tv1, 0); if (tv1.tv_sec > tv2.tv_sec || tv1.tv_sec == tv2.tv_sec && tv1.tv_usec >= tv2.tv_usec) diff -u picprog-1.7/picport.h picprog-1.7-slow-test/picport.h --- picprog-1.7/picport.h 2004-04-29 06:09:38.000000000 +0200 +++ picprog-1.7-slow-test/picport.h 2005-08-03 04:08:41.000000000 +0200 @@ -46,6 +46,7 @@ int modembits; void picport::set_clock_data (int rts, int dtr); + void picport::set_vpp(int value); void p_out (int b); int p_in (); @@ -59,6 +60,10 @@ public: + static int t_on; + static int t_off; + static int t_edge; + static void delay (long ns); enum commands { @@ -87,8 +92,22 @@ // Flag for erase delay nop_erase = 0200, }; - - picport (const char *tty); + + /* + * testing is either NULL for normal mode, or an array of 3 elements for + * testing mode. Each element of the array represents an output channel, in + * order: vpp, rb6, rb7. True means enabling the channel, false is + * disabling. Note that the vss and vdd channel or not controllable: vdd is + * constant, vss is dependant on either vpp (TxD) or rb6 (RTS) to be low to + * be low. + */ + picport (const char *tty, bool* testing); + + enum testing_indices { + TEST_VPP = 0, + TEST_RB6, + TEST_RB7, + }; ~picport (); diff -u picprog-1.7/picprog.1 picprog-1.7-slow-test/picprog.1 --- picprog-1.7/picprog.1 2004-04-29 06:09:57.000000000 +0200 +++ picprog-1.7-slow-test/picprog.1 2005-08-15 12:22:48.758791712 +0200 @@ -35,7 +35,11 @@ .B \-\-erase .B \-\-burn .B \-\-force\-calibration -.B \-q \-h \-? +.B \-\-test\-vpp +.B \-\-test\-rb6 +.B \-\-test\-rb7 +.B \-\-slow +.B \-q \-s \-h \-? .SH DESCRIPTION See . .SH OPTIONS