/*******************************************************************/ /* Advanced Communication Board Developer Toolkit 1995 */ /*******************************************************************/ /* Please read the program abstract for details on this */ /* program. */ /* DMAINT2.C */ /* */ /* (c)Copyright Sealevel Systems Incorporated, 1993 - 1995 */ /* */ /*******************************************************************/ #include #include #include #include #include #include #include "acb.h" #include "dma.h" #include "int.h" #include "buffer.h" #define Z85230 #define Z85C30 #include "Z8530.h" #ifdef _BORLAND #include #include #else #include #include #endif /*******************************************************************/ /* Things to make the program "compiler friendly"! */ /*******************************************************************/ #ifndef _BORLAND #define IN _inp #define OUT _outp #define FAR __far #define INTERRUPT __far __interrupt #define HUGE __huge #define FARMALLOC _fmalloc #define FARFREE _ffree #define KBHIT _kbhit #else #define IN inportb #define OUT outportb #define FAR far #define INTERRUPT far interrupt #define HUGE huge #define FARMALLOC farmalloc #define FARFREE farfree #define KBHIT kbhit #endif /*******************************************************************/ /* Systems Resources */ /*******************************************************************/ #define PORT 0x238 #define IRQ 0x05 #define TX_DMA_MODE TX3 #define TX_DMA_CHANNEL DMA3 #define TX_DMA_ON CLEARDMA3 #define TX_DMA_OFF SETDMA3 #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 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 | RTS_ON, 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 | RTS_ON, 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 *fpF)(void); /* far void function pointer */ int i; int ESCC = 0; 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]; /*******************************************************************/ /*******************************************************************/ int main (void) { printf("\nAdvanced Communication Board Interrupt Driven 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*/ /*******************************************************************/ /* Test for ESCC (85230) */ /*******************************************************************/ SCCout(PORT, WR15, WR7P_ACCESS); c = SCCin(PORT, RR15); if(c & 0x01) { SCCout(PORT, WR15, 0x00); c = SCCin(PORT, RR15); if((c & 0x01) == 0) ESCC = 1; } if( ESCC ) /* 85230 specific actions */ { printf("Detected an 85230.\n"); SCCout(PORT, WR15, WR7P_ACCESS); SCCout(PORT, WR7_PRIME, AUTO_TX_FLAG | AUTO_EOM_RST | DTR_REQ_TIMING | EX_READ_ENABLE ); SCCout(PORT, WR15, 0x00); } else { printf("Detected an 8530.\n"); SCCout(PORT, WR15, 0x00); } /*Initialize ACB */ SCCInitEx(PORT, (unsigned char FAR *)&init[0], PRAM_COUNT); printf("\nBase Address: %X, Rx DMA channel: 1, Tx DMA channel: 3\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 = FARMALLOC(MEMORY_REQUESTED); /* assume 20 buffers of 500 bytes*/ if (CheckDMAPageEx(MEMORY_REQUESTED,fpMemoryBlock )) { printf("Error: Memory Buffer resides on a segment boundary!"); FARFREE(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 */ SingleMaskDMA(TX_DMA_OFF); /* before we program the DMA channel*/ 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); 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*/ /* Program Tx DMA on Channel 3 using DTR/REQ */ 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 monitored and dumped to the standard output device. */ do { c = 0; if (KBHIT()) { c = getch(); 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); SingleMaskDMA(TX_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*/ FARFREE(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*/ movedata(FP_SEG(TxFrame),FP_OFF(TxFrame),FP_SEG(fpTemp),FP_OFF(fpTemp), wLength); TxDevPtr->npCurrent->wByteCount = wLength; if (BM_DEVICE_STOPPED == ReleaseBuffer(TxDevPtr)) { /*if Tx is idle,*/ RestartTx++; /*restart the transmitter*/ SingleMaskDMA(TX_DMA_OFF); SCCout(PORT, WR0, RESET_EXT_STATUS_INT); SCCout(PORT,WR0, RESET_TX_CRC); SetDMAMode(TX_DMA_MODE); SetPageRegisterEx( TX_DMA_CHANNEL, TxDevPtr->npNext_RED->fpBufferAddress); SetTC(TX_DMA_CHANNEL,TxDevPtr->npNext_RED->wByteCount -1); SingleMaskDMA(TX_DMA_ON); SCCout(PORT, WR0, RESET_TX_UR_EOM); /*Reset TX Underun/End of Message latch so that the TX CRC will be sent when the Transmitter underruns at the end of our DMA transfer. */ } return(1); } } /*******************************************************************/ /* Interrupt Service Routine (ISR) */ /* This Routine is called when an interrupt is generated by the */ /* ACB adapter */ /*******************************************************************/ void INTERRUPT 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*/ TxFrameCount++; /* There should be one Tx interrupt per SDLC/HDLC frame. When the last byte of the CRC is shifted out of the transmitter and the transmitter underruns, a Tx buffer empty interrupt will occur.*/ SCCout(PORT, WR0, RESET_TX_INT_PEND); /* Reset the Tx Interrupt */ /* Now disable Tx interrupts, Tx interrupt will be enabled again once an External Status Interrupt is serviced. */ SCCout(PORT, WR1, WAIT_REQ_ENABLE | WAIT_DMA_FUNCTION | WAIT_DMA_RX | RX_INT_SP_COND | EXT_INT_ENABLE); SingleMaskDMA(TX_DMA_OFF); /*Disable DMA at the DMA controller*/ if (SwapBuffer(TxDevPtr)==BM_STOP_IO) { return; } SetDMAMode( TX_DMA_MODE); SetPageRegisterEx( TX_DMA_CHANNEL, TxDevPtr->npNext_RED->fpBufferAddress); SetTC(TX_DMA_CHANNEL,TxDevPtr->npNext_RED->wByteCount -1); SingleMaskDMA(TX_DMA_ON); SCCout( PORT, WR0, RESET_TX_UR_EOM); } /*******************************************************************/ /* 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); SCCout(PORT, WR1, WAIT_REQ_ENABLE | WAIT_DMA_FUNCTION | WAIT_DMA_RX | RX_INT_SP_COND | EXT_INT_ENABLE | TX_INT_ENABLE); } /*******************************************************************/ /* 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 */ /*******************************************************************/