; PIC firmware for , ; a music robot by G.-W.Raes, Logosfoundation Ghent ; code by Johannes Taelman list p=18f252 ;list directive to define processor #include ;processor specific definitions ; #define simulate 1 ; enable simulation ; #define heartbeat 1 ; enable heatbeats ;****************************************************************************** ;Configuration bits ; The __CONFIG directive defines configuration data within the .ASM file. ; The labels following the directive are defined in the P18F252.INC file. ; The PIC18FXX2 Data Sheet explains the functions of the configuration bits. ; Change the following lines to suit your application. __CONFIG _CONFIG1H, _OSCS_OFF_1H & _HSPLL_OSC_1H __CONFIG _CONFIG2L, _BOR_OFF_2L & _PWRT_OFF_2L __CONFIG _CONFIG2H, _WDT_OFF_2H __CONFIG _CONFIG3H, _CCP2MX_OFF_3H __CONFIG _CONFIG4L, _STVR_OFF_4L & _LVP_OFF_4L & _DEBUG_OFF_4L __CONFIG _CONFIG5L, _CP0_OFF_5L & _CP1_OFF_5L & _CP2_OFF_5L & _CP3_OFF_5L __CONFIG _CONFIG5H, _CPB_OFF_5H & _CPD_OFF_5H __CONFIG _CONFIG6L, _WRT0_OFF_6L & _WRT1_OFF_6L & _WRT2_OFF_6L & _WRT3_OFF_6L __CONFIG _CONFIG6H, _WRTC_OFF_6H & _WRTB_OFF_6H & _WRTD_OFF_6H __CONFIG _CONFIG7L, _EBTR0_OFF_7L & _EBTR1_OFF_7L & _EBTR2_OFF_7L & _EBTR3_OFF_7L __CONFIG _CONFIG7H, _EBTRB_OFF_7H ;---------------------------------------------------------------------------- ;Constants ;SPBRG_VAL EQU 027h ;set baud rate 31250 for 20Mhz clock SPBRG_VAL EQU 04Fh ;set baud rate 31250 for 40Mhz clock TX_BUF_LEN EQU 010h ;length of transmit circular buffer RX_BUF_LEN EQU TX_BUF_LEN ;length of receive circular buffer ;---------------------------------------------------------------------------- ;Bit Definitions TxBufFull EQU 0 ;bit indicates Tx buffer is full TxBufEmpty EQU 1 ;bit indicates Tx buffer is empty RxBufFull EQU 2 ;bit indicates Rx buffer is full RxBufEmpty EQU 3 ;bit indicates Rx buffer is empty ;ReceivedCR EQU 4 ;bit indicates character received ;---------------------------------------------------------------------------- ;Variables CBLOCK 0x000 WREG_TEMP ;to save WREG during interrupt STATUS_TEMP ;to save STATUS during interrupt BSR_TEMP ;to save BSR during interrupt FSR0H_TEMP ;to save FSR0H during interrupt FSR0L_TEMP ;to save FSR0L during interrupt FSR0H_SHADOW ;to save FSR0H during high interrupt FSR0L_SHADOW ;to save FSR0L during high interrupt MidiInByte ; Rcv'd Byte MidiByte0 ; status MidiByte1 ; data1 MidiByte2 ; data2 MidiCurData ; current data byte index MidiNumData ; expected data bytes MidiTestByte ; for testing only TmpM ; non-ISR scratch TmpT ; non-ISR scratch LatWriteState ; 0=do nothing ; 1=set data ; 2=set addr ; 2=release addr FifoRdIndx; FifoWrIndx; ErrorLed; TISRData; TISRAddrA; TISRAddrC; ENDC CBLOCK 0x40 ; Flags ;byte for indicator flag bits TempData ;temporary data in main routines TempRxData ;temporary data in Rx buffer routines TempTxData ;temporary data in Tx buffer routines TxStartPtrH ;pointer to start of data in Tx buffer TxStartPtrL ;pointer to start of data in Tx buffer TxEndPtrH ;pointer to end of data in Tx buffer TxEndPtrL ;pointer to end of data in Tx buffer RxStartPtrH ;pointer to start of data in Rx buffer RxStartPtrL ;pointer to start of data in Rx buffer RxEndPtrH ;pointer to end of data in Rx buffer RxEndPtrL ;pointer to end of data in Rx buffer TxBuffer:TX_BUF_LEN ;Tx buffer for data to transmit RxBuffer:RX_BUF_LEN ;Rx buffer for received data ENDC CBLOCK 0xA0 ExtLatAData ; external latch A data ExtLatAAddrA ; external latch A address port A ExtLatAAddrC ; external latch A address port C ExtLatAdummy ; to align data by 4 ExtLatBData ExtLatBAddrA ExtLatBAddrC ExtLatBdummy ExtLatCData ExtLatCAddrA ExtLatCAddrC ExtLatCdummy ExtLatDData ExtLatDAddrA ExtLatDAddrC ExtLatDdummy ExtLatEData ExtLatEAddrA ExtLatEAddrC ExtLatEdummy ExtLatFData ExtLatFAddrA ExtLatFAddrC ExtLatFdummy ENDC CBLOCK 0xF8 ; fifo from main to timer ISR Fifo0LatPtr Fifo1LatPtr Fifo2LatPtr Fifo3LatPtr Fifo4LatPtr Fifo5LatPtr Fifo6LatPtr Fifo7LatPtr ENDC ;---------------------------------------------------------------------------- ;This code executes when a reset occurs. ORG 0x0000 ;place code at reset vector ResetVector: bra Main ;go to beginning of program ;---------------------------------------------------------------------------- ;This code executes when a high priority interrupt occurs. ORG 0x0008 HighInt: bra HighIntCode ;go to high priority interrupt routine ;---------------------------------------------------------------------------- ;This code executes when a low priority interrupt occurs. ORG 0x0018 LowInt: movff STATUS,STATUS_TEMP ;save STATUS register movff WREG,WREG_TEMP ;save working register movff BSR,BSR_TEMP ;save BSR register movff FSR0H,FSR0H_TEMP ;save FSR0H register movff FSR0L,FSR0L_TEMP ;save FSR0L register ;test other interrupt flags here btfss PIR1,RCIF ;test for RCIF receive interrupt flag bra LowInt1 ;if RCIF is not set, done with test btfsc PIE1,RCIE ;else test if Rx interrupt enabled bra GetData ;if so, go get received data LowInt1: btfss PIR1,TXIF ;test for TXIF transmit interrupt flag bra LowInt2 ;if TXIF is not set, done with test btfsc PIE1,TXIE ;else test if Tx interrupt is enabled bra PutData ;if so, go transmit data ;can do special error handling here - an unexpected interrupt occurred LowInt2: reset ;error if no valid interrupt so reset ;------------------------------------ ;Read data from the transmit buffer and put into transmit register. PutData: btfss Flags,TxBufEmpty ;check if transmit buffer is empty bra PutDat1 ;if not then go transmit bcf PIE1,TXIE ;else disable Tx interrupt bra EndLowInt PutDat1: rcall GetTxBuffer ;get data from transmit buffer movwf TXREG ;and transmit ;------------------------------------ ;End of low priority interrupt routine restores context. EndLowInt: movff FSR0L_TEMP,FSR0L ;restore FSR0L register movff FSR0H_TEMP,FSR0H ;restore FSR0H register movff BSR_TEMP,BSR ;restore BSR register movff WREG_TEMP,WREG ;restore working register movff STATUS_TEMP,STATUS ;restore STATUS register retfie ;---------------------------------------------------------------------------- ;High priority interrupt routine. HighIntCode: movff FSR0H,FSR0H_SHADOW ;save FSR0H register movff FSR0L,FSR0L_SHADOW ;save FSR0L register ;test other interrupt flags here btfss PIR2,TMR3IF ;test for Timer3 receive interrupt flag bra HighInt1 ;if RCIF is not set, done with test btfsc PIE2,TMR3IE ;else test if Timer3 interrupt enabled bra Timer3ISR ;if so, go get received data ;can do special error handling here - an unexpected interrupt occurred HighInt1: reset ;error if no valid interrupt so reset ;------------------------------------ ;Get received data and write into receive buffer. GetData: ; btg LATA,1; ; toggle LATA:1 = HEARTBEAT btfsc RCSTA,OERR ;if overrun error bra ErrOERR ;then go handle error btfsc RCSTA,FERR ;if framing error bra ErrFERR ;then go handle error btfsc Flags,RxBufFull ;if buffer full bra ErrRxOver ;then go handle error ; btg LATA,1; ; toggle LATA:1 = HEARTBEAT movf RCREG,W ;get received data ; xorlw 0x0d ;compare with ; btfsc STATUS,Z ;check if the same ; bsf Flags,ReceivedCR ;indicate character received ; xorlw 0x0d ;change back to valid data rcall PutRxBuffer ;and put in buffer bra EndLowInt ;error because OERR overrun error bit is set ;can do special error handling here - this code simply clears and continues ErrOERR: bcf RCSTA,CREN ;reset the receiver logic bsf RCSTA,CREN ;enable reception again setf ErrorLed; error LED movlw 0xFA; ; MIDI RT Start rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;error because FERR framing error bit is set ;can do special error handling here - this code simply clears and continues ErrFERR: movf RCREG,W ;discard received data that has error bcf RCSTA,CREN ;reset the receiver logic bsf RCSTA,CREN ;enable reception again setf ErrorLed; error LED movlw 0xFB; ; MIDI RT Continue rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;error because receive buffer is full ;can do special error handling here - this code checks and discards the data ErrRxOver: movf RCREG,W ;discard received data ; xorlw 0x0d ;but compare with ; btfsc STATUS,Z ;check if the same ; bsf Flags,ReceivedCR ;indicate character received setf ErrorLed; error LED movlw 0xFB; ; MIDI RT Start rcall PutTxBuffer ;put data in transmit buffer bra EndLowInt ;------------------------------------ ;End of high priority interrupt routine restores context. EndHighInt: movff FSR0L_SHADOW,FSR0L ;restore FSR0L register movff FSR0H_SHADOW,FSR0H ;restore FSR0H register retfie FAST ;return and restore context ;---------------------------------------------------------------------------- ;Main routine checks for for reception of a and then calls a routine to ; move the data to transmit back. Main: setf LATA ; Address strobes high clrf LATB ; All outputs low setf LATC ; All outputs low clrf TRISA ; Config PORTA as all outputs clrf TRISB ; Config PORTB as all outputs movlw 0x80 ; movwf TRISC ; Config PORTC all outputs + tristate for serial rx movlw 0x07 ; init adc movwf ADCON1 ; init adc clrf ADCON0 ; poweroff adc clrf TRISA ; Config PORTA again as all outputs setf LATA ; Address strobes high clrf LATB ; All outputs low setf LATC ; All outputs low nop nop nop nop nop nop nop nop clrf LATA clrf LATB nop nop nop nop nop nop nop nop setf LATA ; Address strobes high setf LATC ; All outputs low clrf ExtLatAData; clrf ExtLatBData; clrf ExtLatCData; clrf ExtLatDData; clrf ExtLatEData; clrf ExtLatFData; movlw 00Fh; movwf ExtLatAAddrA; movwf ExtLatBAddrA; movlw 020h; movwf ExtLatAAddrC; movlw 010h; movwf ExtLatBAddrC; movlw 030h; movwf ExtLatCAddrC; movwf ExtLatDAddrC; movwf ExtLatEAddrC; movwf ExtLatFAddrC; movlw 00Eh; movwf ExtLatCAddrA; movlw 00Dh; movwf ExtLatEAddrA; ; movwf ExtLatDAddrA; movlw 00Bh; movwf ExtLatFAddrA; ; movwf ExtLatEAddrA; movlw 007h; ; movwf ExtLatFAddrA; movwf ExtLatDAddrA; movlw ExtLatAData; movwf Fifo0LatPtr; movlw ExtLatBData; movwf Fifo1LatPtr; movlw ExtLatCData; movwf Fifo2LatPtr; movlw ExtLatDData; movwf Fifo3LatPtr; movlw ExtLatEData; movwf Fifo4LatPtr; movlw ExtLatFData; movwf Fifo5LatPtr; movlw ExtLatAData; movwf Fifo6LatPtr; movlw ExtLatBData; movwf Fifo7LatPtr; ; pwm init movlw 0x80; movwf PR2; movlw 0x00; movwf CCPR1L; movlw 0x01; movwf TMR2; movlw 0x04; movwf T2CON; movlw 0x0C; movwf CCP1CON; bsf LATC,0 ; Light error LED on powerup ; Wait a second with ALoop and BLoop setf TmpM BLoop1: movlw 0xff; ALoop1: decfsz WREG; goto ALoop1 decfsz TmpM; goto BLoop1 bcf LATC,0 ; Been patient enough, dim error LED and start movlw Fifo0LatPtr; movwf FifoRdIndx; movlw Fifo5LatPtr; movwf FifoWrIndx; lfsr FSR0 ,0000h lfsr FSR1 ,0000h rcall SetupSerial ;set up serial port and buffers rcall SetupTimer3 MainLoop: ;do other stuff here ; btg LATC,3; ; toggle LATC:3 = IDLE HEARTBEAT ; btg LATA,0; ; toggle LATA:0 = IDLE HEARTBEAT #ifdef simulate nop; your chance to schedule midi cmd movff MidiTestByte,WREG; rcall MidiInParser; rcall Timer3ISR #endif call PollMidiIn; bra MainLoop ;go wait for more data ;---------------------------------------------------------------------------- ;Set up serial port and buffers. SetupSerial: movlw 0x80 ;set tris bits for Tx and RX iorwf TRISC,F movlw SPBRG_VAL ;set baud rate movwf SPBRG movlw 0x04 ;no transmission, high baud rate ;0x24 ;enable transmission and high baud rate movwf TXSTA movlw 0x90 ;enable serial port and reception movwf RCSTA clrf Flags ;clear all flags rcall InitTxBuffer ;initialize transmit buffer rcall InitRxBuffer ;initialize receive buffer movlw 0x30 ;enable Tx and Rx interrupts movwf PIE1 movlw 0x00 ;set Rx low and Tx low priority movwf IPR1 bsf RCON,IPEN ;enable interrupt priorities movlw 0xc0 ;enable global high and low ints movwf INTCON return ;---------------------------------------------------------------------------- ;Circular buffer routines. ;---------------------------------------------------------------------------- ;Initialize transmit buffer. InitTxBuffer: movlw HIGH TxBuffer ;take high address of transmit buffer movwf TxStartPtrH ;and place in transmit start pointer movwf TxEndPtrH ;and place in transmit end pointer movlw LOW TxBuffer ;take low address of transmit buffer movwf TxStartPtrL ;and place in transmit start pointer movwf TxEndPtrL ;and place in transmit end pointer bcf Flags,TxBufFull ;indicate Tx buffer is not full bsf Flags,TxBufEmpty ;indicate Tx buffer is empty return ;---------------------------------------------- ;Initialize receive buffer. InitRxBuffer: movlw HIGH RxBuffer ;take high address of receive buffer movwf RxStartPtrH ;and place in receive start pointer movwf RxEndPtrH ;and place in receive end pointer movlw LOW RxBuffer ;take low address of receive buffer movwf RxStartPtrL ;and place in receive start pointer movwf RxEndPtrL ;and place in receive end pointer bcf Flags,RxBufFull ;indicate Rx buffer is not full bsf Flags,RxBufEmpty ;indicate Rx buffer is empty return ;---------------------------------------------------------------------------- ;Add a byte (in WREG) to the end of the transmit buffer. PutTxBuffer: bcf PIE1,TXIE ;disable Tx interrupt to avoid conflict btfsc Flags,TxBufFull ;check if transmit buffer full bra ErrTxBufFull ;go handle error if full movff TxEndPtrH,FSR0H ;put EndPointer into FSR0 movff TxEndPtrL,FSR0L ;put EndPointer into FSR0 movwf POSTINC0 ;copy data to buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with end pointer bra PutTxBuf1 ;skip low bytes if high bytes not equal movlw LOW (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with end pointer bra PutTxBuf1 ;go save new pointer if at end lfsr 0,TxBuffer ;point to beginning of buffer if at end PutTxBuf1: movff FSR0H,TxEndPtrH ;save new EndPointer high byte movff FSR0L,TxEndPtrL ;save new EndPointer low byte ;test if buffer is full movf TxStartPtrH,W ;get start pointer cpfseq TxEndPtrH ;and compare with end pointer bra PutTxBuf2 ;skip low bytes if high bytes not equal movf TxStartPtrL,W ;get start pointer cpfseq TxEndPtrL ;and compare with end pointer bra PutTxBuf2 bsf Flags,TxBufFull ;if same then indicate buffer full PutTxBuf2: bcf Flags,TxBufEmpty ;Tx buffer cannot be empty bsf PIE1,TXIE ;enable transmit interrupt return ;error because attempting to store new data and the buffer is full ;can do special error handling here - this code simply ignores the byte ErrTxBufFull: bsf PIE1,TXIE ;enable transmit interrupt return ;no save of data because buffer is full ;---------------------------------------------- ;Add a byte (in WREG) to the end of the receive buffer. PutRxBuffer: btfsc Flags,RxBufFull ;check if receive buffer full bra ErrRxBufFull ;go handle error if full movff RxEndPtrH,FSR0H ;put EndPointer into FSR0 movff RxEndPtrL,FSR0L ;put EndPointer into FSR0 movwf POSTINC0 ;copy data to buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with end pointer bra PutRxBuf1 ;skip low bytes if high bytes not equal movlw LOW (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with end pointer bra PutRxBuf1 ;go save new pointer if not at end lfsr 0,RxBuffer ;point to beginning of buffer if at end PutRxBuf1: movff FSR0H,RxEndPtrH ;save new EndPointer high byte movff FSR0L,RxEndPtrL ;save new EndPointer low byte ;test if buffer is full movf RxStartPtrH,W ;get start pointer cpfseq RxEndPtrH ;and compare with end pointer bra PutRxBuf2 ;skip low bytes if high bytes not equal movf RxStartPtrL,W ;get start pointer cpfseq RxEndPtrL ;and compare with end pointer bra PutRxBuf2 bsf Flags,RxBufFull ;if same then indicate buffer full PutRxBuf2: bcf Flags,RxBufEmpty ;Rx buffer cannot be empty return ;error because attempting to store new data and the buffer is full ;can do special error handling here - this code simply ignores the byte ErrRxBufFull: return ;no save of data because buffer is full ;---------------------------------------------- ;Remove and return (in WREG) the byte at the start of the transmit buffer. GetTxBuffer: btfsc Flags,TxBufEmpty ;check if transmit buffer empty bra ErrTxBufEmpty ;go handle error if empty movff TxStartPtrH,FSR0H ;put StartPointer into FSR0 movff TxStartPtrL,FSR0L ;put StartPointer into FSR0 movff POSTINC0,TempTxData ;save data from buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with start pointer bra GetTxBuf1 ;skip low bytes if high bytes not equal movlw LOW (TxBuffer+TX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with start pointer bra GetTxBuf1 ;go save new pointer if at end lfsr 0,TxBuffer ;point to beginning of buffer if at end GetTxBuf1: movff FSR0H,TxStartPtrH ;save new StartPointer value movff FSR0L,TxStartPtrL ;save new StartPointer value ;test if buffer is now empty movf TxEndPtrH,W ;get end pointer cpfseq TxStartPtrH ;and compare with start pointer bra GetTxBuf2 ;skip low bytes if high bytes not equal movf TxEndPtrL,W ;get end pointer cpfseq TxStartPtrL ;and compare with start pointer bra GetTxBuf2 bsf Flags,TxBufEmpty ;if same then indicate buffer empty GetTxBuf2: bcf Flags,TxBufFull ;Tx buffer cannot be full movf TempTxData,W ;restore data from buffer return ;error because attempting to read data from an empty buffer ;can do special error handling here - this code simply returns zero ErrTxBufEmpty: retlw 0 ;buffer empty, return zero ;---------------------------------------------- ;Remove and return (in WREG) the byte at the start of the receive buffer. GetRxBuffer: bcf PIE1,RCIE ;disable Rx interrupt to avoid conflict btfsc Flags,RxBufEmpty ;check if receive buffer empty bra ErrRxBufEmpty ;go handle error if empty movff RxStartPtrH,FSR0H ;put StartPointer into FSR0 movff RxStartPtrL,FSR0L ;put StartPointer into FSR0 movff POSTINC0,TempRxData ;save data from buffer ;test if buffer pointer needs to wrap around to beginning of buffer memory movlw HIGH (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0H ;and compare with start pointer bra GetRxBuf1 ;skip low bytes if high bytes not equal movlw LOW (RxBuffer+RX_BUF_LEN) ;get last address of buffer cpfseq FSR0L ;and compare with start pointer bra GetRxBuf1 ;go save new pointer if at end lfsr 0,RxBuffer ;point to beginning of buffer if at end GetRxBuf1: movff FSR0H,RxStartPtrH ;save new StartPointer value movff FSR0L,RxStartPtrL ;save new StartPointer value ;test if buffer is now empty movf RxEndPtrH,W ;get end pointer cpfseq RxStartPtrH ;and compare with start pointer bra GetRxBuf2 ;skip low bytes if high bytes not equal movf RxEndPtrL,W ;get end pointer cpfseq RxStartPtrL ; and compare with start pointer bra GetRxBuf2 bsf Flags,RxBufEmpty ;if same then indicate buffer empty GetRxBuf2: bcf Flags,RxBufFull ;Rx buffer cannot be full movf TempRxData,W ;restore data from buffer bsf PIE1,RCIE ;enable receive interrupt return ;error because attempting to read data from an empty buffer ;can do special error handling here - this code simply returns zero ErrRxBufEmpty: bsf PIE1,RCIE ;enable receive interrupt retlw 0 ;buffer empty, return zero ;---------------------------------------------------------------------------- ;Move data from receive buffer to transmit buffer to echo the line back. CopyRxToTx: ; bcf Flags,ReceivedCR ;clear received indicator Copy1: btfsc Flags,RxBufEmpty ;check if Rx buffer is empty return ;if so then return rcall GetRxBuffer ;get data from receive buffer ; movwf TempData ;save data rcall PutTxBuffer ;put data in transmit buffer ; movf TempData,W ;restore data ; xorlw 0x0d ;compare with ; bnz Copy1 ;if not the same then move another byte bra Copy1 return ;---------------------------------------------------------------------------- ; Timer3 setup SetupTimer3: movlw 0x01 movwf T3CON ; timer3 on, other bits cleared bsf IPR2,1 ; timer3 = high priority interrupt bsf PIE2,1 ; timer3 interrupt enable return Timer3ISR: bcf PIR2,TMR3IF ; clear interrupt flag movlw 0E0h ;0x7F; 0xA0 movwf TMR3L ; preset timer setf TMR3H ; preset timer ; bsf LATC,1; ; LATC:1 = TIMER ISR HEARTBEAT #ifdef heartbeat bsf LATC,0; ; LATC:5 = TIMER ISR HEARTBEAT #endif ; pseudocode: ; if state = 1 ; set data bus ; increment state ; end ; if state = 2 ; set addr bus ; increment state ; end ; if state = 3 ; reset addr bus ; increment state ; end ; ; if data on fifo ; set state=1 ; copy fifo data ; end ; state selector movf LatWriteState,0; bz T3ISRProcessFifo; decf WREG; bz T3ISR_LWS1; decf WREG; bz T3ISR_LWS2; decf WREG; bz T3ISR_LWS3; decf WREG; ; shouldn't get here setf ErrorLed; clrf LatWriteState; bra T3ISRProcessFifo; T3ISR_LWS1: ; bsf LATC,0; ; errorLED heartbeat ; btg LATC,3; ; LATC:1 = TIMER ISR HEARTBEAT incf LatWriteState movff TISRData,LATB; bra TISRDone; T3ISR_LWS2: incf LatWriteState movff TISRAddrA,LATA; movff TISRAddrC,LATC; bra TISRDone; T3ISR_LWS3: clrf LatWriteState movlw 00Fh; movwf LATA; movlw 070h; movwf LATC; bra TISRDone; T3ISRProcessFifo: lfsr FSR0 ,0000h movf FifoRdIndx, W; subwf FifoWrIndx, W ; result in w bz TISRDone; no new task on cmd queue movff FifoRdIndx, FSR0L; incf FifoRdIndx; bnz NoWrap; movlw Fifo0LatPtr; Wrap to start movwf FifoRdIndx; NoWrap: movf INDF0, 0; W = ExtLatPtr movwf FSR0L; movff POSTINC0,TISRData; movff POSTINC0,TISRAddrA; movff POSTINC0,TISRAddrC; movlw 1; movwf LatWriteState; TISRDone: ; bcf LATC,1; ; heatbeat #ifdef heartbeat bcf LATC,1; ; heatbeat #endif #ifdef simulate return ; OUTSIDE ISR *WARNING* FOR SIMULATION ONLY #endif bra EndHighInt ; resume ;---------------------------------------------------------------------------- ; MIDI Input parser ; ; pseudocode: ; ; MidiInParser: ; if (inByte & 0x80) ; MidiStatus = inByte ; goto MidiInStatus ; else ; goto MidiInData ; return ; ; MidiInStatus: ; Look up # databytes ; 1000xxxx -> 2 (noteOn) ; 1001xxxx -> 2 (noteOff) ; 1010xxxx -> 2 (polyKeyPr) ; 1011xxxx -> 2 (ctrlChange) ; 1100xxxx -> 1 (pgmChg ; 1101xxxx -> 1 (chnlPr) ; 1110xxxx -> 0 (System Common Messages -> ignore) ; 1111xxxx -> 0 (SysEx) ; ; store in MidiNumData ; MidiCurDataBytes=0 ; return ; ; MidiInData: ; If (CurDBytes==0) ; MidiData1=inByte ; If (CurDBytes==1) ; MidiData2=inByte ; CurDBytes++; ; ; If (CurDBytes>MidiNumData) ; If (MidiStatus==NoteOn) ; If (channel = x) ; ... ; ... ; ; If (MidiStatus==NoteOff) ; If (channel = x) ; ... ; ; goto MidiInStatus PollMidiIn: btfsc Flags,RxBufEmpty ;check if Rx buffer is empty return ;if so then return rcall GetRxBuffer ;get data from receive buffer MidiInParser: movwf MidiInByte; btfss MidiInByte,7; bra MidiInData; ; jump if it wasn't a status byte movwf MidiByte0; MidiInStatus: movlw 0; clrf MidiCurData; btfss MidiByte0,6; bra MidiInStatus2words; btfss MidiByte0,5; movlw 1; movwf MidiNumData; bra MidiInStatusEnd; MidiInStatus2words: movlw 2; movwf MidiNumData; MidiInStatusEnd: return MidiInData: tstfsz MidiCurData; bra MidiInDataM2; bra MidiInDataM1; MidiInDataM2: ; 2nd byte movff MidiInByte,MidiByte2; clrf MidiCurData; bra MidiInAction2Bytes; MidiInDataM1: movff MidiInByte,MidiByte1; incf MidiCurData,1; movf MidiCurData,0; subwf MidiNumData,0; bz MidiInAction1Byte; return; MidiInAction1Byte: return; MidiInAction2Bytes: movlw 09Fh; noteOn, ch F subwf MidiByte0,0; bz MidiInNoteOn; movlw 08Fh; noteOff, ch F subwf MidiByte0,0; bz MidiInNoteOff; movlw 0BFh; cc, ch F subwf MidiByte0,0; bz MidiInCC; return; MidiInNoteOn: ;************** ; lookup timer #, read from table in PM:0Fvv movf MidiByte2,0; bz MidiInNoteOff; ; velocity=0 -> NOTE OFF ; bsf LATC,0; ; errorLED heartbeat movlw 10h; movwf TBLPTRH; page = note number to latch pointer table MOVFF MidiByte1,TBLPTRL TBLRD* ; read into TABLAT movf TABLAT,0 bz MidiInNoteOn2; ; bcf LATC,0; ; errorLED heartbeat movwf TmpT ; TmpT = Latch pointer ; modify data with OR mask lfsr FSR2 ,0000h movff TmpT, FSR2L; incf TBLPTRH; page = note number to OR mask table TBLRD* ; read into TABLAT movf TABLAT,0; iorwf INDF2; ; add to fifo movff FifoWrIndx, FSR2L; movff TmpT,POSTINC2; ; update FifoWrIndex movf FSR2L,0; bz NoWrap2; corrected: was: bnz movff FSR2L, FifoWrIndx; return NoWrap2 movlw Fifo0LatPtr; Wrap to start movwf FifoWrIndx; return MidiInNoteOff: ;************** ; lookup timer #, read from table in PM:0Fvv movlw 10h; movwf TBLPTRH; page = note number to latch pointer table MOVFF MidiByte1,TBLPTRL TBLRD* ; read into TABLAT movf TABLAT,0 bz MidiInNoteOff2; movwf TmpT ; TmpT = Latch pointer ; modify data with OR mask lfsr FSR2 ,0000h movff TmpT, FSR2L; incf TBLPTRH; page = note number to OR mask table incf TBLPTRH; page = note number to AND mask table TBLRD* ; read into TABLAT movf TABLAT,0; andwf INDF2; ; add to fifo movff FifoWrIndx, FSR2L; movff TmpT,POSTINC2; ; update FifoWrIndex movf FSR2L,0; bz NoWrap3; corrected: was: bnz movff FSR2L, FifoWrIndx; return NoWrap3 movlw Fifo0LatPtr; Wrap to start movwf FifoWrIndx; return MidiInNoteOn2 return MidiInNoteOff2 return MidiInCC movlw 0x07; CC Volume, ch F subwf MidiByte1,0; bz MidiInCCVol; movlw 0x7B; CC NotesOff, ch F subwf MidiByte1,0; bz MidiInCCAllNotesOff; return MidiInCCVol: movff MidiByte2,CCPR1L; return MidiInCCAllNotesOff: clrf ExtLatAData; clrf ExtLatBData; clrf ExtLatCData; clrf ExtLatDData; clrf ExtLatEData; clrf ExtLatFData; movlw ExtLatAData; movwf Fifo0LatPtr; movlw ExtLatBData; movwf Fifo1LatPtr; movlw ExtLatCData; movwf Fifo2LatPtr; movlw ExtLatDData; movwf Fifo3LatPtr; movlw ExtLatEData; movwf Fifo4LatPtr; movlw ExtLatFData; movwf Fifo5LatPtr; movlw ExtLatAData; movwf Fifo6LatPtr; movlw Fifo0LatPtr; movwf FifoRdIndx; movlw Fifo6LatPtr; movwf FifoWrIndx; movlw Fifo0LatPtr; movwf FifoRdIndx; movlw Fifo6LatPtr; movwf FifoWrIndx; return ;************************************************************* ; latch pointer per note org 1000h ; NoteLatchPtr: DB 0,0,0,0,0,0,0,0; 0..7 DB 0,0,0,0,0,0,0,0; 8.. DB 0,0,0,0,0,0,0,0; 16.. DB 0,0,0,0,0,0,0,0; 24.. DB ExtLatAData,ExtLatAData,ExtLatAData,ExtLatAData,ExtLatAData,ExtLatAData,ExtLatAData,ExtLatAData; 32.. DB ExtLatBData,ExtLatBData,ExtLatBData,ExtLatBData,ExtLatBData,ExtLatBData,ExtLatBData,ExtLatBData; 40.. DB ExtLatCData,ExtLatCData,ExtLatCData,ExtLatCData,ExtLatCData,ExtLatCData,ExtLatCData,ExtLatCData; 48.. DB ExtLatDData,ExtLatDData,ExtLatDData,ExtLatDData,ExtLatDData,ExtLatDData,ExtLatDData,ExtLatDData; 56.. DB ExtLatEData,ExtLatEData,ExtLatEData,ExtLatEData,ExtLatEData,ExtLatEData,ExtLatEData,ExtLatEData; 64.. DB ExtLatFData,ExtLatFData,ExtLatFData,ExtLatFData,ExtLatFData,ExtLatFData,ExtLatFData,ExtLatFData; 72.. DB 0,0,0,0,0,0,0,0; 80.. DB 0,0,0,0,0,0,0,0; 88.. DB 0,0,0,0,0,0,0,0; 96.. DB 0,0,0,0,0,0,0,0; 104.. DB 0,0,0,0,0,0,0,0; 112.. DB 0,0,0,0,0,0,0,0; 120..127 org 1100h ; NoteLatchOnOrMask: DB 0,0,0,0,0,0,0,0; 0..7 DB 0,0,0,0,0,0,0,0; 8.. DB 0,0,0,0,0,0,0,0; 16.. DB 0,0,0,0,0,0,0,0; 24.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 32.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 40.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 48.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 56.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 64.. DB 0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01; 72.. DB 0,0,0,0,0,0,0,0; 80.. DB 0,0,0,0,0,0,0,0; 88.. DB 0,0,0,0,0,0,0,0; 96.. DB 0,0,0,0,0,0,0,0; 104.. DB 0,0,0,0,0,0,0,0; 112.. DB 0,0,0,0,0,0,0,0; 120..127 org 1200h ; NoteLatchOffAndMask: DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 0..7 DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 8.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 16.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 24.. ; DB 0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F; 32.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 32.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 40.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 48.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 56.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 64.. DB 0x7F,0xBF,0xDB,0xE7,0xF7,0xFB,0x7D,0x7E; 72.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 80.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 88.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 96.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 104.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 112.. DB 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; 120..127 END