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.

Further Advancements On My MIDI Project

Status
Not open for further replies.

Jon Wilder

Active Member
So I've been making further progress in writing MIDI source code for the PIC16F628.

What I'm building is a MIDI controlled relay controller for channel switching a guitar amplifier. The goal here was to make it so that it can "learn" the assigned MIDI channel via placing it in learn mode, then sending either a Program Change or Control Change message from the foot controller, and whatever MIDI channel the message was sent on is the channel it assigns itself to. It then writes this channel assignment to data EEPROM and does not change until the user makes it relearn a different MIDI channel.

Furthermore, it will have 100 preset locations in which you can store up to 6 different channel/solo boost/fx loop enable/disable configurations in. I figure since the 16F628 only has 128 data EEPROM locations that this would leave me 100 preset locations with the other 28 for MIDI channel assignment as well as CC assignments.

Lastly the front panel buttons on the amp for channel select, solo select and FX loop select will be user mappable to a CC number as well.

All of this will be "learned" by the chip.

It will also come with pre-loaded "preset configurations". While the user will be able to remap the preset locations via "learning", it will also have a "restore factory defaults" function as well, which will remap the CC assignments, preset locations as well as default the MIDI channel to MIDI channel 1.

I just finished coding/debugging the Channel Learn routine and it works like a charm.

What I plan to do is have the preset configurations stored in data EEPROM, then at the start of the program it will load channel assignment, CC assignment and preset locations into RAM and work with them from there for faster access time and minimized preset recall latency.

Will keep you all posted. Once it's all done I might decide to make the source code and schematic open source.
 
Last edited:
Here is the source code I've written so far. Same as before...toggles green and red LEDs on/off when receiving CC on/off messages on Controller 80, but has the added function of being able to learn the assigned MIDI channel -

Code:
;*********************************************************************************************************
;*********************************************************************************************************
;**										                        **
;**												        **
;**			        	 Guitar Amp MIDI Decoder				        **
;**					 With 16F628 PIC Micro					        **
;**												        **
;**					         By						        **
;**					                  					        **
;**					     Jon Wilder						        **
;**												        **
;**												        **
;*********************************************************************************************************
;*********************************************************************************************************
;** 												        **
;**					   Processor Config					        **
;**												        **
;**												        **
;*********************************************************************************************************
;*********************************************************************************************************

		processor	16F628
		include		<P16F628.INC>
		
		__CONFIG 0x3D22	;disable cp, dcp, lvp, boden, wdt & enable mclre, pwrt, hs osc

;		external clock speed = 20MHz

;*********************************************************************************************************
;*********************************************************************************************************
;** 											                **
;**					   Port Initialization				  	        **
;**												        **
;**													**
;*********************************************************************************************************
;*********************************************************************************************************  
		
		org	0x00		;start at address 0
		clrf	PORTA		;initialize Port A register
		clrf	PORTB		;initialize Port B register
		bsf	STATUS,RP0	;switch to Bank 1
		bcf	STATUS,RP1	;switch to Bank 1
		movlw	B'00000001'
		movwf	TRISA		;set up RA0 as input for "learn" button, RA1-RA4 as outputs
		movlw	B'00000110'	;set up RB0, RB3-7 as outputs
		movwf	TRISB		;configure RB1 and RB2 as USART RX/TX
		bcf	STATUS,RP0	;switch to Bank 0
		bcf	STATUS,RP1	;switch to Bank 0
		movlw	0x07		;disable on board
		movwf	CMCON		;comparator

;*********************************************************************************************************
;*********************************************************************************************************
;** 											                **
;**					  USART Initialization				  	        **
;**												        **
;**													**
;*********************************************************************************************************
;*********************************************************************************************************                                       								
		bsf	STATUS,RP0	;switch to Bank 1
		bcf	STATUS,RP1	;switch to Bank 1
		movlw	0x09		;set Baud Rate Generator up for 
		movwf	SPBRG		;31,250 baud with 20MHz crystal
		bcf	TXSTA,SYNC	;enable asynchronous serial comm mode
		bcf	STATUS,RP0	;switch to Bank 0
		bcf	STATUS,RP1	;switch to Bank 0
		bsf	RCSTA,SPEN	;serial port enable
		bsf	RCSTA,CREN	;continuous receive enable

;*********************************************************************************************************
;*********************************************************************************************************
;** 											                **
;**					   RAM Locations				  	        **
;**												        **
;**													**
;*********************************************************************************************************
;*********************************************************************************************************

		cblock	0x20
			MIDI_PC_RAM
			MIDI_CC_RAM
			MIDI_PC
			MIDI_CC
			MIDI_TEMP
			EEPROM_ADDR
			EEPROM_DATA
			LOOP1
			LOOP2
			
		endc			

;*********************************************************************************************************
;*********************************************************************************************************
;** 											                **
;**					   Program Start        			  	        **
;**												        **
;**													**
;*********************************************************************************************************
;*********************************************************************************************************



Main		call	Init
		btfss	PORTA,0		;check if learn button is pressed
		call	Debounce	;if pressed, call Debounce subroutine
		btfss	PORTA,0		;check again after Debounce subroutine
		call	Learn_CH	;if button pressed, call Learn MIDI Channel subroutine
		call	Load_RAM	;if button not pressed, call Load RAM subroutine

Byte1		call	receivemidi	;call MIDI receive subroutine
		
Status_Detect	btfss	MIDI_TEMP,7	;check bit 7 in MIDI_TEMP set
		goto	Byte1		;if not set, clear data and wait for next byte
		goto	PC_Detect	;if bit 7 set, detect MIDI channel
	
PC_Detect	clrw			;clear W
		movf	MIDI_TEMP,W	;move new byte in MIDI_TEMP into W
		xorwf	MIDI_PC_RAM,W	;xor with byte in MIDI_PC_RAM
		btfss	STATUS,Z	;check zero flag
		goto	CC_Detect	;if zero flag not set, proceed to test for CC message
		goto	PC_Data		;if zero flag set, proceed to receive PC data value

CC_Detect	clrw			;clear W
		movf	MIDI_TEMP,W	;copy byte in MIDI_TEMP into W
		xorwf	MIDI_CC_RAM,W	;xor with byte in MIDI_CC_RAM
		btfss	STATUS,Z	;check zero flag
		goto	Byte1		;if zero flag not set, clear registers and wait for next byte
		goto	CC_Cont		;if zero flag set, proceed to detect CC number

CC_Cont		call 	receivemidi	;call MIDI receive subroutine

Cont_Detect	xorlw	0x50		;xor with 0x50 (Controller 80)
		btfss	STATUS,Z	;check zero flag
		goto	Byte1		;if zero flag not set, clear registers and wait for next byte
		goto	CC_Data		;if zero flag set, proceed to read CC data value

Byte3		call	receivemidi	;call MIDI receive subroutine

		btfss	MIDI_TEMP,6	;check bit 6 set in data value
		goto	Green_On	;if bit 6 not set, proceed to Green_On
		goto	Red_On		;if bit 6 set, proceed to Red_On

Green_On	bsf	PORTB,3		;turn Green LED on
		bcf	PORTB,0		;turn Red LED off
		goto	MIDI_Status	;go back and wait for next byte

Red_On		bsf	PORTB,0		;turn Red LED on
		bcf	PORTB,3		;turn Green LED off
		goto	MIDI_Status	;go back and wait for next byte

PC_Data		goto	MIDI_Status	;if PC message, go back and wait for next byte (to be continued)
				

	
;*********************************************************************************************************
;*********************************************************************************************************
;** 											                **
;**					   Subroutines          			  	        **
;**												        **
;**													**
;*********************************************************************************************************
;*********************************************************************************************************

;initialize all registers

Init		clrf	MIDI_PC_RAM	;initialize all registers
		clrf	MIDI_CC_RAM
		clrf	MIDI_PC
		clrf	MIDI_CC
		clrf	MIDI_TEMP
		clrf	EEPROM_ADDR
		clrf	EEPROM_DATA
		clrf	LOOP1
		clrf	LOOP2
		clrw
		return

;*********************************************************************************************************
;*********************************************************************************************************

;waste some time in nested delay loops to give switch contacts time to stabilize

Debounce	movlw	0xFF
		movwf	LOOP1
		movwf	LOOP2
Loop1		decfsz	LOOP1
		goto	Loop1
Loop2		decfsz	LOOP2
		goto	Loop1
		return

;*********************************************************************************************************
;*********************************************************************************************************

;load data in EEPROM into RAM

Load_RAM	bsf	STATUS,RP0	;switch to bank 1
		movlw	0x65		;address EEPROM location 0x65
		movwf	EEADR
		bsf	EECON1,RD	;read EEPROM, place data at location 0x65 in EEDATA
		movf	EEDATA,W	;move data in EEDATA to W
		bcf	STATUS,RP0	;switch to Bank 0
		movwf	MIDI_CC_RAM	;move contents of W into MIDI CC RAM

		bsf	STATUS,RP0	;switch to Bank 1
		movlw	0x66		;address EEPROM location 0x66
		movwf	EEADR		
		bsf	EECON1,RD	;read EEPROM, place data at location 0x66 in EEDATA
		movf	EEDATA,W	;move contents of EEDATA into W
		bcf	STATUS,RP0	;switch to Bank 0
		movwf	MIDI_PC_RAM	;move contents of W into MIDI PC RAM
		return

;*********************************************************************************************************
;*********************************************************************************************************	

;receive MIDI

receivemidi	clrw
		clrf	MIDI_TEMP
rcvmidi		btfss	PORTA,0		;check if learn button is pressed
		call	Debounce	;if pressed, call Debounce subroutine
		btfss	PORTA,0		;check again after Debounce subroutine
		call	Learn_PC	;if button still pressed, call MIDI PC Learn subroutine
		nop			;if button not pressed, proceed to receive MIDI byte
		btfss	PIR1,RCIF	;wait for receive flag to set
		goto	rcvmidi		;if not set, go back and wait for receive flag to set
		movf	RCREG,W		;if set, move received data into W	
		movwf	MIDI_TEMP	;copy received data into MIDI_TEMP
		return			;return

Learn_RCV	btfss	PIR1,RCIF	;wait for receive flag to set
		goto	Learn_RCV	;if not set, go back and wait for receive flag to set
		movf	RCREG,W		;if set, move received data into W	
		movwf	MIDI_TEMP	;copy received data into MIDI_TEMP
		return			;return
	
;*********************************************************************************************************
;*********************************************************************************************************

;MIDI channel learn subroutine

Learn_CH	bsf	PORTB,3		;turn on "Learn" LED
		call	Init		;call initialize all registers subroutine
		
MIDI_RCV	call	Learn_RCV	;call MIDI channel receive subroutine

;make sure it's a status byte

MIDI_CH_RCV	btfss	MIDI_TEMP,7	;check bit 7 in MIDI_TEMP set
		goto	MIDI_RCV	;if not set, clear data and wait for next byte
		goto	CHK_PC		;if bit 7 set, detect MIDI channel

;make sure it's either a PC or a CC message. If not...get rid of it and wait for next byte

CHK_PC		movf	MIDI_TEMP,W	;move original received byte into W
		andlw	0xF0		;mask low nibble
		xorlw	0xC0		;compare to value 0xC0 (Program Change)
		btfss	STATUS,Z	;check for zero
		goto	CHK_CC		;if not zero, proceed to check for Control Change message
		goto	STORE		;if zero, proceed to store MIDI channel

CHK_CC		movf	MIDI_TEMP,W	;move original received byte into W
		andlw	0xF0		;mask low nibble
		xorlw	0xB0		;compare to value 0xB0 (Control Change)
		btfss	STATUS,Z	;check for zero
		goto	Learn_CH	;if not zero, clear data and wait for next byte
		goto	STORE		;if zero, proceed to store MIDI channel
	
;add detected channel to 0xB0 and 0xC0 to set up status compare constants for use in normal program

STORE		clrw
		movf	MIDI_TEMP,W	;place original received byte in MIDI_TEMP in W
		andlw	0x0F		;mask high nibble
		movwf	MIDI_TEMP	;move result into MIDI_TEMP
		clrw
		movlw	0xB0		;write value 0xB0 in W
		addwf	MIDI_TEMP,W	;add byte in MIDI_TEMP to 0xB0 to set CC Detect Constant
		movwf	MIDI_CC_RAM	;move new CC constant into MIDI_CC_RAM
		clrw
		movlw	0xC0		;write value 0xC0 in W
		addwf	MIDI_TEMP,W	;add byte in MIDI_TEMP to 0xC0 to set PC Detect Constant
		movwf	MIDI_PC_RAM	;move new PC constant into MIDI_PC_RAM

;address data EEPROM

		clrw			;clear w
PROM_ADDR1	movlw	0x65		;write EEPROM address to W
		bsf	STATUS,RP0	;change to Bank 1
		movwf	EEADR		;move byte in W to EEPROM Address register
		bcf	STATUS,RP0	;change to Bank 0

;place data in data EEPROM buffer register

		clrw
PROM_DATA1	movf	MIDI_CC_RAM,W	;move contents of MIDI_CC_RAM into W
		bsf	STATUS,RP0	;change to Bank 1
		movwf	EEDATA		;move contents of W into EEPROM Data register
		bcf	STATUS,RP0	;change to Bank 0
		
;initiate write to EEPROM and verify write
	
		call	EEPROM_WRT	;call EEPROM Write subroutine
		movlw	0x65		;write EEPROM write verify address to W
		call	WRT_VRFY	;call EEPROM Write Verify subroutine
		
;address data EEPROM

		clrw			;clear w
PROM_ADDR2	movlw	0x66		;write EEPROM address to W
		bsf	STATUS,RP0	;change to Bank 1
		movwf	EEADR		;move byte in W to EEPROM Address register
		bcf	STATUS,RP0	;change to Bank 0

;place data in data EEPROM buffer register
		clrw
PROM_DATA2	movf	MIDI_PC_RAM,W	;move contents of MIDI_PC_RAM into W
		bsf	STATUS,RP0	;change to Bank 1
		movwf	EEDATA		;move contents of W into EEPROM Data register
		bcf	STATUS,RP0	;change to Bank 0

;initiate write to EEPROM and verify write
	
		call	EEPROM_WRT	;call EEPROM Write subroutine
		movlw	0x66		;write EEPROM write verify address to W
		call	WRT_VRFY	;call EEPROM Write Verify subroutine
		return			;return to main program
		
;*********************************************************************************************************
;*********************************************************************************************************

;EEPROM Write	

EEPROM_WRT	bsf	EECON1, WREN	;enable data EEPROM Write
		bcf	INTCON, GIE	;disable all interrupts
		movlw	0x55		;write 0x55 to W
		movwf	EECON2		;copy W into EEPROM Control register
		movlw	0xAA		;write 0xAA to W
		movwf	EECON2		;copy W into EEPROM Control register
		bsf	EECON1, WR	;write contents of EEDATA to Data EEPROM register address in EEADR
		bcf	STATUS,RP0	;change to Bank 0
		return

;*********************************************************************************************************
;*********************************************************************************************************

;EEPROM write verify

WRT_VRFY	bsf	STATUS,RP0	;change to Bank 1
		movwf	EEADR		;write EEPROM address in W to EEADR
		bsf	EECON1, RD	;read data at address in EEADR
		movf	EEDATA, W	;copy data at address in EEADR to W
		subwf	EEDATA, W	;subtract data in EEDATA with data in W
		bcf	STATUS,RP0	;change to Bank 0
		btfss	STATUS,Z	;test for zero
		call	WRT_ERR		;call Write Error subroutine
		call	WRT_OK		;call Write OK subroutine
		return			;return
		
;*********************************************************************************************************
;*********************************************************************************************************

;write error indicator

WRT_ERR		bsf	PORTB,0		;illuminate red led to indicate write error
		goto	PWR_DWN		;lock out processor

;*********************************************************************************************************
;*********************************************************************************************************

;write ok indication

WRT_OK		bcf	PORTB,3		;flash green LED to indicate successful write
		call	Loop1
		bsf	PORTB,3
		call	Loop1
		bcf	PORTB,3
		call	Loop1
		bsf	PORTB,3
		call	Loop1
		bcf	PORTB,3
		call	Loop1
		bsf	PORTB,3
		call	Loop1
		bcf	PORTB,3
		return

;*********************************************************************************************************
;*********************************************************************************************************		

;Error Lock Out

PWR_DWN		goto	PWR_DWN		;must power cycle to resume normal program

;*********************************************************************************************************
;*********************************************************************************************************		

Learn_PC	bsf	PORTB,3
		movf	PORTB,W
		movwf	MIDI_TEMP

RCV_PC		call	Learn_RCV
			
;*********************************************************************************************************
;*********************************************************************************************************				
	
		End
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top