TITLE "baud.asm: baud rate converter, @8.0MHz" LIST p=12F683 ERRORLEVEL 0, -302 ; The 12F683 has no UART for asynchronous serial communication. ; For receive a pin change interrupt is used to detect the ; startbit and timer2 interrupts is used to poll the data bits. ; For transmit the output compare module with timer1 is used to ; set or clear the TX pin. ; ; 1 startbit, 8 databits, 1 stopbit, 64 bytes FIFO buffer. ; ; RS1/0 and TS1/0 set the receive and transmit baudrates: ; (pins have internal pullups: open=1, GND=0) ; 00 = 9600bps, 01 = 19200bps, 10 = 31250bps MIDI, 11 = 38400bps ; ; ********** ********** ; * *** * ; VCC VDD ** 1 8 ** VSS GND ; * * ; RS0 GP5 ** 2 7 ** GP0 TS0 ; * * ; RS1 GP4 ** 3 6 ** GP1 TS1 ; * * ; RXD GP3 ** 4 5 ** GP2 TXD ; * PIC12F683 * ; *********************** ; application: MIDI in: or MIDI out: ; _______ ; 1| |8---+---VCC ; MIDI 4---220R--2| 6N136 |7 2K2 VCC----------4 MIDI ; in 5---------3| OptoC |6---+-->RXD TXD>--220R---5 out ; 4|_______|5-------GND __IDLOCS H'BDBD' __CONFIG H'33C4' ; noFSC BODEN noMCLR noCP noWDT INTosc INDF EQU 0 ; indirect file access TMR0 EQU 1 ; timer 0 PCL EQU 2 ; program counter lsb STATUS EQU 3 ; program status FSR EQU 4 ; file selection register GPIO EQU 5 ; i/o ports PCLATH EQU H'0A' ; program counter msb INTCON EQU H'0B' ; interrupt control PIR1 EQU H'0C' ; peripheral interrupt flags TMR1L EQU H'0E' ; timer 1 lower byte TMR1H EQU H'0F' ; timer 1 higher byte T1CON EQU H'10' ; timer 1 control TMR2 EQU H'11' ; timer 2 counter T2CON EQU H'12' ; timer 2 control CCPR1L EQU H'13' ; capture/compare low CCPR1H EQU H'14' ; capture/compare high CCP1CON EQU H'15' ; capture/compare control WDTCON EQU H'18' ; watch dog timer control CMCON0 EQU H'19' ; comparator control 0 CMCON1 EQU H'1A' ; comparator control 1 ADRESH EQU H'1E' ; most significant ADC bits ADCON EQU H'1F' ; ad control _OPTION EQU H'81' ; option register (bank 1) _TRISIO EQU H'85' ; gpio tristate register (bank 1) _PIE1 EQU H'8C' ; peripheral interrupt enable (bank 1) _PCON EQU H'8E' ; power control (bank 1) _OSCCON EQU H'8F' ; oscillator control (bank 1) _OSCTUNE EQU H'90' ; osc tune, 5 bit signed (bank 1) _PR2 EQU H'92' ; timer 2 period (bank 1) _WPU EQU H'95' ; individual weak pullups (bank 1) _IOC EQU H'96' ; interrupt on change (bank 1) _VRCON EQU H'99' ; voltage reference control (bank 1) _EEDAT EQU H'9A' ; eeprom data (bank 1) _EEADR EQU H'9B' ; eeprom address (bank 1) _EECON1 EQU H'9C' ; eeprom control 1 (bank 1) _EECON2 EQU H'9D' ; eeprom control 2 (bank 1) _ADRESL EQU H'9E' ; least significant ADC bits (bank 1) _ANSEL EQU H'9F' ; analog select (bank 1) C EQU 0 ; carry DC EQU 1 ; digit carry Z EQU 2 ; zero PD EQU 3 ; power down TO EQU 4 ; watch dog time out RP0 EQU 5 ; register bank select RS0 EQU 5 ; baud rate select RS1 EQU 4 ; baud rate select RXD EQU 3 ; receive data pin TS0 EQU 0 ; baud rate select TS1 EQU 1 ; baud rate select TXD EQU 2 ; transmit data pin stim EQU H'20' ; sample delay to mid bit ttim EQU H'21' ; transmit bit time rcnt EQU H'22' ; receive bit counter tcnt EQU H'23' ; transmit bit counter rxsh EQU H'24' ; receive shift register txsh EQU H'25' ; transmit shift register rptr EQU H'26' ; buffer read pointer wptr EQU H'27' ; buffer write pointer buff EQU H'28' ; 64 bytes FIFO buffer ORG H'0000' ; reset GOTO main ; When waiting for a startbit we do not read or write to GPIO for ; not missing the pin change interrupt. Changing the TXD pin is only ; done through the timer1 compare function. ORG H'0004' ; interrupt intserv BSF T2CON,2 ; [3] start timer BTFSC GPIO,RXD ; [4] poll data bit BSF rxsh,7 ; [5] BCF PIR1,1 ; [6] clear timer2 int flag BCF INTCON,3 ; [7] disable pin change int BSF rcnt,5 ; [8] flag bit received RETFIE ; [10] ORG H'0020' ; main main CLRF GPIO ; tx line idle BSF GPIO,TXD MOVLW B'00000111' ; comparator not used MOVWF CMCON0 BSF STATUS,RP0 ; bank 1 MOVLW B'01110000' ; 8 MHz MOVWF _OSCCON MOVLW B'00000000' ; adjust (-16..15) MOVWF _OSCTUNE MOVLW B'00000000' ; all analog pins digital MOVWF _ANSEL MOVLW B'11111111' ; tx output MOVWF _TRISIO BCF _TRISIO,TXD MOVLW B'01011111' ; pu, noint, iclk, wdt:128 MOVWF _OPTION MOVLW B'00111111' ; pu on all inputs MOVWF _WPU BSF _IOC,RXD ; enable IOC for RX pin CLRF STATUS ; bank 0 (direct and indexed) MOVLW H'20' ; begin reset vars MOVWF FSR initvar CLRF 0 INCF FSR,F MOVLW H'80' XORWF FSR,W BTFSS STATUS,Z GOTO initvar ; end reset vars inirx CLRF T2CON ; timer2 prescaler:1, postscaler:1, stop BSF STATUS,RP0 ; bank 1 BSF _PIE1,1 ; enable timer2 interrupt BCF STATUS,RP0 ; bank 0 BTFSC GPIO,RS1 ; check rx speed setting GOTO rxsp1 MOVLW D'52' ; rx bit time, 9600bps BTFSS GPIO,RS0 BSF T2CON,0 ; prescaler:4 for 9600bps BTFSC GPIO,RS0 MOVLW D'104' ; rx bit time, 19200bps GOTO rxsp0 rxsp1 MOVLW D'64' ; rx bit time, 31250bps BTFSC GPIO,RS0 MOVLW D'52' ; rx bit time, 38400bps rxsp0 BSF STATUS,RP0 ; bank 1 MOVWF _PR2 ; tmr2 period register DECF _PR2,F ; period is PR2+1 BCF STATUS,RP0 ; bank 0 MOVWF stim ; half bit time BCF STATUS,C RRF stim,F MOVLW D'7' ; intserv time lag correction BTFSS T2CON,0 ; not for 9600bps (prescaler:4) SUBWF stim,F initx BTFSC GPIO,TS1 ; check tx speed setting GOTO txsp1 MOVLW D'208' ; tx bit time, 9600bps BTFSC GPIO,TS0 MOVLW D'104' ; tx bit time, 19200bps GOTO txsp0 txsp1 MOVLW D'64' ; tx bit time, 31250bps BTFSC GPIO,TS0 MOVLW D'52' ; tx bit time, 38400bps txsp0 MOVWF ttim CLRF T1CON ; timer1, prescaler:1, stop CLRF TMR1H ; clear timer CLRF TMR1L CLRF CCPR1H ; clear compare match CLRF CCPR1L MOVLW B'00001000' ; immediate match: set tx high MOVWF CCP1CON BSF T1CON,0 ; start timer 1 MOVLW B'11000000' ; GIE, PEIE MOVWF INTCON ; rxck must call cktx at least every 52 cycles @38400bps. ; BTFSC PIR1,5 + CALL cktx need max 27 cycles: this leaves only ; 25 cycles for receive code in between of which intserv takes 10. ; Code is optimized in many ways and may be difficult to read. rxck BTFSC PIR1,5 ; cktx if needed CALL cktx ; BTFSS GPIO,RXD ; [1] wait for idle RX line GOTO rxck ; [3] GPIO rd clears pin mismatch BCF INTCON,0 ; [3] clear pinchange flag BSF INTCON,3 ; [4] enable pin change int rxsav BTFSS rcnt,3 ; [5] unsaved byte? GOTO rxst ; [7] MOVF wptr,W ; [7] write rx data to buff ADDLW buff ; [8] MOVWF FSR ; [9] MOVF rxsh,W ; [10] MOVWF INDF ; [11] INCF wptr,F ; [12] wptr = (wptr+1) % 64 BCF wptr,6 ; [13] [+10 int = 23] rxst BTFSC PIR1,5 ; cktx if needed CALL cktx ; BTFSS rcnt,5 ; [1] start bit received? GOTO rxst ; [3] CLRF rcnt ; [3] clear flag and count MOVF stim,W ; [4] first sample after 1.5 bittime SUBWF TMR2,F ; [5] rxbit BCF STATUS,C ; [6] shift zero bit in RRF rxsh,F ; [7] [+10 int = 17] rxdat BTFSC PIR1,5 ; cktx if needed CALL cktx ; BTFSS rcnt,5 ; [1] data bit received? GOTO rxdat ; [3] BCF rcnt,5 ; [3] clear flag INCF rcnt,F ; [4] count bit BTFSS rcnt,3 ; [5] last bit? GOTO rxbit ; [7] [+10 int, +2 rxbit = 19] BCF T2CON,2 ; [7] stop timer2 CLRF TMR2 ; [8] clear timer2 GOTO rxck ; [10] [+10 int = 20] cktx BCF PIR1,5 ; [3] clear compare flag MOVF ttim,W ; [4] prepare next timer match ADDWF CCPR1L,F ; [5] BTFSC STATUS,C ; [6] INCF CCPR1H,F ; [7] BTFSC tcnt,7 ; [8] transmit pending if tcnt < 0 GOTO txbit ; [10] MOVF rptr,W ; [10] data in buffer? XORWF wptr,W ; [11] BTFSC STATUS,Z ; [12] RETLW 0 ; [14] idle: keep tx stop bits MOVLW B'00001001' ; [14] startbit: clear TXD on match MOVWF CCP1CON ; [15] MOVF rptr,W ; [16] read tx data from buff ADDLW buff ; [17] MOVWF FSR ; [18] MOVF INDF,W ; [19] MOVWF txsh ; [20] INCF rptr,F ; [21] rptr = (rptr+1) % 64 BCF rptr,6 ; [22] MOVLW -D'9' ; [23] 8 data, 1 stop MOVWF tcnt ; [24] RETLW 0 ; [26] [max tx time] txbit COMF txsh,W ; [11] if last bit of txsh XORWF CCP1CON,W ; [12] same as LSB of CCP1CON ANDLW H'01' ; [13] change it BTFSS STATUS,Z ; [14] else don't write CCP1CON XORWF CCP1CON,F ; [15] BSF STATUS,C ; [16] shift stop bits in RRF txsh,F ; [17] INCF tcnt,F ; [18] next bit RETLW 0 ; [20] [tx bit time] END ;