@Hrsinto#Req = 1 ; assembly @HrsOut#Req = 1 ; replacing the HRSOut FUNCTION WITH the one here ' Interrupt-driven serial buffer for USART1 MIDI receive using a hardware high priority interrupt. ' This subroutine replaces the compiler's Hserin/Hrsin and HrsOut commands library subroutines ' For use with 18F devices ' #Disable HRSIn, HRSINTO, HRSIN_RCREG_READ, HRSOut ' Disable the compiler's library subroutines for Hrsin ' statements starting with # are ASM compiler directives ' Create the SYSTEM variables and aliases for the Buffered commands Dim PP0 As Byte System ' \ Dim PP0H As Byte System ' / Storage for FSR0L\H registers Dim FSR0SaveInt As PP0 Dim FSR0SaveIntH As PP0H Dim USART_FSR0_Save As FSR0SaveInt.Word ' Alias the FSR0L\H storage to PP0\H Dim USART_FSR1_Save As Word System ' Storage for FSR1L\H registers Dim USART_IndexIn As Byte System ' Pointer to the next empty location in the buffer Dim USART_IndexOut As Byte System ' Pointer to the location of the oldest character in the buffer Dim Cnt As Dword System ' our 32bit counter Dim gw As Word System ' Create the actual serial buffer in high memory ' Warnings = OFF ' Reminders = OFF Reserve_RAM 40 ' Reserve some RAM at the top of memory as a serial buffer (MAX 255) ' 40 could be enough Symbol USART_BufferSize = __Reserve_Ram_Size ' The amount of RAM reserved is the buffer size (MAX 255) Dim USART_RingBuffer[USART_BufferSize] As Byte At __Start_Of_Reserve_Ram ' Array for holding received characters ' Reminders = On ' Warnings = On Dim USART_FSR0 As FSR0L.Word ' alias Dim USART_FSR1 As FSR1L.Word ' alias ' ' Point the Low Priority interrupt handler to the Timer0 IRQ subroutine ' On_Low_Interrupt GoTo Low_Prior_Interrupt ' for timer 0 , Low Interrupt sub ' not required here ' Point to the high priority hardware interrupt handler On_Hardware_Interrupt GoTo High_Prior_Interrupt GoTo _Over_IRQ_Handler ' Jump over the subroutines '---------------------------------------------------------------- ' USART1 ring buffer interrupt handler for MIDI and 32-bit timer0 ' Input : Interrupt is triggered on reception of a byte from the USART and on timer0 overflow ' Output : Array USART_RingBuffer holds the bytes received ' : Byte USART_IndexIn points to the current location within the buffer ' Notes : Does not indicate if an error occurs but does clear the error flags and carries on ' High_Int_Sub_Start High_Prior_Interrupt: If PIR1bits_RCIF = 1 Then ' Was it a USART1 byte Receive that triggered the interrupt ? movlw 6 ' Yes. So Mask out unwanted bits andwf RCSTA,w ' Check for errors bnz _Uart_Error ' Was either error status bit set? USART_FSR1_Save = USART_FSR1 ' Save FSR1L\H registers Inc USART_IndexIn ' Move up the buffer If USART_IndexIn >= USART_BufferSize Then ' End of buffer reached ? Clear USART_IndexIn ' Yes. So clear _USART_IndexIn EndIf USART_FSR1 = VarPtr USART_RingBuffer ' Point FSR1L\H to _USART_RingBuffer USART_FSR1 = USART_FSR1 + USART_IndexIn ' Add the buffer position to FSR1L\H INDF1 = RCREG ' Place the received character into the buffer USART_FSR1 = USART_FSR1_Save ' Restore FSR1L\H registers retfie Fast ' Exit from the interrupt, restoring the WREG, STATUS, and BSR registers _Uart_Error: WREG = RCREG ' empty the 2 byte UART buffer WREG = RCREG Clear RCSTAbits_CREN ' Clear receiver status Set RCSTAbits_CREN retfie Fast 'EndIf Else _Timer0_IRQ: If INTCONbits_T0IF = 1 Then Clear INTCONbits_T0IF ' Clear the Timer0 Overflow flag ' Clear Cnt.LowWord, not required, may jitter ' even more if we do this If Velflags > 0 Then Inc Cnt.Word1 'Else Clear Cnt.HighWord ' gives compile error??? If Velflags = 0 Then Clear Cnt.Word1 ' Clear TMR0H ' Clear TMR0L EndIf EndIf 'apparently the compiler needs this extra endif for the irq. retfie Fast High_Int_Sub_End '------------------------------------------------------------------------------ ' Wait for a character from the interrupt driven circular buffer with minimum timeout ' if no new byte is available, the function will return 255. ' This is the function we call to read a midi byte from the buffer ' Input : GEN\GENH hold the timeout value in approx ms (0 to 65535) ' to speed up, and for no timeout, we clear this completely. ' Output : PP0 and WREG hold the value received ' : CARRY Flag (STATUS.0) Clear if timeout out ' Notes : Uses PRODL\H as temporary variable storage ' : Uses FSR0L\H as buffer the pointer ' #ifdef Hrsinto#Req ' this is defined in the header. @HRSIn: ; assembly FUNCTION redefinition @Read#Buffer_Req = 1 ; ENABLE the _USART_GET_CHAR subroutine by ' Bra $ + 2 ' Delay for 2 cycles within the outside loop. Why??? ' movf USART_IndexIn,w ' \ ' subwf USART_IndexOut,w ' / Is there anything in the serial buffer ? ' bnz _Usart_Get_Char ' Yes. So fetch it , and jump out of these loops 'bnz = branch if not zero _M_Loop: 'this loop is essential for the function to work! gw = USART_IndexIn - USART_IndexOut If gw <> 0 Then Inc USART_IndexOut ' Increment USART_IndexOut pointer (0 to 100) If USART_IndexOut >= USART_BufferSize Then ' End of buffer reached ? Clear USART_IndexOut ' Yes. So clear _USART_IndexOut. EndIf USART_FSR0_Save = USART_FSR0 ' Save FSR0L\H registers USART_FSR0 = VarPtr USART_RingBuffer ' Point FSR0L\H to USART_RingBuffer USART_FSR0 = USART_FSR0 + USART_IndexOut ' Add the buffer position to FSR0L\H WREG = INDF0 ' Read buffer location (USART_IndexOut) into WREG PP0 = WREG ' Also place it into PP0 USART_FSR0 = USART_FSR0_Save ' Restore FSR0\H registers Set STATUSbits_C ' Set the CARRY flag to indicate a byte received ret Else WREG = 255 ' \ btfss STATUS,C ret ' Return with the CARRY flag clear to indicate timed out EndIf Bra _M_Loop #endif '-------------------------------------------------------------------------------- ' Initialise the USART1 interrupt ' Input : None ' Output : None ' Notes : Enables interrupt on USART1 receive. ' : Enables global and peripheral interrupts ' : If Prioritised interrupts are used, the USART interrupt priority is made high $define InitUSARTInterrupt () Init_Usart_Interrupt 'added 31.08.2010 gwr Init_Usart_Interrupt Macro GoSub _Init_Usart Endm #ifdef Init_Usart_Interrupt#Req _Init_Usart: Clear USART_IndexIn ' Clear the buffer internal pointer Clear USART_IndexOut ' Clear the buffer external pointer Set PIE1bits_RCIE ' Enable interrupt on USART1 receive ' #ifdef __Low_Interrupts_Enabled ' Are we using low priority interrupts as well ? Set IPR1bits_RCIP ' Yes. So USART1 Receive Interrupt to High priority ' #endif Set INTCONbits_GIE ' enable general interrups Set INTCONbits_PEIE ' Enable global and peripheral interrupts ' Set INTCONbits_T0IE ' Enable Timer0 overflow interrupt, done on opentimer0() Return #endif '-------------------------------------------------------------------------------- ' Clear the Serial Buffer ' ' Input : None ' Output : None ' Notes : Also resets the index pointers to the serial buffer $define ClearSerialBuffer () Clear_Serial_Buffer ' added 31.08.2010 - gwr Clear_Serial_Buffer Macro GoSub _Clear_Usart_Buffer Endm #ifdef Clear_Serial_Buffer#Req _Clear_Usart_Buffer: PIE1bits_RCIE = 0 ' Disable interrupt on USART1 receive Clear USART_RingBuffer ' Clear the serial buffer Clear USART_IndexIn ' Clear the buffer internal pointer Clear USART_IndexOut ' Clear the buffer external pointer Set PIE1bits_RCIE ' Re-Enable interrupt on USART1 receive Return #endif ' ----------------------------------------------------------------------------- ' Low priority timer-overflow interrupt code ' we do not use this one anymore though. Low_Int_Sub_Start ' Indicate to context save the System Variables for a Low Priority interrupt Low_Prior_Interrupt: ' Save the compiler's system variables used in the interrupt routine only ' Also save some important SFR's. i.e. WREG, STATUS, BSR, PRODL\H, FSR0L\H, ' FSR1L\H, FSR2L\H, TBLPTRL\H, TABLAT Context Save If INTCONbits_T0IF = 1 Then ' Was it a Timer0 overflow that triggered the interrupt? ' Clear Cnt.LowWord '25.08 ' Inc Cnt.HighWord ' 'Clear TMR0H ' 'Clear TMR0L ' 'for debug: ' If Cnt.HighWord // 3 = 1 Then 'this is o.k., we do get here ' Low RA5 'of course if the counter is reset fast ' Else 'dHighCounter never increments ' High RA5 ' EndIf ' Toggle RA5 ' check whether we ever get here... Clear INTCONbits_T0IF ' Clear Timer0 overflow flag - added gwr 24.08 EndIf ' Restore the compiler's system variables used in the interrupt routine only, and exit the interrupt with "Retfie" ' Also restore the important SFR's. i.e. WREG, STATUS, BSR, PRODL\H, ' FSR0L\H, FSR1L\H, FSR2L\H, TBLPTRL\H, TABLAT Context Restore Low_Int_Sub_End ' Indicate Low Priority Interrupt block has ended '-------------------------------------------------------------------------------- ' Replace the library HRSOUT with this routine for MIDI-Output ' Sets the RS485 Tranceiver's pin High before transmitting #ifdef HRSOUT#REQ 'defined in header Asm- HRSOut EndAsm ' Clrwdt ' Keep Watchdog clear, if this is enabled btfss PIR1bits_TXIF ' Wait till transmitter ready Bra ($ - 2) movwf TXREG ' Send the byte Return ' Exit the subroutine #endif _Over_IRQ_Handler: