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