source: fact/tools/hvMCUtest/fakePLD/fakePLD.pde@ 18123

Last change on this file since 18123 was 12142, checked in by neise, 13 years ago
Arduino code for fake PLD arduino
File size: 11.9 KB
Line 
1#include "macros.h"
2#include <avr/io.h>
3/*
4Mockup for the PLD of Volker Commichaus
5Bias Crate Controller of the FACt Bias
6voltage supply system
7
8Interface to FT245R or
9something that behaves similarly:
10
11I am not going to use the Arduino specific digital input
12and digital output routines anymore . they are slow and stupid.
13But I like Serial.println very much.... so :-)
14
15
16
17Digital I/O:
18
19ATmega: Net Name : Int/Out/Bi : mnemonic
20---------------------------------------------------------------------
21PC0 : RXF# : IN : Read from FIFO possible
22PC1 : TXE# : IN : transmit enable
23PC2 : RD# : OUT : Read from 'FIFO'
24PC3 : WR : OUT : Write to 'FIFO'
25PC4 : : IN : HV down request button - low active
26PD2 : D0 : BI
27PD3 : D1 : BI
28PD4 : D2 : BI
29PD5 : D3 : BI
30PD6 : D4 : BI : Data
31PD7 : D5 : BI
32PB0 : D6 : BI
33PB1 : D7 : BI
34*/
35#define WR PC3
36#define RD PC2
37#define TXE PC1
38#define RXF PC0
39#define BUTTON PC4
40/*
41-----------------------------------------------------------------------------
42
43Analog Inputs:
44
45This Software is intended to be run on an Arduino-like board.
4612 of the digi I/Os are used to communicate with the outside world,
47which is the FTDI245R in the first place.
48The FTDI245R interconnects this mockup via USB with a PC.
49This mockup will *not* provide any real functionality, as
50the PLD in the CrateController does. It will just fake this
51functionality.
52So when it is ordered to set the voltage to e.g. 80V,
53it will store, that it was ordered so.
54If later it is asked to set the voltage to 10V, with a single
55command, it will endure a fake 'trip'.
56Everything, which happens, will be output via Serial Interface.
57
58It is not intended to input anything via the serial interface,
59since this is not possible in reality anyway.
60*/
61
62// comment this line out, if you want to skip the Serial
63// Port entirely
64// #define SERIAL_ON
65
66#define DATABUSWIDTH 8
67#define MAXBOARDS 13
68#define EXISTINGBOARDS 10
69#define CHPERBOARD 32
70#define NUMCHANNELS EXISTINGBOARDS*CHPERBOARD
71
72#define BUTTON_PRESSED_BIT_POS 4
73#define DANGEROUSSTEP 200
74
75#define REFFGAPD 3
76
77
78
79
80unsigned char message[3];
81unsigned char messageindex=0;
82unsigned char answer[3];
83unsigned char answerindex=0;
84
85unsigned char overcurrentbitmap[NUMCHANNELS/8 ];
86unsigned short voltages[NUMCHANNELS];
87unsigned short setvoltage =0;
88unsigned char statusbit =0;
89unsigned char w = 0;
90unsigned short current =0;
91unsigned char errorbits = 0;
92unsigned char board = 0;
93unsigned char channel = 0;
94
95unsigned char timeoutcounter =0;
96
97typedef enum {
98 state_receiving,
99 state_parsing,
100 state_system_reset,
101 state_read_status,
102 state_global_set,
103 state_set_voltage,
104 state_sending
105} state_t;
106
107 state_t last_state = state_set_voltage;
108 state_t state = state_receiving;
109 unsigned char command =0;
110
111
112void setup(){
113
114 DDRC |= 1<<PC5;
115 PORTC ^= 1<<PC5;
116 PORTC ^= 1<<PC5;
117 #ifdef SERIAL_ON
118 Serial.begin(9600);
119 #endif
120
121 // WR and RD are outputs
122 DDRC |= (1<<WR) | (1<<RD);
123 // WR idles low
124 PORTC &= ~1<<WR;
125 // RD idles high
126 PORTC |= (1<<RD);
127
128 // RXF, TXE and BUTTON are inputs
129 DDRC &= ~( (1<<TXE) | (1<<RXF) | (1<<BUTTON) );
130
131 // TXE and RXF should be held high by the FT245 or Arduino anyway,
132 // but for convenience
133 // I pull them up, with ~20kohm reistors.
134
135 PORTC |= 1<<TXE;
136 PORTC |= 1<<RXF;
137
138 // The button should be low active.
139 // so I need a pull up here as well.
140 PORTC |= 1<< BUTTON;
141
142 // this affects PD2..PD7, PB0 and PB1.
143 //MakeDataBusInput ();
144 MAKEDATABUSINPUT;
145
146 // for security, all unused pins I set to inputs, but
147 // this might be anyway the atmega default case...
148 //DDRC &= ~( (1<<PC5) | (1<<PC6) | (1<<PC7) ); //arduino states: PC7 is not defined in this scope
149 DDRC &= ~( (1<<PC5) | (1<<PC6) );
150 DDRC |= 1<<PC5;
151 DDRB &= ~( (1<<PB2) | (1<<PB3) | (1<<PB4) );
152
153 // to PB5 a LED is connected
154 DDRB |= 1<<PB5;
155 // this LED is high active ... I switch it on & off quickly
156 PORTB |= 1<<PB5;
157 delay (100);
158 PORTB &= ~(1<<PB5);
159
160 #ifdef SERIAL_ON
161 Serial.println("\n\nwelcome to the arduino FACT bias crate controller");
162 #endif
163
164 for (unsigned short channel = 0; channel < NUMCHANNELS; channel++)
165 voltages[channel] = 0;
166 for (unsigned short channel = 0; channel < NUMCHANNELS/8; channel++)
167 overcurrentbitmap[channel] = 0x00;
168
169 /*
170 delay (1000);
171 delay (1000);
172 delay (1000);
173 delay (1000);
174 delay (1000);
175 delay (1000);
176 delay (1000);
177 delay (1000);
178 delay (1000);
179 delay (1000);
180 delay (1000);
181 delay (1000);
182 delay (1000);
183 delay (1000);
184 delay (1000);
185 delay (1000);
186 delay (1000);
187 delay (1000);
188 delay (1000);
189 delay (1000);
190 delay (1000);
191 delay (1000);
192 delay (1000);
193*/
194 PORTC ^= 1<<PC5;
195 PORTC ^= 1<<PC5;
196 PORTC ^= 1<<PC5;
197 PORTC ^= 1<<PC5;
198}
199
200void loop(){
201 PORTC ^= 1<<PC5;
202 PORTC ^= 1<<PC5;
203
204 #ifdef SERIAL_ON
205 if (state != last_state){
206 Serial.print("state: ");
207 switch (state){
208 case state_receiving:
209 Serial.println("receiving");
210 break;
211 case state_parsing:
212 Serial.println("parsing");
213 break;
214 case state_system_reset:
215 Serial.println("sys reset");
216 break;
217 case state_read_status:
218 Serial.println("read stat");
219 break;
220 case state_global_set:
221 Serial.println("global set");
222 break;
223 case state_set_voltage:
224 Serial.println("set volt");
225 break;
226 case state_sending:
227 Serial.println("sending");
228 break;
229 }
230 }
231 last_state = state;
232 #endif
233
234switch( state ) {
235 case state_receiving:
236 //PORTB |= 1<<PB5;
237 //delay (100);
238 //PORTB &= ~(1<<PB5);
239 // empfange bytes vom FT245 und
240 // schreibe diese in ein byte-array der Länge 3
241 // wenn vollständig, dann gehe in zustand: state_parsing
242 if ( ISRXFLOW ){
243 // read one byte
244 CLRBIT(PORTC, RD);
245 message[messageindex]=READFROMDATABUS;
246 SETBIT(PORTC, RD);
247 messageindex++;
248 while ( ISRXFLOW ){}
249 }
250 if (messageindex == 3) {
251 messageindex = 0;
252 state = state_parsing;
253 }
254 break;
255
256 case state_parsing:
257 PORTC ^= 1<<PC5;
258 PORTC ^= 1<<PC5;
259 #ifdef SERIAL_ON
260 for (int i=0; i<3; i++){
261 Serial.print(message[i], HEX);
262 if (i<2)
263 Serial.print(" ");
264 else
265 Serial.println("");
266 }
267 #endif
268 // schau in das 3-byte array und finde heraus, was zu tun ist.
269 // je nachdem was zu tun ist, wird die state variable anders gesetzt.
270 // die message wird nicht verändert .. also die ersten bits nicht weggeschnitten oder so.
271 //
272 command = (message[0]) >> 5;
273 // das & 0x07 ist hier garnicht unbedingt notwendig, aber
274 // es stellt sicher, dass ich mit case 0 bis case 7
275 // wirklich alle cases bearbeitet habe.. dann brauch
276 // ich keinen default case.
277 switch ( command & 0x07 ) {
278 case 0:
279 // System Reset
280 state = state_system_reset;
281 break;
282
283 case 1:
284 // Read Channel Status & Current
285 state = state_read_status;
286 break;
287
288 case 2:
289 // Global Set
290 state = state_global_set;
291 break;
292
293 case 3:
294 // Channel Set to voltage
295 state = state_set_voltage;
296 break;
297
298 default:
299 // TODO Alarm, das ist unfug, aber nur zum testen
300 answer[0] = 0xff ;
301 answer[1] = 0x00 ;
302 answer[2] = 0xff ;
303 state = state_sending;
304 break;
305 }
306 //state = state_receiving;
307 break;
308
309 case state_system_reset:
310 PORTC ^= 1<<PC5;
311 PORTC ^= 1<<PC5;
312 PORTC ^= 1<<PC5;
313 PORTC ^= 1<<PC5;
314 w = (w+1)%8;
315 // Die message hat also den Befehl 'crate_reset' enthalten
316 // Also werde ich mal alles resetten, was ich so weiss
317 // Ist aber wichtig, nochmal nach zu lesen, was eigentlich
318 // wirklich resetted werden muss.
319 //
320 // System reset setzt nicht die Spannungen auf null
321 // for (unsigned short channel = 0; channel < NUMCHANNELS; channel++)
322 // voltages[channel] = 0;
323 for (unsigned short channel = 0; channel < NUMCHANNELS/8; channel++)
324 overcurrentbitmap[channel] = 0x00;
325 answer[0] = w<<4;
326 answer[1] = 0x00;
327 answer[2] = 0x00;
328 state = state_sending;
329 break;
330
331 case state_read_status:
332 PORTC ^= 1<<PC5;
333 PORTC ^= 1<<PC5;
334 PORTC ^= 1<<PC5;
335 PORTC ^= 1<<PC5;
336 PORTC ^= 1<<PC5;
337 PORTC ^= 1<<PC5;
338 w = (w+1)%8;
339 // Hier hat der User, nach dem status eines bestimmten
340 // boards und channels gefragt. Wo nach wurde gefragt?
341 board = (message[0] & 0x1e) >> 1;
342 channel = ((message[0] & 0x01) << 4) | ((message[1] & 0xf0) >> 4) ;
343 // Jetzt ist interessant, ob das angefragte board vorhanden ist
344 if (board < EXISTINGBOARDS){ // board exists
345 // we calculate the current I=U/R
346 current = voltages[board * CHPERBOARD + channel] / REFFGAPD;
347 answer[0] = (statusbit<<7) | (w<<4) | (unsigned char)((current>>8) & 0x000f);
348 answer[1] = (unsigned char)(current & 0x00ff);
349 answer[2] = (errorbits<<4) | (board&0x0f);
350 } else { // board is not exisiting
351 answer[0] = w<<4;
352 answer[1] = 0x00;
353 answer[2] = 0xf0 | (board&0x0f);
354 }
355 state = state_sending;
356 break;
357
358
359 case state_set_voltage:
360 PORTC ^= 1<<PC5;
361 PORTC ^= 1<<PC5;
362 PORTC ^= 1<<PC5;
363 PORTC ^= 1<<PC5;
364 PORTC ^= 1<<PC5;
365 PORTC ^= 1<<PC5;
366 PORTC ^= 1<<PC5;
367 PORTC ^= 1<<PC5;
368 w = (w+1)%8;
369 board = (message[0] & 0x1e) >> 1;
370 channel = ((message[0] & 0x01) << 4) | ((message[1] & 0xf0) >> 4) ;
371 errorbits = 0;
372 statusbit = 0;
373
374 errorbits |= ISBUTTONPRESSED<<(BUTTON_PRESSED_BIT_POS);
375
376 if ( board < EXISTINGBOARDS){
377 setvoltage = ((unsigned short)*message+1) & 0x0fff;
378 if ( abs(voltages[board*CHPERBOARD + channel] - setvoltage) > DANGEROUSSTEP ) {// overcurrent!
379 overcurrentbitmap[board*CHPERBOARD/8+channel/8] |= 1<<channel%8;
380 statusbit = 1;
381 }
382 voltages[board*CHPERBOARD + channel] = setvoltage;
383 current = voltages[board * CHPERBOARD + channel] / REFFGAPD;
384 } else {
385 current = 0;
386 errorbits |= 0x07;
387 }
388
389
390 answer[0] = statusbit<<7 | w<<4 | (unsigned char)((current>>8) & 0x000f);
391 answer[1] = (unsigned char)(current & 0x00ff);
392 answer[2] = errorbits<<4 | (board&0x0f);
393
394 state = state_sending;
395 break;
396
397 case state_global_set:
398 PORTC ^= 1<<PC5;
399 PORTC ^= 1<<PC5;
400 PORTC ^= 1<<PC5;
401 PORTC ^= 1<<PC5;
402 PORTC ^= 1<<PC5;
403 PORTC ^= 1<<PC5;
404 PORTC ^= 1<<PC5;
405 PORTC ^= 1<<PC5;
406 PORTC ^= 1<<PC5;
407 PORTC ^= 1<<PC5;
408 w = (w+1)%8;
409 // Erstmal schauen, was der user für eine Spannung setzen wollte
410 setvoltage = ((unsigned short)*message+1) & 0x0fff;
411 // so .. da jemand eine Spannung hoch oder runter setzt, könnte es sein
412 // dass ein überstrom zustand auftritt ... sagen wir mal, wenn die Spannung in einem
413 // Schritt um mehr als 3 geändert wird, dann gibts nen Überstrom
414 // das ist eigentlich mist, aber ich will erstmal irgendwas hier einbauen.
415 for (unsigned char b=0; b < EXISTINGBOARDS; b++)
416 for (unsigned char c=0; c < CHPERBOARD; c++){
417 if ( abs(voltages[b*CHPERBOARD + c] - setvoltage) > DANGEROUSSTEP )// overcurrent!
418 overcurrentbitmap[b*CHPERBOARD/8+c/8] |= 1<<c%8;
419 voltages[b*CHPERBOARD + c] = setvoltage;
420 }
421 answer[0] = w<<4 ;
422 answer[1] = 0x00 ;
423 answer[2] = 0x00 ;
424 state = state_sending;
425 break;
426
427 case state_sending:
428 PORTC ^= 1<<PC5;
429 PORTC ^= 1<<PC5;
430 PORTC ^= 1<<PC5;
431 PORTC ^= 1<<PC5;
432 PORTC ^= 1<<PC5;
433 PORTC ^= 1<<PC5;
434 PORTC ^= 1<<PC5;
435 PORTC ^= 1<<PC5;
436 PORTC ^= 1<<PC5;
437 PORTC ^= 1<<PC5;
438 PORTC ^= 1<<PC5;
439 PORTC ^= 1<<PC5;
440 PORTC ^= 1<<PC5;
441 PORTC ^= 1<<PC5;
442 // in diesem State bleibe ich solange es dauert, um die 'answer'
443 // zu senden. Falls das senden aus irgendeinem Grund nicht gehen sollte
444 // bleibe ich *für immer* in diesem state.
445 if ( ISTXELOW ){
446 MAKEDATABUSOUTPUT;
447 PUTONDATABUS(answer[answerindex]);
448 SETBIT (PORTC, WR);
449 delayMicroseconds(6);
450 CLRBIT (PORTC, WR);
451 MAKEDATABUSINPUT;
452
453 answerindex++;
454 //wait for txe going high
455 while ( ISTXELOW ){ }
456 }
457
458 if (answerindex == 3 || timeoutcounter >250) {
459 answerindex =0;
460 state = state_receiving;
461 }
462 break;
463
464 default:
465 // ungültiger Zustand!
466 // Sollte eigentlich nie auftreten
467 // Wenn er auftritt, dann erzeuge ich eine Nachricht via
468 // USB.
469 break;
470 }
471
472}
473
Note: See TracBrowser for help on using the repository browser.