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