'*************************************************** ' IRQ coding for midi-in * ' by * ' Godfried-Willem Raes * ' Version 2.5 * '*************************************************** ' 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 - first redaction ' 12.10.2010 - included in Pedal firmware ' 20.04.2011 - included in Fa firmware, hub ' 30.04.2011 - now user low prior. irq for sampling the sensor ' include renamed Midi_Hub_Irq.inc ' Timers include no longer required. ' 23.05.2011 - 32 bit timer coding improved ' 20.08.2013 - used for ' low interrupts will not happen here! ' 20.04.2015 - adapted to compiler upgrade. ' some minor changes. ' 06.06.2015 - trying to get it to work properly again... ' works fine on ' 27.08.2015 - included in code for ' 16.03.2016 - included in code for ' 25.04.2016 - included in de code for with Low interrupt for timer3. ' 20.06.2016 - found o.k. ' 24.06.2016 - Version for the Flex Hub. ' 29.08.2016 - Version for the HybrLo hub. ' 09.09.2016 - version for Bourdonola. #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 ' remmed out 15.04.2015, compiler compaint... ' 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 ' now declared in the main program to avoid memory corruption 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_Prior_Interrupt: ' Context Save ' added in after compiler upgrade 20.04.2015- not required for High IRQ _Timer0_IRQ: If INTCONbits_T0IF = 1 Then Clear INTCONbits_T0IF ' Clear the Timer0 Overflow flag ' Inc Cnt.Word1 ' would it be slower to do Inc Cnt.Word1 instead of CntHw here? ' CntLw = 5 ' to correct prescaler errors on writing to tmr0L 'Inc CntLw ' seems that without this, we are missing steps. Btg PORTC,0 ' asm bit toggle - debug led watchdog Retfie Fast EndIf _UART_IRQ: 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 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 EndIf Retfie Fast ' Context Restore @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 Interrupt on Timer3 overflow ' not used on the hub board Low_Prior_Interrupt: Timer3_ISR: Context Save ' Save the contents of WREG, STATUS, and BSR Clear PIR2bits_TMR3IF ' Clear the Timer3 interrupt flag. Tim3 = 0 'Period ' period wordt bepaald bij ontvangst van een note on ' Tim3 = 46036 ' gives 64 S/s rate, 19500 ticks, each 0.8uS, to FFFF. Period = 15.6ms ' Tim3 = 0 ' gives slowest possible period, 52.43ms or f= 19Hz ' Tim3 = 65506 ' gives 24us, or f= 41kHz ' TMR3L = 225 ' Btg Mot_Klok Context Restore ' Restore the contents of WREG, STATUS, and BSR, then exit interrupt ' Retfie ' required? 'Return '------------------------------------------------------- '-------------------------------------------------------------------------------- ' 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: