]>
Commit | Line | Data |
---|---|---|
189db3d4 UH |
1 | /** |
2 | * Copyright (C) 2009 Ubixum, Inc. | |
3 | * Copyright (C) 2015 Jochen Hoenicke | |
4 | * | |
5 | * This library is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2.1 of the License, or (at your option) any later version. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
18 | **/ | |
19 | ||
20 | #include <fx2macros.h> | |
21 | #include <fx2ints.h> | |
22 | #include <autovector.h> | |
23 | #include <delay.h> | |
24 | #include <setupdat.h> | |
25 | ||
26 | #ifdef DEBUG_FIRMWARE | |
27 | #include <serial.h> | |
28 | #include <stdio.h> | |
29 | #else | |
30 | #define printf(...) | |
31 | #endif | |
32 | ||
33 | volatile WORD ledcounter = 0; | |
34 | ||
35 | ||
36 | volatile __bit dosud=FALSE; | |
37 | volatile __bit dosuspend=FALSE; | |
38 | ||
39 | // custom functions | |
40 | extern void main_loop(); | |
41 | extern void main_init(); | |
42 | ||
43 | void main() { | |
44 | ||
45 | SETCPUFREQ(CLK_12M); // save energy | |
46 | ||
47 | main_init(); | |
48 | ||
49 | // set up interrupts. | |
50 | USE_USB_INTS(); | |
51 | ||
52 | ENABLE_SUDAV(); | |
53 | ENABLE_USBRESET(); | |
54 | ENABLE_HISPEED(); | |
55 | ENABLE_SUSPEND(); | |
56 | ENABLE_RESUME(); | |
57 | ||
58 | EA=1; | |
59 | ||
60 | // init timer2 | |
61 | RCAP2L = -500 & 0xff; | |
62 | RCAP2H = (-500 >> 8) & 0xff; | |
63 | T2CON = 0; | |
64 | ET2 = 1; | |
65 | TR2 = 1; | |
66 | ||
67 | // iic files (c2 load) don't need to renumerate/delay | |
68 | // trm 3.6 | |
69 | #ifndef NORENUM | |
70 | RENUMERATE(); | |
71 | #else | |
72 | USBCS &= ~bmDISCON; | |
73 | #endif | |
74 | ||
75 | PORTCCFG = 0; | |
76 | PORTACFG = 0; | |
77 | OEC = 0xff; | |
78 | OEA = 0x80; | |
79 | ||
80 | while(TRUE) { | |
81 | ||
82 | main_loop(); | |
83 | ||
84 | if (dosud) { | |
85 | dosud=FALSE; | |
86 | handle_setupdata(); | |
87 | } | |
88 | ||
89 | if (dosuspend) { | |
90 | dosuspend=FALSE; | |
91 | do { | |
92 | printf ( "I'm going to Suspend.\n" ); | |
93 | WAKEUPCS |= bmWU|bmWU2; // make sure ext wakeups are cleared | |
94 | SUSPEND=1; | |
95 | PCON |= 1; | |
96 | __asm | |
97 | nop | |
98 | nop | |
99 | nop | |
100 | nop | |
101 | nop | |
102 | nop | |
103 | nop | |
104 | __endasm; | |
105 | } while ( !remote_wakeup_allowed && REMOTE_WAKEUP()); | |
106 | printf ( "I'm going to wake up.\n"); | |
107 | ||
108 | // resume | |
109 | // trm 6.4 | |
110 | if ( REMOTE_WAKEUP() ) { | |
111 | delay(5); | |
112 | USBCS |= bmSIGRESUME; | |
113 | delay(15); | |
114 | USBCS &= ~bmSIGRESUME; | |
115 | } | |
116 | ||
117 | } | |
118 | ||
119 | } // end while | |
120 | ||
121 | } // end main | |
122 | ||
123 | void resume_isr() __interrupt RESUME_ISR { | |
124 | CLEAR_RESUME(); | |
125 | } | |
126 | ||
127 | void sudav_isr() __interrupt SUDAV_ISR { | |
128 | dosud=TRUE; | |
129 | CLEAR_SUDAV(); | |
130 | } | |
131 | void usbreset_isr() __interrupt USBRESET_ISR { | |
132 | handle_hispeed(FALSE); | |
133 | CLEAR_USBRESET(); | |
134 | } | |
135 | void hispeed_isr() __interrupt HISPEED_ISR { | |
136 | handle_hispeed(TRUE); | |
137 | CLEAR_HISPEED(); | |
138 | } | |
139 | ||
140 | void suspend_isr() __interrupt SUSPEND_ISR { | |
141 | dosuspend=TRUE; | |
142 | CLEAR_SUSPEND(); | |
143 | } | |
144 | ||
145 | void timer2_isr() __interrupt TF2_ISR { | |
146 | PA7 = !PA7; | |
147 | if (ledcounter) { | |
148 | if (--ledcounter == 0) { | |
149 | // clear LED | |
150 | PC0 = 1; | |
151 | PC1 = 1; | |
152 | } | |
153 | } | |
154 | TF2 = 0; | |
155 | } | |
156 | /** | |
157 | * Copyright (C) 2009 Ubixum, Inc. | |
158 | * Copyright (C) 2015 Jochen Hoenicke | |
159 | * | |
160 | * This library is free software; you can redistribute it and/or | |
161 | * modify it under the terms of the GNU Lesser General Public | |
162 | * License as published by the Free Software Foundation; either | |
163 | * version 2.1 of the License, or (at your option) any later version. | |
164 | * | |
165 | * This library is distributed in the hope that it will be useful, | |
166 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
167 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
168 | * Lesser General Public License for more details. | |
169 | * | |
170 | * You should have received a copy of the GNU Lesser General Public | |
171 | * License along with this library; if not, write to the Free Software | |
172 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
173 | **/ | |
174 | ||
175 | #include <fx2macros.h> | |
176 | #include <delay.h> | |
177 | ||
178 | #ifdef DEBUG_FIRMWARE | |
179 | #include <stdio.h> | |
180 | #else | |
181 | #define printf(...) | |
182 | #endif | |
183 | ||
184 | // change to support as many interfaces as you need | |
185 | BYTE altiface = 0; // alt interface | |
186 | extern volatile WORD ledcounter; | |
187 | ||
188 | ||
189 | ||
190 | /* This sets three bits for each channel, one channel at a time. | |
191 | * For channel 0 we want to set bits 5, 6 & 7 | |
192 | * For channel 1 we want to set bits 2, 3 & 4 | |
193 | * | |
194 | * We convert the input values that are strange due to original firmware code into the value of the three bits as follows: | |
195 | * val -> bits | |
196 | * 1 -> 010b | |
197 | * 2 -> 001b | |
198 | * 5 -> 000b | |
199 | * 10 -> 011b | |
200 | * | |
201 | * The third bit is always zero since there are only four outputs connected in the serial selector chip. | |
202 | * | |
203 | * The multiplication of the converted value by 0x24 sets the relevant bits in | |
204 | * both channels and then we mask it out to only affect the channel currently | |
205 | * requested. | |
206 | */ | |
207 | BOOL set_voltage(BYTE channel, BYTE val) | |
208 | { | |
209 | BYTE bits, mask; | |
210 | switch (val) { | |
211 | case 1: | |
212 | bits = 0x24 * 2; | |
213 | break; | |
214 | case 2: | |
215 | bits = 0x24 * 1; | |
216 | break; | |
217 | case 5: | |
218 | bits = 0x24 * 0; | |
219 | break; | |
220 | case 10: | |
221 | bits = 0x24 * 3; | |
222 | break; | |
223 | default: | |
224 | return FALSE; | |
225 | } | |
226 | ||
227 | mask = channel ? 0xe0 : 0x1c; | |
228 | IOC = (IOC & ~mask) | (bits & mask); | |
229 | return TRUE; | |
230 | } | |
231 | ||
232 | BOOL set_numchannels(BYTE numchannels) | |
233 | { | |
234 | if (numchannels == 1 || numchannels == 2) { | |
235 | BYTE fifocfg = 7 + numchannels; | |
236 | EP2FIFOCFG = fifocfg; | |
237 | EP6FIFOCFG = fifocfg; | |
238 | return TRUE; | |
239 | } | |
240 | return FALSE; | |
241 | } | |
242 | ||
243 | void clear_fifo() | |
244 | { | |
245 | GPIFABORT = 0xff; | |
246 | SYNCDELAY3; | |
247 | FIFORESET = 0x80; | |
248 | SYNCDELAY3; | |
249 | FIFORESET = 0x82; | |
250 | SYNCDELAY3; | |
251 | FIFORESET = 0x86; | |
252 | SYNCDELAY3; | |
253 | FIFORESET = 0; | |
254 | } | |
255 | ||
256 | void stop_sampling() | |
257 | { | |
258 | GPIFABORT = 0xff; | |
259 | SYNCDELAY3; | |
260 | if (altiface == 0) { | |
261 | INPKTEND = 6; | |
262 | } else { | |
263 | INPKTEND = 2; | |
264 | } | |
265 | } | |
266 | ||
267 | void start_sampling() | |
268 | { | |
269 | int i; | |
270 | clear_fifo(); | |
271 | ||
272 | for (i = 0; i < 1000; i++); | |
273 | while (!(GPIFTRIG & 0x80)) { | |
274 | ; | |
275 | } | |
276 | SYNCDELAY3; | |
277 | GPIFTCB1 = 0x28; | |
278 | SYNCDELAY3; | |
279 | GPIFTCB0 = 0; | |
280 | if (altiface == 0) | |
281 | GPIFTRIG = 6; | |
282 | else | |
283 | GPIFTRIG = 4; | |
284 | ||
285 | // set green led | |
286 | // don't clear led | |
287 | ledcounter = 0; | |
288 | PC0 = 1; | |
289 | PC1 = 0; | |
290 | } | |
291 | ||
292 | extern __code BYTE highspd_dscr; | |
293 | extern __code BYTE fullspd_dscr; | |
294 | void select_interface(BYTE alt) | |
295 | { | |
296 | const BYTE *pPacketSize = (USBCS & bmHSM ? &highspd_dscr : &fullspd_dscr) | |
297 | + (9 + 16*alt + 9 + 4); | |
298 | altiface = alt; | |
299 | if (alt == 0) { | |
300 | // bulk on port 6 | |
301 | EP2CFG = 0x00; | |
302 | EP6CFG = 0xe0; | |
303 | EP6GPIFFLGSEL = 1; | |
304 | ||
305 | EP6AUTOINLENL = pPacketSize[0]; | |
306 | EP6AUTOINLENH = pPacketSize[1]; | |
307 | } else { | |
308 | // iso on port 2 | |
309 | EP2CFG = 0xd8; | |
310 | EP6CFG = 0x00; | |
311 | EP2GPIFFLGSEL = 1; | |
312 | ||
313 | EP2AUTOINLENL = pPacketSize[0]; | |
314 | EP2AUTOINLENH = pPacketSize[1] & 0x7; | |
315 | EP2ISOINPKTS = (pPacketSize[1] >> 3) + 1; | |
316 | } | |
317 | } | |
318 | ||
319 | const struct samplerate_info { | |
320 | BYTE rate; | |
321 | BYTE wait0; | |
322 | BYTE wait1; | |
323 | BYTE opc0; | |
324 | BYTE opc1; | |
325 | BYTE out0; | |
326 | BYTE ifcfg; | |
327 | } samplerates[] = { | |
328 | { 48,0x80, 0, 3, 0, 0x00, 0xea }, | |
329 | { 30,0x80, 0, 3, 0, 0x00, 0xaa }, | |
330 | { 24, 1, 0, 2, 1, 0x40, 0xca }, | |
331 | { 16, 1, 1, 2, 0, 0x40, 0xca }, | |
332 | { 12, 2, 1, 2, 0, 0x40, 0xca }, | |
333 | { 8, 3, 2, 2, 0, 0x40, 0xca }, | |
334 | { 4, 6, 5, 2, 0, 0x40, 0xca }, | |
335 | { 2, 12, 11, 2, 0, 0x40, 0xca }, | |
336 | { 1, 24, 23, 2, 0, 0x40, 0xca }, | |
337 | { 50, 48, 47, 2, 0, 0x40, 0xca }, | |
338 | { 20, 120, 119, 2, 0, 0x40, 0xca }, | |
339 | { 10, 240, 239, 2, 0, 0x40, 0xca } | |
340 | }; | |
341 | ||
342 | BOOL set_samplerate(BYTE rate) | |
343 | { | |
344 | BYTE i = 0; | |
345 | while (samplerates[i].rate != rate) { | |
346 | i++; | |
347 | if (i == sizeof(samplerates)/sizeof(samplerates[0])) | |
348 | return FALSE; | |
349 | } | |
350 | ||
351 | IFCONFIG = samplerates[i].ifcfg; | |
352 | ||
353 | AUTOPTRSETUP = 7; | |
354 | AUTOPTRH2 = 0xE4; | |
355 | AUTOPTRL2 = 0x00; | |
356 | ||
357 | /* The program for low-speed, e.g. 1 MHz, is | |
358 | * wait 24, CTL2=0, FIFO | |
359 | * wait 23, CTL2=1 | |
360 | * jump 0, CTL2=1 | |
361 | * | |
362 | * The program for 24 MHz is | |
363 | * wait 1, CTL2=0, FIFO | |
364 | * jump 0, CTL2=1 | |
365 | * | |
366 | * The program for 30/48 MHz is: | |
367 | * jump 0, CTL2=Z, FIFO, LOOP | |
368 | */ | |
369 | ||
370 | EXTAUTODAT2 = samplerates[i].wait0; | |
371 | EXTAUTODAT2 = samplerates[i].wait1; | |
372 | EXTAUTODAT2 = 1; | |
373 | EXTAUTODAT2 = 0; | |
374 | EXTAUTODAT2 = 0; | |
375 | EXTAUTODAT2 = 0; | |
376 | EXTAUTODAT2 = 0; | |
377 | EXTAUTODAT2 = 0; | |
378 | ||
379 | EXTAUTODAT2 = samplerates[i].opc0; | |
380 | EXTAUTODAT2 = samplerates[i].opc1; | |
381 | EXTAUTODAT2 = 1; | |
382 | EXTAUTODAT2 = 0; | |
383 | EXTAUTODAT2 = 0; | |
384 | EXTAUTODAT2 = 0; | |
385 | EXTAUTODAT2 = 0; | |
386 | EXTAUTODAT2 = 0; | |
387 | ||
388 | EXTAUTODAT2 = samplerates[i].out0; | |
389 | EXTAUTODAT2 = 0x44; | |
390 | EXTAUTODAT2 = 0x44; | |
391 | EXTAUTODAT2 = 0x00; | |
392 | EXTAUTODAT2 = 0x00; | |
393 | EXTAUTODAT2 = 0x00; | |
394 | EXTAUTODAT2 = 0x00; | |
395 | EXTAUTODAT2 = 0x00; | |
396 | ||
397 | EXTAUTODAT2 = 0; | |
398 | EXTAUTODAT2 = 0; | |
399 | EXTAUTODAT2 = 0; | |
400 | EXTAUTODAT2 = 0; | |
401 | EXTAUTODAT2 = 0; | |
402 | EXTAUTODAT2 = 0; | |
403 | EXTAUTODAT2 = 0; | |
404 | EXTAUTODAT2 = 0; | |
405 | ||
406 | for (i = 0; i < 96; i++) | |
407 | EXTAUTODAT2 = 0; | |
408 | return TRUE; | |
409 | } | |
410 | ||
189db3d4 UH |
411 | //************************** Configuration Handlers ***************************** |
412 | ||
413 | // set *alt_ifc to the current alt interface for ifc | |
414 | BOOL handle_get_interface(BYTE ifc, BYTE* alt_ifc) { | |
415 | (void) ifc; // ignore unused parameter | |
416 | *alt_ifc=altiface; | |
417 | return TRUE; | |
418 | } | |
419 | // return TRUE if you set the interface requested | |
420 | // NOTE this function should reconfigure and reset the endpoints | |
421 | // according to the interface descriptors you provided. | |
422 | BOOL handle_set_interface(BYTE ifc,BYTE alt_ifc) { | |
423 | printf ( "Set Interface.\n" ); | |
424 | if (ifc == 0) { | |
425 | select_interface(alt_ifc); | |
426 | } | |
427 | return TRUE; | |
428 | } | |
429 | ||
430 | // handle getting and setting the configuration | |
431 | // 1 is the default. We don't support multiple configurations. | |
432 | BYTE handle_get_configuration() { | |
433 | return 0; | |
434 | } | |
435 | ||
436 | BOOL handle_set_configuration(BYTE cfg) { | |
437 | (void) cfg; // ignore unused parameter | |
438 | return TRUE; | |
439 | } | |
440 | ||
441 | ||
442 | //******************* VENDOR COMMAND HANDLERS ************************** | |
443 | ||
444 | BOOL handle_vendorcommand(BYTE cmd) { | |
445 | stop_sampling(); | |
446 | // Set Red LED | |
447 | PC0 = 0; | |
448 | PC1 = 1; | |
449 | ledcounter = 1000; | |
450 | switch (cmd) { | |
451 | case 0xe0: | |
452 | case 0xe1: | |
453 | EP0BCH=0; | |
454 | EP0BCL=0; | |
455 | while (EP0CS & bmEPBUSY); | |
456 | set_voltage(cmd - 0xe0, EP0BUF[0]); | |
457 | return TRUE; | |
458 | case 0xe2: | |
459 | EP0BCH=0; | |
460 | EP0BCL=0; | |
461 | while (EP0CS & bmEPBUSY); | |
462 | set_samplerate(EP0BUF[0]); | |
463 | return TRUE; | |
464 | case 0xe3: | |
465 | EP0BCH=0; | |
466 | EP0BCL=0; | |
467 | while (EP0CS & bmEPBUSY); | |
468 | if (EP0BUF[0] == 1) | |
469 | start_sampling(); | |
470 | return TRUE; | |
471 | case 0xe4: | |
472 | EP0BCH=0; | |
473 | EP0BCL=0; | |
474 | while (EP0CS & bmEPBUSY); | |
475 | set_numchannels(EP0BUF[0]); | |
476 | return TRUE; | |
477 | } | |
478 | return FALSE; // not handled by handlers | |
479 | } | |
480 | ||
481 | //******************** INIT *********************** | |
482 | ||
483 | void main_init() { | |
484 | EP4CFG = 0; | |
485 | EP8CFG = 0; | |
486 | ||
487 | // in idle mode tristate all outputs | |
488 | GPIFIDLECTL = 0x00; | |
489 | GPIFCTLCFG = 0x80; | |
490 | GPIFWFSELECT = 0x00; | |
491 | GPIFREADYSTAT = 0x00; | |
492 | ||
493 | stop_sampling(); | |
494 | set_voltage(0, 1); | |
495 | set_voltage(1, 1); | |
496 | set_samplerate(1); | |
497 | set_numchannels(2); | |
498 | select_interface(0); | |
499 | ||
500 | printf ( "Initialization Done.\n" ); | |
501 | } | |
502 | ||
503 | ||
504 | void main_loop() { | |
505 | } | |
506 | ||
507 |