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.

16F628 Midi In problem

Status
Not open for further replies.

ivlenk

New Member
I built a little circuit that takes midi input from RX on a 16f628 usart and turns on some LEDS based on what notes are played.

I have two MIDI keyboards. When I connect my 1982 Roland which sends 6 midi bytes per keyboard note hit 90 xx xx b0 xx xx my PIC project device works perfectly.
I can play all 8 test notes at once and all 8 leds turn on and off super fast and correctly in time with when each note is hit and released.


When I connect it to my newer 1990's Roland keyboard which only sends 90 xx xx for a note the device seems to miss fast played notes. I can't hit 2 notes at a time...if I go slowly it works ok, but anything faster than half a second (only when playing different notes!?) and it acts all sticky and gummed up and misses notes.
I can hit the same not repeatedly and my test device turns that one LED on and off as fast as I can hit the key following the note on and note off messages, but if I try to play 2 at a time or more...only one note (led) registers. If I slowly roll over the 8 notes taking up to half a second per note, it works as expected.

Why is the USART so STICKY in this case? I moved it from direct code to a buffered interrupt (following many online examples) and it exhibits the exact same behavior.

I am using a 16F628 20/p in 4MHZ (internal oscillator) mode.
I compile using GPASM on a mac, flashing the chip using PICkit 2 and a little custom board I made for the 16F628. The USART behaved the same way when I used to use an old DOS PC to compile and burn.

Is the sticky USART a known issue? What on earth am I doing wrong? Is the 1982 keyboard actually sending the MIDI bytes more slowly? I don't understand why this won't work. I have written tons of Machine Language MIDI input routines for 6502, 6510 etc with no issues at all. Must I code a bit-wise input for the 16F628? I thought the USART supported MIDI speed? Is the sluggish USART a known issue? Did I miss something important? 4Mhz should be plenty fast...and IS when I plug in the 1982 keyboard.

Please offer any assistance you can. Thanks.

ivlenk

MIDI Note examples showing what each keyboard is sending during my tests:
90 is note on channel 1, 28 is note # 28 hex (on the lower left of the musical keyboard), velocity is how hard the note was hit

[NoteOn Command and channel] [Note Number][Velocity of key hit]
B0 is a controller command followed by 2 data bytes. Old Roland sends a controller message for each note hit (before midi spec standardized)

1982 KBD:
Note On 90 28 44 B0 00 00 (sends a note on plus a controller message each time)
Note Off 90 28 00 B0 00 00 (before standard spec, note off was just a note on with 00 velocity)

1990's KBD:
Note On 90 28 44 (same note as above example on channel 1) 44 would vary with each key hit strength
Note Off 80 28 44 (standard midi implements note off on channel 1 as 80) 44 would vary with each key lift up speed


Source code follows:

;------------------------------------------------------------------------------------
LIST P=16F628A
#include "P16F628A.INC"

__CONFIG _INTRC_OSC_NOCLKOUT & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _MCLRE_ON & _DATA_CP_OFF & _CP_OFF

; Variables

Loop1 equ 0x20
Loop2 equ 0x21
shLoop equ 0x22
UsartClear equ 0x23
tmpMidi equ 0x24
MIDI equ 0x25
channel equ 0x26
REG1 equ 0x27
REG2 equ 0x28
byte1 equ 0x29
byte2 equ 0x2a
byte3 equ 0x2b
ntonvalue equ 0x2c
ntoffvalue equ 0x2d
temp_w equ 0x2e
status_temp equ 0x2f
tempchar equ 0x30
buffer_head equ 0x31
buffer_read equ 0x32

constant buffer_begin=0x40 ; Buffer starts 0x40
constant buffer_end=0x60 ; Buffer end 0x60 32 midi values

org 0x0000
goto INIT

;-----Interrupt-----
org 0x0004 ; Interrupt start


intread
MOVWF temp_w ; backup W register
MOVF STATUS, W
MOVWF status_temp ; backup STATUS register

btfsc RCSTA,OERR ; Is overrun bit set?
call ClearOverrun ; Call clear OERR routine

btfss PIR1,RCIF
goto exitread

movf RCREG,W ; Get the midi character store in tempchar
movwf tempchar
movf buffer_head, W
movwf FSR
movf tempchar, W
movwf INDF

incf buffer_head,f
movlw buffer_end
xorwf buffer_head, W
btfss STATUS, Z
goto exitread

movlw buffer_begin
movwf buffer_head

exitread ; interrupt end

BCF PIR1, RCIF ; clear the RCIF flag bit
MOVF status_temp, W ; restore saved STATUS and W
MOVWF STATUS
SWAPF temp_w, F
SWAPF temp_w, W
RETFIE ; Return from interrupt

INIT
bcf STATUS,RP0
bcf STATUS,RP1
clrf PORTA
clrf PORTB
;movlw 0x00
;movwf VRCON
movlw 0x07
movwf CMCON

bsf STATUS,RP0 ; bank 1
clrf TRISB ; init all port B to outputs
bsf TRISB,1 ; Midi input on port B1
;bsf TRISB,0 ; button input on port B0
bsf TRISB,6 ; Channel Switch input 8
bsf TRISB,7 ; Channel Switch input 4
clrf TRISA ; init all port A to outputs
movlw 0xE0
movwf TRISA
movlw 0x07; use 07
movwf SPBRG ; 31250 baud at 4mhz in HighSpeed
BCF TXSTA,SYNC ; Setup Asyncronous Serial Port
BSF TXSTA,BRGH ; set highspeed bit
bsf TXSTA,TXEN ; enable async transmission
bcf STATUS,RP0 ; bank 0
bsf RCSTA,SPEN
bsf RCSTA,CREN
clrf UsartClear

movlw buffer_begin ; Init interrupt buffer
movwf buffer_head
movwf buffer_read

;----- Interrupt enable -----

BSF STATUS,RP0
BSF PIE1,RCIE ; Enable receive interrupts triggered from USART RX (RB1)
BCF STATUS,RP0
clrf PIR1 ; Clear interrupt flags
BSF INTCON,GIE ; enable all interrupts
BSF INTCON,PEIE
BCF STATUS,RP0 ; bank 0

settle
decfsz UsartClear,F
goto settle
MOVWF RCREG ; Clear receive register
MOVWF RCREG
MOVWF RCREG ; flush receive buffer
clrf tmpMidi
btfsc RCSTA,OERR ; Is overrun bit set?
call ClearOverrun ; Clear OERR routine

BSF PORTA,0 ; flash led on
CALL delay
BCF PORTA,0 ; flash led off
CALL shortdelay

BSF PORTA,1 ; flash led on
CALL delay
BCF PORTA,1 ; flash led off
CALL shortdelay

BSF PORTA,2 ; flash led on
CALL delay
BCF PORTA,2 ; flash led off
CALL shortdelay

BSF PORTA,3 ; flash led on
CALL delay
BCF PORTA,3 ; flash led off
CALL shortdelay

BSF PORTB,0 ; flash led on
CALL delay
BCF PORTB,0 ; flash led off
CALL shortdelay

BSF PORTB,3 ; flash led on
CALL delay
BCF PORTB,3 ; flash led off
CALL shortdelay

BSF PORTB,4 ; flash led on
CALL delay
BCF PORTB,4 ; flash led off
CALL shortdelay

BSF PORTB,5 ; flash led on
CALL delay
BCF PORTB,5 ; flash led off
CALL delay

goto MAIN

MAIN
CALL GETMIDI
btfsc tmpMidi,6 ; Skip System common
goto MAIN

MOVF ntonvalue, W
XORWF tmpMidi,W
BTFSC STATUS,Z
GOTO NoteOn

MOVF ntoffvalue, W
XORWF tmpMidi,W
BTFSC STATUS,Z
GOTO NoteOff

GOTO MAIN


NoteOn
CALL GETMIDI
MOVF tmpMidi,W
MOVWF byte2
;CALL GETMIDI
;MOVF tmpMidi,W
;MOVWF byte3

;btfsc STATUS,Z
;GOTO VelocityZero

MOVLW 0x24
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note0

MOVLW 0x25
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note1

MOVLW 0x26
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note2

MOVLW 0x27
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note3

MOVLW 0x28
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note4

MOVLW 0x29
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note5

MOVLW 0x2A
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note6

MOVLW 0x2B
XORWF byte2,W
BTFSC STATUS,Z
GOTO Note7

GOTO MAIN

NoteOff
CALL GETMIDI
MOVF tmpMidi,W
MOVWF byte2
;CALL GETMIDI
;MOVF tmpMidi,W
;MOVWF byte3

;VelocityZero

MOVLW 0x24
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off0

MOVLW 0x25
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off1

MOVLW 0x26
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off2

MOVLW 0x27
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off3

MOVLW 0x28
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off4

MOVLW 0x29
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off5

MOVLW 0x2A
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off6

MOVLW 0x2B
XORWF byte2,W
BTFSC STATUS,Z
GOTO Off7

GOTO MAIN

getChannel
MOVLW 0x00

BTFSC PORTA,7
call addone
BTFSC PORTA,6
call addtwo
BTFSC PORTB,7
call addfour
BTFSC PORTB,6
call addeight

; ANDLW 0x0F

MOVWF channel

MOVLW 0x90
IORWF channel,W
MOVWF ntonvalue

MOVLW 0x80
IORWF channel,W
MOVWF ntoffvalue

RETURN

addone
ADDLW 0x01
RETURN
addtwo
ADDLW 0x02
RETURN
addfour
ADDLW 0x04
RETURN
addeight
ADDLW 0x08
RETURN

Note0
BSF PORTA,0
GOTO MAIN
Note1
BSF PORTA,1
GOTO MAIN
Note2
BSF PORTA,2
GOTO MAIN
Note3
BSF PORTA,3
GOTO MAIN
Note4
BSF PORTB,0
GOTO MAIN
Note5
BSF PORTB,3
GOTO MAIN
Note6
BSF PORTB,4
GOTO MAIN
Note7
BSF PORTB,5
GOTO MAIN

Off0
BCF PORTA,0
GOTO MAIN
Off1
BCF PORTA,1
GOTO MAIN
Off2
BCF PORTA,2
GOTO MAIN
Off3
BCF PORTA,3
GOTO MAIN
Off4
BCF PORTB,0
GOTO MAIN
Off5
BCF PORTB,3
GOTO MAIN
Off6
BCF PORTB,4
GOTO MAIN
Off7
BCF PORTB,5
GOTO MAIN

; It reads the character from the buffer.
GETMIDI
call getChannel
movf buffer_read, W
xorwf buffer_head, W
btfsc STATUS, Z
goto GETMIDI

; Read character into tmpMidi
movf buffer_read, W
movwf FSR ; buffer_read to FSR
movf INDF, W ; buffer_read position
movwf tmpMidi ; store in tmpMidi

incf buffer_read, f ; move buffer_read
movlw buffer_end ; buffer_end in W
xorwf buffer_read, W
btfss STATUS, Z ; end of buffer check
return

movlw buffer_begin ;start at buffer top
movwf buffer_read ;reset read
return


ClearOverrun
bcf RCSTA,CREN ; Disable USART receive
bsf RCSTA,CREN ; Enable USART receive
; This clears OERR!
movf RCREG,W ; Flush receive register
movf RCREG,W
movf RCREG,W
clrf tmpMidi
return

ClearMem
movf RCREG,W ; Flush receive register
movf RCREG,W
movf RCREG,W
clrf tmpMidi
return

; delay routines

delay
MOVLW 0xf0
MOVWF Loop1
Outer MOVLW 0xc8
MOVWF Loop2
Inner
NOP
NOP
DECFSZ Loop2,F
GOTO Inner
DECFSZ Loop1,F
GOTO Outer
RETURN

shortdelay
MOVLW 0x80
MOVWF shLoop
shInner NOP
NOP
DECFSZ shLoop,F
GOTO shInner
RETURN

END
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top