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