TITLE "s2i_b.asm: serial to i2c converter, @4.0MHz" LIST p=12F675 ERRORLEVEL 0, -302 ; A modified version of s2i.asm - for easy connection to an RS232 port ; without line drivers/receivers. The range of available bit rates is ; changed to 9600..38400bps and includes the 31250bps MIDI data rate. ; ; write: 1010nnnn aaaaaaa0 data.. response: 00000000 ; ; read: 1010nnnn aaaaaaa1 response: 0000nnnn data.. ; ; The first byte to the serial port must start with the 1010 bit pattern. ; (other bytes are ignored to lock to commands if the track was lost) ; ; nnnn is the number of i2c data bytes (0001 = 1 .. 1111 = 15, 0000 = 16). ; ; The second byte is the i2c control code containing the device address ; aaaaaaa and bit0 cleared for write or set for read. ; ; Example 1: writing to a 24LC16 (data 0x55 to address 0x22): ; transmit: 0xA2 0xA0 0x22 0x55, reponse: 0x00 (or 0xFF on error) ; ; Example 2: reading from a 24LC16 (set address to 0x22, read one byte): ; transmit: 0xA1 0xA0 0x22, response: 0x00 (or 0xFF on error) ; transmit: 0xA1 0xA1, reponse: 0x01 0x55 (or 0xFF on error) ; ; The error code 0xFF is returned if the addressed device did not repond. ; Connections: ; ; ********** ********** ; * *** * ; +5V VCC ** 1 8 ** GND GND ; * * ; RXD GP5 ** 2 7 ** GP0 SDA ; * * ; TXD GP4 ** 3 6 ** GP1 SCL ; * * ; BD1 GP3 ** 4 5 ** GP2 BD0 ; * PIC12F675 * ; *********************** ; ; +---1 DCD ; | 2 TXD --------- TXD ; | 3 RXD ---22k--- RXD ; RS232 +---4 DTR ; (9 pin f.) | 5 GND --------- GND ; +---6 DSR ; 7 RTS ---+ ; 8 CTS ---+ ; 9 RI ; ; BD1 and BD0 select the baudrate (BD0 has an internal pullup) ; ; BD1 | BD0 | bits per second ; ---------|---------|--------------------- ; GND | GND | 9600 ; GND | VDD | 19200 ; VDD | GND | 31250 MIDI ; VDD | VDD | 38400 ; The i2c signals SCL and SDA have internal weak pullups enabled. ; This works if a single i2c device is connected width short wires ; but for a larger bus capacity external pullups are recommended. ; Since the PIC fakes open collector outputs with tristate pins ; i2c peripherals should share the same supply voltage. ; The PIC12F675 ADC is not used: a PIC12F629 may be used a well. ; No timers or interrupts used: code may be adapted to any PIC12xxx. __IDLOCS H'521B' ; s2i_b __CONFIG H'01CC' ; no CP, BOD, no MCLR, WDT, internal osc INDF EQU 0 ; indirect file access PCL EQU 2 ; program counter lsb STATUS EQU 3 ; program status FSR EQU 4 ; file selection register GPIO EQU 5 ; i/o port CMCON EQU H'19' ; comparator control _OPTION EQU H'81' ; option register (bank 1) _TRISIO EQU H'85' ; gpio tristate register (bank 1) _OSCCAL EQU H'90' ; oscillator calibration (bank 1) _WPU EQU H'95' ; weak pullup enables (bank 1) _ANSEL EQU H'9F' ; analog select (bank 1) C EQU 0 ; carry Z EQU 2 ; zero RP0 EQU 5 ; register bank select SDA EQU 0 ; GPIO pins SCL EQU 1 TXD EQU 4 RXD EQU 5 BD0 EQU 2 BD1 EQU 3 ORG H'20' ; RAM (64 Bytes) tmp0 RES 1 ; temporary storage tmp1 RES 1 ctrl RES 1 ; i2c control byte dcnt RES 1 ; data count bcnt RES 1 ; byte counter rxsh RES 1 ; receiver shift register txsh RES 1 ; transmit shift register buff RES 16 ; data buffer ORG H'000' ; reset GOTO main ; ORG H'010' ; main CLRWDT ; MOVLW B'00000000' ; MOVWF GPIO ; BSF STATUS,RP0 ; bank 1 MOVLW B'11101111' ; tx=output, others are inputs MOVWF _TRISIO ; MOVLW B'11111111' ; weak pullups to all inputs MOVWF _WPU ; MOVLW B'00000000' ; all analog pins digital MOVWF _ANSEL MOVLW B'01011111' ; pu, intoff, iclk, fall, wdt:128 MOVWF _OPTION ; CALL H'3FF' ; oscillator calibration MOVWF _OSCCAL ; BCF STATUS,RP0 ; bank 0 MOVLW B'11111111' ; comparator off MOVWF CMCON ; MOVLW H'20' ; begin init vars MOVWF FSR initvar CLRF 0 INCF FSR,F MOVLW H'60' XORWF FSR,W BTFSS STATUS,Z GOTO initvar ; end reset vars loop0 CALL rxbyte ANDLW H'F0' ; valid command? XORLW H'A0' BTFSS STATUS,Z GOTO loop0 ; no: try next byte MOVF rxsh,W ; yes: save data count ANDLW H'0F' BTFSC STATUS,Z MOVLW D'16' ; 0 = 16 MOVWF dcnt CALL rxbyte ; receive ctrl byte MOVWF ctrl BTFSC ctrl,0 ; i2c read or write? GOTO iread iwrite MOVLW buff ; receive data bytes MOVWF FSR MOVF dcnt,W ; wait for data bytes MOVWF bcnt loop1 CALL rxbyte MOVWF INDF INCF FSR,F DECFSZ bcnt,F GOTO loop1 CALL iistart ; i2c start condition BTFSC STATUS,C ; check for error GOTO iierr MOVF ctrl,W ; send i2c control byte CALL iiwr BTFSC STATUS,C ; check for error GOTO iierr MOVLW buff ; send data bytes MOVWF FSR MOVF dcnt,W MOVWF bcnt loop2 CLRWDT ; MOVF INDF,W CALL iiwr BTFSC STATUS,C ; check for error GOTO iierr INCF FSR,F DECFSZ bcnt,F GOTO loop2 CALL iistop MOVLW H'00' ; signal success CALL txbyte GOTO loop0 iread CLRWDT ; CALL iistart ; i2c start condition BTFSC STATUS,C ; check for error GOTO iierr MOVF ctrl,W ; send i2c control byte CALL iiwr BTFSC STATUS,C ; check for error GOTO iierr MOVLW buff ; read data bytes MOVWF FSR MOVF dcnt,W MOVWF bcnt loop3 CLRWDT ; CALL iird MOVWF INDF INCF FSR,F DECFSZ bcnt,F GOTO loop3 CALL iistop MOVF dcnt,W ; signal success ANDLW H'0F' CALL txbyte MOVLW buff ; transmit data bytes MOVWF FSR MOVF dcnt,W MOVWF bcnt loop4 CLRWDT ; MOVF INDF,W CALL txbyte INCF FSR,F DECFSZ bcnt,F GOTO loop4 GOTO loop0 iierr CALL iistop MOVLW H'FF' ; signal an error CALL txbyte GOTO loop0 iistart BTFSS GPIO,SDA ; check for GND short GOTO iihang ; BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SDA ; start condition BCF STATUS,RP0 ; bank 0 BTFSS GPIO,SCL ; check for GND or bus short GOTO iihang ; BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SCL ; BCF STATUS,RP0 ; bank 0 BCF STATUS,C ; BTFSS GPIO,SCL ; check for a VDD short RETLW 0 ; iihang BSF STATUS,C ; RETLW 0 ; iistop BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SDA ; BCF STATUS,RP0 ; bank 0 GOTO $+1 ; BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SCL ; BCF STATUS,RP0 ; bank 0 CLRF txsh ; clock stretching timeout iist0 BTFSC GPIO,SCL ; continue if clock hi GOTO iist1 ; DECFSZ txsh,F ; continue at timeout GOTO iist0 ; iist1 BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SDA ; stop condition BCF STATUS,RP0 ; bank 0 RETLW 0 ; iiwr MOVWF tmp0 ; save the byte MOVLW H'08' ; bit counter MOVWF tmp1 ; iiwr8 RLF tmp0,F ; BSF STATUS,RP0 ; bank 1 BTFSC STATUS,C ; BSF _TRISIO,SDA ; SDA high BTFSS STATUS,C ; BCF _TRISIO,SDA ; SDA low BCF STATUS,RP0 ; bank 0 BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SCL ; SCL high BCF STATUS,RP0 ; bank 0 CLRF txsh ; clock stretching timeout iiwr0 BTFSC GPIO,SCL ; continue if clock hi GOTO iiwr1 ; DECFSZ txsh,F ; continue at timeout GOTO iiwr0 ; iiwr1 BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SCL ; SCL low BCF STATUS,RP0 ; bank 0 DECFSZ tmp1,F ; next byte GOTO iiwr8 ; BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SDA ; SDA high BCF STATUS,RP0 ; bank 0 GOTO $+1 ; BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SCL ; SCL high BCF STATUS,RP0 ; bank 0 BSF STATUS,C ; BTFSS GPIO,SDA ; check ack BCF STATUS,C ; BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SCL ; SCL low BCF STATUS,RP0 ; bank 0 RETLW 0 ; iird BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SDA ; SDA high (input!) BCF STATUS,RP0 ; bank 0 MOVLW H'01' ; data register (set bit0) MOVWF tmp0 ; iird8 BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SCL ; SCL high BCF STATUS,RP0 ; bank 0 CLRF txsh ; clock stretching timeout iird0 BTFSC GPIO,SCL ; continue if clock hi GOTO iird1 ; DECFSZ txsh,F ; continue at timeout GOTO iird0 ; iird1 BCF STATUS,C ; BTFSC GPIO,SDA ; read bit BSF STATUS,C ; BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SCL ; SCL low BCF STATUS,RP0 ; bank 0 RLF tmp0,F ; save bit BTFSS STATUS,C ; done if bit0 out GOTO iird8 ; DECF bcnt,W ; no ack for last byte BSF STATUS,RP0 ; bank 1 BTFSS STATUS,Z ; if not last byte: BCF _TRISIO,SDA ; ack with SDA low BCF STATUS,RP0 ; bank 0 BSF STATUS,RP0 ; bank 1 BSF _TRISIO,SCL ; SCL high BCF STATUS,RP0 ; bank 0 GOTO $+1 ; BSF STATUS,RP0 ; bank 1 BCF _TRISIO,SCL ; SCL low BCF STATUS,RP0 ; bank 0 MOVF tmp0,W ; result to W RETURN ; rxbyte BTFSS GPIO,BD1 ; check baudrate settings GOTO rxbytl BTFSC GPIO,BD0 ; higher baudrates GOTO rxb384 GOTO rxmidi rxbytl BTFSC GPIO,BD0 ; lower baudrates GOTO rxb192 GOTO rxbt96 rxbt96 BTFSC GPIO,RXD ; polled receive 9600bps @4MHz GOTO rxbt96 ; wait for idle RX line rxbt96a CLRWDT ; BTFSS GPIO,RXD ; [1] wait for start bit GOTO rxbt96a ; [2] CLRF rxsh ; [3] BSF STATUS,C ; [4] shift in start bit RRF rxsh,F ; [5] MOVLW D'18' ; [6] delay to middle of start bit MOVWF tmp0 ; [7] rxbt96b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxbt96b ; [60] rxbt96c MOVLW D'32' ; [7] delay to middle of next bit MOVWF tmp0 ; [8] NOP ; [9] rxbt96d DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxbt96d ; [104] BTFSS GPIO,RXD ; [1] poll rx-line BSF STATUS,C ; [2] RRF rxsh,F ; [3] shift in new bit BTFSS STATUS,C ; [4] startbit rotated to carry? GOTO rxbt96c ; [6] MOVF rxsh,W ; RETURN rxb192 BTFSC GPIO,RXD ; polled receive 9600bps @4MHz GOTO rxb192 ; wait for idle RX line rxb192a CLRWDT ; BTFSS GPIO,RXD ; [1] wait for start bit GOTO rxb192a ; [2] CLRF rxsh ; [3] BSF STATUS,C ; [4] shift in start bit RRF rxsh,F ; [5] MOVLW D'9' ; [6] delay to middle of start bit MOVWF tmp0 ; [7] rxb192b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxb192b ; [33] rxb192c MOVLW D'15' ; [7] delay to middle of next bit MOVWF tmp0 ; [8] rxb192d DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxb192d ; [52] BTFSS GPIO,RXD ; [1] poll rx-line BSF STATUS,C ; [2] RRF rxsh,F ; [3] shift in new bit BTFSS STATUS,C ; [4] startbit rotated to carry? GOTO rxb192c ; [6] MOVF rxsh,W ; RETURN rxmidi BTFSC GPIO,RXD ; polled receive 9600bps @4MHz GOTO rxmidi ; wait for idle RX line rxmidia CLRWDT ; BTFSS GPIO,RXD ; [1] wait for start bit GOTO rxmidia ; [2] CLRF rxsh ; [3] BSF STATUS,C ; [4] shift in start bit RRF rxsh,F ; [5] MOVLW D'5' ; [6] delay to middle of start bit MOVWF tmp0 ; [7] rxmidib DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxmidib ; [21] rxmidic MOVLW D'8' ; [7] delay to middle of next bit MOVWF tmp0 ; [8] NOP ; [9] rxmidid DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxmidid ; [32] BTFSS GPIO,RXD ; [1] poll rx-line BSF STATUS,C ; [2] RRF rxsh,F ; [3] shift in new bit BTFSS STATUS,C ; [4] startbit rotated to carry? GOTO rxmidic ; [6] MOVF rxsh,W ; RETURN rxb384 BTFSC GPIO,RXD ; polled receive 9600bps @4MHz GOTO rxb384 ; wait for idle RX line rxb384a CLRWDT ; BTFSS GPIO,RXD ; [1] wait for start bit GOTO rxb384a ; [2] CLRF rxsh ; [3] BSF STATUS,C ; [4] shift in start bit RRF rxsh,F ; [5] MOVLW D'4' ; [6] delay to middle of start bit MOVWF tmp0 ; [7] rxb384b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxb384b ; [18] rxb384c MOVLW D'6' ; [7] delay to middle of next bit MOVWF tmp0 ; [8] NOP ; [9] rxb384d DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO rxb384d ; [26] BTFSS GPIO,RXD ; [1] poll rx-line BSF STATUS,C ; [2] RRF rxsh,F ; [3] shift in new bit BTFSS STATUS,C ; [4] startbit rotated to carry? GOTO rxb384c ; [6] MOVF rxsh,W ; RETURN txbyte BTFSS GPIO,BD1 ; check baudrate settings GOTO txbytl BTFSC GPIO,BD0 ; higher baudrates GOTO txb384 GOTO txmidi txbytl BTFSC GPIO,BD0 ; lower baudrates GOTO txb192 GOTO txbt96 txbt96 MOVWF txsh ; bit banging transmit 9600bps @4MHz MOVLW D'10' ; bitcounter MOVWF tmp1 ; BCF STATUS,C ; startbit to carry txbt96a MOVLW (1 << TXD) ; [6] tx high BTFSC STATUS,C ; [7] CLRW ; [8] tx low MOVWF GPIO ; [9] MOVLW D'31' ; [10] bit delay MOVWF tmp0 ; [11] NOP ; [12] txbt96b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO txbt96b ; [104] BSF STATUS,C ; [1] stop bit to txsh RRF txsh,F ; [2] data bit to carry DECFSZ tmp1,F ; [3] done? GOTO txbt96a ; [5] RETLW 0 ; txb192 MOVWF txsh ; bit banging transmit 9600bps @4MHz MOVLW D'10' ; bitcounter MOVWF tmp1 ; BCF STATUS,C ; startbit to carry txb192a MOVLW (1 << TXD) ; [6] tx high BTFSC STATUS,C ; [7] CLRW ; [8] tx low MOVWF GPIO ; [9] MOVLW D'14' ; [10] bit delay MOVWF tmp0 ; [11] txb192b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO txb192b ; [52] BSF STATUS,C ; [1] stop bit to txsh RRF txsh,F ; [2] data bit to carry DECFSZ tmp1,F ; [3] done? GOTO txb192a ; [5] RETLW 0 ; txmidi MOVWF txsh ; bit banging transmit 9600bps @4MHz MOVLW D'10' ; bitcounter MOVWF tmp1 ; BCF STATUS,C ; startbit to carry txmidia MOVLW (1 << TXD) ; [6] tx high BTFSC STATUS,C ; [7] CLRW ; [8] tx low MOVWF GPIO ; [9] MOVLW D'7' ; [10] bit delay MOVWF tmp0 ; [11] NOP ; [12] txmidib DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO txmidib ; [32] BSF STATUS,C ; [1] stop bit to txsh RRF txsh,F ; [2] data bit to carry DECFSZ tmp1,F ; [3] done? GOTO txmidia ; [5] RETLW 0 ; txb384 MOVWF txsh ; bit banging transmit 9600bps @4MHz MOVLW D'10' ; bitcounter MOVWF tmp1 ; BCF STATUS,C ; startbit to carry txb384a MOVLW (1 << TXD) ; [6] tx high BTFSC STATUS,C ; [7] CLRW ; [8] tx low MOVWF GPIO ; [9] MOVLW D'5' ; [10] bit delay MOVWF tmp0 ; [11] NOP ; [12] txb384b DECFSZ tmp0,F ; [+(tmp0 * 3 - 1)] GOTO txb384b ; [26] BSF STATUS,C ; [1] stop bit to txsh RRF txsh,F ; [2] data bit to carry DECFSZ tmp1,F ; [3] done? GOTO txb384a ; [5] RETLW 0 ; END ;