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