; --Hoyt A. Stearns Jr. ; --Wed 03/17/2013 RAMbegin equ 1c00h RAMsize equ 1024 ; FIFOSIZE equ 64 ; Must be power of 2 RXOFFTRIGGER equ 20 ; Send XOFF when Receive fifo has < this room RXONPT equ 48 ; Send XON when Receive fifo has > this room ; ; XOFF equ 13h XON equ 11h BEL equ 7 CtlC equ 3 CtlO equ 15 BIT0 equ 1<<0 BIT1 equ 1<<1 BIT2 equ 1<<2 BIT3 equ 1<<3 BIT4 equ 1<<4 BIT5 equ 1<<5 BIT6 equ 1<<6 BIT7 equ 1<<7 BIT8 equ 1<<8 BIT9 equ 1<<9 BIT10 equ 1<<10 BIT11 equ 1<<11 /***************Serial communication variables**********/ XOFFsent equ BIT0 SendXOFF equ BIT1 XOFFreceived equ BIT2 CtlOreceived equ BIT3 UARTbreak equ BIT4 TxBusy equ BIT5 RfifoFull equ BIT6 //send BEL RtsCts equ BIT7 ; ; ; ;Mini state machine description for XOFF transmitting process: ; ; SendxOFF XOFFsent ; 0 0 ; normal processing ; 1 0 ; XOFF pending to be sent ; 1 1 ; XOFF sent, must send an XON when Rfifo room appears. ; 0 1 ; XON pending to be sent when xmtr ready ; // RtsCts RfifoFull TxBusy UARTbreak CtlOreceived XOFFreceived SendXOFF XOFFsent UARTflags: ds 1 RxInptr ds 1 RxOutptr ds 1 RxCount ds 1 ; even RxFifo ds FIFOSIZE*2 ; TxInptr ds 1 TxOutptr ds 1 TxCount ds 1 ; TxFifo ds FIFOSIZE ; ; /***************************************************/ reset: main: mov.w #5a80h, &15ch //Stop watchdog ; DCOCLK: Internal digitally controlled oscillator (DCO). ; Startup clock system in max. DCO setting 24 MHz mov.b #0a5h, &161h //unlock mov.b #86h, &162h // 24MHz mov #333h, &164h //set all to dcO mov #0, &166h mov.b #1, &161h ; INT( [ (N/16) - INT(N/16) ] × 16 ); ; ; Configure UART pins P2.0 (UCA0TXD) & P2.1 (UCA0RXD) ; bis.b #0x03, &0x20d ; P2SEL1 |= BIT0 + BIT1; and.b #0xfc, &0x20b ; P2SEL0 &= ~(BIT0 + BIT1); mov #0000000010110001b,&5c0h mov #0x0003, &0x5c2 //UCA0CTLW1 200ns deglitch (default) mov #0x009C, &0x5c6 //UCA0BRW for 9600 baud, 24MHz clock mov #0x2241, &0x5c8 //UCA0MCTLW " bic.b #0x01, &0x5c0 //UCA0CTLW0 &= ~UCSWRST // release from reset //Clear RAM RamClr: mov #RAMsize,r11 ; //known pattern for testing uart now RamClrLoop; sub #2,r11 mov #4d4eh,RAMbegin(r11) jnz RamClrLoop ; mov.b #0,RxInptr mov.b #0,RxOutptr mov.b #0,RxCount mov.b #0,TxInptr mov.b #0,TxOutptr mov.b #0,TxCount mov.b #0,UARTflags /*****************Setup stacks and user variables**************/ mov #rstack, sp bis #1,&5dah //Enable UART receive interrupt eint #define UART_ECHO_TEST #if defined UART_ECHO_TEST mov #XON,tos call #TputIn ; tloop: call #RpullOut //Wait 'til something in there cmp #-1,tos jeq tloop tloop2: call #TputIn jne tloop jmp tloop2 //Wait 'til XMIT space available #endif /***********Serial transmit*************/ ; ; User side transmit, jeq after return signifies no room ; Character input in r7, output is zero flag, set if no more room ; Must clear Rx interrupt enable also, 'cuz it fusses with TxFifo ; TputIn: bic #3,&5dah //Clear TX interrupt enable nop //very necessary nop nop ; cmp.b #FIFOSIZE,&TxCount jeq tpx //No room left bit.b #CtlOreceived,&UARTflags jne tpx ; ;There is room ; tp1: mov.b &TxInptr, r14 mov.b tos,TxFifo(r14) ; inc r14 and #FIFOSIZE-1,r14 mov.b r14, &TxInptr ; inc.b &TxCount ; bit.b #XOFFreceived,&UARTflags jne tpx2 ; bis #3,&5dah //re-enable Tx and Rx interrupts bic #2,sr //Clear zero flag ; tpx: bis #1,&5dah //re-enable Rx interrupt tpx2: ret ; /************************Serial port Function `RpullOut'***********************/ ; ; User side getchar. -1 returned means no char available (NULL is a valid character) ; ; Output is in r7 (tos), char in high addressed (LSB) byte ; RpullOut: bic #1,&5dah //Clear UART Rx interrupt nop nop nop ; tst.b &RxCount jeq L6 ; dec.b &RxCount ; mov.b &RxOutptr, r14 rla r14 mov RxFifo(r14),tos ; rra r14 //carry is 0 inc r14 and #FIFOSIZE-1, r14 mov.b r14, &RxOutptr ; ; If > RXONPT remaining spaces, send XON on tx interrupt ; cmp.b #FIFOSIZE-RXONPT,&RxCount jne L5 ; bic.b #SendXOFF, &UARTflags //Clear SendXOFF prepare to send XON bis #2,&5dah //Enable Tx interrupt jmp L5 ; L6: mov #-1,tos L5: bis #1,&5dah //Enable UART receive interrupt ret ; /***************************Serial Communiction interrupt**************/ ; uart_isr: pushm.w #4,r15 nop nop nop nop ; ;all IFG flags were zero when read here, making them unusable in an ISR ; mov &5deh, r15 //Interrupt vector register cmp #2, r15 //Rx vector jeq ReceiveISR ; cmp #4, r15 //Tx vector jeq XmitISR ; L27: popm.w #4,r15 reti ; //Receiver ; ReceiveISR: mov &5cah, r12 //UCA0 status mov &5cch, r13 //Recv buffer bis &5cah, r12 //UCA0 status OR in overrun and #7ch, r12 //clear bits we're not interested in bit.b #8,r12 //check break jeq NoBreak ; bis.b #UARTbreak,&UARTflags //Set break flag mov.b #CtlC,r13 //Put CTRL_C into receive character NoBreak: tst.b r12 swpb r12 bis.b r13,r12 //Merge errors to received character jne SkipTests //from tst.b above, don't test special ; ; Check special cases on error free characters ; cmp.b #XOFF,r13 //XOFF jeq GotXoff ; cmp.b #XON,r13 //XON jeq GotXon ; cmp.b #CtlC,r13 //CTRL_C jeq GotCtlC ; cmp.b #CtlO,r13 //CTRL_O, send XMIT Chars to /dev/null jeq GotCtlO ; //Check state of receive fifo ; SkipTests: mov.b &RxCount, r14 cmp.b #FIFOSIZE,r14 jhs DoBEL //No room ; ; If remaining RX space < RXOFFTRIGGER, send XOFF ; cmp #FIFOSIZE-RXOFFTRIGGER, r14 jhs doXOFF ; ; Insert char and err into RxFifo ; mov.b &RxInptr, r15 rla r15 mov r12, RxFifo(r15) //store the character and error bits ; rra r15 add.b #1, r15 and #FIFOSIZE-1, r15 mov.b r15, &RxInptr ; add.b #1, &RxCount jmp L27 ; ; ; GotXoff:bis.b #XOFFreceived,&UARTflags //XOFF received bit bic #2,&5dah //Disable Tx interrupt jmp L27 ; GotXon: bic.b #XOFFreceived,&UARTflags //clear XOFF received bit jmp L27 ; GotCtlC:bis.b #UARTbreak,&UARTflags //Set UARTbreak jmp L27 ; GotCtlO:bit.b #CtlOreceived,&UARTflags //CtlO toggles jeq DoCtlO ; bic.b #CtlOreceived,&UARTflags jmp L27 ; DoCtlO: bis.b #CtlOreceived,&UARTflags //Toggle CTRL_O mov #0,&TxInptr //does TxOutptr also, .w mov.b #0,&TxCount //Empty the XMIT fifo bic #2,&5dah //Disable Tx interrupt jmp L27 ; ;Here's a big problem: we can't tell if the xmitter is free to load :-( ;but if we don't load it and it's idle, tx interrupts stop. ;Inside the ISR, the IFG bits seem to always read 0, even before reading the vector reg. ;So the XMTR UCTXCPIFG bit is useless here. ; DoBEL: tst.b &TxCount jne BelLater ; mov #BEL,&5ceh bis.b #2,&5dah //Enable Tx interrupt jmp L27 BelLater: bis.b #RfifoFull,&UARTflags //send BEL when xmtr available jmp L27 ; ; If remaining RX space < RXOFFTRIGGER, send XOFF ; (same big problem here) ; doXOFF: tst.b &TxCount jne XoffLater ; mov #XOFF,&5ceh bis.b #2,&5dah //Enable Tx interrupt jmp L27 ; XoffLater: bis.b #SendXOFF, &UARTflags //Set SendXOFF if not much more room jmp L27 //Transmitter ; ;Mini state machine description for XOFF transmitting process: ; ; SendxOFF XOFFsent ; 0 0 ; normal processing ; 1 0 ; XOFF pending to be sent ; 1 1 ; XOFF sent, must send an XON when Rfifo room appears. ; 0 1 ; XON pending to be sent when xmtr ready ; //UARTflags: // RtsCts RfifoFull TxBusy UARTbreak CtlOreceived XOFFreceived SendXOFF XOFFsent ; //Transmitter XmitISR:bic.b #TxBusy, &UARTflags //Clear TxBusy (not currently used) ; mov.b &UARTflags, r15 bit.b #RfifoFull, r15 jne SendBEL ; bit.b XOFFreceived, r15 jne StopSending ; and #SendXOFF|XOFFsent, r15 cmp #SendXOFF, r15 jeq DoXOFF //XOFF pending ; cmp #XOFFsent, r15 //XON pending when tx ready jeq DoXON ; TestXct:tst.b &TxCount jne DoSend ; StopSending: bic #2,&5dah //disable TX interrupts jmp L27 ; ; //Send character from TxFIFO ; DoSend: mov.b &TxOutptr, r15 mov.b TxFifo(r15),r14 //Collect byte as word bis.b #TxBusy,&UARTflags mov.w r14,&5ceh //Send it out ; inc.b r15 and.b #FIFOSIZE-1, r15 mov.b r15, &TxOutptr ; dec.b &TxCount jne L27 ; bic #2,&5dah //disable TX interrupts, Tx fifo was empty jmp L27 ; ; SendBEL: bic.b #RfifoFull,&UARTflags bis.b #TxBusy,&UARTflags ; mov #BEL, &5ceh jmp L27 ; ; DoXOFF: bis.b #TxBusy,&UARTflags mov #XOFF, &5ceh //XOFF -> Tx buffer bis.b #XOFFsent, &UARTflags //Set XOFFsent jmp L27 ; DoXON: bis.b #TxBusy,&UARTflags mov #XON, &5ceh //XON -> Tx buffer bic.b #XOFFsent, &UARTflags //Clear XOFFsent jmp L27 ; nop ; /*********************************************************************/ ; Interrupt Vectors rseg INTVEC intvecs: dc16 nullirq ; $FF80 - reserved org 0fff0h dc16 uart_isr ; $FFF0 - eUSCI_A0 rx,tx org 0fffeh dc16 reset ; $FFFE - reset end