1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

MIDI Handler for PIC18F

Discussion in 'Code Repository' started by Jon Wilder, Oct 16, 2015.

  1. Jon Wilder

    Jon Wilder Active Member

    Joined:
    Oct 22, 2010
    Messages:
    852
    Likes:
    80
    Location:
    Fresno, CA
    Here is a simple MIDI message handler for PIC18 written in assembly. It's a receive routine that is meant to be "included" as a module within an interrupt handler. Currently it will receive both Program Change and Control Change messages. It does not support real time or running status type messages.

    After the last byte of each message is received, the UART is disabled and a software flag known as "MSGRDY" is set. This flag should be read in main in order for main to know when to process the received message.

    Here is the source file -

    Code (text):

    ;================================================================================
    ; Build Date: October 9th, 2015
    ;   MIDI Message Receive Handler for PIC18 PICmicro Devices  
    ;   By Jon Wilder
    ;
    ;   (c) 2015 Jon Wilder
    ;================================================================================

           
    ;================================================================================
    ; GNU General Public License v3
    ;
    ; MIDI Message Receive Handler for PIC18 PICmicro Devices
    ;
    ; Copyright (c) 2015 Jon Wilder
    ;    
    ; This program is free software: you can redistribute it and/or modify
    ; it under the terms of the GNU General Public License as published by
    ; the Free Software Foundation, either version 3 of the License, or
    ; (at your option) any later version.
    ;    
    ; This program is distributed in the hope that it will be useful,
    ; but WITHOUT ANY WARRANTY; without even the implied warranty of
    ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    ; GNU General Public License for more details.
    ;
    ; You should have received a copy of the GNU General Public License
    ; along with this program. If not, see <http://www.gnu.org/licenses/>.
    ;================================================================================
                   

    ;================================================================================
    ; Important Instructions
    ;
    ; In order to use this source file, you must include the associated header file
    ; in the beginning of your main source file as it contains very important label
    ; definitions used by both midiuart.asm as well as your main source file.
    ;
    ; You must also create a main.inc file and place it in your main project directory.
    ; In this file you can define all of your own custom register name labels as well
    ; as redefine certain constants which override default constants supplied with this
    ; source code.
    ;
    ; You should use the following directory tree -
    ;
    ;                               MPLABXProjects
    ;                                   /PIC18
    ;                                   /ASM
    ;       /include                    /projects                       /sources
    ;     <.inc files>             <project directories>              <.asm files>
    ;      
    ; As an example, assuming the aforementioned directory tree is used, if we were to
    ; use the PIC18F46K22, we would include it in the following manner -
    ;    
    ;       list            p=18F46K22, r=dec
    ;       include         <p18f46k22.inc>     ;.inc file supplied by MPLAB
    ;       include         main.inc            ;create this file and place it in your
                                                ;main project directory
    ;       include         ../../include/midiuart.inc
    ;
    ;    
    ; You can then include the source file right before the "end" directive in your
    ; main .asm soure file in the following manner -
    ;      
    ;       include         "../../sources/midiuart.asm"
    ;      
    ; Failure to include midiuart.inc in your main source file as shown above will
    ; result in "Symbol not defined" assembler errors.
    ;================================================================================
           
    ;<label:>
    ;   <inst>      <operand>                   <comments>
           
    ;================================================================================
    ; UART Initialization for MIDI Operation
    ;================================================================================
           
    ; This software function will initialize the on chip UART for MIDI operation.
    ; Pin assignable variables are defined by default to the following -
    ;
    ; _MIDI_TxD_ANSEL - ANSELC,ANSC6
    ; _MIDI_RxD_ANSEL - ANSELC,ANSC7
    ; _MIDI_TxD_TRIS - TRISC,RC6
    ; _MIDI_RxD_TRIS - TRISC,RC7
    ;
    ; For most 28 pin and 40 pin devices, these settings will suffice. However, if your
    ; PIC's TxD & RxD pins either reside on different pins OR you wish to use UART2 for
    ; the MIDI handling (for PIC's so equipped with a second UART), you must redefine
    ; these variables in your main.inc file.
    ;
    ; There is no reason to modify midiuart.inc to accomplish this. You can override the
    ; settings by simply defining the aforementioned variables to different ANSEL and
    ; TRIS pin assignments within your main.inc file.
       
    uartInit:
        clrf        MIDIFLAGS,BANKED            ;clear all MIDI receive flags
        clrf        MIDI_TEMP,BANKED            ;clear MIDI temp register
        clrf        DATA1_RX,BANKED             ;clear data1 register
        clrf        DATA2_RX,BANKED             ;clear data2 register
        movlw       _UART_BRG                   ;set baud rate
        movwf       SPBRG,ACCESS
        movlw       b'00100100'                 ;async serial, high speed baud clock, TxD enable
        movwf       TXSTA,ACCESS
        movlw       b'10010000'                 ;serial port enable, continuous receive enable
        movwf       RCSTA,ACCESS
        movlb       0xF                         ;bank 15
        bcf         _MIDI_TxD_ANSEL,BANKED      ;RC6 digital I/O mode
        bcf         _MIDI_RxD_ANSEL,BANKED      ;RC7 digital I/O mode
        movlb       0x0                         ;bank 0
        bsf         _MIDI_TxD_TRIS,ACCESS       ;hand control of RC6 to TxD
        bsf         _MIDI_RxD_TRIS,ACCESS       ;hand control of RC7 to RxD
        bsf         PIE1,RCIE,ACCESS            ;enable UART receive interrupts
        return
           
    ;================================================================================
    ; Begin MIDI UART Receive
    ;================================================================================
           
    ; First, we read the UART receive buffer into a temp register to clear the UART
    ; receive interrupt flag. We then check to see if a valid MIDI status byte was
    ; received on a previous pass. If a valid status byte has already been received
    ; (indicated by the state of the MIDISTAT bit in the MIDIFLAGS register), we then
    ; jump down to data1Rx to receive the first MIDI data byte. If not, then we continue
    ; on to receive and decode the MIDI status byte.
     
    uartRx:
        movlb       _MIDI_BANK                  ;select MIDI bank in GPR
        movff       RCREG,MIDI_TEMP             ;yes, read UART receive buffer
        btfsc       MIDIFLAGS,MIDISTAT,BANKED   ;has status byte been received yet?
        goto        data1Rx                     ;yes, receive data byte 1
       
    ; Since we're here, this indicates that a valid status byte has not been received
    ; yet. So now we'll check bit 7 of the received byte to see if it's high, indicating
    ; that the byte is a status byte. If it is not high, then we will ignore the byte
    ; and exit the MIDI handler.
       
        btfss       MIDI_TEMP,STATBIT,BANKED    ;MIDI status byte?
        goto        uartRx_Exit                 ;no, exit

    ; So the previous bit test revealed that our received byte is a MIDI status byte.
    ; Now we will compare the byte to the device's assigned MIDI channel and supported
    ; MIDI message types, starting with program change messages.
       
    midiPCRx:
        movf        MIDI_CHAN,W,BANKED          ;fetch MIDI channel assignment
        addlw       0xC0                        ;add 0xC0 to MIDI channel
        xorwf       MIDI_TEMP,W,BANKED          ;XOR received byte with this value
        btfss       STATUS,Z,ACCESS             ;is it a program change message?
        goto        midiCCRx                    ;no, check for CC message type
        bcf         MIDIFLAGS,CC,BANKED         ;yes, clear CC message type flag
        goto        statFlagSet
       
    ; If we made it here, this reveals that either the message type or the MIDI channel
    ; of our status byte did not match up. Now we will check our status byte against
    ; the device's MIDI channel and see if it is a control change message. If either
    ; of these two do not match, we will ignore the byte and exit the MIDI handler.
    ; If, however, it is determined that the status byte is a valid control change
    ; message, we will set the CC flag in the MIDIFLAGS register, then continue on to the
    ; statFlagSet function, where we will also set the MIDISTAT flag in the MIDIFLAGS
    ; register, then exit.

    midiCCRx:    
        movf        MIDI_CHAN,W,BANKED          ;fetch MIDI channel assignment
        addlw       0xB0                        ;add 0xB0 to MIDI channel
        xorwf       MIDI_TEMP,W,BANKED          ;XOR received byte with this value
        btfss       STATUS,Z,ACCESS             ;is it a control change message?
        goto        uartRx_Exit                 ;no, exit
        bsf         MIDIFLAGS,CC,BANKED         ;yes, set CC message type flag

    ; Upon determining that our received MIDI status byte is a valid status byte, we
    ; will now set the MIDISTAT flag in the MIDIFLAGS register. As long as this bit
    ; is set, the code will jump to data1Rx to receive the first data byte upon entering
    ; the MIDI receive handler and reading the received byte from the receive buffer.
    ;
    ;
    ; Once we set this bit, we exit the handler and go back to the main function until
    ; the next byte is received.
       
    statFlagSet:
        bsf         MIDIFLAGS,MIDISTAT          ;yes, set status byte received flag
        goto        uartRx_Exit
       
    ; Upon entering the MIDI handler, the code will jump here after reading the UART
    ; receive buffer, then determining if the MIDISTAT flag in the MIDIFLAGS register
    ; is set. We will also check the D1RCV flag in MIDIFLAGS and determine if it is
    ; set, indicating that we've already received the 1st data byte. If it is high,
    ; we will jump to data2Rx and receive the 2nd data byte (control change messages
    ; only), else we will continue with normal code flow.
       
    data1Rx:
        btfsc       MIDIFLAGS,D1RCV,BANKED      ;has 1st data byte been received?
        goto        data2Rx                     ;yes, receive data byte 2
       
    ; Data byte 1 has not yet been received. So we will copy our received byte from
    ; MIDI_TEMP to DATA1, where it can be accessed in the main function.
       
        movff       MIDI_TEMP,DATA1_RX          ;no, store data byte 1
       
    ; Here we check to see if the CC flag in MIDIFLAGS is set, telling us that we are
    ; receiving a control change message. If it is not set, then we will proceed to
    ; messageComplete. However, if it is set, then we will set the D1RCV flag in
    ; MIDIFLAGS to indicate that we've received the first data byte in the control
    ; change message.
       
        btfss       MIDIFLAGS,CC                ;are we receiving a CC message?
        goto        messageComplete             ;no, jump to message complete routine
        bsf         MIDIFLAGS,D1RCV             ;yes,set data 1 received flag
        goto        uartRx_Exit                 ;exit
       
    ; If we are receiving a control change message and the first data byte has already
    ; been received, we will now write the second data byte from MIDI_TEMP to DATA2,
    ; where it can be accessed in the main function.
       
    data2Rx:
        movff       MIDI_TEMP,DATA2_RX          ;receive data byte 2
       
    ; We have now completed receiving our MIDI message. Here we will clear all of the
    ; flags in MIDIFLAGS, but set the MSGRDY flag, which will notify the main function
    ; that it has a MIDI message waiting to be processed.
       
    ; We will also disable the UART here. This prevents any further MIDI messages from
    ; being received until the UART is enabled in main. This allows the main function
    ; to process the received message without further incoming MIDI messages interfering
    ; with the process.
       
    ; Once main has completed processing the received MIDI message, the message is
    ; discarded and main will then re-enable the UART and listen for further MIDI
    ; messages.
       
    messageComplete:    
        bcf         MIDIFLAGS,MIDISTAT,BANKED   ;clear MIDISTAT flag
        bcf         MIDIFLAGS,D1RCV,BANKED      ;clear D1RCV flag
        bsf         MIDIFLAGS,MSGRDY,BANKED     ;set MSGRDY flag
        bcf         RCSTA,CREN                  ;disable UART receiver
     
    uartRx_Exit:
        return
     
    And here is the associated include file to add to the very top of your main file -

    Code (text):
       
    ;================================================================================
    ; Build Date: October 9th, 2015
    ;   MIDI Message Receive Handler for PIC18 PICmicro Devices
    ;   Header File
    ;   By Jon Wilder
    ;
    ;   (c) 2015 Jon Wilder
    ;================================================================================

           
    ;================================================================================
    ; GNU General Public License v3
    ;
    ; MIDI Message Receive Handler for PIC18 PICmicro Devices
    ;
    ; Copyright (c) 2015 Jon Wilder
    ;    
    ; This program is free software: you can redistribute it and/or modify
    ; it under the terms of the GNU General Public License as published by
    ; the Free Software Foundation, either version 3 of the License, or
    ; (at your option) any later version.
    ;    
    ; This program is distributed in the hope that it will be useful,
    ; but WITHOUT ANY WARRANTY; without even the implied warranty of
    ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    ; GNU General Public License for more details.
    ;
    ; You should have received a copy of the GNU General Public License
    ; along with this program. If not, see <http://www.gnu.org/licenses/>.
    ;================================================================================
       
       
    ;================================================================================
    ; Important Instructions
    ;
    ; This header file is required by midiuart.asm. It must be included in your main
    ; source file. See midiuart.asm for further instructions.
    ;================================================================================
       
       
    ;------MIDI Handler Registers----------------------------------------------------
       
    MIDIFLAGS   EQU         0x10        ;MIDI software flags register
    MIDI_TEMP   EQU         0x11        ;MIDI temp buffer register
    DATA1_RX    EQU         0x12        ;MIDI data byte 1 buffer register
    DATA2_RX    EQU         0x13        ;MIDI data byte 2 buffer register
    MIDI_CHAN   EQU         0x14        ;MIDI channel assignment register

    ;------MIDI Handler Flag Bits----------------------------------------------------

    MSGRDY      EQU         0x0000      ;MIDI message ready flag
    MIDISTAT    EQU         0x0001      ;MIDI status byte received flag
    CC      EQU         0x0002      ;MIDI control change message flag
    D1RCV       EQU         0x0003      ;MIDI data byte 1 received flag
    STATBIT     EQU         0x0007      ;MIDI status byte flag

    ;------Hard Defined Constants----------------------------------------------------
       
    #define     _UART_BAUD      31250       ;default UART baud = 31.25kbps for MIDI
    #define     _UART_BRG       ((_XTAL_FREQ / _UART_BAUD) / 16) - 1   
       
    ;------Redefinable Defined Constants---------------------------------------------
    ;
    ; The values of the following defined constants can be overridden in your main.inc
    ; file by simply defining them with a #define statement in your main.inc file. As
    ; shown, these are the default settings for these constants.
       
    #ifndef     _XTAL_FREQ
    #define     _XTAL_FREQ      4000000     ;default Fosc = 4MHz
    #endif
       
    #ifndef     _MIDI_BANK
    #define     _MIDI_BANK      0x1         ;default GPR bank for MIDI = bank 1
    #endif
       
    #ifndef     _MIDI_TxD_TRIS
    #define     _MIDI_TxD_TRIS      TRISC,RC6       ;default TxD pin = RC6
    #endif 
       
    #ifndef         _MIDI_RxD_TRIS
    #define     _MIDI_RxD_TRIS      TRISC,RC7       ;default RxD pin = RC7
    #endif

    #ifndef     _MIDI_TxD_ANSEL
    #define     _MIDI_TxD_ANSEL     ANSELC,ANSC6    ;default TxD ANSEL bit = ANSC6
    #endif
       
    #ifndef     _MIDI_RxD_ANSEL
    #define     _MIDI_RxD_ANSEL     ANSELC,ANSC7    ;default RxD ANSEL bit = ANSC7
    #endif
       
     
     

Share This Page