Continue to Site

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.

  • 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.

MIDI Handler for PIC18F

Status
Not open for further replies.

Jon Wilder

Active Member
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:
;================================================================================
; 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:
;================================================================================
; 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
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top