'*************************************************** ' IRQ coding for midi-in * ' by * ' Godfried-Willem Raes * ' Version 2.3 * '*************************************************** ' Interrupt-driven serial buffer for USART 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 ' 25.09.2010 'Device = 18F2525 #Disable HRSIn, 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_FSR0 As FSR0L.Word ' alias Dim USART_FSR1 As FSR1L.Word ' alias Dim IndexIn As Byte System ' Pointer to the next empty location in the buffer Dim IndexOut As Byte System ' Pointer to the location of the oldest character in the buffer ' Create the actual serial buffer in high memory ' Warnings = OFF ' Reminders = OFF Reserve_RAM 256 ' 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 Ringbuffer[USART_BufferSize+1] As Byte At __Start_Of_Reserve_Ram ' Array for holding received characters '25.09.2010: by setting it to 256 'we get an automatic overflow to 0 Hence: 'Symbol USART_BufferSize = 255 ' The amount of RAM reserved is the buffer size (MAX 255) Dim Ringbuffer[256] As Byte At __Start_Of_Reserve_Ram ' Array for holding received characters ' Reminders = On ' Warnings = On ' Point to the high priority hardware interrupt handler On_Hardware_Interrupt GoTo High_Prior_Interrupt GoTo _Over_IRQ_Handler ' Jump over the subroutines '---------------------------------------------------------------- ' USART 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 Ringbuffer holds the bytes received ' : Byte 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 IndexIn ' Move up the buffer index (0-255) 'If IndexIn >= USART_BufferSize Then ' End of buffer reached ? ' Clear IndexIn ' Yes. So clear _USART_IndexIn 'EndIf USART_FSR1 = VarPtr Ringbuffer ' Point FSR1L\H to _USART_RingBuffer USART_FSR1 = USART_FSR1 + 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 Else _Timer0_IRQ: If INTCONbits_T0IF = 1 Then Clear INTCONbits_T0IF ' Clear the Timer0 Overflow flag Inc CntHw Cnt.Word0 = Cntl btg DebugLed 'debug LED - checked. This works perfectly - period ca. 1s btg Note8 retfie fast EndIf EndIf 'apparently the compiler needs this extra endif for the irq. retfie fast High_Int_Sub_End @HRSIn: ; assembly FUNCTION redefinition ' ' Bra $ + 2 ' Delay for 2 cycles within the outside loop. Why??? If IndexIn <> IndexOut Then Inc IndexOut ' Increment IndexOut pointer (0 to 255) ' If IndexOut >= USART_BufferSize Then ' End of buffer reached ? ' Clear IndexOut ' Yes. So clear _USART_IndexOut. ' EndIf USART_FSR0_Save = USART_FSR0 ' Save FSR0L\H registers USART_FSR0 = VarPtr Ringbuffer ' Point FSR0L\H to Ringbuffer USART_FSR0 = USART_FSR0 + IndexOut ' Add the buffer position to FSR0L\H WREG = INDF0 ' Read buffer location (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 ' compulsary here! Else WREG = 255 PP0 = WREG ' \ btfss STATUS,C ' Return with the CARRY flag clear to indicate timed out ret 'compulsary here EndIf ret 'compulsary here 'GetMidiIn: 'attempt to recode this in Basic... NOT WORKING!!! ' Set ByteIn ' If IndexIn <> IndexOut Then ' Inc IndexOut ' Increment IndexOut pointer (0 to 100) ' USART_FSR0_Save = USART_FSR0 ' Save FSR0L\H registers ' USART_FSR0 = VarPtr Ringbuffer ' Point FSR0L\H to Ringbuffer ' USART_FSR0 = USART_FSR0 + IndexOut ' Add the buffer position to FSR0L\H ' ByteIn = INDF0 ' WREG = INDF0 ' Read buffer location (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 ' Return ByteIn ' Else ' WREG = 255 ' PP0 = WREG ' btfss STATUS,C ' Return with the CARRY flag clear to indicate timed out ' Return ByteIn ' EndIf 'Return ByteIn 'GetMidi: ' Set ByteIn 'makes it 255 ' If IndexOut + 1 = IndexIn Then Return ' 'If IndexIn <> IndexOut Then ' Inc IndexOut ' Increment IndexOut pointer (0 to 255) ' ByteIn = Ringbuffer[IndexOut] ' 'EndIf 'Return '-------------------------------------------------------------------------------- ' 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 IndexIn ' Clear the buffer internal pointer Clear 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 Ringbuffer ' Clear the serial buffer Clear IndexIn ' Clear the buffer internal pointer Clear 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 Asm- HRSOut EndAsm btfss PIR1bits_TXIF ' Wait till transmitter ready bra ($ - 2) movwf TXREG ' Send the byte Return ' Exit the subroutine _Over_IRQ_Handler: