'*************************************************** ' 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 only ' 25.09.2010 ' 12.10.2010 - included in Pedal firmware ' 20.04.2011 - included in Fa firmware, hub ' 28.04.2011 - low priority IRQ added for timer3 ' 24.05.2011 - irq coding for timer 0 improved for roll-over glitches ' 28.08.2012 - included in the firmware ' 04.09.2012 - low irq code changed to use only the bits used for valves. ' 09.06.2013 - included in coding for Asa valves. ' 10.01.2014 - included, without the Asa specific coding, for Rodo-beaters. ' 15.04.2014 - included, without changes for Snar2-beaters. 'Device = 18F4620 #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 ' alias Dim FSR0SaveIntH As PP0H ' alias 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 On_Low_Interrupt GoTo Low_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 the buffer is smaller, but still a power of 2, we can 'implement circularity simply as: 'IndexIn = IndexIn & ~USART_Buffersize 'or, if it's faster, mask the highest limit bit: 'Clear IndexIn.7 = for a 128 byte buffer 'Clear IndexIn.6 = for a 64 byte buffer '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 'Toggle PORTB.5 'debug - checked. This works. 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 ' would it be slower to do Inc Cnt.Word1 here? btg PORTB.5 ' asm bit toggle ' checked. This works perfectly - period ca. 1s Clear Cnt.Byte1 Cnt.Byte0 = TMR0L retfie fast EndIf EndIf 'apparently the compiler needs this extra endif for the irq. retfie fast High_Int_Sub_End @HRSIn: ; assembly FUNCTION redefinition If IndexIn <> IndexOut Then Inc IndexOut ' Increment IndexOut pointer (0 to 255) 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 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 '-------------------------------------------------------------------------------- ' 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 on Timer3 overflow Low_Int_Sub_Start Low_Prior_Interrupt: Timer3_ISR: Context Save ' Save the contents of WREG, STATUS, and BSR Clear PIR2bits_TMR3IF ' Clear the Timer3 interrupt flag. If Velflags0.1 = 1 Then 'Tim3 = VibratoPeriod ' here we reload with the time required for the vibrato ' note the define: Tim3 As TMR3L.Word Inc Cnt3Hw ' for a :4 postscaler If Cnt3Hw.1 = 1 Then ' :4 Cnt3Hw.0 would give :2 Clear Cnt3Hw 'BranchL VibratoValve, [i_end, iV1, iV2, iV3, iV4, iV5, iV6, iV7, iV8, iV9, iV10, iV11, iV12, iV13, iV14, iV15, iV16, iV17, iV18] EndIf GoTo i_end EndIf Clear Cnt3Hw i_end: 'Toggle PortD.0 Context Restore ' Restore the contents of WREG, STATUS, and BSR, then exit interrupt Low_Int_Sub_End '------------------------------------------------------- '-------------------------------------------------------------------------------- ' 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) ' jump back if not ready movwf TXREG ' Send the byte Return ' Exit the subroutine _Over_IRQ_Handler: