]> sigrok.org Git - sigrok-firmware-fx2lafw.git/blame - fx2lafw.c
Added first device specific directory for the CWAV USBee AX
[sigrok-firmware-fx2lafw.git] / fx2lafw.c
CommitLineData
d5f5ea73
UH
1/*
2 * This file is part of the fx2lafw project.
3 *
4 * Copyright (C) 2011-2012 Uwe Hermann <uwe@hermann-uwe.de>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * fx2lafw is an open-source firmware for Cypress FX2 based logic analyzers.
23 *
24 * It is written in C, using fx2lib as helper library, and sdcc as compiler.
25 * The code is licensed under the terms of the GNU GPL, version 2 or later.
26 *
27 * Technical notes:
28 *
29 * - We use the FX2 in GPIF mode to sample the data (asynchronously).
30 * - We use the internal 48MHz clock for GPIF.
31 * - The 8 channels/pins we sample (the GPIF data bus) are PB0-PB7.
32 * Support for 16 channels is not yet included, but might be added later.
33 * - Endpoint 2 is used for data transfers from FX2 to host.
34 * - The endpoint is quad-buffered.
35 *
36 * Documentation:
37 *
38 * - See http://sigrok.org/wiki/Fx2lafw
39 */
40
41#include <fx2regs.h>
42#include <fx2macros.h>
43#include <delay.h>
44#include <autovector.h>
45#include <setupdat.h>
46#include <eputils.h>
47#include <gpif.h>
48
c7283c28
UH
49/* Protocol commands */
50#define CMD_SET_SAMPLERATE 0xb0
51#define CMD_START 0xb1
52#define CMD_STOP 0xb2
53#define CMD_GET_FW_VERSION 0xb3
54/* ... */
55
d5f5ea73
UH
56#define SYNCDELAY() SYNCDELAY4
57
58/* ... */
59volatile bit got_sud;
60
61/* GPIF terminology: DP = decision point, NDP = non-decision-point */
62
fb0b6d28
UH
63/*
64 * GPIF waveforms.
65 *
66 * See section "10.3.4 State Instructions" in the TRM for details.
67 */
d5f5ea73
UH
68static const BYTE wavedata[128] = {
69 /* Waveform 0: */
70
fb0b6d28
UH
71 /*
72 * This is the basic algorithm implemented in our GPIF state machine:
73 *
74 * State 0: NDP: Sample the FIFO data bus.
75 * State 1: DP: If EP2 is full, go to state 7 (the IDLE state), i.e.,
76 * end the current waveform. Otherwise, go to state 0 again,
77 * i.e., sample data until EP2 is full.
78 * State 2: Unused.
79 * State 3: Unused.
80 * State 4: Unused.
81 * State 5: Unused.
82 * State 6: Unused.
83 */
d5f5ea73
UH
84
85 /* S0-S6: LENGTH/BRANCH */
fb0b6d28
UH
86 /*
87 * For NDPs (LENGTH): Number of IFCLK cycles to stay in this state.
88 * For DPs (BRANCH): [7] ReExec, [5:3]: BRANCHON1, [2:0]: BRANCHON0.
89 *
90 * 0x01: Stay one IFCLK cycle in this state.
91 * 0x38: No Re-execution, BRANCHON1 = state 7, BRANCHON0 = state 0.
92 */
dc7ac8bf
UH
93 // 0x01, 0x38, 0x01, 0x01, 0x01, 0x01, 0x01,
94 // FIXME: For now just loop over the "sample data" state forever.
95 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01,
d5f5ea73
UH
96 /* TRM says "reserved", but GPIF designer always puts a 0x07 here. */
97 0x07,
fb0b6d28 98
d5f5ea73 99 /* S0-S6: OPCODE */
fb0b6d28
UH
100 /*
101 * 0x02: NDP, sample the FIFO data bus.
102 * 0x01: DP, don't sample the FIFO data bus.
103 */
104 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
105 /* Reserved */
106 0x00,
fb0b6d28 107
d5f5ea73 108 /* S0-S6: OUTPUT */
fb0b6d28 109 /* Unused, we don't output anything, we only sample the pins. */
d5f5ea73
UH
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 /* Reserved */
112 0x00,
fb0b6d28 113
d5f5ea73 114 /* S0-S6: LOGIC FUNCTION (not used for NDPs) */
fb0b6d28
UH
115 /*
116 * 0x36: LFUNC = "A AND B", A = FIFO flag, B = FIFO flag.
117 * The FIFO flag (FF == full flag, in our case) is configured via
118 * EP2GPIFFLGSEL.
119 *
120 * So: If the EP2 FIFO is full and the EP2 FIFO is full, go to
121 * the state specified by BRANCHON1 (state 7), otherwise BRANCHON0
122 * (state 0). See the LENGTH/BRANCH value above for details.
123 */
124 0x00, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00,
d5f5ea73
UH
125 /* TRM says "reserved", but GPIF designer always puts a 0x3f here. */
126 0x3f,
127
128 /* TODO: Must unused waveforms be "valid"? */
129
130 /* Waveform 1 (unused): */
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
135
136 /* Waveform 2 (unused): */
137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
140 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
141
142 /* Waveform 3 (unused): */
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
146 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
147};
148
149static void gpif_setup_registers(void)
150{
151 /* TODO. Value probably irrelevant, as we don't use RDY* signals? */
152 GPIFREADYCFG = 0;
153
154 /*
155 * Set TRICTL = 0, thus CTL0-CTL5 are CMOS outputs.
156 * TODO: Probably irrelevant, as we don't use CTL0-CTL5?
157 */
158 GPIFCTLCFG = 0;
159
160 /* When GPIF is idle, tri-state the data bus. */
161 /* Bit 7: DONE, bit 0: IDLEDRV. TODO: Set/clear DONE bit? */
162 GPIFIDLECS = (1 << 0);
163
164 /* When GPIF is idle, set CTL0-CTL5 to 0. */
165 GPIFIDLECTL = 0;
166
167 /*
168 * Map index 0 in wavedata[] to FIFORD. The rest is assigned too,
169 * but not used by us.
170 *
171 * GPIFWFSELECT: [7:6] = SINGLEWR index, [5:4] = SINGLERD index,
172 * [3:2] = FIFOWR index, [1:0] = FIFORD index
173 */
174 GPIFWFSELECT = (0x3 << 6) | (0x2 << 4) | (0x1 << 2) | (0x0 << 0);
175
176 /* Contains RDY* pin values. Read-only according to TRM. */
177 GPIFREADYSTAT = 0;
178}
179
180static void gpif_write_waveforms(void)
181{
182 int i;
183
184 /*
185 * Write the four waveforms into the respective WAVEDATA register
186 * locations (0xe400 - 0xe47f) using the FX2's autopointer feature.
187 */
188 AUTOPTRSETUP = 0x07; /* Increment autopointers 1 & 2. */
189 AUTOPTRH1 = MSB((WORD)wavedata); /* Source is the 'wavedata' array. */
190 AUTOPTRL1 = LSB((WORD)wavedata);
191 AUTOPTRH2 = 0xe4; /* Dest is WAVEDATA (0xe400). */
192 AUTOPTRL2 = 0x00;
193 for (i = 0; i < 128; i++)
194 EXTAUTODAT2 = EXTAUTODAT1;
195}
196
197static void gpif_init_addr_pins(void)
198{
199 /*
200 * Configure the 9 GPIF address pins (GPIFADR[8:0], which consist of
201 * PORTC[7:0] and PORTE[7]), and output an initial address (zero).
202 * TODO: Probably irrelevant, the 56pin FX2 has no ports C and E.
203 */
204 PORTCCFG = 0xff; /* Set PORTC[7:0] as alt. func. (GPIFADR[7:0]). */
205 OEC = 0xff; /* Configure PORTC[7:0] as outputs. */
206 PORTECFG |= 0x80; /* Set PORTE[7] as alt. func. (GPIFADR[8]). */
207 OEE |= 0x80; /* Configure PORTE[7] as output. */
208 SYNCDELAY();
209 GPIFADRL = 0x00; /* Clear GPIFADR[7:0]. */
210 SYNCDELAY();
211 GPIFADRH = 0x00; /* Clear GPIFADR[8]. */
212}
213
214static void gpif_init_flowstates(void)
215{
216 /* Clear all flowstate registers, we don't use this functionality. */
217 FLOWSTATE = 0;
218 FLOWLOGIC = 0;
219 FLOWEQ0CTL = 0;
220 FLOWEQ1CTL = 0;
221 FLOWHOLDOFF = 0;
222 FLOWSTB = 0;
223 FLOWSTBEDGE = 0;
224 FLOWSTBHPERIOD = 0;
225}
226
227static void gpif_init_la(void)
228{
229 /*
230 * Setup the FX2 in GPIF master mode, using the internal clock
231 * (non-inverted) at 48MHz, and using async sampling.
232 */
233 IFCONFIG = 0xee;
234
235 /* Abort currently executing GPIF waveform (if any). */
236 GPIFABORT = 0xff;
237
238 /* Setup the GPIF registers. */
239 gpif_setup_registers();
240
241 /* Write the four GPIF waveforms into the WAVEDATA register. */
242 gpif_write_waveforms();
243
244 /* Initialize GPIF address pins, output initial values. */
245 gpif_init_addr_pins();
246
247 /* Initialize flowstate registers (not used by us). */
248 gpif_init_flowstates();
249}
250
251static void setup_endpoints(void)
252{
d5f5ea73
UH
253 /* Setup EP2 (IN). */
254 EP2CFG = (1 << 7) | /* EP is valid/activated */
255 (1 << 6) | /* EP direction: IN */
256 (1 << 5) | (0 << 4) | /* EP Type: bulk */
257 (0 << 3) | /* EP buffer size: 512 */
258 (0 << 2) | /* Reserved. */
259 (0 << 1) | (0 << 0); /* EP buffering: quad buffering */
260 SYNCDELAY();
261
c430e296
JH
262 /* Setup EP6 (IN) in the debug build. */
263#ifdef DEBUG
264 EP6CFG = (1 << 7) | /* EP is valid/activated */
265 (1 << 6) | /* EP direction: IN */
266 (1 << 5) | (0 << 4) | /* EP Type: bulk */
267 (0 << 3) | /* EP buffer size: 512 */
268 (0 << 2) | /* Reserved */
269 (1 << 1) | (0 << 0); /* EP buffering: double buffering */
270#else
271 EP6CFG &= ~bmVALID;
272#endif
273 SYNCDELAY();
274
275 /* Disable all other EPs (EP4 and EP8). */
4ad20a4c
UH
276 EP1INCFG &= ~bmVALID;
277 SYNCDELAY();
278 EP1OUTCFG &= ~bmVALID;
279 SYNCDELAY();
d5f5ea73
UH
280 EP4CFG &= ~bmVALID;
281 SYNCDELAY();
d5f5ea73
UH
282 EP8CFG &= ~bmVALID;
283 SYNCDELAY();
284
4ad20a4c 285 /* EP2: Reset the FIFOs. */
d5f5ea73 286 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
d5f5ea73 287 RESETFIFO(0x02)
c430e296
JH
288#ifdef DEBUG
289 /* Reset the FIFOs of EP6 when in debug mode. */
290 RESETFIFO(0x06)
291#endif
d5f5ea73 292
dc7ac8bf
UH
293 /* EP2: Enable AUTOIN mode. Set FIFO width to 8bits. */
294 EP2FIFOCFG = bmAUTOIN | ~bmWORDWIDE;
295 SYNCDELAY();
296
297 /* EP2: Auto-commit 512 (0x200) byte packets (due to AUTOIN = 1). */
298 EP2AUTOINLENH = 0x02;
299 SYNCDELAY();
300 EP2AUTOINLENL = 0x00;
301 SYNCDELAY();
302
4ad20a4c 303 /* EP2: Set the GPIF flag to 'full'. */
fb0b6d28 304 EP2GPIFFLGSEL = (1 << 1) | (0 << 1);
d5f5ea73
UH
305 SYNCDELAY();
306}
307
308BOOL handle_vendorcommand(BYTE cmd)
309{
c7283c28
UH
310 /* Protocol implementation */
311
312 switch (cmd) {
313 case CMD_SET_SAMPLERATE:
314 /* TODO */
315 break;
316 case CMD_START:
317 /* TODO */
318 break;
319 case CMD_STOP:
320 GPIFABORT = 0xff;
321 /* TODO */
322 return TRUE;
323 break;
324 case CMD_GET_FW_VERSION:
325 /* TODO */
326 break;
327 default:
328 /* Unimplemented command. */
329 break;
330 }
4ad20a4c 331
d5f5ea73
UH
332 return FALSE;
333}
334
335BOOL handle_get_interface(BYTE ifc, BYTE *alt_ifc)
336{
337 /* We only support interface 0, alternate interface 0. */
338 if (ifc != 0)
339 return FALSE;
340
341 *alt_ifc = 0;
342 return TRUE;
343}
344
345BOOL handle_set_interface(BYTE ifc, BYTE alt_ifc)
346{
347 /* We only support interface 0, alternate interface 0. */
348 if (ifc != 0 || alt_ifc != 0)
349 return FALSE;
350
351 /* Perform procedure from TRM, section 2.3.7: */
352
353 /* (1) TODO. */
354
355 /* (2) Reset data toggles of the EPs in the interface. */
356 /* Note: RESETTOGGLE() gets the EP number WITH bit 7 set/cleared. */
d5f5ea73 357 RESETTOGGLE(0x82);
c430e296 358 RESETTOGGLE(0x76);
d5f5ea73
UH
359
360 /* (3) Restore EPs to their default conditions. */
361 /* Note: RESETFIFO() gets the EP number WITHOUT bit 7 set/cleared. */
d5f5ea73
UH
362 RESETFIFO(0x02);
363 /* TODO */
364
c430e296
JH
365 RESETFIFO(0x06);
366
d5f5ea73
UH
367 /* (4) Clear the HSNAK bit. Not needed, fx2lib does this. */
368
369 return TRUE;
370}
371
372BYTE handle_get_configuration(void)
373{
374 /* We only support configuration 1. */
375 return 1;
376}
377
378BOOL handle_set_configuration(BYTE cfg)
379{
380 /* We only support configuration 1. */
381 return (cfg == 1) ? TRUE : FALSE;
382}
383
384void sudav_isr(void) interrupt SUDAV_ISR
385{
386 got_sud = TRUE;
387 CLEAR_SUDAV();
388}
389
390void sof_isr(void) interrupt SOF_ISR using 1
391{
392 CLEAR_SOF();
393}
394
395void usbreset_isr(void) interrupt USBRESET_ISR
396{
397 handle_hispeed(FALSE);
398 CLEAR_USBRESET();
399}
400
401void hispeed_isr(void) interrupt HISPEED_ISR
402{
403 handle_hispeed(TRUE);
404 CLEAR_HISPEED();
405}
406
1cbff47d 407void fx2lafw_init(void)
d5f5ea73
UH
408{
409 /* Set DYN_OUT and ENH_PKT bits, as recommended by the TRM. */
e7434142 410 REVCTL = bmNOAUTOARM | bmSKIPCOMMIT;
d5f5ea73
UH
411
412 got_sud = FALSE;
413
414 /* Renumerate. */
415 RENUMERATE_UNCOND();
416
417 SETCPUFREQ(CLK_48M);
418
419 USE_USB_INTS();
420
421 /* TODO: Does the order of the following lines matter? */
422 ENABLE_SUDAV();
423 ENABLE_SOF();
424 ENABLE_HISPEED();
425 ENABLE_USBRESET();
426
427 /* Global (8051) interrupt enable. */
428 EA = 1;
429
430 /* Setup the endpoints. */
431 setup_endpoints();
432
433 /* Put the FX2 into GPIF master mode and setup the GPIF. */
434 gpif_init_la();
435
dc7ac8bf 436 /* Perform the initial GPIF read. */
d5f5ea73 437 gpif_fifo_read(GPIF_EP2);
1cbff47d 438}
d5f5ea73 439
1cbff47d
JH
440void fx2lafw_run(void)
441{
442 if (got_sud) {
443 handle_setupdata();
444 got_sud = FALSE;
d5f5ea73
UH
445 }
446}
1cbff47d
JH
447
448void main(void)
449{
450 fx2lafw_init();
451
452 while(1)
453 fx2lafw_run();
454}