MIDI Bit Bang Serial Routine Look Over

Status
Not open for further replies.

Jon Wilder

Active Member
I just wrote a bit bang serial routine for MIDI and was wondering if someone could look it over as this is my first time coding any sort of bit bang routine -

Code:
#define			RX		PORTB,1
#define			TX		PORTB,2


TX_REG			EQU		0x0C
RC_REG			EQU		0x0D
bitcounter		EQU		0x0E

;8 MHz crystal oscillator. Timer 0 set for prescaler of 1:32. TMR0 bit 0 is incremented every 16uS
;while TMR0 bit 1 is incremented every 32uS. TMR0 bit 2 is polled for baud rate of 31,250.
;Data is transmitted and received LSB first with 1 start bit and 1 stop bit.

;***********************************************************************************************************
;MIDI Transmit
;***********************************************************************************************************

TRANSMIT		movlw		0x08
			movwf		bitcounter	;set bit counter to count 8 bits to be transmitted
		
TX_start		btfss		INTCON,T0IF	;wait for timer to reset
			goto		TX_start
			bcf		TX		;send start bit
			
TX_bit			btfss		TX_REG,0	;see if bit 0 in TXREG is high or low
			goto		TX_low		;send low bit if low
			goto		TX_high		;send high bit if high

TX_low			btfss		TMR0,1		;wait for baud
			goto		TX_low
			bcf		TX		;send low bit
			goto		TX_shift
					
TX_high			btfss		TMR0,1		;wait for baud
			goto		TX_high
			bsf		TX		;send high bit
			goto		TX_shift

TX_shift		rrf		TX_REG,F	;shift bits in transmit register
			decfsz		bitcounter,F	;decriment bit counter, branch if 0
			goto		TX_bit
			goto		TX_stop		;proceed to send stop bit

TX_stop			btfss		TMR0,1		;wait for baud
			goto		TX_stop
			bsf		TX		;send stop bit
			return

;***********************************************************************************************************
;MIDI Receive
;***********************************************************************************************************

RECEIVE			movlw		0x08
			movwf		bitcounter	;set bit counter to count 8 bits to be recieved

RX_start		btfsc		RX		;wait for start bit rising edge
			goto		RX_start

			clrf		TMR0		;reset timer 0
			movlw		b'00000100'	;set timer 0 prescaler for 1:32
			option			
				
bitcenter		btfss		TMR0,0		;wait additional 16uS for bit center
			goto		bitcenter
			btfsc		RX		;recheck start bit, return if not start bit
			return

RX_bit			btfss		TMR0,1		;wait for baud
			goto		RX_bit

			btfss		RX		;see if bit on RX is high or low
			goto		RX_low		;receive low bit if low
			goto		RX_high		;receive high bit if high

RX_low			bcf		RC_REG,7	;set bit 7 in receive register
			goto		RX_shift

RX_high			bsf		RC_REG,7	;clear bit 7 in receive register
			goto		RX_shift

RX_shift		rrf		RC_REG,F	;shift bits in RCREG register
			decfsz		bitcounter,F	;decriment bit counter, branch if 0
			goto		RX_bit		;receive next bit
			goto		RX_stop		;receive stop bit

RX_stop			btfss		TMR0,1		;wait for baud
			goto		RX_stop

stop_w8			btfss		rx		;check for stop bit
			goto		frame_error	;return if stop bit received
			return

Any and all suggestions would be greatly appreciated.

EDIT: On an interesting note I tried simulating this in MPLAB and for some reason it will not skip the next instruction upon bit 1 of TMR0 being set at the "btfss TMR0,1" instruction. Does anyone know why this is?
 
Last edited:
hi Jon,
Whats the PIC type..?

Can I suggest that you drop the 'bit bang' expression thats in common use, for goodness knows why. ??? and substitute 'bit switching'.

I will run it thru Oshonsoft, let you know..
 
hi Jon,
Whats the PIC type..?

Can I suggest that you drop the 'bit bang' expression thats in common use, for goodness knows why. ??? and substitute 'bit switching'.

I will run it thru Oshonsoft, let you know..

Ah yes...it's for a 16F84 or any other type of 16F series PIC that doesn't have an on chip UART. I use the 16F628 so I don't really need it. I'm just merely writing the code in order to gain an understanding of 'bit switching'.
 
Ah yes...it's for a 16F84 or any other type of 16F series PIC that doesn't have an on chip UART. I use the 16F628 so I don't really need it. I'm just merely writing the code in order to gain an understanding of 'bit switching'.

hi Jon
A lot of coding errors, you are calling 'low' and 'high' and there is no low or high label....do you mean TX_ or RX low , high. ?
 
Hi Jon,

If it helps, here are general purpose bit-banged TX and RX routines which rely on a general purpose fixed delay subsystem to provide precise "cycle accurate" bit timing with almost any clock (4, 8, 12, 16, or 20-MHz);

Code:
;
;   19200 baud ->  52.1 usec bit time
;   57600 baud ->  17.4 usec bit time
;  115200 baud ->   8.7 usec bit time
;
        radix   dec
clock   equ     8               ; clock, 4, 8, 12, 16, or 20 MHz
usecs   equ     clock/4         ; cycles/usec operand multiplier
;
bitTime equ     52*usecs        ; cycles per bit @ 19200 baud
;
Code:
Put232
        movwf   serbyte         ;                                 |B0
        movlw   10              ; 1 start + 8 data + 1 stop bit   |B0
        movwf   BitCtr          ; setup bit counter               |B0
        clrc                    ; C = 0 = start bit               |B0
        goto    SendBit         ; send start bit                  |B0
TxBit
        DelayCy(bitTime-10)     ; 52-usecs minus 10 cycles        |B0
        setc                    ; always shift in a 'stop' bit    |B0
        rrf     serbyte,F       ; put data bit in Carry           |B0
SendBit
        movf    PORTB,W         ; read port                       |B0
        iorlw   1<<TxPin        ; TxPin = 1                       |B0
        skpc                    ;                                 |B0
        xorlw   1<<TxPin        ; TxPin = 0                       |B0
        movwf   PORTB           ; precise "bitTime" intervals     |B0
        decfsz  BitCtr,F        ; done? yes, skip, else           |B0
        goto    TxBit           ; send next bit                   |B0
        return                  ;                                 |B0
;
Code:
Get232
        btfss   PORTB,RxPin     ; start bit (1)? yes, skip, else  |B0
        goto    Get232          ; loop (wait for start bit)       |B0
        DelayCy(bitTime/2)      ; delay 1/2 bit time              |B0
        movlw   8               ;                                 |B0
        movwf   BitCtr          ; BitCtr = 8                      |B0
RxBit
        DelayCy(bitTime-7)      ; precise 208-usec bit timing     |B0
        clrc                    ; assume '0'                      |B0
        btfss   PORTB,RxPin     ; a '0' bit? yes, skip, else      |B0
        setc                    ; set to '1'                      |B0
        rrf     serbyte,F       ; b0 first, b7 last               |B0
        decfsz  BitCtr,F        ; done? yes, skip, else           |B0
        goto    RxBit           ; get another bit                 |B0
        return                  ;                                 |B0
;
 
Last edited:
Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…