C1541-III mbed edition

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers IEC_bus.c Source File

IEC_bus.c

00001 /*------------------------------------------------------------------------------------------*/
00002 /*This is the lowlevel IEC-bus_driver,                                                         */
00003 /*                                                                                            */
00004 /*Note that this driver is dirty because it polls the drive for it's flags. The             */
00005 /*routines in this driver should therefore only be called from a low priority task            */
00006 /*                                                                                          */
00007 /*Attention: routines tuned for 20MHz                                                       */
00008 /*------------------------------------------------------------------------------------------*/
00009 /*  History:                                                                        
00010     --------      
00011     2007-04-28    KeepItSimpleStupid, so hanging on to this live style I removed the 'filter' from the IEC_receive routine (it was unneccessary nonsense anyway)
00012     2007-04-25    CheckForCommand had an delay of 200uS to ensure the "frame to release of ATN'-time" of min 20uS, this is removed and now in the higher level IEC staemachine (main.c)
00013     2007-04-23    IECundoturnaround() was checking for the clok, this is not reuiqed in this situation, that's why the timeout worked bettre then no timeout, simply because the CLOCK check is not required at THIS stage of the communication
00014     2007-04-16    removed a semicolon in the acknowledge timeout check... there should not be a semicolon after the while :-) (oops)
00015     2007-04-15    ADDED a ATN check on IEC_turnaround routine
00016     2007-04-09    removed all code that was made commentary with //
00017     2007-04-08    added the same 'filter' on FreeIEC and CheckForCommand... and then disabled the new code with "//" simply because the new improvements made it even worse...
00018     2007-04-07    added some extra checks to make sure we trigger/test the clock/data signals correctly (software signal filtering).
00019                 this is required because sometimes the device triggers incorrectly on signals meant for other devices on the bus
00020                 which is best noticable during intense bus trafic. But it is very likely to happen at any moment (you can't predict glitches/spikes).
00021     2007-04-01    the check IEC_CLOCK == 1 in UNDOTURNAROUND now has a time-out, simply to improve reliablillity... it helps a lot!
00022     2006-11-01    the channel value was always extracted from the commandbyte, even if there was no channel value. This caused problems in the new statemachine (before the new statemachine the channel was used before the 3f/5f command so this problme was no problem then)
00023     2006-10-31    added thefunction IEC_monitor this function can be used to monitor bus activity without interfering
00024                 removed the setdeviceaddress function, since this is handled in MAIN.C
00025     2006-10-30    the data and open command are identical when the errorchannel (15) is addressed
00026     2006-10-22    changed the channel-variable to a variable outside the IEC_bus code, so it can be used in MAIN.c where it is declared
00027     2006-10-20    added a function to set the timings of the IEC-bus (required for 25% faster VIC20-mode)
00028     2006-07-03    changed 'FreeIEC' routine, this routine caused busylooping at an unwanted level, the busy-loop waiting for ATN going low 
00029                 is now located in main, so we can do other things while not communicating over the IEC-bus (manual file selection for instance)
00030     2006-07-02    changed WaitForCommand into CheckForCommand, since the routine is no longer a while loop
00031     2006-03-28    change in release and pulldown ATN-line routines, caused by new PCB design
00032     2006-02-22    added frame_handshake signal for later use
00033     2006-02-02    improvements in code layout... i.o.w. making it more readable                                                                  
00034     2005-10-18    start of IEC bus driver
00035     2005-10-19    further details on EOI condition
00036     2005-10-22    delay routines for IEC timing
00037     2005-10-25    corrected the IEC-receive routine (without EOI detection)
00038     2005-10-26    timeouts and EOI handling
00039     2005-10-27    bus turnaround routines and testing of write routines. Optimisation of the send routines
00040     2006-01-04    added IEC_send_string, is much more convinient then printf
00041     2006-01-10    TALK and LISTEN definitions were mixed up, is corrected. FreeIEC-routine added and improved
00042     2006-01-13    adjusted delay in waitforcommand routine, now external devices work
00043     2006-01-16    rewritten the waitforcommand routine
00044 */
00045 
00046 /*  TO DO:                                                                          
00047     ------      
00048     - EOI acknowledge delay, set/test this to correct timings for 20MHz
00049 
00050 */
00051 
00052 /*------------------------------------------------------------------------------------------*/
00053 
00054 /*--------------------------------------------------------*/
00055 /*                        includes                        */
00056 /*--------------------------------------------------------*/
00057 #include <mbed.h>
00058 
00059 #include <stdio.h>
00060 #include <IEC_bus.h>
00061 #include <delay.h>
00062 #include <hardware.h>
00063 
00064 /*--------------------------------------------------------*/
00065 /*                        constants                       */   
00066 /*--------------------------------------------------------*/
00067 #define    FALSE            0                            /*FALSE*/
00068 #define    TRUE            1                            /*TRUE*/
00069 
00070 /*--------------------------------------------------------*/
00071 /*                         globals                        */
00072 /*--------------------------------------------------------*/
00073 unsigned char            IEC_receive_delay;            /*set delay to ..uSec*/
00074 unsigned char            IEC_send_delay;                /*set delay to ..uSec*/
00075 
00076 /*external variables (variables also used in other .c files)*/
00077 /*external variables (variables also used in other .c files)*/
00078 extern bit                 EOI;                        /*End Of Indicator: this flag (when TRUE) indicates that the last byte is being transmitted or received*/
00079 extern bit                 TimeOut;                    /*Timeout-flag*/
00080 extern unsigned char    channel;                    /*this register holds the channel value*/
00081 
00082 /*--------------------------------------------------------*/
00083 /*                     local functions                    */
00084 /*--------------------------------------------------------*/
00085 
00086 
00087 /*--------------------------------------------------------*/
00088 /*                    external functions                  */
00089 /*--------------------------------------------------------*/
00090 
00091 //IEC_ATN : when IEC_ATN=0 it means that all devices must switch to listen (receive) mode immediatly
00092 
00093 
00094 /*set all IEC_signal lines in the correct mode*/
00095 void InitIEC(void)
00096 {
00097     SetIEC_timings(TIMINGS_DEFAULT);    /*set timings according the default settings (C64 compatible mode)*/
00098     IEC_ATN_REL();
00099     IEC_CLOCK_REL();
00100     IEC_DATA_REL();
00101     IEC_SRQ_REL();
00102     EOI = FALSE;
00103     TimeOut = FALSE;                
00104 }
00105 
00106 void SetIEC_timings(unsigned char settings)
00107 {
00108     switch(settings)
00109     {
00110         case TIMINGS_VIC20:                /*Timings for VIC-20 mode*/
00111         {                                /*-----------------------*/
00112             IEC_receive_delay = 52;        /*set delay to ..uSec*/
00113             IEC_send_delay = 60;        /*set delay to ..uSec*/
00114             break;
00115         }
00116 
00117         case TIMINGS_DTV:                /*Timings for DTV (tuned IEC-bus speeds)*/
00118         {                                /*--------------------------------------*/
00119             IEC_receive_delay = 60;        /*set delay to ..uSec*/
00120             IEC_send_delay = 80;        /*set delay to ..uSec*/
00121             break;
00122         }
00123 
00124         default:                        /*Timings according (C64) IEC-specs*/
00125         {                                /*---------------------------------*/
00126             IEC_receive_delay = 70;        /*set delay to ..uSec*/
00127             IEC_send_delay = 80;        /*set delay to ..uSec*/
00128             break;
00129         }        
00130     }
00131 }
00132 
00133 /*free the IEC bus for use by other devices, the bus is free'd until ATN is released*/
00134 void FreeIEC(void)
00135 {
00136     IEC_ATN_REL();
00137     IEC_CLOCK_REL();
00138     IEC_DATA_REL();
00139     while(IEC_ATN() == 0);
00140 }
00141 
00142 
00143 /*this routine will wait untill it receives one byte over the IEC-bus*/
00144 unsigned char IEC_receive(unsigned char frame_handshake)
00145 {
00146     unsigned char data;
00147     unsigned char bitcount;
00148     unsigned long t;
00149 
00150     EOI = FALSE;                            /*clear the EOI flag*/
00151     TimeOut = FALSE;                        /*clear the timeout flag*/
00152     data = 0;                                /*clear destination register*/
00153     bitcount = 8;                            /*the number of bits within a byte are still eight*/
00154 
00155     /*-----Step1:Ready to send--------------------------------------------------------------------------------*/
00156     while (IEC_CLOCK() == 0);                    /*wait (endlessly) until we see some action on the bus, we may respond whenever we please*/
00157 
00158     /*Step2:Ready for data--------------------------------------------------------------------------------*/
00159     IEC_DATA_REL();                        /*response to talker READY FOR DATA, this signal has no time-limit since we may be busy formatting a disk or printing out a chunk of text to paper*/
00160 
00161     /*-----intermission:EOI--------------------------------------------------------------------------------*/
00162     t = 5000;                        /*timeout value for detecting an EOI condition*/
00163     while (IEC_CLOCK() == 1)            /*wait for the talker to indicate that the transmission will start (this signal must be received within 200uS, otherwise we may consider it as an EOI)*/
00164     {
00165         t--;                        /*when timed out, we have detected an EOI condition*/
00166         if (t == 0)                    /*timeout detected ?*/
00167         {
00168             EOI = TRUE;                    /*set the EOI flag*/
00169             IEC_DATA_PULL();        /*acknowledge the EOI condition*/
00170             DelayBigUs(IEC_receive_delay);    /*delay for .. uSec*/
00171             IEC_DATA_REL();            /*acknowledge the EOI condition*/
00172         }
00173     }
00174 
00175     /*-----Step3:receiving the bits--------------------------------------------------------------------------------*/
00176     while (bitcount != 0)            /*data is received with LSB first*/
00177     {
00178         data>>=1;                    /*shift the byte one bit to the right*/
00179         bitcount--;                    /*decrement bitcounter by one*/
00180         t = 5000;                    /*timeout value*/
00181         while (IEC_CLOCK() == 0);        /*wait for the talker to release the clock line to signal "bit ready"*/
00182         {
00183             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00184             if (t == 0)                /*timeout detected ?*/
00185             {
00186                 TimeOut = TRUE;        /*set the timeout flag*/
00187                 return(0);            /*exit*/
00188             }
00189         }    
00190 
00191         if (IEC_DATA() == 1)            /*test if bit is set or cleared (attention:documentation states that signals are inverted ?!?! error ?!?!*/
00192             data = data + 128;        /*make bit 7 high*/
00193 
00194         t = 5000;                    /*timeout value*/
00195         while (IEC_CLOCK() == 1);        /*wait for the talker to pulldown the clock line*/
00196         {
00197             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00198             if (t == 0)                /*timeout detected ?*/
00199             {
00200                 TimeOut = TRUE;        /*set the timeout flag*/
00201                 return(0);            /*exit*/
00202             }
00203         }        
00204     }
00205 
00206     /*-----Step4:frame handshake--------------------------------------------------------------------------------*/
00207     if (frame_handshake == FALSE)    /*we must acknowledge within 1 mS that we have received the data, if not the talker knows there is something wrong*/
00208         DelayBigUs(1250);            /*delay for more then 1000 uSec*/        
00209 
00210     IEC_DATA_PULL();            
00211     return(data);                    /*exit with the received data*/
00212 }
00213 
00214 
00215 /*this routine will send one byte over the IEC-bus*/
00216 unsigned char IEC_send(unsigned char data)
00217 {
00218     unsigned char bitcount;
00219     unsigned long t;
00220     bitcount = 8;                    /*the number of bits within a byte are still eight*/
00221     TimeOut = FALSE;                /*clear the timeout flag*/
00222 
00223     /*-----Step1:Ready to send--------------------------------------------------------------------------------*/
00224 
00225     IEC_CLOCK_REL();            /*indicate to the listener that we are ready to send*/
00226 
00227     /*-----Step2:Ready for data--------------------------------------------------------------------------------*/
00228     while (IEC_DATA() == 0);            /*wait for the listener (computer) to release the data-line (ready to receive data), this may take forever... (according the IEC-bus definition)*/
00229 
00230     /*intermission:EOI--------------------------------------------------------------------------------*/
00231     if (EOI == TRUE)
00232     {
00233         DelayUs(200);                /*delay for more then 200 uSec*/
00234         t = 5000;                    /*timeout value*/
00235         while (IEC_DATA() == 1);        /*check for acknowledge of the EOI. The acknowledge is simply pulling the data-line down for a brief period*/
00236         {
00237             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00238             if (t == 0)                /*timeout detected ?*/
00239             {
00240                 TimeOut = TRUE;        /*set the timeout flag*/
00241                 return(FALSE);        /*exit*/
00242             }
00243         }
00244         t = 5000;                    /*timeout value*/
00245         while (IEC_DATA() == 0);        /**/
00246         {
00247             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00248             if (t == 0)                /*timeout detected ?*/
00249             {
00250                 TimeOut = TRUE;        /*set the timeout flag*/
00251                 return(FALSE);           /*exit*/
00252             }
00253         }
00254         /*EOI is acknowledged by the listener (computer)*/
00255     }
00256     IEC_CLOCK_PULL();            /*indicate to the listener (computer) that the transmission will start*/
00257     DelayUs(IEC_send_delay);            /*delay for .. uSec*/
00258 
00259     /*-----Step3:receiving the bits--------------------------------------------------------------------------------*/
00260     while (bitcount != 0)            /*data is transmitted with LSB first*/
00261     {
00262         IEC_CLOCK_PULL();        /*release the clockline in order to set the next bit on the data-line*/
00263         DelayUs(IEC_send_delay);    /*delay for .. uSec*/
00264         bitcount--;
00265         if (data & 0x01)
00266         {
00267             IEC_DATA_REL();        
00268         }
00269         else
00270         {        
00271             IEC_DATA_PULL();            
00272         }
00273         IEC_CLOCK_REL();        /*indicate to the listener (computer) "bit ready"*/
00274         data>>=1;                    /*shift the byte one bit to the right*/
00275         DelayUs(IEC_send_delay);    /*delay for at least 60uSec when a C64 is listening*/
00276     }
00277     IEC_CLOCK_PULL();            /*the whole byte has been transmitted*/
00278     DelayUs(IEC_send_delay);        /*delay for at least 60uSec when a C64 is listening*/
00279     IEC_DATA_REL();                /*set clock and data in the correct order and wait for an acknowledge*/
00280     DelayUs(25);                    /*wait a few uSec to prevent a false trigger*/
00281     
00282     /*----Step4:frame handshake--------------------------------------------------------------------------------*/
00283     t = 5000;                        /*timeout value*/
00284     while (IEC_DATA() == 1)            /*wait for the listener (computer) to acknowledge this byte it must respond within 1 mSec*/
00285     {
00286             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00287             if (t == 0)                /*timeout detected ?*/
00288             {
00289                 TimeOut = TRUE;        /*set the timeout flag*/
00290                 return(FALSE);        /*exit*/
00291             }
00292     }        
00293     DelayUs(100);                    /*time between bytes is according IEC-specs at least 100 uSec*/
00294     return(TRUE);                    /*the byte has been succesfully transmitted*/
00295 }
00296 
00297 
00298 /*this routine will wait untill it receives one byte over the IEC-bus*/
00299 /*this routine does NOT generate any signals, it only listens...     */
00300 unsigned char IEC_monitor(void)
00301 {
00302     unsigned char data;
00303     unsigned char bitcount;
00304     unsigned long t;
00305 
00306     EOI = FALSE;                    /*clear the EOI flag*/
00307     TimeOut = FALSE;                /*clear the timeout flag*/
00308     data = 0;                        /*clear destination register*/
00309     bitcount = 8;                    /*the number of bits within a byte are still eight*/
00310 
00311     /*-----Step1:Ready to send--------------------------------------------------------------------------------*/
00312     while (IEC_CLOCK() == 0);            /*wait (endlessly) until we see some action on the bus, we may respond whenever we please*/
00313 
00314     /*-----intermission:EOI--------------------------------------------------------------------------------*/
00315     t = 5000;                        /*timeout value for detecting an EOI condition*/
00316     while (IEC_CLOCK() == 1)            /*wait for the talker to indicate that the transmission will start (this signal must be received within 200uS, otherwise we may consider it as an EOI)*/
00317     {
00318         t--;                        /*when timed out, we have detected an EOI condition*/
00319         if (t == 0)                    /*timeout detected ?*/
00320             EOI = TRUE;                /*set the EOI flag*/
00321     }
00322 
00323     /*-----Step3:receiving the bits--------------------------------------------------------------------------------*/
00324     while (bitcount != 0)            /*data is received with LSB first*/
00325     {
00326         data>>=1;                    /*shift the byte one bit to the right*/
00327         bitcount--;                    /*decrement bitcounter by one*/
00328         t = 5000;                    /*timeout value*/
00329         while (IEC_CLOCK() == 0);        /*wait for the talker to release the clock line to signal "bit ready"*/
00330         {
00331             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00332             if (t == 0)                /*timeout detected ?*/
00333             {
00334                 TimeOut = TRUE;        /*set the timeout flag*/
00335                 return(0);            /*exit*/
00336             }
00337         }    
00338 
00339         if (IEC_DATA() == 1)            /*test if bit is set or cleared (attention:documentation states that signals are inverted ?!?! error ?!?!*/
00340             data = data + 128;        /*make bit 7 high*/
00341 
00342         t = 5000;                    /*timeout value*/
00343         while (IEC_CLOCK() == 1);        /*wait for the talker to pulldown the clock line*/
00344         {
00345             t--;                    /*timeout detection is required to prevent "hanging" in case of data transmission erros*/
00346             if (t == 0)                /*timeout detected ?*/
00347             {
00348                 TimeOut = TRUE;        /*set the timeout flag*/
00349                 return(0);            /*exit*/
00350             }
00351         }        
00352     }
00353     return(data);                    /*exit with the received data*/
00354 }
00355 
00356 
00357 /*this routine will handle strings, for sending strings over the IEC-bus*/
00358 void IEC_send_string(const unsigned char *inputstring)
00359 {
00360     unsigned char lp;
00361 
00362     lp = 0;
00363     while(inputstring[lp] != 0)
00364     {    
00365         IEC_send(inputstring[lp]);
00366         lp++;
00367     }
00368 }
00369 
00370 void IEC_send_number_as_ASCII(unsigned char number)
00371 {
00372     unsigned char i;
00373 
00374     i = 0x30 + (number/10);            /*10's of the value*/
00375     IEC_send(i);        
00376     i = 0x30 + (number%10);            /*1's of the value*/
00377     IEC_send(i);        
00378 }
00379 
00380 /*this routine will reverse the direction of the bus*/
00381 void IEC_turnaround(void)
00382 {
00383     while (IEC_ATN() == 0);            /*wait (endlessly) until the computer releases ATN*/
00384     while (IEC_CLOCK() == 0);            /*wait (endlessly) until the computer releases the clock line*/
00385     IEC_DATA_REL();
00386     DelayUs(25);                    /*small delay... to make the timing look like the timing of a real drive*/
00387     IEC_CLOCK_PULL();
00388     DelayUs(160);                    /*Tda = 80 uSec minimum acknowledge time for acknowledging the device is now a talker*/
00389 }
00390 
00391 
00392 /*this routine will set the direction on the bus back to normal (the way it was when the computer was switched on)*/
00393 void IEC_undoturnaround(void)
00394 {
00395 //    unsigned int timeout_cnt;
00396 //    DelayUs(50);                    /*Talk-Attention release (max. 100uS)*/
00397     IEC_DATA_PULL();
00398     IEC_CLOCK_REL();
00399     DelayUs(25);                    /*small delay for .. uSec in order to prevent a false trigger*/
00400 //    timeout_cnt = 0;
00401 //    while (IEC_CLOCK() == 1)            /*wait until the computer pulls down the clock line or we timeout*/
00402 //    {
00403 //        if (timeout_cnt == 1000)
00404 //            break;                    /*timeout exceeded, leave routine*/
00405 //        else
00406 //            timeout_cnt++;
00407 //    }
00408 }
00409 
00410 /*this routine will let the bus lines go, as Jim Butterfield described, both talker and listener 'letgo'*/
00411 void IEC_letgo(void)
00412 {
00413     DelayUs(50);                    /*after a suitable pause*/
00414     IEC_DATA_REL();                /*dataline and clockline are released*/
00415     IEC_CLOCK_REL();
00416 }
00417 
00418 extern DigitalOut(myled3);
00419 
00420 unsigned char CheckForCommand(unsigned char *outputcommand, unsigned char frame_handshake)
00421 {
00422     if(IEC_ATN() == 1)                /* wait untill there is relevant info (a command is indicated by the attention signal) on the bus */
00423     {
00424         IEC_DATA_REL();            /*free the bus... (if not allready released)*/
00425         return(FALSE);                /*no command received, yet...*/
00426     }
00427 
00428     IEC_DATA_PULL();            /*join the bus...*/
00429     *outputcommand = IEC_receive(frame_handshake);    /*save the received command to a register specified by the caller of this routine*/
00430     if ((TimeOut == FALSE) && (IEC_ATN() == 0))
00431     {
00432         if (*outputcommand == UNLISTEN)                /*check for command:UNLISTEN, device:..., Attention-line must still be active*/
00433             return(UNLISTEN);
00434     
00435         if (*outputcommand == UNTALK)                /*check for command:UNTALK, device:..., Attention-line must still be active*/
00436             return(UNTALK);
00437 
00438         if ((*outputcommand & 0xF0) == DATA)        /*check for command:DATA, channel:..., Attention-line must still be active*/
00439         {
00440             channel = *outputcommand & 0x0F;                /*(if send) the channel is stored in the low-nibble of the command*/        
00441             return(DATA);
00442         }
00443 
00444         if ((*outputcommand & 0xF0) == CLOSE)        /*check for command:CLOSE, channel:..., Attention-line must still be active*/
00445         {
00446             channel = *outputcommand & 0x0F;                /*(if send) the channel is stored in the low-nibble of the command*/        
00447             return(CLOSE);
00448         }
00449 
00450         if ((*outputcommand & 0xF0) == OPEN)        /*check for command:OPEN, channel:..., Attention-line must still be active*/
00451         {
00452             channel = *outputcommand & 0x0F;                /*(if send) the channel is stored in the low-nibble of the command*/        
00453             return(OPEN);
00454         }
00455 
00456         return(*outputcommand);                        /*when none of the above... it's for another device, return the entire command for further analasys*/
00457     }
00458     return(FALSE);                                    /*code should never reach this point!!!*/
00459 }
00460 
00461 
00462 /*--------------------------------------------------------*/
00463 /*                      local functions                   */
00464 /*--------------------------------------------------------*/
00465 
00466 
00467 
00468 
00469 /*
00470 The person who writes their sourcecode without comments is either very smart or very stupid
00471 */