First addition of dsPIC33F/PIC24H chip family programmer!
[goodfet] / firmware / apps / pic / dspic33f.c
1 /*! \file dspic33f.c
2
3   \author Scott Livingston
4
5   \brief dsPIC33F programmer application for the GoodFET. Structure
6          and style is somewhat modeled after avr.c
7
8   \date March, April 2010
9 */
10
11
12 #include "apps.h"
13 #include "platform.h"
14 #include "command.h"
15
16 #include "dspic33f.h"
17
18
19 void pic33f_setup()
20 {
21         // Initialize pins; do NOT begin transaction.
22         P5DIR |= PGC|MCLR;
23         P5REN &= ~(PGC|PGD|MCLR);
24         DIR_PGD_WR; // Initially PGD in write mode
25
26         SET_MCLR;
27         CLR_PGC;
28         CLR_PGD;
29
30         prep_timer(); // What better time than now?
31 }
32
33
34 //! Handle a PIC command; currently assumes dsPIC33F/PIC24H
35 void pichandle( unsigned char app,
36                                 unsigned char verb,
37                                 unsigned long len )
38 {
39         unsigned int nb; // Number of bytes
40         unsigned int highb, loww; // Used for ICSP commands
41
42         switch (verb) {
43
44         case PIC_DEVID33F:
45                 nb = pic33f_getid();
46                 txdata(app,verb,nb);
47                 break;
48
49         case PIC_SIX33F:
50                 loww = *cmddata;
51                 loww |= (*(cmddata+1)) << 8;
52                 highb = *(cmddata+2);
53                 pic33f_six( highb, loww );
54                 txdata(app,verb,0);
55                 break;
56
57         case PIC_SIXLIST33F:
58                 pic33f_sixlist( len ); // Reply to host is handled by pic33f_sixlist.
59                 break;
60
61         case PIC_REGOUT33F:
62                 loww = pic33f_regout();
63                 *cmddata = loww & 0xff;
64                 *(cmddata+1) = loww >> 8;
65                 txdata(app,verb,2);
66                 break;
67
68         case PIC_START33F:
69                 pic33f_connect();
70                 txdata(app,verb,0);
71                 break;
72
73         case PIC_STOP33F:
74                 pic33f_disconnect();
75                 txdata(app,verb,0);
76                 break;
77
78         default:
79                 debugstr( "Verb unimplemented in PIC application." );
80                 txdata(app,NOK,0);
81                 break;
82
83         }
84 }
85
86
87 void pic33f_trans8( unsigned char byte )
88 {
89         /* We only twiddle the PGD and PGC lines.
90            MCLR is assumed to be in the correct state. */
91         unsigned int i;
92         
93         DIR_PGD_WR; // Write mode
94         i = 1;
95         while (i & 0xff) {
96                 if (byte & i) {
97                         SET_PGD;
98                 } else {
99                         CLR_PGD;
100                 }
101                 delay_ticks(10);
102                 SET_PGC;
103                 delay_ticks(10);
104
105                 CLR_PGC;
106                 delay_ticks(10);
107                 i = i << 1;
108         }
109         CLR_PGD;
110         DIR_PGD_RD; // Read mode
111 }
112
113 void pic33f_trans16( unsigned int word )
114 {
115         pic33f_trans8( word & 0xff );
116         pic33f_trans8( word >> 8 );
117 }
118
119
120 void pic33f_six( unsigned int highb, unsigned int loww )
121 {
122         /* dsPIC33F/PIC24H instructions have width 24 bits, so we use the
123            lower 8 bits of highb and (all 16 bits of) loww to form the
124            instruction.
125
126            Shift in the instruction.  Note that it does not execute until
127            the next 4 clock cycles (which also corresponds to a command
128            receipt time). */
129         unsigned int i;
130         DIR_PGD_WR;
131         CLR_PGD;
132         CLR_PGC;
133         for (i = 0; i < 4; i++) {
134                 SET_PGC;
135                 delay_ticks(10);
136                 CLR_PGC;
137                 delay_ticks(10);
138         }
139         pic33f_trans16( loww );
140         pic33f_trans8( highb );
141         DIR_PGD_RD;
142 }
143
144
145 unsigned int pic33f_regout()
146 {       
147         unsigned int i;
148         unsigned int result = 0x0000;
149
150         DIR_PGD_WR;
151         
152         // Shift in command (REGOUT: 0001b).
153         SET_PGD;
154         delay_ticks(10);
155         SET_PGC;
156         delay_ticks(10);
157         CLR_PGC;
158         delay_ticks(10);
159         
160         CLR_PGD;
161         delay_ticks(10);
162         for (i = 0; i < 3; i++) {
163                 SET_PGC;
164                 delay_ticks(10);
165                 CLR_PGC;
166                 delay_ticks(10);
167         }
168
169         // Pump clock for 8 cycles, and switch PGD direction to read.
170         for (i = 0; i < 7; i++) {
171                 SET_PGC;
172                 delay_ticks(10);
173                 CLR_PGC;
174                 delay_ticks(10);
175         }
176         DIR_PGD_RD;
177
178         /* Now read VISI register (LSb first, as usual).
179        Note that when reading from attached device, data is valid (to
180            be read) on falling clock edges. */
181         for (i = 0; i < 16; i++) {
182                 SET_PGC;
183                 delay_ticks(10);
184                 CLR_PGC;
185                 result |= READ_PGD << i;
186                 delay_ticks(10);
187         }
188
189         /* One last tick apparently is needed here, at least by the
190            dsPIC33FJ128GP708 chip that I am working with. Note that this
191            is not in the flash programming specs. */
192         SET_PGC; 
193         delay_ticks(10);
194         CLR_PGC;
195         delay_ticks(10);
196
197         return result;
198 }
199
200
201 void pic33f_sixlist( unsigned int list_len )
202 {
203         unsigned int k;
204         unsigned int instr_loww;
205
206         // Bound to Rx buffer size.
207         if (list_len > CMDDATALEN)
208                 list_len = CMDDATALEN;
209
210         // Run each instruction!
211         for (k = 0; k < list_len-2; k+=3) {
212                 instr_loww = *(cmddata+k);
213                 instr_loww |= (*(cmddata+k+1)) << 8;
214                 pic33f_six( *(cmddata+k+2), instr_loww );
215         }
216
217         // Reply with total number of bytes used from Rx buffer.
218         txdata( PIC, PIC_SIXLIST33F, k );
219 }
220
221
222 unsigned int pic33f_getid()
223 {
224         unsigned int result;
225         unsigned int nb = 0;
226
227         pic33f_connect();
228
229         // Read application ID.
230         pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
231         pic33f_six( 0x04, 0x0200 ); // goto 0x200 (i.e. reset)
232         pic33f_six( 0x00, 0x0000 ); // nop
233         pic33f_six( 0x20, 0x0800 ); // mov #0x80, W0
234         pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
235         pic33f_six( 0x20, 0x7F00 ); // mov #0x7F0, W0
236         pic33f_six( 0x20, 0x7841 ); // mov #VISI, W1
237         pic33f_six( 0x00, 0x0000 ); // nop
238         pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0], [W1]
239         pic33f_six( 0x00, 0x0000 ); // nop
240         pic33f_six( 0x00, 0x0000 ); // nop
241         result = pic33f_regout();
242         *cmddata = result & 0xff;
243         nb += 1;
244
245         // Read DEVID.
246         pic33f_six( 0x20, 0x0FF0 ); // mov #0xFF, W0
247         pic33f_six( 0x88, 0x0190 ); // mov W0, TBLPAG
248         pic33f_six( 0xEB, 0x0000 ); // clr W0
249         pic33f_six( 0x00, 0x0000 ); // nop
250         pic33f_six( 0xBA, 0x08B0 ); // TBLRDL [W0++], [W1]
251         pic33f_six( 0x00, 0x0000 ); // nop
252         pic33f_six( 0x00, 0x0000 ); // nop
253         result = pic33f_regout();
254         *(cmddata+1) = result & 0xff;
255         *(cmddata+2) = result >> 8;
256         nb += 2;
257
258         // Read hardware revision.
259         pic33f_six( 0xBA, 0x0890 ); // TBLRDL [W0++], [W1]
260         pic33f_six( 0x00, 0x0000 ); // nop
261         pic33f_six( 0x00, 0x0000 ); // nop
262         result = pic33f_regout();
263         *(cmddata+3) = result & 0xff;
264         *(cmddata+4) = result >> 8;
265         nb += 2;
266
267         pic33f_disconnect();
268
269         return nb;
270 }
271
272
273 void pic33f_connect()
274 {
275         unsigned int key_low;
276         unsigned int key_high;
277
278         key_low = ICSP_KEY_LOW;
279         key_high = ICSP_KEY_HIGH;
280
281         pic33f_setup();
282
283         CLR_PGC;
284         delay_us(1);
285         
286         CLR_MCLR;
287         delay_ms(3);
288         SET_MCLR;
289         delay_us(200);
290         CLR_MCLR;
291         delay_us(10);
292         
293         // Enter ICSP key
294         pic33f_trans8( key_low & 0xff );
295         key_low = key_low >> 8;
296         pic33f_trans8( key_low & 0xff );
297         pic33f_trans8( key_high & 0xff );
298         key_high = key_high >> 8;
299         pic33f_trans8( key_high & 0xff );
300
301         delay_us(1);
302         SET_MCLR; // ...and pull MCLR pin back up.
303         delay_ms(25); // Now wait about 25 ms (required per spec!).
304
305         /* The first ICSP command must be a SIX, and further, 9 bits are
306        required before the instruction (to be executed), rather than
307        the typical 4 bits. Thus, to simplify code, I simply load a nop
308        here; hence 33 bits are shifted into the dsPIC33F/PIC24H. */
309         DIR_PGD_WR;
310         CLR_PGD;
311         CLR_PGC;
312         for (key_low = 0; key_low < 33; key_low++) {
313                 SET_PGC;
314                 delay_us(1);
315                 CLR_PGC;
316                 delay_us(1);
317         }
318         DIR_PGD_RD;
319
320 }
321
322
323 void pic33f_disconnect()
324 {
325         DIR_PGD_WR;
326         CLR_PGD;
327         CLR_PGC;
328         delay_ms(10);
329         CLR_MCLR;
330 }