porting over 16F877 USART to 16F1789 Eusart MIDI

Thread Starter

techristian

Joined Aug 27, 2013
26
Rich (BB code):
#include "p16F877A.inc"

; CONFIG
; __config 0x3FB2
 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _BOREN_OFF & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF





rcvreg    equ       0x20
delay    equ    0x22
BIGdelay equ 0x23
NOTE equ 0x24 
temp equ 0x25
temp2 equ 0x26

   
              org     00              
              goto    begin
 org     04
goto dummy ;interrupt
 
           




    org     30
begin
    banksel PORTA
        clrf    PORTA
        clrf    PORTB
        clrf    PORTC
        clrf    PORTD
    clrf    PORTE
    
    
       banksel ADCON1
      MOVLW 6             
          MOVWF ADCON1        ;set port A as digital
          CLRF TRISA         ;all pins outputs
      CLRF TRISB         ;all pins outputs
          CLRF TRISD         ;all pins outputs   
    movlw b'00000000'
banksel TRISD; make all outputs
movwf TRISD
movwf TRISE
    


        
   
        
   
   ; Set up USART
   
           banksel TRISC
           movlw   b'10000000'     
           movwf   TRISC       
           movlw   0x27             ; 31250 baud for MIDI
           movwf   SPBRG
           movlw   b'00100100'     ; async tx 8 bit
           movwf   TXSTA
           banksel RCSTA
           movlw   b'10010000'     ; async rx 8 bit
           movwf   RCSTA
   clrw
       


    clrf    PORTA ; set all outputs to '0000 0000'
        clrf    PORTB        
        clrf    PORTD
clrf    PORTC
    movlw    0x03    ;turn off all segments
        movwf    PORTE
movlw b'00000000'
movwf    PORTA
movwf    PORTB

    
          
    

    goto start

start

         
  banksel PIR1
   getmidi btfss   PIR1,RCIF   ; test for incoming data
               goto     nextime ;continue on with other duties
               movf    RCREG,W
           movwf   rcvreg
nextime
banksel 0
movwf temp2
andlw 0x80 ;don't display status only MIDI NOTES
bz update
goto start
 update movf temp2,0 ; get new midi value
disp movwf NOTE

DISPLAY    movf NOTE,0
    movwf temp                     ;copy number to temp here

 movlw b'00001111' ;least signifigant digit mask
    andwf temp,0

    CALL hexTable
movwf    PORTD ;DISPLAY LOW DIGIT

movlw     b'00000010'
movwf    PORTE   ; turn on least signifigant digit
                movlw 0x2          ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250
 movlw     b'00000011'
movwf    PORTE  ; turn off most signifigant digit
                movlw 0x1   ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250

movf NOTE,0

movlw b'11110000' ;high bit mask
andwf temp, 1
    RRF temp, 1
    RRF temp, 1
   RRF temp, 1
    RRF temp, 0 ;shift right 3 times store in W

    CALL hexTable
movwf    PORTD ;DISPLAY CHARACTER

movlw     b'00000001'
movwf    PORTE  ; turn on most signifigant digit
                movlw 0x2    ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250        ; ----------------------------------

movlw     b'00000011'
movwf    PORTE  ; turn off most signifigant digit
                movlw 0x1    ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250
clrf  RCREG ; throw out any extra bytes



    goto start    ; no




    







;bit 7DOT bit 6E bit 5G BIT 4A BIT 3D BIT 2B BIT 1F BIT 0C

    hexTable movwf temp2
MOVF temp2,0
bnz disp2
ZERO  RETLW   b'01011111' ;0
disp2 DECFSZ temp2,1
    goto   xONE
ONE  RETLW   b'00000101' ;1
xONE DECFSZ temp2,1
goto xTWO
TWO  RETLW   b'01111100' ;2
 xTWO  DECFSZ temp2,1
goto xTHREE
THREE  RETLW   b'00111101' ;3
 xTHREE DECFSZ temp2,1
goto xFOUR
FOUR RETLW   b'00100111' ;4


xFOUR DECFSZ temp2,1
goto xFIVE
     FIVE  RETLW   b'00111011' ;5
xFIVE DECFSZ temp2,1
goto xSIX
SIX  RETLW   b'01111011' ;6
 xSIX DECFSZ temp2,1
goto xSEVEN
SEVEN  RETLW   b'00010101' ;7


xSEVEN DECFSZ temp2,1
goto xEIGHT
EIGHT  RETLW   b'01111111' ;8
 xEIGHT DECFSZ temp2,1
goto xNINE
  NINE  RETLW   b'00110111' ;9
 xNINE DECFSZ temp2,1
goto xA
A  RETLW   b'01110111' ;a


xA DECFSZ temp2,1
goto xBEE
   BEE RETLW   b'01101011' ;b
xBEE DECFSZ temp2,1
goto xCEE
     CEE  RETLW   b'01011010' ;c
xCEE DECFSZ temp2,1
goto xDEE
  DEE  RETLW   b'01101101' ;d
xDEE DECFSZ temp2,1
goto xE
 E RETLW   b'01111010' ;e
xE RETLW   b'01110010' ;f
      


PAUSE movlw 0xff
    MOVWF BIGdelay
D250    movlw    0x80
    movwf    delay
l250    decfsz    delay,f
    goto    l250
DECFSZ BIGdelay,f
GOTO D250
    return

dummy retfie
    end
The above code example works well on the 16F877A. I'm just hoping that someone will give me a few pointers on getting the same code to work with the 16F1789.

Obviosly my code works. It is just a matter of setting up the USART or as in the case of the 16F1789 the EUSART. The setup is the tricky part for the 16F1789. Here is my setup code ,LISTED BELOW , so far, for the 16F1789. What do I need here and what can I throw out ? What am I missing? I would rather work with the 16F1789. i have been pulling my hair out literally for months trying to figure the proper Eusart setup just to get the above code sample to work on the 1789

Rich (BB code):
#include "P16F1789.INC"

; CONFIG1
; __config 0xF9C2
 __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF   
; CONFIG2
; __config 0xDFFF
 __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF  & _LVP_OFF


rcvreg    equ  0x30
delay    equ    0x32
BIGdelay equ 0x33
NOTE equ 0x34 ; if over 80h or greater next bank
temp equ 0x35
temp2 equ 0x36

    
              org     0x0               ; reset vector
              goto    begin
 org     0x4
goto dummy

 
           




    org    0x30
begin
    banksel PORTA
        clrf    PORTA
        clrf    PORTB
        clrf    PORTC
        clrf    PORTD
    clrf    PORTE
    
    
  



   ; Set up USART
   banksel BAUD1CON
 movlw   b'00001000'
movwf BAUD1CON
BANKSEL PIE1
 movlw   b'00100000'
movwf PIE1
movlw b'11010000'  ;enable global and peripheral ints
movwf INTCON
           banksel SPBRG
           movlw   0x27             ; 31250 baud for MIDI
           movwf  SPBRG

;BANKSEL ANSELC
;CLRF PORTC ;Init PORTA
; LATC ;Data Latch
;CLRF LATC ;
;BANKSEL ANSELC ;
;CLRF ANSELC ;digital I/O
BANKSEL TRISC ;
MOVLW B'10000000'
MOVWF TRISC

CLRF TRISA         ;all pins outputs
      CLRF TRISB         ;all pins outputs
          CLRF TRISD         ;all pins outputs
    movlw b'00000000'
banksel TRISD; make all outputs
movwf TRISD
movwf TRISE





    clrf    PORTA ; set all outputs to '00000000'
        clrf    PORTB
        clrf    PORTD

    movlw    0x03    ;turn off all segments
        movwf    PORTE
movlw b'00000000'
movwf    PORTA
movwf    PORTB



       BANKSEL APFCON1
  movlw   b'00000010'
movwf APFCON1
    banksel TX1STA
           movlw   b'00100100'     ; async tx 8 bit
           movwf   TX1STA
           banksel RC1STA
           movlw   b'10000000'     ; async rx 8 bit  SET SPEN
           movwf   RC1STA
    movlw   b'10010000'
 movwf   RC1STA ;SET cren
   clrw

    
          
    

    goto start
 
Last edited:

MMcLaren

Joined Feb 14, 2010
842
I suspect something like this might work;

Rich (BB code):
;
;  BRG value for 31250 baud with Fosc = 16 MHz (BRGH=1/BRG16=1)
;
        radix dec
brgval  equ (16000000/31250/4)-1
;
;  setup EUSART module for asynchronous 31250/8/1/N
;
        banksel SP1BRGL         ; bank 3                          |B3
        movlw   low(brgval)     ; setup baud rate generator       |B3
        movwf   SP1BRGL         ;                                 |B3
        movlw   high(brgval)    ;                                 |B3
        movwf   SP1BRGH         ;                                 |B3
        movlw   1<<BRG16        ;                                 |B3
        movwf   BAUD1CON        ; BRG16 = 1                       |B3
        movlw   1<<TXEN|1<<BRGH ;                                 |B3
        movwf   TX1STA          ; TXEN=1, BRGH=1, SYNC=0	  |B3
        movlw   1<<SPEN|1<<CREN ;				  |B3
        movwf   RC1STA          ; SPEN=1, CREN=1		  |B3
You also need to pay close attention to banking since all of the EUSART registers are located in bank 3 in these newer "enhanced mid-range" 14-bit core devices.

Good luck on your project.

Cheerful regards, Mike
 

Thread Starter

techristian

Joined Aug 27, 2013
26
Thanks Mike for the suggestion. I'm using a 20 mhz crystal, but I think your code will help as a starting point. I also learned from the errata sheet that BRA and BRW commands can't be used if I want to use interrupts. Those commands mess up the program counter during an interrupt.

Thanks again

Dan
 
Last edited:

MMcLaren

Joined Feb 14, 2010
842
Hi Dan,

I was looking at your code and I was wondering what the incoming MIDI data looks like? I see you ignore any incoming byte with bit 7 set and I also noticed that you seem to throw away an incoming character within your 'update' code.

Cheerful regards, Mike
 

Thread Starter

techristian

Joined Aug 27, 2013
26
Hey Mike

I'm just looking at MIDI NOTE numbers. I wrote some code last year for the Commodore 64 MIDI setting up an interrput 3125 times a second to poll the port of a Sentech/Passport type interface. It was good but not good enough. It would miss 3% to 5% of the notes and play wrong notes. The Passport and Sentech ports DON'T have a buffer. So I am designing my own...with either a buffer, or a MIDI interface that makes intelligent decisions. I don't like the 2 byte standard for MIDI.

If you want to see what the output looks like, I posted a youtube video. I'm using no resistors for the LED segments but don't worry. They won't burn out. I had to turn up the contrast on the video and pull all of my curtains to record the video. It's not too impressive...unless you consider that I walked away from Machine Language programming over 30 years ago and just got back into it in 2011 . http://www.youtube.com/watch?v=leUeKmhmEqs

BTW I use BRW command for the "hexTable" on the 16F1789 and that's something I will need to avoid so that I can use interrupts. That's why I mentioned it above.
Dan
 
Last edited:

MMcLaren

Joined Feb 14, 2010
842
Hi Dan,

That video matches the behavior I expected after studying your program. So, is the first byte of the two byte MIDI standard the "note"? And what is the second byte? Duration? How do you distinguish between the two? Is there a 'header' or 'separator' byte, or something like that? It looks like you're throwing away the second byte of the two byte sequence in your "update" code. Is that correct? Are you just making sure that you're delaying longer than one character time at 31250 baud (320 usecs) and less than two character times (640 usecs) in that code section?

As far as using interrupts... can you use the BRW instruction within the ISR? If so, why not refresh the display in the ISR?

Rich (BB code):
;
;  interrupt service routine (1-msec TMR2 interrupts)
;
        org     0x004
isrproc
        movlb   0               ; bank 0                                  |B0
        bcf     PIR1,TMR2IF     ; clear TMR2 interrupt flag               |B0
;
;  refresh display (refresh rate = 500 Hz)
;
        clrf    PORTD           ; blank the display                       |B0
        movlw   b'00000011'     ; bit mask for RE0 and RE1 bits           |B0
        xorwf   PORTE,F         ; toggle active lo digit select bits      |B0
        movf    NOTE,W          ; lo digit bits in b3..b0                 |B0
        btfsc   PORTE,0         ; lo digit selected? yes, skip, else      |B0
        swapf   NOTE,W          ; hi digit bits in b3..b0                 |B0
        call    hexTable        ; get segment data                        |B0
        movwf   PORTD           ; display new digit                       |B0
        retfie                  ;                                         |B0
Rich (BB code):
;
;  number-to-segment data table for 7-segment displays
;
hexTable
        andlw   b'00001111'     ; lower nibble only                       |B0
        brw                     ;     'pEGADBFC'                          |B0
        retlw   b'01011111'     ; 0   '-E-ADBFC'
        retlw   b'00000101'     ; 1   '-----B-C'
        retlw   b'01111100'     ; 2   '-EGADB--'
        retlw   b'00111101'     ; 3   '--GADB-C'
        retlw   b'00100111'     ; 4   '--G--BFC'
        retlw   b'00111011'     ; 5   '--GAD-FC'
        retlw   b'01111011'     ; 6   '-EGAD-FC'
        retlw   b'00010101'     ; 7   '---A-B-C'
        retlw   b'01111111'     ; 8   '-EGADBFC'
        retlw   b'00110111'     ; 9   '--GA-BFC'
        retlw   b'01110111'     ; A   '-EGA-BFC'
        retlw   b'01101011'     ; b   '-EG-D-FC'
        retlw   b'01011010'     ; C   '-E-AD-F-'
        retlw   b'01101101'     ; d   '-EG-DB-C'
        retlw   b'01111010'     ; E   '-EGAD-F-'
        retlw   b'01110010'     ; F   '-EGA--F-'
 
Last edited:

Thread Starter

techristian

Joined Aug 27, 2013
26
Down the road I will use the CLOCK based (44.1khz) interrupts for updating audio out to the DAC and for filtering ,glide etc. I'll need to read the errata sheet again to see if I'm allowed BRW within an interrupt.

From my 1985 MIDI 1.0 Detailed Specification


All MIDI communication is achieved through multi-byte "messages" consisting of one "Status Byte" followed by one or two Data bytes, except Real Time and Exclusive messages. (see below)

MESSAGE TYPES

Channel ...4 bit in the Status byte which address the message specifically to one of 16 channels.

There are 2 types of Channel Messages .....VOICE and MODE

System messages are encoded with channel numbers.

Anyway I'm only really concerned with NOTE ON, NOTE OFF , AND VELOCITY (VOLUME) messages.

Channel Voice messages
(nnnn channel # bits)

1000nnnn 2 bytes Note off IOW 81hex channel 1 note on followed by the actual note #
1001nnnn 2 bytes Note on IOW 92hex channel 2 note off followed by the actual note #
1100nnn 1 byte program change (changes the sound from piano to trumpet for an example)

Running Status mode

For Voice and Mode messages only when a Status byte is received and processed the receiver will remain in that status until a different Status byte is received.

The Running Status feature is especially useful for communicating long strings of Note on/off messages, where Note ON with a Velocity of ZERO is used (instead of Note Off).
Dan
 
Last edited:

Thread Starter

techristian

Joined Aug 27, 2013
26
Rich (BB code):
radix dec
brgval  equ (20000000/31250/16)-1
Hi Mike

First I tried your code exactly as you wrote it except I changed it to 20 mhz. No cigar. (why did you use /4 ? for the calculation? I'm using the HS oscillator.)

Then I changed it to the listing above. This works exactly as the same thing I wrote before, but I do admit that your way of writing it is more elegant. After examining the Disassembly, I could see that the same values were placed into the registers.

Anyway...the bottom line..... as soon as I plug in the live MIDI cable....this still writes "00" to my display and stops dead....When I start hitting keys it still shows 00 until I reset...The EUSART and NOT the program that is. If the program stopped dead one digit or the other OR NONE would display because I can't have 2 segments energized at the same time.

I need to learn how to use the MPLABX debugger to follow this, but I suspect that the OVERFLOW bit is triggered and shutting down the EUSART.

Thanks again for all of your help !

Rich (BB code):
#include "P16F1789.INC"

; CONFIG1
; __config 0xF9C2
 __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _CP_OFF & _CPD_OFF & _BOREN_OFF   
; CONFIG2
; __config 0xDFFF
 __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF  & _LVP_OFF





delay    equ    0x22
BIGdelay equ 0x23
NOTE equ 0x24 ; if over 80h or greater next bank
temp equ 0x25
temp2 equ 0x26
LastNote equ 0x27





    org     30
begin

banksel TRISA

          CLRF TRISA         ;all pins outputs
      CLRF TRISB         ;all pins outputs
          CLRF TRISD         ;all pins outputs
    movlw b'00000000'
banksel TRISD; make all outputs
movwf TRISD
movwf TRISE

           movlw   b'10000000'     ; RC7 is RX input
           movwf   TRISC




 ; Set up USART
;
;  BRG value for 31250 baud with Fosc = 16 MHz (BRGH=1/BRG16=1)
;
        radix dec
brgval  equ (20000000/31250/16)-1
;
;  setup EUSART module for asynchronous 31250/8/1/N
;
        banksel SP1BRGL         ; bank 3                          |B3
        movlw   low(brgval)     ; setup baud rate generator       |B3
        movwf   SP1BRGL         ;                                 |B3
        movlw   high(brgval)    ;                                 |B3
        movwf   SP1BRGH         ;                                 |B3
        movlw   1<<BRG16        ;                                 |B3
        movwf   BAUD1CON        ; BRG16 = 1                       |B3
        movlw   1<<TXEN|1<<BRGH ;                                 |B3
        movwf   TX1STA          ; TXEN=1, BRGH=1, SYNC=0      |B3
        movlw   1<<SPEN|1<<CREN ;                  |B3
        movwf   RC1STA          ; SPEN=1, CREN=1

 ; BANKSEL LATC ;Data Latch
;CLRF LATC ;
;BANKSEL ANSELC ;
;CLRF ANSELC ;digital I/O

 





 
    clrf    PORTA ; set all outputs to '0000 0000'
        clrf    PORTB
        clrf    PORTD
clrf    PORTC
    movlw    0x03    ;turn off all segments
        movwf    PORTE
movlw b'00000000'
movwf    PORTA
movwf    PORTB





    
;************************************************
start
 ; BANKSEL FERR
;CLRF    FERR ;CLEAR ERRORS
;banksel RCSTA
      ;movlw   b'00010000'     ;clear overun error OERR by flipping CREN
    ; movwf   RCSTA
       ; movlw   b'10010000'     ; async rx 8 bit bit 6 for 8 or 9 bit
         ;movwf   RCSTA

       
  banksel PIR1
   getmidi btfss   PIR1,RCIF   ; test for incoming data
goto     nextime
               movf    RCREG,W

MOVWF TXREG
CLRF RCREG


nextime
banksel 0
movwf PORTA  ; send Note to C64
movwf temp2

andlw 0x80 ;don't display status
bz update
goto start
 update movf temp2,0 ; get new midi value

 movwf NOTE

CALL DISPLAY

    goto start    ; no












;bit 7DOT bit 6E bit 5G BIT 4A BIT 3D BIT 2B BIT 1F BIT 0C
org     0x130
DISPLAY    movf NOTE,0
    movwf temp                     ;copy number to temp here

 movlw b'00001111' ;least signifigant digit mask
    andwf temp,0

    CALL hexTable
movwf    PORTD ;DISPLAY LOW DIGIT

movlw     b'00000010'
movwf    PORTE   ; turn on least signifigant digit
                movlw 0x5          ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250
 movlw     b'00000011'
movwf    PORTE  ; turn off most signifigant digit
                movlw 0x2   ; ----------------------------------
                MOVWF BIGdelay
                call D250

movf NOTE,0

movlw b'11110000' ;high bit mask
andwf temp, 1
    LSRF temp, 1
    LSRF temp, 1
   LSRF temp, 1
   LSRF temp, 0 ;shift right 3 times store in W

    CALL hexTable
movwf    PORTD ;DISPLAY CHARACTER

movlw     b'00000001'
movwf    PORTE  ; turn on most signifigant digit
                movlw 0x5    ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250        ; ----------------------------------

movlw     b'00000011'
movwf    PORTE  ; turn off most signifigant digit
                movlw 0x2    ; ----------------------------------
                MOVWF BIGdelay  ;keep on for a while.. small PAUSE
                call D250
clrf  RCREG ; throw out any extra bytes
RETURN


    hexTable movwf temp2
MOVF temp2,0
bnz disp2
ZERO  RETLW   b'01011111' ;0
disp2 DECFSZ temp2,1
    goto   xONE
ONE  RETLW   b'00000101' ;1
xONE DECFSZ temp2,1
goto xTWO
TWO  RETLW   b'01111100' ;2
 xTWO  DECFSZ temp2,1
goto xTHREE
THREE  RETLW   b'00111101' ;3
 xTHREE DECFSZ temp2,1
goto xFOUR
FOUR RETLW   b'00100111' ;4


xFOUR DECFSZ temp2,1
goto xFIVE
     FIVE  RETLW   b'00111011' ;5
xFIVE DECFSZ temp2,1
goto xSIX
SIX  RETLW   b'01111011' ;6
 xSIX DECFSZ temp2,1
goto xSEVEN
SEVEN  RETLW   b'00010101' ;7


xSEVEN DECFSZ temp2,1
goto xEIGHT
EIGHT  RETLW   b'01111111' ;8
 xEIGHT DECFSZ temp2,1
goto xNINE
  NINE  RETLW   b'00110111' ;9
 xNINE DECFSZ temp2,1
goto xA
A  RETLW   b'01110111' ;a


xA DECFSZ temp2,1
goto xBEE
   BEE RETLW   b'01101011' ;b
xBEE DECFSZ temp2,1
goto xCEE
     CEE  RETLW   b'01011010' ;c
xCEE DECFSZ temp2,1
goto xDEE
  DEE  RETLW   b'01101101' ;d
xDEE DECFSZ temp2,1
goto xE
 E RETLW   b'01111010' ;e
xE RETLW   b'01110010' ;f





;bit 7DOT bit 6E bit 5G BIT 4A BIT 3D BIT 2B BIT 1F BIT 0C


PAUSE movlw 0xff
    MOVWF BIGdelay
D250    movlw    0x80
    movwf    delay
l250    decfsz    delay,f
    goto    l250
DECFSZ BIGdelay,f
GOTO D250
    return




    end
Dan
 
Last edited:
Top