/*******************************************************************/ /* Advanced Communication Board Developer Toolkit 1995 */ /*******************************************************************/ /* Please read the program abstract for details on this */ /* program. */ /* INTDMA2.C */ /* */ /* (c)Copyright Sealevel Systems Incorporated, 1993 - 1995 */ /* */ /*******************************************************************/ #include #include #include #include #include #include #include #include "acb.h" #include "dma.h" #include "int.h" #include "buffer.h" #include "Z8530.h" /*******************************************************************/ /* Things to make the program "compiler friendly"! */ /*******************************************************************/ #ifndef _BORLAND #define IN _inp #define OUT _outp #define FAR __far #else #define IN inportb #define OUT outportb #define FAR far #endif /*******************************************************************/ /* Systems Resources */ /*******************************************************************/ #define PORT 0x238 #define IRQ 0x05 #define RX_DMA_MODE RX1 #define RX_DMA_CHANNEL DMA1 #define RX_DMA_ON CLEARDMA1 #define RX_DMA_OFF SETDMA1 #define MAX_BUFFERS 10 #define BUFFER_LENGTH 100 #define MEMORY_REQUESTED ((MAX_BUFFERS) * (BUFFER_LENGTH) * (2)) #define TERM_COUNT 45 /*Test string length for Tx*/ /*******************************************************************/ /* Prototypes */ /*******************************************************************/ void PrintRxFrameInQueue(void); int QueueTxFrame(unsigned char FAR * , unsigned short); void printbuf( unsigned char FAR * buf, unsigned short wLength); int main(void); void __interrupt FAR ACB_isr(void); static void SCCB_TxBufferEmpty (void); static void SCCB_ExtStatChange (void); static void SCCB_RxCharAvail (void); static void SCCB_SpRxCondition (void); static void SCCA_TxBufferEmpty (void); static void SCCA_ExtStatChange (void); static void SCCA_RxCharAvail (void); static void SCCA_SpRxCondition (void); /*******************************************************************/ /* Z85x30 Init Values */ /*******************************************************************/ #define PRAM_COUNT 54 unsigned char init[PRAM_COUNT]= { WR0, NULL_CODE, /* MODES */ WR4, X1_CLOCK | SYNC_MODE_ENABLE | SDLC_MODE, WR1, WAIT_DMA_DISABLE | INT_DISABLE, WR2, 0x00, /* not used in polled mode */ WR3, RX_8_BITS | RX_CRC_ENABLE | SYNC_CHAR_LOAD_INHIBIT , WR5, TX_8_BITS | CRC_SDLC | TX_CRC_ENABLE, WR6, 0x00, /* not used-SDLC Address field */ WR7, 0x7e, /* SDLC Flag */ WR9, MI_DISABLE, WR10, CRC_PRESET_TO_ZERO, WR11, TX_CLK_BRG | RX_CLK_RTXC_PIN | TRXC_IS_OUTPUT | TRXC_OUT_BRG, WR12, 0x7e, /*time constant-low byte 19.2K bps*/ WR13, 0x0, /*time constant-high byte */ WR14, BRG_SOURCE_PCLK | DPLL_NULL, WR14, BRG_SOURCE_PCLK | DPLL_NULL, WR14, BRG_SOURCE_PCLK | DPLL_NULL, WR14, BRG_ENABLE | BRG_SOURCE_PCLK | DPLL_NULL , /* ENABLES */ WR3, RX_8_BITS | RX_CRC_ENABLE | SYNC_CHAR_LOAD_INHIBIT | RX_ENABLE, WR5, TX_8_BITS | CRC_SDLC | TX_CRC_ENABLE | TX_ENABLE, WR0, RESET_TX_CRC, WR0, ERROR_RESET, WR1, WAIT_DMA_DISABLE | INT_DISABLE, WR15, NO_EXT_STAT_INT, /*INTERRUPT*/ WR0, RESET_EXT_STATUS_INT, WR0, RESET_EXT_STATUS_INT, WR1, WAIT_DMA_DISABLE | INT_DISABLE, WR9, MI_DISABLE }; /*******************************************************************/ /* end of init table, adjust variable PRAM_COUNT after modifying */ /*******************************************************************/ unsigned char txbuff[]="The Quick Brown Fox Jumped Over The Lazy Dog.\0"; /*45 CHARACTERS INCLUDING '.' */ void FAR *fp; void ( __interrupt FAR *fpF)(void); /* far void function pointer */ int i; unsigned char c = 0; unsigned short number=0; unsigned char update[4]={'/', '|', '\\', '-'}; /* Must escape the "\" char*/ unsigned char updatePtr = 0; unsigned int RX_INT_COUNT,TX_INT_COUNT,RX_SP_INT_COUNT,EXT_STAT_INT_COUNT; int RestartTx=0; int RestartRx=0; int ParityError=0; int CRCError=0; int OverrunError=0; int RxFrameCount=0; int TxFrameCount=0; int ReturnValue=0; void __huge * fpMemoryBlock; unsigned char FAR * fpMemory; struct DEVICE_INFO TxDevice; struct DEVICE_INFO RxDevice; fpDEVICE_INFO TxDevPtr; fpDEVICE_INFO RxDevPtr; struct BUFFER_INFO RxBuffer[MAX_BUFFERS]; struct BUFFER_INFO TxBuffer[MAX_BUFFERS]; unsigned short TxCharCount = 0; /*******************************************************************/ /*******************************************************************/ int main (void) { printf("\nAdvanced Communication Board Interrupt Driven Half-Duplex DMA Test Program.\n\n"); printf("Type \"T\" to transmit and \"X\" to exit to DOS.\n"); /*******************************************************************/ /* Verify Address of SCC (85x30) */ /*******************************************************************/ SCCout(PORT, WR2,0x55); /*write to WR2*/ if(SCCin(PORT, RR2)!=0x55) /*read back RR2*/ { printf("\nError: Device not found at address %x HEX.\n",PORT); return(1); /*return code 1 for ERROR*/ } else { printf("Device verified at address %x HEX.\n",PORT); } /*******************************************************************/ /* Initialize ACB card */ /*******************************************************************/ SCCout(PORT, WR9, FORCE_HW_RESET); /*channel reset A and B*/ /*Initialize ACB */ SCCInitEx(PORT ,(unsigned char FAR *)&init[0] ,PRAM_COUNT); printf("\nBase Address: %X, Rx DMA channel: 1\n",PORT); /* Clean SCC FIFO, just a precaution */ while( RX_CHAR_AVAIL & (c = SCCin(PORT, RR0))) { c = (unsigned char) IN(PORT); } /* Allocate memory buffers */ fpMemoryBlock = _fmalloc(MEMORY_REQUESTED); /* assume 20 buffers of 500 bytes*/ if(CheckDMAPageEx(MEMORY_REQUESTED,fpMemoryBlock )) { printf("Error: Memory Buffer resides on a segment boundary!"); _ffree(fpMemoryBlock); return(1); } /* For ACB-VI un-comment this line to enable on-board interrupts */ /* OUT(PORT+4, 0x40); */ SingleMaskDMA(RX_DMA_OFF); /* Turn DMA off at the DMA controller */ SaveIRQMask(); /* Save the IRQ Mask*/ fpF = ACB_isr; /* Set isr far function pointer*/ IRQSetupEx(IRQ ,fpF); /*Save/Replace Interrupt Vector, etc. */ /* Program Rx DMA on Channel 1 using WAIT/REQ */ SCCout(PORT, WR1, WAIT_REQ_ENABLE | WAIT_DMA_FUNCTION | WAIT_DMA_RX | RX_INT_SP_COND | EXT_INT_ENABLE | TX_INT_ENABLE); SCCout(PORT, WR15, TX_UNDERRUN_IE); SCCout(PORT, WR0, RESET_EXT_STATUS_INT); SCCout(PORT, WR0, RESET_EXT_STATUS_INT); SCCout(PORT, WR9, MI_ENABLE); /* Z8530 Master Interrupt Enable*/ SCCout(PORT, WR14, BRG_ENABLE | BRG_SOURCE_PCLK | REQUEST_FUNCTION ); /* Setup memory buffers */ fpMemory = fpMemoryBlock; TxDevice.wTotal = 0; RxDevice.wTotal = 0; TxDevPtr = &TxDevice; RxDevPtr = &RxDevice; for (i = 0; i < MAX_BUFFERS; i++) { AddBuffer( TxDevPtr, &TxBuffer[i] ,fpMemory); fpMemory = (unsigned char FAR* ) (fpMemory + BUFFER_LENGTH); AddBuffer( RxDevPtr, &RxBuffer[i] ,fpMemory); fpMemory = (unsigned char FAR* ) (fpMemory + BUFFER_LENGTH); } StartBuffer( TxDevPtr, OUTPUT_DEVICE); StartBuffer( RxDevPtr, INPUT_DEVICE); /* Start the Receiver */ SingleMaskDMA(RX_DMA_OFF); SetPageRegisterEx(RX_DMA_CHANNEL, RxDevPtr->npNext_RED->fpBufferAddress); SetDMAMode(RX_DMA_MODE); SetTC(RX_DMA_CHANNEL,BUFFER_LENGTH); SingleMaskDMA(RX_DMA_ON); /******************************************************************** ** Here is the main loop of the program. Program execution will ** ** remain here until the 'X' is pressed from the keyboard. If 'T' ** ** is pressed, the transmit frame buffers will be filled with the ** ** test string. The receive frame buffers are continually ** ** monitoredand dumped to the standard output device. ** ********************************************************************/ do { c = 0; if (_bios_keybrd(_KEYBRD_READY)) { c = (unsigned char)_bios_keybrd(_KEYBRD_READ); switch(c) { case 'x': case 'X': c = 'x'; break; case 't': case 'T': /*Fill all Tx frame buffers*/ for (i = 0; i < MAX_BUFFERS; i++) { if (0==QueueTxFrame((unsigned char FAR *)&txbuff, TERM_COUNT)) { break; } } break; default: break; } /*end switch case*/ } /*end if*/ PrintRxFrameInQueue(); if (number== 0x3fff) { number=0; printf("Tx Frames : %d , Rx Frames : %d ", TxFrameCount,RxFrameCount); printf("%c\r",update[updatePtr]); /*print a cute little cursor*/ updatePtr++; if (updatePtr==4) { updatePtr=0; } } /* end if*/ number++; } while (c != 'x'); for (i = 0; i < MAX_BUFFERS; i++) /*Purge Rx Frame buffer*/ { PrintRxFrameInQueue(); } printf("Tx Frames : %d , Rx Frames : %d \n",TxFrameCount,RxFrameCount); /*Disable DMA channels at the DMA controller */ SingleMaskDMA(RX_DMA_OFF); /* Turn off DTR/REQ, WAIT/REQ and Ints on the SCC*/ SCCout(PORT, WR14, BRG_ENABLE | BRG_SOURCE_PCLK ); SCCout(PORT, WR1, WAIT_DMA_DISABLE); SCCout(PORT ,WR9 ,MI_DISABLE); /*Master Interrupt Enable OFF*/ SCCout(PORT ,WR1 ,INT_DISABLE); /*All Interrupt conditions OFF*/ IRQUnsetup(IRQ); /*Restore Interrupt Vector, etc. */ ReturnIRQMask(); /*Restore IRQ Mask */ printf("\n\nTx DATA: "); printbuf((unsigned char FAR *)&txbuff, TERM_COUNT); printf("Special Rx Condition Interrupts : %d\n", RX_SP_INT_COUNT); printf("Tx Interrupts : %d\n", TX_INT_COUNT); printf("External Status Interrupts : %d\n", EXT_STAT_INT_COUNT); if (RX_INT_COUNT) { printf("Rx Interrupts : %d\n", RX_INT_COUNT); } if(RestartRx) { printf("Rx Restarts: %d\n",RestartRx); } if(RestartTx) { printf("Tx Restarts: %d\n",RestartTx); } if(ParityError) { printf("Parity Error(s): %d\n",ParityError); } if(OverrunError) { printf("Rx Overrun Error(s): %d\n",OverrunError); } if(CRCError) { printf("CRC Error(s): %d\n",CRCError); } /* deallocate memory buffers*/ _ffree(fpMemoryBlock); return(ReturnValue); } /*******************************************************************/ /* This routine will print the specified buffer */ /* Note that a CR LF is added to the end. */ /*******************************************************************/ void printbuf( unsigned char FAR * buf, unsigned short wLength) { unsigned int i; if(wLength > BUFFER_LENGTH) { wLength = BUFFER_LENGTH; } for (i = 0; i < wLength; i++) { printf("%c", buf[i]); } printf("\n"); } /*******************************************************************/ /* PrintRxFrameInQueue */ /* This routine will fetch a received frame from the Rx Frame */ /* buffer and display the contents on the screen. If no frames */ /* are available then a zero is returned. */ /*******************************************************************/ void PrintRxFrameInQueue(void) { unsigned char FAR * fpTemp; fpTemp = AssignBuffer(RxDevPtr); if (fpTemp == NULL) { return; } printbuf(fpTemp,RxDevPtr->npCurrent->wByteCount); if (BM_DEVICE_STOPPED == ReleaseBuffer(RxDevPtr)) { RestartRx++; SingleMaskDMA(RX_DMA_OFF); SCCout(PORT, WR0, ERROR_RESET); SCCout(PORT, WR0, RESET_RX_CRC); SetPageRegisterEx(RX_DMA_CHANNEL, RxDevPtr->npNext_RED->fpBufferAddress); SetDMAMode(RX_DMA_MODE); SetTC(RX_DMA_CHANNEL,BUFFER_LENGTH); SingleMaskDMA(RX_DMA_ON); } } /*******************************************************************/ /* QueueTxFrame */ /* This will queue the specified frame in the Tx Frame buffer. */ /*******************************************************************/ int QueueTxFrame(unsigned char FAR * TxFrame,unsigned short wLength) { unsigned char FAR * fpTemp; if(wLength > BUFFER_LENGTH) /* make sure we do not over fill */ { wLength = BUFFER_LENGTH; /* the buffer*/ } fpTemp = AssignBuffer(TxDevPtr); if(fpTemp == NULL) { return(0); /* queue is full*/ } else { /*move the frame into our queue*/ _fmemmove(fpTemp, TxFrame, wLength); TxDevPtr->npCurrent->wByteCount = wLength; if (BM_DEVICE_STOPPED == ReleaseBuffer(TxDevPtr)) { /*if Tx is idle,*/ RestartTx++; /*restart the transmitter*/ SCCout(PORT, WR0, RESET_EXT_STATUS_INT); SCCout(PORT, WR0, RESET_TX_CRC); /************************************************************** ** To avoid timing problems caused by getting interrupted by ** ** sending the first character, increment the counter and ** ** pointers before sending the data ** **************************************************************/ TxCharCount = 1; OUT(PORT, *(TxDevPtr->npNext_RED->fpBufferAddress)); SCCout( PORT, WR0, RESET_TX_UR_EOM); } return(1); } } /*******************************************************************/ /* Interrupt Service Routine (ISR) */ /* This Routine is called when an interrupt is generated by the */ /* ACB adapter */ /*******************************************************************/ void __interrupt FAR ACB_isr(void) { static unsigned char isr_ptr, counter=0; static void (*sccisr[8])(void) = { SCCB_TxBufferEmpty, /* This is an array of routines */ SCCB_ExtStatChange, /* that are called when an */ SCCB_RxCharAvail, /* interrupt is pending on the */ SCCB_SpRxCondition, /* 85x30. */ SCCA_TxBufferEmpty, SCCA_ExtStatChange, SCCA_RxCharAvail, SCCA_SpRxCondition, }; while(SCCin(PORT, RR3)) /* While Interrupt is Pending*/ { isr_ptr = SCCin(PORT+2, RR2); /* Read Register 2 on Ch B */ isr_ptr >>= 1; /* Adjust interrupt pointer */ (*sccisr[isr_ptr])(); /* Call isr sub routine */ counter++; if (counter > 200) /* Time out just in case something*/ { break; /* goes wrong. */ } } counter = 0; /* Reset Time out counter */ #if (IRQ > 7) OUT(0xa0 ,0x20); /* AT PIC EOI */ #endif OUT(0x20, 0x20); /* XT PIC EOI */ } /*******************************************************************/ /* SCCA_TxBufferEmpty : called from ISR */ /* This routine is called when a Transmit Buffer Empty */ /* interrupt is pending on channel A of the SCC */ /*******************************************************************/ static void SCCA_TxBufferEmpty (void) { TX_INT_COUNT++; /* count for diagnostic purposes*/ if (TxCharCount == TxDevPtr->npNext_RED->wByteCount) { /* End of Frame? */ SCCout(PORT, WR0, RESET_TX_INT_PEND); /* Reset the Tx Interrupt */ TxCharCount++; return; } if (TxCharCount == TxDevPtr->npNext_RED->wByteCount+1) { TxFrameCount++; if (SwapBuffer(TxDevPtr)== BM_STOP_IO) { /* If all of the Tx Buffers have been sent, reset the Tx Interrupt and return */ SCCout(PORT, WR0, RESET_TX_INT_PEND); return; } TxCharCount = 0; } OUT(PORT, *(TxDevPtr->npNext_RED->fpBufferAddress + TxCharCount)); TxCharCount++; /* if the first character in the frame is sent, then reset the allow the CRC to be sent at the end of the frame */ if (TxCharCount == 1) { SCCout(PORT, WR0, RESET_TX_UR_EOM); /* Reset the Tx Interrupt */ return; } } /*******************************************************************/ /* SCCA_ExtStatChange : called from ISR */ /* This routine is called when a External Status Change */ /* interrupt is pending on channel A of the SCC */ /*******************************************************************/ static void SCCA_ExtStatChange (void) { /*External status interrupts, in this example will occur when the SCC loads the Transmitter with the CRC. On the Z8530 we must wait until this bit is shifted out before another DMA Tx transfer can be started or the two frames will be sent as one. Note that this is not the case on a Z85230 ESCC. */ EXT_STAT_INT_COUNT++; /* count for diagnostic purposes*/ SCCout(PORT, WR0, RESET_EXT_STATUS_INT); SCCout(PORT, WR0, RESET_EXT_STATUS_INT); } /*******************************************************************/ /* SCCA_RxCharAvail : called from ISR */ /* This routine will read all characters on channel A of the SCC */ /* at interrupt time */ /*******************************************************************/ static void SCCA_RxCharAvail (void) { RX_INT_COUNT++; /* count for diagnostic purposes*/ } /*******************************************************************/ /* SCCA_SpRxCondition : called from ISR */ /* This routine is called when a Receive Special Condition */ /* interrupt is pending on channel A of the SCC */ /*******************************************************************/ static void SCCA_SpRxCondition (void) { unsigned char FAR * fpTemp; unsigned char RR1_Image; RX_SP_INT_COUNT++; /* count for diagnostic purposes*/ RR1_Image = SCCin(PORT, RR1); if (RR1_Image & ( PARITY_ERROR | RX_OVERRUN_ERROR | CRC_FRAMING_ERROR | END_OF_FRAME)) { SCCout(PORT, WR0, ERROR_RESET); if (RR1_Image & PARITY_ERROR) { ParityError++; } if (RR1_Image & RX_OVERRUN_ERROR) { OverrunError++; } if (RR1_Image & END_OF_FRAME) { RxFrameCount++; if (RR1_Image & CRC_FRAMING_ERROR) { CRCError++; fpTemp = RxDevPtr->npNext_RED->fpBufferAddress; fpTemp[10] = 'X'; } SingleMaskDMA(RX_DMA_OFF); RxDevPtr->npNext_RED->wByteCount = ((BUFFER_LENGTH-2) - GetTC(RX_DMA_CHANNEL)); if (SwapBuffer(RxDevPtr)==BM_STOP_IO) { return; } SetPageRegisterEx( RX_DMA_CHANNEL, RxDevPtr->npNext_RED->fpBufferAddress); SetDMAMode(RX_DMA_MODE); SetTC(RX_DMA_CHANNEL,BUFFER_LENGTH); SingleMaskDMA(RX_DMA_ON); } } } /*******************************************************************/ /* SCCB_TxBufferEmpty : called from ISR */ /* This routine is called when a Transmit Buffer Empty */ /* interrupt is pending on channel B of the SCC */ /*******************************************************************/ static void SCCB_TxBufferEmpty (void) { /*Channel B is not used in this program. */ } /*******************************************************************/ /* SCCB_ExtStatChange : called from ISR */ /* This routine is called when a External Status Change */ /* interrupt is pending on channel B of the SCC */ /*******************************************************************/ static void SCCB_ExtStatChange (void) { /*Channel B is not used in this program. */ } /*******************************************************************/ /* SCCB_RxCharAvail : called from ISR */ /* This routine will read all characters on channel B of the SCC */ /* at interrupt time */ /*******************************************************************/ static void SCCB_RxCharAvail (void) { /*Channel B is not used in this program. */ } /*******************************************************************/ /* SCCB_SpRxCondition : called from ISR */ /* This routine is called when a Receive Special Condition */ /* interrupt is pending on channel B of the SCC */ /*******************************************************************/ static void SCCB_SpRxCondition (void) { /*Channel B is not used in this program. */ } /*******************************************************************/ /* END OF FILE */ /*******************************************************************/