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