'*************************************************** ' IRQ coding for midi-in * ' and timer interrupts * ' 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 ' 16.01.2012 - taken over from Fa-code. This is now specific for Synchrochord. ' 04.08.2014 - copied from Zi coding. Different mapping of watchdog LED. ' 03.12.2016 - adapted to work with the 10-output pulse-hold board for ' 26.01.2017 - included in code for melauton solenoids '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 MidiIn As Byte System 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 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: 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.3 ' 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 ' werkt niet meer onder de nieuwste compiler versie: '@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 'nieuwe kode: Sub GetMidiIn () 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 MidiIn = 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 MidiIn = WREG ' \ Btfss STATUS,C ' Return with the CARRY flag clear to indicate timed out Ret 'compulsary here EndIf 'Ret EndSub '-------------------------------------------------------------------------------- ' 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 ' not used in 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 ' ' Branch Solenoid, [i_end,iV1, iV2, iV3, iV4, iV5, iV6, iV7, iV8, iV9, iV10, iV11, iV12] ' EndIf ' ' GoTo i_end ' EndIf ' Clear Cnt3Hw Context Restore ' Restore the contents of WREG, STATUS, and BSR, then exit interrupt '-------------------------------------------------------------------------------- ' Replace the library HRSOUT with this routine for MIDI-Output ' Sets the RS485 Tranceiver's pin High before transmitting ' 18.12.2018: this does not work anymore in the compiler version 3.6.2.7 ' so now, we use the standard HRSOut function. 'Asm- 'HRSOut 'EndAsm ' Btfss PIR1bits_TXIF ' Wait till transmitter ready ' Bra ($ - 2) ' Movwf TXREG ' Send the byte 'Return ' Exit the subroutine 'Small_Micro_Model = OFF ' refused by compiler _Over_IRQ_Handler: