view gpib.cc @ 5:1a405bda2ffe

rewrite gpib using state machine instead of procedural code, add proper timeout, command queueing, several new commands, improve hardcopy utility
author Frank Kingswood <frank@kingswood-consulting.co.uk>
date Sat, 29 Mar 2014 23:23:58 +0000
parents a70e0a8ac73e
children acbd0ddd002b
line wrap: on
line source
1 /* #------------------------------------------------------------------------#
2 | |
3 | gpib.cc |
4 | |
5 | USB-GPIB GPIB processing and state machine. |
6 | |
7 | Copyright 2014, Frank A. Kingswood, www.kingswood-consulting.co.uk |
8 | |
9 #------------------------------------------------------------------------# */
11 #include <avr/pgmspace.h>
12 #include <avr/interrupt.h>
13 #include <stdint.h>
14 #include <ctype.h>
15 #include <util/delay.h>
16 #include "usb_serial.h"
17 #include "serial.h"
18 #include "gpib.h"
20 // GPIB Connector
21 //
22 // Pin Name Signal Description Pin Name Signal Description
23 // --- ------ ------------------------- --- ------ -------------------------
24 // 1 DIO1 Data Input/Output Bit 1 13 DIO5 Data Input/Output Bit 5
25 // 2 DIO2 Data Input/Output Bit 2 14 DIO6 Data Input/Output Bit 6
26 // 3 DIO3 Data Input/Output Bit 3 15 DIO7 Data Input/Output Bit 7
27 // 4 DIO4 Data Input/Output Bit 4 16 DIO8 Data Input/Output Bit 8
28 // 5 EIO End-Or-Identify 17 REN Remote Enable
29 // 6 DAV Data Valid 18 GND Ground DAV
30 // 7 NRFD Not Ready For Data 19 GND Ground NRFD
31 // 8 NDAC Not Data Accepted 20 GND Ground NDAC
32 // 9 IFC Interface Clear 21 GND Ground IFC
33 // 10 SRQ Service Request 22 GND Ground SRQ
34 // 11 ATN Attention 23 GND Ground ATN
35 // 12 Shield Chassis Ground 24 GND Ground DIO, REN, EOI
36 //
37 // Handshake Output
38 // --------- ---------
39 // NRFD Listener
40 // NDAC Listener
41 // DAV Talker
42 //
43 // Control Output
44 // --------- ---------
45 // ATN Controller
46 // IFC Controller
47 // REN Controller
48 // SRQ Any
49 // EOI Talker and Controller
50 //
51 // Teensy 2.0 has two complete 8-bit ports PB and PD
52 // Arduino Leonardo and "Pro Micro" have 15 out of 16, good try!
53 // 20 mA/pin, 100 mA max for 8-bit port
54 //
55 // 32U4 Arduino GPIB 32U4 Arduino GPIB
56 // ---------- ----- ---- ---------- ----- ----
57 // PB0 (SS) - : DIO1 PD0 (INT0) "d3" : EOI
58 // PB1 (SCLK) "sck" : DIO2 PD1 (INT1) "d2" : NRFD
59 // PB2 (MOSI) "mosi" : DIO3 PD2 (INT2) "rxi" : NDAC
60 // PB3 (MISO) "miso" : DIO4 PD3 (INT3) "txo" : SRQ
61 // PB4 "d8" : DIO5 PD4 "d4" (pull down for arduino)
62 // PB5 "d9" : DIO6 PD5 (LED) (debug serial)
63 // PB6 "d10" : DIO7 PD6 (LED) - -
64 // PB7 - : DIO8 PD7 "d6" : DAV
65 //
66 // Other pins
67 //
68 // 32U4 Arduino GPIB 32U4 Arduino GPIB
69 // ---------- ----- ---- ---------- ----- ----
70 // PF0 (ADC0) - - PC6 "d5" DIO8
71 // PF1 (ADC1) - - PC7 -
72 // PF4 (ADC4) "a3" : ATN PE6 "d7" DIO1
73 // PF5 (ADC5) "a2" : IFC
74 // PF6 (ADC6) "a1" : REN
75 // PF7 (ADC7) "a0" :
76 //
77 // Teensy has LED on PD6 to GND (shared)
78 // Arduino has LED on PD5 to VCC
79 // and on PB0 to VCC (shared with DIO1)
81 #undef DEBUG
83 Queue<128> GPIBDriver::CommandQueue;
84 Queue<128> GPIBDriver::ReadQueue;
86 uint16_t GPIBDriver::MyAddress;
87 uint16_t GPIBDriver::DeviceAddress;
88 uint16_t GPIBDriver::Timeout;
89 bool GPIBDriver::MicroPro;
90 GPIBDriver::State_t GPIBDriver::State;
92 GPIBDriver::GPIBDriver()
93 {
94 Initialize();
95 }
97 void GPIBDriver::Initialize()
98 {
99 Float();
100 MyAddress=0;
101 DeviceAddress=1;
102 Timeout=1000; // one second
103 MicroPro=test_bit_clear(PIND,PORTD_TEENSY_N_ARDUINO);
104 FloatData();
106 CommandQueue.Clear();
107 ReadQueue.Clear();
108 State=RESET;
110 TCCR0A=(1<<WGM01)|(1<<WGM00); // fast pwm mode (but no PWM output)
111 TCCR0B=(1<<WGM02)|(1<<CS01)|(1<<CS00); // prescaler=64
112 OCR0A=250-1; // 258*64=16000 cycles, 1ms
113 OCR0B=255;
114 TIMSK0=(1<<TOIE0); // enable overflow interrupt
115 }
117 uint16_t Timer;
118 bool TimedOut;
119 ISR(TIMER0_OVF_vect)
120 {
121 if(Timer)
122 { if(--Timer==0)
123 TimedOut=true;
124 }
125 }
127 void StartTimer()
128 {
129 cli();
130 TimedOut=false;
131 Timer=GPIBDriver::Timeout;
132 sei();
133 }
136 // float data bus
137 void GPIBDriver::FloatData()
138 {
139 DDRB=0;
140 PORTB=0xff;
141 if(MicroPro)
142 { clear_bit(DDRE,6);
143 clear_bit(DDRC,6);
144 }
145 }
147 // float all pins
148 void GPIBDriver::Float()
149 {
150 // data lines all inputs
151 FloatData();
153 static const uint8_t used_c=(1<<PORTC_DIO8);
154 DDRC&=0xff^used_c;
155 PORTC=(PORTC&~used_c)|(0xff&used_c);
157 static const uint8_t used_e=(1<<PORTE_DIO1);
158 DDRE&=0xff^used_e;
159 PORTE=(PORTE&~used_e)|(0xff&used_e);
161 static const uint8_t used_d=(1<<PORTD_EOI) |
162 (1<<PORTD_NDAC) |
163 (1<<PORTD_NRFD) |
164 (1<<PORTD_SRQ) |
165 (1<<PORTD_TEENSY_N_ARDUINO) |
166 (1<<PORTD_DAV);
167 DDRD=0xff^used_d;
168 PORTD=(PORTD&~used_d)|(0xff&used_d);
170 // controls, used indicates bits that are used by us
171 static const uint8_t used_f=(1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN);
172 DDRF&=0xff^used_f;
173 PORTF=(PORTF&~used_f)|(0xff&used_f);
174 }
176 // drive LED
177 void GPIBDriver::LED(bool on)
178 {
179 if(MicroPro)
180 { if(on)
181 set_bit(PORTD,PORTD_LED_MP);
182 else
183 clear_bit(PORTD,PORTD_LED_MP);
184 }
185 else
186 { if(on)
187 set_bit(PORTD,PORTD_LED_T);
188 else
189 clear_bit(PORTD,PORTD_LED_T);
190 }
191 }
193 // Become controller in charge of the bus
194 //
195 // ++cic
196 // - float all pins
197 // - REN=0
199 void GPIBDriver::Controller()
200 {
201 Float();
203 // start driving ATN IFC and REN
204 PORTF |= (1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN);
205 DDRF |= (1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN);
207 // pull /REN low to become actice controller
208 REN(true);
209 }
212 uint8_t GPIBDriver::Lines()
213 {
214 uint8_t pd=PIND & ((1<<PORTD_EOI) | (1<<PORTD_NRFD) | (1<<PORTD_NDAC) |
215 (1<<PORTD_SRQ) | (1<<PORTD_DAV));
216 uint8_t pf=PINF & ((1<<PORTF_ATN) | (1<<PORTF_IFC) | (1<<PORTF_REN));
218 return ~(pf | pd);
219 }
221 void GPIBDriver::Report(_ROMS msg)
222 {
223 if(msg)
224 USB<<msg<<':';
225 else
226 USB<<'<';
227 if(DDRB==0)
228 USB<<"i=";
229 else
230 USB<<"o=";
231 USB.Hex(Data());
233 uint8_t lines=Lines();
234 if(lines & (1<<PORTD_EOI)) USB<<ROMS(" EOI");
235 if(lines & (1<<PORTF_ATN)) USB<<ROMS(" ATN");
236 if(lines & (1<<PORTD_SRQ)) USB<<ROMS(" SRQ");
237 if(lines & (1<<PORTF_REN)) USB<<ROMS(" REN");
238 if(lines & (1<<PORTF_IFC)) USB<<ROMS(" IFC");
239 if(lines & (1<<PORTD_NRFD)) USB<<ROMS(" NRFD");
240 if(lines & (1<<PORTD_NDAC)) USB<<ROMS(" NDAC");
241 if(lines & (1<<PORTD_DAV)) USB<<ROMS(" DAV");
243 if(msg)
244 USB<<endl;
245 else
246 USB<<'>';
247 }
249 static const uint32_t TIMEOUT=0x1ff000ULL; // 20 seconds
251 void GPIBDriver::Data(uint8_t byte)
252 {
253 PORTB=~byte;
254 DDRB=SAFER ? byte : 0xff;
255 if(MicroPro)
256 {
257 clear_bit(DDRB,0)
258 ;
259 // pathetic board does not have an 8-bit port
260 if(byte&1)
261 { clear_bit(PORTE,6);
262 set_bit(DDRE,6);
263 }
264 else
265 { clear_bit(DDRE,6);
266 set_bit(PORTE,6);
267 }
269 if(byte&0x80)
270 { clear_bit(PORTC,6);
271 set_bit(DDRC,6);
272 }
273 else
274 { clear_bit(DDRC,6);
275 set_bit(PORTC,6);
276 }
277 }
278 }
280 uint8_t GPIBDriver::Data()
281 {
282 uint8_t byte=~PINB;
283 if(MicroPro)
284 {
285 // pathetic board does not have an 8-bit port
286 byte &= 0x7e;
287 if(test_bit_clear(PINE,6))
288 byte |= 1;
289 if(test_bit_clear(PINC,6))
290 byte |= 0x80;
291 }
292 return byte;
293 }
295 bool GPIBDriver::Command(uint16_t data)
296 {
297 #ifdef DEBUG
298 USB<<ROMS("Command(");
299 USB.Hex(data);
300 USB<<ROMS(")\r\n");
301 #endif
302 if(data==0)
303 return true;
304 return CommandQueue.Put(data);
305 }
307 uint16_t GPIBDriver::Read()
308 {
309 return ReadQueue.Get();
310 }
312 #ifdef DEBUG
313 GPIBDriver::State_t last=(GPIBDriver::State_t)~0; // debug
314 uint16_t lasttimer=0;
315 #endif
317 int8_t GPIBDriver::Poll()
318 {
319 // tune this so we go round the loop often enough to send/receive one byte
320 for(uint8_t loop=0; loop<100; loop++)
321 {
322 #ifdef DEBUG
323 if(Timer%128==1 && Timer!=lasttimer)
324 {
325 last=(GPIBDriver::State_t)~0;
326 lasttimer=Timer;
327 }
329 if(State!=last)
330 {
331 //Report();
332 USB<<ROMS(" state=")<<State<<
333 ROMS(" cq=")<<CommandQueue.Used()<<
334 ROMS(" rq=")<<ReadQueue.Used()<<
335 ROMS(" t=")<<Timer;
336 if(TimedOut)
337 {
338 USB<<ROMS(" TO");
339 }
340 USB<<endl;
341 last=State;
342 }
343 #endif
345 switch(State)
346 {
347 case RESET:
348 Float();
349 TimedOut=false;
350 CommandQueue.Clear();
351 State=IDLE;
352 return 0;
354 case IDLE:
355 { uint16_t data=CommandQueue.Peek();
357 #ifdef DEBUG
358 if(data)
359 {
360 USB<<ROMS("data=");
361 USB.Hex(data);
362 USB<<endl;
363 }
364 #endif
366 switch(data & CMD_MASK)
367 { case 0:
368 return 0; // idle
369 case CMD_SOURCE:
370 State=SH_START;
371 break;
372 case CMD_ACCEPT:
373 State=AH_START;
374 break;
375 case CMD_CONTROLLER:
376 State=CAC_START;
377 break;
378 case CMD_SIC:
379 State=SIC_START;
380 break;
381 case CMD_RELEASE:
382 Float();
383 State=IDLE;
384 break;
385 default:
386 // drop unknown command
387 CommandQueue.Get();
388 return EINTERN; // internal error
389 }
390 } break;
393 /* ..... source handshake ................................................... */
395 case SH_START:
396 { uint16_t data=CommandQueue.Peek();
397 ATN(data&CMD_ATN);
398 DAV(false);
400 // settling delay
401 _delay_us(2);
403 if(!NRFD() && !NDAC())
404 { State=RESET;
405 return EACPROT; // acceptor protocol error
406 }
407 State=SH_DATA;
408 } break;
410 case SH_DATA:
411 { // remove command from the queue
412 uint16_t data=CommandQueue.Get();
414 // drive data
415 EOI(data&CMD_EOI);
416 Data(data);
418 // settling delay
419 _delay_us(2);
421 // start timer default
422 StartTimer();
424 State=SH_WAIT_NRFD;
425 } break;
427 case SH_WAIT_NRFD:
428 if(!NRFD())
429 State=SH_DAV;
430 else if(TimedOut)
431 { State=RESET;
432 return EACTMO; // acceptor timeout
433 }
434 break;
436 case SH_DAV:
437 DAV(true);
439 // start timer default
440 StartTimer();
442 State=SH_WAIT_NDAC;
443 break;
445 case SH_WAIT_NDAC:
446 if(!NDAC())
447 State=SH_N_DAV;
448 else if(TimedOut)
449 { State=RESET;
450 return EACTMO; // acceptor timeout
451 }
452 break;
454 case SH_N_DAV:
455 DAV(false);
456 EOI(false);
457 FloatData();
458 State=IDLE;
459 break;
462 /* ..... acceptor handshake ................................................. */
464 case AH_START:
465 // NRFD(true); // old code used to do this
466 NDAC(true);
468 if(ATN())
469 { // settling delay
470 _delay_us(1);
471 State=AH_N_ATN;
472 }
473 else
474 State=AH_READY;
475 break;
477 case AH_N_ATN:
478 // negate ATN
479 ATN(false);
480 State=AH_READY;
481 break;
483 case AH_READY:
484 // ready for data
485 NRFD(false);
487 // start timer default
488 StartTimer();
490 State=AH_WAIT_DAV;
491 break;
493 case AH_WAIT_DAV:
494 if(DAV())
495 State=AH_NRFD;
496 else if(TimedOut)
497 { State=RESET;
498 return ESRCTMO; // source timeout
499 }
500 break;
502 case AH_NRFD:
503 { NRFD(true);
505 uint16_t cmd=CommandQueue.Peek();
506 uint8_t eoi=EOI();
508 uint16_t data=CMD_ACCEPT | Data();
509 if(ATN())
510 data|=CMD_ATN;
511 if(eoi)
512 data|=CMD_EOI;
514 #ifdef DEBUG
515 USB<<ROMS("data=");
516 USB.Hex(data);
517 if((data&0xff)>=32 && (data&0xff)<127)
518 { USB<<' '<<'\''<<char(data)<<'\'';
519 }
520 USB<<endl;
521 #endif
523 bool last=((cmd&CMD_AC_EOI)!=0 && eoi) || // EOI on byte
524 ((cmd&CMD_AC_BYTE)!=0 && ((cmd^data)&0xff)==0) || // byte match
525 ((cmd&CMD_AC_COUNT)!=0); // counter
527 if(ReadQueue.Put(data))
528 State=last ? AH_N_NDAC_LAST : AH_N_NDAC;
529 else if(TimedOut)
530 { State=last ? AH_WAIT_NDAV_LAST : AH_WAIT_NDAV;
531 return EFULL; // timeout on read queue
532 }
533 else
534 return 0;
535 } break;
537 case AH_N_NDAC:
538 NDAC(false);
539 State=AH_WAIT_NDAV;
540 break;
542 case AH_WAIT_NDAV:
543 if(!DAV())
544 State=AH_NDAC;
545 else if(TimedOut)
546 { State=RESET;
547 return ESRCTMO; // source timeout
548 }
549 break;
551 case AH_NDAC:
552 NDAC(true);
553 State=AH_READY;
554 break;
556 case AH_N_NDAC_LAST:
557 NDAC(false);
558 State=AH_WAIT_NDAV_LAST;
559 break;
561 case AH_WAIT_NDAV_LAST:
562 if(!DAV())
563 { CommandQueue.Get(); // remove command from queue
564 State=IDLE;
565 }
566 else if(TimedOut)
567 { State=RESET;
568 return ESRCTMO; // source timeout
569 }
570 break;
573 /* ..... take control ....................................................... */
575 case CAC_START:
576 GPIB.ATN(false);
577 GPIB.EOI(false);
578 GPIB.NRFD(false);
579 GPIB.DAV(false);
580 GPIB.NDAC(false);
582 if(CommandQueue.Get()&CMD_CTRL_FORCE)
583 State=CAC_COMPLETE;
584 else
585 {
586 StartTimer();
587 State=CAC_WAIT;
588 }
589 break;
591 case CAC_WAIT:
592 if(!(GPIB.ATN() || GPIB.NRFD() || GPIB.NDAC() || GPIB.DAV()))
593 State=CAC_COMPLETE;
594 else if(TimedOut)
595 { State=RESET;
596 return ECTRLTMO; // controller timeout
597 }
598 break;
600 case CAC_COMPLETE:
601 Controller();
602 State=IDLE;
603 break;
606 /* ..... send interface clear ............................................... */
608 case SIC_START:
609 CommandQueue.Get();
610 GPIB.IFC(true);
611 StartTimer();
612 State=SIC_WAIT;
613 break;
615 case SIC_WAIT:
616 if(!(GPIB.DAV() || GPIB.NRFD() || GPIB.NDAC()))
617 State=SIC_COMPLETE;
618 else if(TimedOut)
619 { State=SIC_COMPLETE;
620 return ECTRLTMO; // controller timeout
621 }
622 break;
624 case SIC_COMPLETE:
625 GPIB.IFC(false);
626 State=IDLE;
627 break;
630 /* ..... parallel poll ...................................................... */
632 case PP_START:
633 GPIB.ATN(true);
634 GPIB.EOI(true);
635 // settling delay
636 _delay_us(1);
637 State=PP_COMPLETE;
638 break;
640 case PP_COMPLETE:
641 { uint16_t data;
643 data=CMD_PARPOLL | Data();
644 GPIB.ATN(false);
645 GPIB.EOI(false);
646 State=IDLE;
648 if(!ReadQueue.Put(data))
649 return EFULL; // timeout on read queue
651 } break;
653 /* .......................................................................... */
655 default:
656 State=RESET;
657 return EINTERN; // internal error
658 }
659 }
660 return 0;
661 }
663 /* ========================================================================== */
665 const GPIBDriver __attribute__((__progmem__)) GPIB;
667 //
669 // GPIB System Concepts
670 // ====================
671 // ______________________
672 // ATN_________________________ATN___/ ATN
673 //
674 // ______ _________ ________ ________
675 // DAV \________/ DAV \________/ DAV
676 //
677 // _____ _____ __________ ____
678 // NRFD__/ \_________/ NRFD \_________/ NRFD
679 //
680 // _____ _____
681 // NDAC__________/ \_______NDAC____________/ \______NDAC
682 //
683 // ________________ ___________________
684 // DATA---<________________>---DATA--<___________________>--DATA
685 //
686 //
687 // TNT4882 Manual
688 // ==============
689 // __________________________
690 // ATN___/ ATN
691 //
692 // ___________ _________
693 // DAV \________/ DAV
694 //
695 // ________ ___
696 // NRFD_____/ \__________/ NRFD
697 //
698 // _____
699 // NDAC________________/ \______NDAC
700 //
701 // ___________________
702 // DATA--------<___________________>--DATA
703 //
705 /* ----- EOF gpib.cc ----- */