]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blob - sainsmart_dds120.c
scopes: Use RENUMERATE_UNCOND() for all devices.
[sigrok-firmware-fx2lafw.git] / sainsmart_dds120.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, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <fx2macros.h>
22 #include <fx2ints.h>
23 #include <autovector.h>
24 #include <delay.h>
25 #include <setupdat.h>
26
27 #define SET_ANALOG_MODE() PA7 = 1
28
29 /* Toggle the 1kHz calibration pin, only accurate up to ca. 8MHz. */
30 /* Note: There's no PE2 as IOE is not bit-addressable (see TRM 15.2). */
31 #define TOGGLE_CALIBRATION_PIN() IOE = IOE ^ 0x04
32
33 #define LED_CLEAR() NOP
34 #define LED_GREEN() NOP
35 #define LED_RED()   NOP
36
37 /* Change to support as many interfaces as you need. */
38 static BYTE altiface = 0;
39
40 static volatile WORD ledcounter = 0;
41
42 static volatile __bit dosud = FALSE;
43 static volatile __bit dosuspend = FALSE;
44
45 extern __code BYTE highspd_dscr;
46 extern __code BYTE fullspd_dscr;
47
48 void resume_isr(void) __interrupt RESUME_ISR
49 {
50         CLEAR_RESUME();
51 }
52
53 void sudav_isr(void) __interrupt SUDAV_ISR
54 {
55         dosud = TRUE;
56         CLEAR_SUDAV();
57 }
58
59 void usbreset_isr(void) __interrupt USBRESET_ISR
60 {
61         handle_hispeed(FALSE);
62         CLEAR_USBRESET();
63 }
64
65 void hispeed_isr(void) __interrupt HISPEED_ISR
66 {
67         handle_hispeed(TRUE);
68         CLEAR_HISPEED();
69 }
70
71 void suspend_isr(void) __interrupt SUSPEND_ISR
72 {
73         dosuspend = TRUE;
74         CLEAR_SUSPEND();
75 }
76
77 void timer2_isr(void) __interrupt TF2_ISR
78 {
79         TOGGLE_CALIBRATION_PIN();
80
81         if (ledcounter && (--ledcounter == 0))
82                 LED_CLEAR();
83
84         TF2 = 0;
85 }
86
87 /**
88  * The gain stage is 2 stage approach. -6dB and -20dB on the first stage
89  * (attentuator). The second stage is then doing the gain by 3 different
90  * resistor values switched into the feedback loop.
91  *
92  * #Channel 0:
93  * PC1=1; PC2=0; PC3= 0 -> Gain x0.1 = -20dB
94  * PC1=1; PC2=0; PC3= 1 -> Gain x0.2 = -14dB
95  * PC1=1; PC2=1; PC3= 0 -> Gain x0.4 =  -8dB
96  * PC1=0; PC2=0; PC3= 0 -> Gain x0.5 =  -6dB
97  * PC1=0; PC2=0; PC3= 1 -> Gain x1   =   0dB
98  * PC1=0; PC2=1; PC3= 0 -> Gain x2   =  +6dB
99  *
100  * #Channel 1:
101  * PE1=1; PC4=0; PC5= 0 -> Gain x0.1 = -20dB 
102  * PE1=1; PC4=0; PC5= 1 -> Gain x0.2 = -14dB
103  * PE1=1; PC4=1; PC5= 0 -> Gain x0.4 =  -8dB
104  * PE1=0; PC4=0; PC5= 0 -> Gain x0.5 =  -6dB
105  * PE1=0; PC4=0; PC5= 1 -> Gain x1   =   0dB
106  * PE1=0; PC4=1; PC5= 0 -> Gain x2   =  +6dB
107  */
108 static BOOL set_voltage(BYTE channel, BYTE val)
109 {
110         BYTE bits_C, bit_E, mask_C, mask_E;
111
112         if (channel == 0) {
113                 mask_C = 0x0E;
114                 mask_E = 0x00;
115                 bit_E = 0;
116                 switch (val) {
117                 case 1:
118                         bits_C = 0x02;
119                         break;
120                 case 2:
121                         bits_C = 0x06;
122                         break;
123                 case 5:
124                         bits_C = 0x00;
125                         break;
126                 case 10:
127                         bits_C = 0x04;
128                         break;
129                 case 20:
130                         bits_C = 0x08;
131                         break;
132                 default:
133                         return FALSE;
134                 }
135         } else if (channel == 1) {
136                 mask_C = 0x30;
137                 mask_E = 0x02;
138                 switch (val) {
139                 case 1:
140                         bits_C = 0x00;
141                         bit_E = 0x02; 
142                         break;
143                 case 2:
144                         bits_C = 0x10;
145                         bit_E = 0x02; 
146                         break;
147                 case 5:
148                         bits_C = 0x00;
149                         bit_E = 0x00; 
150                         break;
151                 case 10:
152                         bits_C = 0x10;
153                         bit_E = 0x00; 
154                         break;
155                 case 20:
156                         bits_C = 0x20;
157                         bit_E = 0x00; 
158                         break;
159                 default:
160                         return FALSE;
161                 }
162         } else {
163                 return FALSE;
164         }
165         IOC = (IOC & ~mask_C) | (bits_C & mask_C);
166         IOE = (IOE & ~mask_E) | (bit_E & mask_E);
167                 
168         return TRUE;
169 }
170
171 /**
172  * Each LSB in the nibble of the byte controls the coupling per channel.
173  *
174  * Setting PE3 disables AC coupling capacitor on CH0.
175  * Setting PE0 disables AC coupling capacitor on CH1.
176  */
177 static void set_coupling(BYTE coupling_cfg)
178 {
179         if (coupling_cfg & 0x01)
180                 IOE |= 0x08;
181         else
182                 IOE &= ~0x08;
183
184         if (coupling_cfg & 0x10)
185                 IOE |= 0x01;
186         else
187                 IOE &= ~0x01;
188 }
189
190 static BOOL set_numchannels(BYTE numchannels)
191 {
192         if (numchannels == 1 || numchannels == 2) {
193                 BYTE fifocfg = 7 + numchannels;
194                 EP2FIFOCFG = fifocfg;
195                 EP6FIFOCFG = fifocfg;
196                 return TRUE;
197         }
198
199         return FALSE;
200 }
201
202 static void clear_fifo(void)
203 {
204         GPIFABORT = 0xff;
205         SYNCDELAY3;
206         FIFORESET = 0x80;
207         SYNCDELAY3;
208         FIFORESET = 0x82;
209         SYNCDELAY3;
210         FIFORESET = 0x86;
211         SYNCDELAY3;
212         FIFORESET = 0;
213 }
214
215 static void stop_sampling(void)
216 {
217         GPIFABORT = 0xff;
218         SYNCDELAY3;
219         INPKTEND = (altiface == 0) ? 6 : 2;
220 }
221
222 static void start_sampling(void)
223 {
224         int i;
225
226         SET_ANALOG_MODE();
227
228         clear_fifo();
229
230         for (i = 0; i < 1000; i++);
231
232         while (!(GPIFTRIG & 0x80))
233                 ;
234
235         SYNCDELAY3;
236         GPIFTCB1 = 0x28;
237         SYNCDELAY3;
238         GPIFTCB0 = 0;
239         GPIFTRIG = (altiface == 0) ? 6 : 4;
240
241         /* Set green LED, don't clear LED afterwards (ledcounter = 0). */
242         LED_GREEN();
243         ledcounter = 0;
244 }
245
246 static void select_interface(BYTE alt)
247 {
248         const BYTE *pPacketSize = \
249                 ((USBCS & bmHSM) ? &highspd_dscr : &fullspd_dscr)
250                 + (9 + (16 * alt) + 9 + 4);
251
252         altiface = alt;
253
254         if (alt == 0) {
255                 /* Bulk on EP6. */
256                 EP2CFG = 0x00;
257                 EP6CFG = 0xe0;
258                 EP6GPIFFLGSEL = 1;
259                 EP6AUTOINLENL = pPacketSize[0];
260                 EP6AUTOINLENH = pPacketSize[1];
261         } else {
262                 /* Iso on EP2. */
263                 EP2CFG = 0xd8;
264                 EP6CFG = 0x00;
265                 EP2GPIFFLGSEL = 1;
266                 EP2AUTOINLENL = pPacketSize[0];
267                 EP2AUTOINLENH = pPacketSize[1] & 0x7;
268                 EP2ISOINPKTS = (pPacketSize[1] >> 3) + 1;
269         }
270 }
271
272 static const struct samplerate_info {
273         BYTE rate;
274         BYTE wait0;
275         BYTE wait1;
276         BYTE opc0;
277         BYTE opc1;
278         BYTE out0;
279         BYTE ifcfg;
280 } samplerates[] = {
281         { 48, 0x80,   0, 3, 0, 0x00, 0xea },
282         { 30, 0x80,   0, 3, 0, 0x00, 0xaa },
283         { 24,    1,   0, 2, 1, 0x40, 0xea },
284         { 16,    1,   1, 2, 0, 0x40, 0xea },
285         { 15,    1,   0, 2, 1, 0x40, 0xaa },
286         { 12,    2,   1, 2, 0, 0x40, 0xea },
287         { 11,    1,   1, 2, 0, 0x40, 0xaa },
288         {  8,    3,   2, 2, 0, 0x40, 0xea },
289         {  6,    2,   2, 2, 0, 0x40, 0xaa },
290         {  5,    3,   2, 2, 0, 0x40, 0xaa },
291         {  4,    6,   5, 2, 0, 0x40, 0xea },
292         {  3,    5,   4, 2, 0, 0x40, 0xaa },
293         {  2,   12,  11, 2, 0, 0x40, 0xea },
294         {  1,   24,  23, 2, 0, 0x40, 0xea },
295         { 50,   48,  47, 2, 0, 0x40, 0xea },
296         { 20,  120, 119, 2, 0, 0x40, 0xea },
297         { 10,  240, 239, 2, 0, 0x40, 0xea },
298 };
299
300 static BOOL set_samplerate(BYTE rate)
301 {
302         BYTE i = 0;
303
304         while (samplerates[i].rate != rate) {
305                 i++;
306                 if (i == sizeof(samplerates) / sizeof(samplerates[0]))
307                         return FALSE;
308         }
309
310         IFCONFIG = samplerates[i].ifcfg;
311
312         AUTOPTRSETUP = 7;
313         AUTOPTRH2 = 0xE4; /* 0xE400: GPIF waveform descriptor 0. */
314         AUTOPTRL2 = 0x00;
315
316         /*
317          * The program for low-speed, e.g. 1 MHz, is:
318          * wait 24, CTLx=0, FIFO
319          * wait 23, CTLx=1
320          * jump 0, CTLx=1
321          *
322          * The program for 24 MHz is:
323          * wait 1, CTLx=0, FIFO
324          * jump 0, CTLx=1
325          *
326          * The program for 30/48 MHz is:
327          * jump 0, CTLx=Z, FIFO, LOOP
328          *
329          * (CTLx is device-dependent, could be e.g. CTL0 or CTL2.)
330          */
331
332         /* LENGTH / BRANCH 0-7 */
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         /* OPCODE 0-7 */
343         EXTAUTODAT2 = samplerates[i].opc0;
344         EXTAUTODAT2 = samplerates[i].opc1;
345         EXTAUTODAT2 = 1; /* DATA=0 DP=1 */
346         EXTAUTODAT2 = 0;
347         EXTAUTODAT2 = 0;
348         EXTAUTODAT2 = 0;
349         EXTAUTODAT2 = 0;
350         EXTAUTODAT2 = 0;
351
352         /* OUTPUT 0-7 */
353         EXTAUTODAT2 = samplerates[i].out0;
354         EXTAUTODAT2 = 0x44; /* OE2=1, CTL2=1 */
355         EXTAUTODAT2 = 0x44; /* OE2=1, CTL2=1 */
356         EXTAUTODAT2 = 0;
357         EXTAUTODAT2 = 0;
358         EXTAUTODAT2 = 0;
359         EXTAUTODAT2 = 0;
360         EXTAUTODAT2 = 0;
361
362         /* LOGIC FUNCTION 0-7 */
363         EXTAUTODAT2 = 0;
364         EXTAUTODAT2 = 0;
365         EXTAUTODAT2 = 0;
366         EXTAUTODAT2 = 0;
367         EXTAUTODAT2 = 0;
368         EXTAUTODAT2 = 0;
369         EXTAUTODAT2 = 0;
370         EXTAUTODAT2 = 0;
371
372         for (i = 0; i < 96; i++)
373                 EXTAUTODAT2 = 0;
374
375         return TRUE;
376 }
377
378 static BOOL set_calibration_pulse(BYTE fs)
379 {
380         switch (fs) {
381         case 0:         // 100Hz
382                 RCAP2L = -10000 & 0xff;
383                 RCAP2H = (-10000 & 0xff00) >> 8;
384                 return TRUE;
385         case 1:         // 1kHz
386                 RCAP2L = -1000 & 0xff;
387                 RCAP2H = (-1000 & 0xff00) >> 8;
388                 return TRUE;
389         case 10:        // 1kHz
390                 RCAP2L = (BYTE)(-100 & 0xff);
391                 RCAP2H = 0xff;
392                 return TRUE;
393         case 50:        // 50kHz
394                 RCAP2L = (BYTE)(-20 & 0xff);
395                 RCAP2H = 0xff;
396                 return TRUE;
397         default:
398                 return FALSE;
399         }
400 }
401
402 /* Set *alt_ifc to the current alt interface for ifc. */
403 BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
404 {
405         (void)ifc;
406
407         *alt_ifc = altiface;
408
409         return TRUE;
410 }
411
412 /*
413  * Return TRUE if you set the interface requested.
414  *
415  * Note: This function should reconfigure and reset the endpoints
416  * according to the interface descriptors you provided.
417  */
418 BOOL handle_set_interface(BYTE ifc,BYTE alt_ifc)
419 {
420         if (ifc == 0)
421                 select_interface(alt_ifc);
422
423         return TRUE;
424 }
425
426 BYTE handle_get_configuration(void)
427 {
428         /* We only support configuration 0. */
429         return 0;
430 }
431
432 BOOL handle_set_configuration(BYTE cfg)
433 {
434         /* We only support configuration 0. */
435         (void)cfg;
436
437         return TRUE;
438 }
439
440 BOOL handle_vendorcommand(BYTE cmd)
441 {
442         stop_sampling();
443
444         /* Set red LED, clear after timeout. */
445         LED_RED();
446         ledcounter = 1000;
447
448         /* Clear EP0BCH/L for each valid command. */
449         if (cmd >= 0xe0 && cmd <= 0xe6) {
450                 EP0BCH = 0;
451                 EP0BCL = 0;
452                 while (EP0CS & bmEPBUSY);
453         }
454
455         switch (cmd) {
456         case 0xe0:
457         case 0xe1:
458                 set_voltage(cmd - 0xe0, EP0BUF[0]);
459                 return TRUE;
460         case 0xe2:
461                 set_samplerate(EP0BUF[0]);
462                 return TRUE;
463         case 0xe3:
464                 if (EP0BUF[0] == 1)
465                         start_sampling();
466                 return TRUE;
467         case 0xe4:
468                 set_numchannels(EP0BUF[0]);
469                 return TRUE;
470         case 0xe5:
471                 set_coupling(EP0BUF[0]);
472                 return TRUE;
473         case 0xe6:
474                 set_calibration_pulse(EP0BUF[0]);
475                 return TRUE;
476         }
477
478         return FALSE; /* Not handled by handlers. */
479 }
480
481 static void init(void)
482 {
483         EP4CFG = 0;
484         EP8CFG = 0;
485
486         SET_ANALOG_MODE();
487
488         /* In idle mode tristate all outputs. */
489         GPIFIDLECTL = 0x00; /* Don't enable CTL0-5 outputs. */
490         GPIFCTLCFG = 0x80; /* TRICTL=1. CTL0-2: CMOS outputs, tri-statable. */
491         GPIFWFSELECT = 0x00;
492         GPIFREADYSTAT = 0x00;
493
494         stop_sampling();
495
496         set_voltage(0, 1);
497         set_voltage(1, 1);
498         set_samplerate(1);
499         set_numchannels(2);
500         select_interface(0);
501 }
502
503 static void main(void)
504 {
505         /* Save energy. */
506         SETCPUFREQ(CLK_12M);
507
508         init();
509
510         /* Set up interrupts. */
511         USE_USB_INTS();
512
513         ENABLE_SUDAV();
514         ENABLE_USBRESET();
515         ENABLE_HISPEED(); 
516         ENABLE_SUSPEND();
517         ENABLE_RESUME();
518
519         /* Global (8051) interrupt enable. */
520         EA = 1;
521
522         /* Init timer2. */
523         RCAP2L = -1000 & 0xff;
524         RCAP2H = (-1000 & 0xff00) >> 8;
525         T2CON = 0;
526         ET2 = 1;
527         TR2 = 1;
528
529         RENUMERATE_UNCOND();
530
531         PORTECFG = 0;
532         PORTCCFG = 0;
533         PORTACFG = 0;
534         OEE = 0xff;
535         OEC = 0xff;
536         OEA = 0xff;
537
538         SET_ANALOG_MODE();
539
540         while (TRUE) {
541                 if (dosud) {
542                         dosud = FALSE;
543                         handle_setupdata();
544                 }
545
546                 if (dosuspend) {
547                         dosuspend = FALSE;
548                         do {
549                                 /* Make sure ext wakeups are cleared. */
550                                 WAKEUPCS |= bmWU | bmWU2;
551                                 SUSPEND = 1;
552                                 PCON |= 1;
553                                 __asm
554                                 nop
555                                 nop
556                                 nop
557                                 nop
558                                 nop
559                                 nop
560                                 nop
561                                 __endasm;
562                         } while (!remote_wakeup_allowed && REMOTE_WAKEUP());
563
564                         /* Resume (TRM 6.4). */
565                         if (REMOTE_WAKEUP()) {
566                                 delay(5);
567                                 USBCS |= bmSIGRESUME;
568                                 delay(15);
569                                 USBCS &= ~bmSIGRESUME;
570                         }
571                 }
572         }
573 }