1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: t -*- */
4 \author Scott Livingston
6 \brief dsPIC33F programmer application for the GoodFET. Structure
7 and style is somewhat modeled after avr.c
18 #define CYCLE_DELAY() delay_ticks(10);
20 //! Handle a PIC command; currently assumes dsPIC33F/PIC24H
21 void pic_handle_fn( uint8_t const app,
25 // define the pic app's app_t
26 app_t const pic_app = {
38 "\tThe PIC app adds support for programming/debugging\n"
39 "\tdsPIC33F based devices.\n"
44 // Initialize pins; do NOT begin transaction.
46 P5REN &= ~(PGC|PGD|MCLR);
47 DIR_PGD_WR; // Initially PGD in write mode
53 prep_timer(); // What better time than now?
57 //! Handle a PIC command; currently assumes dsPIC33F/PIC24H
58 void pic_handle_fn( uint8_t const app,
62 unsigned int nb; // Number of bytes
63 unsigned int highb, loww; // Used for ICSP commands
74 loww |= (*(cmddata+1)) << 8;
76 pic33f_six( highb, loww );
81 pic33f_sixlist( len ); // Reply to host is handled by pic33f_sixlist.
85 loww = pic33f_regout();
86 *cmddata = loww & 0xff;
87 *(cmddata+1) = loww >> 8;
108 pic33f_cmdlist(len); // reply is handled by pic33f_cmdlist
112 debugstr( "Verb unimplemented in PIC application." );
119 void pic33f_transcmd(unsigned char cmd) {
123 for (i = 0; i < 4; i++) {
137 void pic33f_trans8( unsigned char byte )
139 /* We only twiddle the PGD and PGC lines.
140 MCLR is assumed to be in the correct state. */
143 DIR_PGD_WR; // Write mode
144 for (i = 0; i < 8; i++) {
159 DIR_PGD_RD; // Read mode
162 void pic33f_trans16( unsigned int word )
164 pic33f_trans8( word & 0xff );
165 pic33f_trans8( word >> 8 );
169 void pic33f_six( unsigned int highb, unsigned int loww )
171 /* dsPIC33F/PIC24H instructions have width 24 bits, so we use the
172 lower 8 bits of highb and (all 16 bits of) loww to form the
175 Shift in the instruction. Note that it does not execute until
176 the next 4 clock cycles (which also corresponds to a command
179 pic33f_trans16( loww );
180 pic33f_trans8( highb );
185 unsigned int pic33f_regout()
188 unsigned int result = 0x0000;
192 // Shift in command (REGOUT: 0001b).
195 // Pump clock for 8 cycles, and switch PGD direction to read.
196 for (i = 0; i < 7; i++) {
204 /* Now read VISI register (LSb first, as usual).
205 Note that when reading from attached device, data is valid (to
206 be read) on falling clock edges. */
207 for (i = 0; i < 16; i++) {
211 result |= READ_PGD << i;
215 /* One last tick apparently is needed here, at least by the
216 dsPIC33FJ128GP708 chip that I am working with. Note that this
217 is not in the flash programming specs. */
227 void pic33f_cmdlist(unsigned int list_len) {
228 /* commands are written as 4-byte little-endian records, where
229 the low 4 bits of first byte contains the command, and the
230 next three bytes contain the data.
232 Currently this only supports the SIX and REGOUT
235 SIX instructions return no data. REGOUT instructions return
236 the 16-bit value read as two bytes, lower byte first.
238 The final two bytes of the response are the 2's complement
239 inverse of the sum of the response words. i.e., if the
240 response is correctly recieved, the sum of the words should
243 This is sent when the goodfet is done running the command
244 list, and is ready for further commands.
248 unsigned int response_word;
249 unsigned int checksum = 0;
252 list_len &= ~3; // truncate to multiple of 4 bytes.
253 if (list_len > CMDDATALEN)
254 list_len = CMDDATALEN;
256 for (i = 0; i < list_len; i += 4) {
265 txhead(PIC, PIC_CMDLIST, response_count << 1);
267 for (i = 0; i < list_len; i+= 4) {
272 pic33f_trans8(cmddata[i+1]);
273 pic33f_trans8(cmddata[i+2]);
274 pic33f_trans8(cmddata[i+3]);
276 } else if (cmd == 1) {
278 response_word = pic33f_regout();
279 checksum += response_word;
281 txword(response_word);
284 txword(~checksum + 1);
285 if (response_count != 1)
286 debugstr("Response count wrong");
292 /* This should be replaced by pic33f_cmdlist */
293 void pic33f_sixlist( unsigned int list_len )
296 unsigned int instr_loww;
298 // Bound to Rx buffer size.
299 if (list_len > CMDDATALEN)
300 list_len = CMDDATALEN;
302 // Run each instruction!
303 for (k = 0; k < list_len-2; k+=3) {
304 instr_loww = *(cmddata+k);
305 instr_loww |= (*(cmddata+k+1)) << 8;
306 pic33f_six( *(cmddata+k+2), instr_loww );
309 // Reply with total number of bytes used from Rx buffer.
310 txdata( PIC, PIC_SIXLIST33F, k );
314 /* This is slated to be replaced by pic33f_cmdlist */
315 unsigned int pic33f_getid()
322 // Read application ID.
323 pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
324 pic33f_six( 0x00, 0x0000 ); // nop
325 pic33f_six( 0x20, 0x0800 ); // mov #0x80, W0
326 pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
327 pic33f_six( 0x20, 0x7F00 ); // mov #0x7F0, W0
328 pic33f_six( 0x20, 0x7841 ); // mov #VISI, W1
329 pic33f_six( 0x00, 0x0000 ); // nop
330 pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0], [W1]
331 pic33f_six( 0x00, 0x0000 ); // nop
332 pic33f_six( 0x00, 0x0000 ); // nop
333 result = pic33f_regout();
334 *cmddata = result & 0xff;
338 pic33f_six( 0x20, 0x0FF0 ); // mov #0xFF, W0
339 pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
340 pic33f_six( 0xEB, 0x0000 ); // clr W0
341 pic33f_six( 0x00, 0x0000 ); // nop
342 pic33f_six( 0xBA, 0x08B0 ); // TBLRDL [W0++], [W1]
343 pic33f_six( 0x00, 0x0000 ); // nop
344 pic33f_six( 0x00, 0x0000 ); // nop
345 result = pic33f_regout();
346 *(cmddata+1) = result & 0xff;
347 *(cmddata+2) = result >> 8;
350 // Read hardware revision.
351 pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0++], [W1]
352 pic33f_six( 0x00, 0x0000 ); // nop
353 pic33f_six( 0x00, 0x0000 ); // nop
354 result = pic33f_regout();
355 *(cmddata+3) = result & 0xff;
356 *(cmddata+4) = result >> 8;
365 void pic33f_connect()
367 unsigned int key_low;
368 unsigned int key_high;
370 key_low = ICSP_KEY_LOW;
371 key_high = ICSP_KEY_HIGH;
386 pic33f_trans8( key_low & 0xff );
387 key_low = key_low >> 8;
388 pic33f_trans8( key_low & 0xff );
389 pic33f_trans8( key_high & 0xff );
390 key_high = key_high >> 8;
391 pic33f_trans8( key_high & 0xff );
394 SET_MCLR; // ...and pull MCLR pin back up.
395 delay_ms(25); // Now wait about 25 ms (required per spec!).
397 /* The first ICSP command must be a SIX, and further, 9 bits are
398 required before the instruction (to be executed), rather than
399 the typical 4 bits. Thus, to simplify code, I simply load a nop
400 here; hence 33 bits are shifted into the dsPIC33F/PIC24H. */
404 for (key_low = 0; key_low < 33; key_low++) {
415 void pic33f_disconnect()