--- /dev/null
+/*! \file dspic33f.c
+
+ \author Scott Livingston
+
+ \brief dsPIC33F programmer application for the GoodFET. Structure
+ and style is somewhat modeled after avr.c
+
+ \date March, April 2010
+*/
+
+
+#include "apps.h"
+#include "platform.h"
+#include "command.h"
+
+#include "dspic33f.h"
+
+
+void pic33f_setup()
+{
+ // Initialize pins; do NOT begin transaction.
+ P5DIR |= PGC|MCLR;
+ P5REN &= ~(PGC|PGD|MCLR);
+ DIR_PGD_WR; // Initially PGD in write mode
+
+ SET_MCLR;
+ CLR_PGC;
+ CLR_PGD;
+
+ prep_timer(); // What better time than now?
+}
+
+
+//! Handle a PIC command; currently assumes dsPIC33F/PIC24H
+void pichandle( unsigned char app,
+ unsigned char verb,
+ unsigned long len )
+{
+ unsigned int nb; // Number of bytes
+ unsigned int highb, loww; // Used for ICSP commands
+
+ switch (verb) {
+
+ case PIC_DEVID33F:
+ nb = pic33f_getid();
+ txdata(app,verb,nb);
+ break;
+
+ case PIC_SIX33F:
+ loww = *cmddata;
+ loww |= (*(cmddata+1)) << 8;
+ highb = *(cmddata+2);
+ pic33f_six( highb, loww );
+ txdata(app,verb,0);
+ break;
+
+ case PIC_SIXLIST33F:
+ pic33f_sixlist( len ); // Reply to host is handled by pic33f_sixlist.
+ break;
+
+ case PIC_REGOUT33F:
+ loww = pic33f_regout();
+ *cmddata = loww & 0xff;
+ *(cmddata+1) = loww >> 8;
+ txdata(app,verb,2);
+ break;
+
+ case PIC_START33F:
+ pic33f_connect();
+ txdata(app,verb,0);
+ break;
+
+ case PIC_STOP33F:
+ pic33f_disconnect();
+ txdata(app,verb,0);
+ break;
+
+ default:
+ debugstr( "Verb unimplemented in PIC application." );
+ txdata(app,NOK,0);
+ break;
+
+ }
+}
+
+
+void pic33f_trans8( unsigned char byte )
+{
+ /* We only twiddle the PGD and PGC lines.
+ MCLR is assumed to be in the correct state. */
+ unsigned int i;
+
+ DIR_PGD_WR; // Write mode
+ i = 1;
+ while (i & 0xff) {
+ if (byte & i) {
+ SET_PGD;
+ } else {
+ CLR_PGD;
+ }
+ delay_ticks(10);
+ SET_PGC;
+ delay_ticks(10);
+
+ CLR_PGC;
+ delay_ticks(10);
+ i = i << 1;
+ }
+ CLR_PGD;
+ DIR_PGD_RD; // Read mode
+}
+
+void pic33f_trans16( unsigned int word )
+{
+ pic33f_trans8( word & 0xff );
+ pic33f_trans8( word >> 8 );
+}
+
+
+void pic33f_six( unsigned int highb, unsigned int loww )
+{
+ /* dsPIC33F/PIC24H instructions have width 24 bits, so we use the
+ lower 8 bits of highb and (all 16 bits of) loww to form the
+ instruction.
+
+ Shift in the instruction. Note that it does not execute until
+ the next 4 clock cycles (which also corresponds to a command
+ receipt time). */
+ unsigned int i;
+ DIR_PGD_WR;
+ CLR_PGD;
+ CLR_PGC;
+ for (i = 0; i < 4; i++) {
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ delay_ticks(10);
+ }
+ pic33f_trans16( loww );
+ pic33f_trans8( highb );
+ DIR_PGD_RD;
+}
+
+
+unsigned int pic33f_regout()
+{
+ unsigned int i;
+ unsigned int result = 0x0000;
+
+ DIR_PGD_WR;
+
+ // Shift in command (REGOUT: 0001b).
+ SET_PGD;
+ delay_ticks(10);
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ delay_ticks(10);
+
+ CLR_PGD;
+ delay_ticks(10);
+ for (i = 0; i < 3; i++) {
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ delay_ticks(10);
+ }
+
+ // Pump clock for 8 cycles, and switch PGD direction to read.
+ for (i = 0; i < 7; i++) {
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ delay_ticks(10);
+ }
+ DIR_PGD_RD;
+
+ /* Now read VISI register (LSb first, as usual).
+ Note that when reading from attached device, data is valid (to
+ be read) on falling clock edges. */
+ for (i = 0; i < 16; i++) {
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ result |= READ_PGD << i;
+ delay_ticks(10);
+ }
+
+ /* One last tick apparently is needed here, at least by the
+ dsPIC33FJ128GP708 chip that I am working with. Note that this
+ is not in the flash programming specs. */
+ SET_PGC;
+ delay_ticks(10);
+ CLR_PGC;
+ delay_ticks(10);
+
+ return result;
+}
+
+
+void pic33f_sixlist( unsigned int list_len )
+{
+ unsigned int k;
+ unsigned int instr_loww;
+
+ // Bound to Rx buffer size.
+ if (list_len > CMDDATALEN)
+ list_len = CMDDATALEN;
+
+ // Run each instruction!
+ for (k = 0; k < list_len-2; k+=3) {
+ instr_loww = *(cmddata+k);
+ instr_loww |= (*(cmddata+k+1)) << 8;
+ pic33f_six( *(cmddata+k+2), instr_loww );
+ }
+
+ // Reply with total number of bytes used from Rx buffer.
+ txdata( PIC, PIC_SIXLIST33F, k );
+}
+
+
+unsigned int pic33f_getid()
+{
+ unsigned int result;
+ unsigned int nb = 0;
+
+ pic33f_connect();
+
+ // Read application ID.
+ pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
+ pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0x20, 0x0800 ); // mov #0x80, W0
+ pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
+ pic33f_six( 0x20, 0x7F00 ); // mov #0x7F0, W0
+ pic33f_six( 0x20, 0x7841 ); // mov #VISI, W1
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0], [W1]
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0x00, 0x0000 ); // nop
+ result = pic33f_regout();
+ *cmddata = result & 0xff;
+ nb += 1;
+
+ // Read DEVID.
+ pic33f_six( 0x20, 0x0FF0 ); // mov #0xFF, W0
+ pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
+ pic33f_six( 0xEB, 0x0000 ); // clr W0
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0xBA, 0x08B0 ); // TBLRDL [W0++], [W1]
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0x00, 0x0000 ); // nop
+ result = pic33f_regout();
+ *(cmddata+1) = result & 0xff;
+ *(cmddata+2) = result >> 8;
+ nb += 2;
+
+ // Read hardware revision.
+ pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0++], [W1]
+ pic33f_six( 0x00, 0x0000 ); // nop
+ pic33f_six( 0x00, 0x0000 ); // nop
+ result = pic33f_regout();
+ *(cmddata+3) = result & 0xff;
+ *(cmddata+4) = result >> 8;
+ nb += 2;
+
+ pic33f_disconnect();
+
+ return nb;
+}
+
+
+void pic33f_connect()
+{
+ unsigned int key_low;
+ unsigned int key_high;
+
+ key_low = ICSP_KEY_LOW;
+ key_high = ICSP_KEY_HIGH;
+
+ pic33f_setup();
+
+ CLR_PGC;
+ delay_us(1);
+
+ CLR_MCLR;
+ delay_ms(3);
+ SET_MCLR;
+ delay_us(200);
+ CLR_MCLR;
+ delay_us(10);
+
+ // Enter ICSP key
+ pic33f_trans8( key_low & 0xff );
+ key_low = key_low >> 8;
+ pic33f_trans8( key_low & 0xff );
+ pic33f_trans8( key_high & 0xff );
+ key_high = key_high >> 8;
+ pic33f_trans8( key_high & 0xff );
+
+ delay_us(1);
+ SET_MCLR; // ...and pull MCLR pin back up.
+ delay_ms(25); // Now wait about 25 ms (required per spec!).
+
+ /* The first ICSP command must be a SIX, and further, 9 bits are
+ required before the instruction (to be executed), rather than
+ the typical 4 bits. Thus, to simplify code, I simply load a nop
+ here; hence 33 bits are shifted into the dsPIC33F/PIC24H. */
+ DIR_PGD_WR;
+ CLR_PGD;
+ CLR_PGC;
+ for (key_low = 0; key_low < 33; key_low++) {
+ SET_PGC;
+ delay_us(1);
+ CLR_PGC;
+ delay_us(1);
+ }
+ DIR_PGD_RD;
+
+}
+
+
+void pic33f_disconnect()
+{
+ DIR_PGD_WR;
+ CLR_PGD;
+ CLR_PGC;
+ delay_ms(10);
+ CLR_MCLR;
+}