errorlevel -302 include p16f688.inc DEBUG equ 1 ;DEBUG_HEX equ 1 ;DEBUG_BANK EQU 1 ;DEBUG_LONGWAIT EQU 1 ;DEBUG_ECHO EQU 1 CLOCK_SPEED equ 4 INSTRUCTION_CYCLE equ .1000 / CLOCK_SPEED * 4 RESPONSE_SUCCESS EQU b'00000000' RESPONSE_ERROR EQU b'11000000' EC_SEQUENCE EQU 0x01 EC_NAK EQU 0x02 EC_ARBITRATION EQU 0x03 EC_COMMAND EQU 0xff DEFAULT_BANK EQU TRISC ; TRISCオペレーションが多いため、処理中のデフォルトのバンクを BANK1 とする I2CPORT EQU PORTC I2CTRIS EQU TRISC I2CDAT EQU 0 INDDAT EQU 1 I2CCLK EQU 2 INDCLK EQU 3 THIGH EQU 1 TLOW EQU 1 TSU_STO EQU 4 INDATA_ORG EQU 0x120 ; IN BNAK2 IRP=1 OUTDATA_ORG EQU 0x140 ; IN BANK2 IRP=1 T_HIGH equ 1 serial_send_w macro ifdef DEBUG_HEX call s_puthex else call s_putc endif endm serial_read macro ifdef DEBUG_HEX call s_gethex else call s_getc endif endm wait_usec macro usec movlw usec call wait_usec_w endm BANKMUST1 macro ifdef DEBUG_BANK btfss STATUS, RP0 goto bank_failure btfsc STATUS, RP1 goto bank_failure endif endm CLOCKL macro BANKMUST1 bcf I2CTRIS, I2CCLK ifdef DEBUG_LONGWAIT call longwait endif endm CLOCKH macro BANKMUST1 bsf I2CTRIS, I2CCLK ifdef DEBUG_LONGWAIT call longwait endif endm DATAL macro BANKMUST1 bcf I2CTRIS, I2CDAT endm DATAH macro BANKMUST1 bsf I2CTRIS, I2CDAT endm WAIT_FS macro smode, fmode, overhead_instructions local n = smode n -= INSTRUCTION_CYCLE * (overhead_instructions + 1) while n > 0 nop n -= INSTRUCTION_CYCLE endw endm PULSE_CLOCK macro CLOCKH WAIT_FS .4000, .600, 0 CLOCKL endm __config _BOD_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT & _MCLRE_OFF cblock 0xa0 ; bank1 0xa0〜 cmd ; command param ; lower 5 bit of command (length paramter) rcdata response_code response_ec response_pos outdata_count count_oct count_bit count_w0 count_w1 count_w2 tx_data tx_count rd_data rd_count wsave hexval hextmp nibble_val endc org 0 goto main org 4 retfie dispatch_cmd: movfw cmd andlw b'11111000' btfss STATUS, Z goto cmd_error movfw cmd addwf PCL, f return goto cmd_bus_reset goto cmd_start goto cmd_stop goto cmd_receive_octet goto cmd_error goto cmd_datal goto cmd_datah dispatch_paramcmd: andlw b'00000111' addwf PCL, f goto cmd_error goto cmd_bulk_transmit_octets goto cmd_bulk_receive_octets goto cmd_bulk_receive_octets_nak goto cmd_error goto cmd_error goto cmd_error goto cmd_error ifdef DEBUG_HEX nibble2hex: addwf PCL, f retlw '0' retlw '1' retlw '2' retlw '3' retlw '4' retlw '5' retlw '6' retlw '7' retlw '8' retlw '9' retlw 'A' retlw 'B' retlw 'C' retlw 'D' retlw 'E' retlw 'F' endif main: banksel PORTC movlw b'00001010' movwf PORTC movlw 0x07 movwf CMCON0 banksel ANSEL clrf ANSEL banksel TRISC movlw b'00100101' movwf TRISC clrf TRISA ; all output, MCLR is still input banksel TXSTA bsf TXSTA, BRGH bsf BAUDCTL, BRG16 movlw LOW EE_BRG call eeread banksel SPBRG movwf SPBRG movlw LOW EE_BRGH call eeread banksel SPBRGH movwf SPBRGH bsf RCSTA, SPEN bcf TXSTA, SYNC bsf RCSTA, CREN bsf TXSTA, TXEN banksel I2CTRIS bsf I2CTRIS, I2CDAT bsf I2CTRIS, I2CCLK bsf STATUS, IRP ifdef DEBUG_ECHO goto echo endif ifdef DEBUG_ECHO goto seq_exec endif ;goto seq_test mainloop: banksel DEFAULT_BANK clrf outdata_count serial_read call exec_cmd_w goto mainloop exec_cmd_w: movwf cmd exec_cmd: movlw b'11100000' ; command with parameter andwf cmd, w btfsc STATUS, Z goto dispatch_cmd movfw cmd andlw b'00011111' movwf param ; cmdの上位3bitが下位3bitにくるようにローテート(左ローテートのほうが1命令少ない) rlf cmd, f rlf cmd, f rlf cmd, f rlf cmd, f movfw cmd andlw b'00000111' goto dispatch_paramcmd send_success: movfw outdata_count movwf count_oct addlw RESPONSE_SUCCESS serial_send_w movlw LOW OUTDATA_ORG movwf FSR ss0: movfw count_oct btfsc STATUS, Z return movfw INDF serial_send_w incf FSR, f decf count_oct, f goto ss0 ; 存在しないコマンドコード cmd_error: movlw RESPONSE_ERROR | 2 serial_send_w movlw EC_COMMAND serial_send_w movlw 0 serial_send_w return ; シーケンスエラー sequence_error: movlw RESPONSE_ERROR | 2 serial_send_w movlw EC_SEQUENCE serial_send_w movlw 0 serial_send_w return cmd_bus_reset: DATAH CLOCKH goto send_success cmd_start: ; CLK=L の場合Srになる DATAH CLOCKH DATAL WAIT_FS .4000, .600, 0 ; tSU;STA CLOCKL ; tLOW (4700/1300)が必要だが、処理により確保 goto send_success cmd_stop: btfsc I2CTRIS, I2CCLK goto sequence_error DATAL nop nop nop CLOCKH WAIT_FS .4000, .600, 0 ; tSU;STO DATAH ; tBUF(4700/1300) 必要だが、処理により確保 goto send_success receive_octet: movlw .8 movwf rd_count DATAH rd1: CLOCKH WAIT_FS .4000, .600, 3 ; tHIGH banksel I2CPORT movfw I2CPORT banksel I2CTRIS CLOCKL WAIT_FS .4700, .1300, 8 ; tLOW rlf rd_data, f bcf rd_data, 0 andlw (1 << I2CDAT) btfss STATUS, Z bsf rd_data, 0 decfsz rd_count, f goto rd1 movfw rd_data return ; RECEIVE_OCTET コマンド処理 ; I2Cバスから1オクテットを読みとり、コントローラーに返す ; ACKビットのクロックは生成しない(ACK/NAKは保留・別コマンドで送出する) cmd_receive_octet: btfsc I2CTRIS, I2CCLK goto sequence_error call receive_octet movlw RESPONSE_SUCCESS | 1 serial_send_w movfw rd_data serial_send_w return cmd_datal: btfsc I2CTRIS, I2CCLK goto sequence_error DATAL CLOCKH WAIT_FS .4000, .600, 0 CLOCKL DATAH goto send_success cmd_datah: btfsc I2CTRIS, I2CCLK goto sequence_error DATAH CLOCKH WAIT_FS .4000, .600, 0 CLOCKL goto send_success cmd_bulk_transmit_octets: btfsc I2CTRIS, I2CCLK goto sequence_error movfw param addlw 1 movwf tx_count movwf count_oct ; PASS1: read data from RS-232C, store to array INDATA_ORG movlw LOW INDATA_ORG movwf FSR cbto1: serial_read movwf INDF incf FSR, f decfsz count_oct, f goto cbto1 ; PASS2: read data from INDATA_ORG length 'transmit_octets' and transmit to I2C movlw LOW INDATA_ORG movwf FSR movfw tx_count movwf count_oct cbto3: movfw INDF movwf tx_data movlw .8 movwf count_bit ; loop for 8 bits cbto2: btfsc tx_data, 7 goto cbto2_h bcf I2CTRIS, I2CDAT goto cbto2_hl cbto2_h: bsf I2CTRIS, I2CDAT cbto2_hl: CLOCKH WAIT_FS .4000, .600, 0 CLOCKL WAIT_FS .4700, .1300, 9 rlf tx_data, f decfsz count_bit, f goto cbto2 ; end of 8 bits loop nop DATAH CLOCKH WAIT_FS .4000, .600, 3 banksel I2CPORT movfw I2CPORT banksel DEFAULT_BANK CLOCKL andlw 1 << I2CDAT btfss STATUS, Z goto cbto_nak_break incf FSR, f decfsz count_oct, f goto cbto3 goto send_success cbto_nak_break movlw RESPONSE_ERROR | 2 serial_send_w movlw EC_NAK serial_send_w movlw LOW INDATA_ORG subwf FSR, W serial_send_w return cmd_bulk_receive_octets btfsc I2CTRIS, I2CCLK goto sequence_error movfw param addlw 1 movwf count_oct movlw LOW OUTDATA_ORG movwf FSR cbro1: call receive_octet DATAL CLOCKH WAIT_FS .4000, .600, 0 CLOCKL DATAH movfw rd_data movwf INDF incf outdata_count, f incf FSR, f decfsz count_oct, f goto cbro1 goto send_success cmd_bulk_receive_octets_nak btfsc I2CTRIS, I2CCLK goto sequence_error movfw param movwf count_oct btfsc STATUS, Z goto onedata movlw LOW OUTDATA_ORG movwf FSR cbron1: call receive_octet DATAL CLOCKH WAIT_FS .4000, .600, 0 CLOCKL DATAH movfw rd_data movwf INDF incf outdata_count, f incf FSR, f decfsz count_oct, f goto cbron1 onedata: ; 最後の1オクテットを受信 & NAK call receive_octet ; DATAH ; receive_octetはDATAHで戻る CLOCKH WAIT_FS .4000, .600, 0 CLOCKL movfw rd_data movwf INDF incf outdata_count, f incf FSR, f goto send_success longwait: movwf wsave ;movlw .5 movlw .1 call wait_w movfw wsave return wait_w: movwf count_w2 wait: wait2: ;;; 約100msループ movlw .100 movwf count_w1 wait1: ;;; 1000 clock loop = 1ms movlw .249 movwf count_w0 nop nop wait0: nop decfsz count_w0, f goto wait0 ;;; decfsz count_w1, f goto wait1 decfsz count_w2, f goto wait2 return ; W <- EEPROM[W] eeread: banksel EECON1 movwf EEADR bcf EECON1, EEPGD bsf EECON1, RD waitee: btfsc EECON1, RD goto waitee movfw EEDAT banksel DEFAULT_BANK return ifdef DEBUG echo: call s_getc serial_send_w goto echo endif hex2nibble: movwf hextmp movlw 0x30 subwf hextmp, w btfss STATUS, C goto h2nfail movlw 0x3a subwf hextmp, w btfss STATUS, C goto h2n_digit movlw 0x41 subwf hextmp, w btfss STATUS, C goto h2nfail movlw 0x47 subwf hextmp, w btfss STATUS, C goto h2n_alpha movlw 0x61 subwf hextmp, w btfss STATUS, C goto h2nfail movlw 0x67 subwf hextmp, w btfss STATUS, C goto h2n_alpha h2nfail: bsf STATUS, C return h2n_digit: movfw hextmp andlw b'00001111' movwf nibble_val return h2n_alpha: movfw hextmp andlw b'00001111' addlw 9 movwf nibble_val return ifdef DEBUG_HEX s_gethex_retry: movlw .7 call s_putc movlw .8 call s_putc s_gethex: movlw ':' call s_putc call s_getc call s_putc ; echo movfw rcdata call hex2nibble btfsc STATUS, C goto s_gethex_retry movwf hexval rlf hexval rlf hexval rlf hexval rlf hexval movlw b'11110000' andwf hexval, f call s_getc call s_putc ; echo movfw rcdata call hex2nibble btfsc STATUS, C goto s_gethex_retry iorwf hexval movfw hexval movwf rcdata ; fake movlw ' ' call s_putc movfw rcdata return s_puthex: movwf hexval movwf hextmp rrf hextmp, f rrf hextmp, f rrf hextmp, f rrf hextmp, w andlw b'00001111' call nibble2hex call s_putc movfw hexval andlw b'00001111' call nibble2hex call s_putc movlw ' ' call s_putc return endif s_putc: banksel PIR1 ; wait TSR empty wait_txif: btfss PIR1, TXIF goto wait_txif movwf TXREG banksel DEFAULT_BANK return s_getc: banksel PIR1 wait_rcif: btfss PIR1, RCIF goto wait_rcif_d movfw RCREG banksel DEFAULT_BANK movwf rcdata return wait_rcif_d: goto wait_rcif ; デバッグ用; アイドル状態でブレーク bank_failure: sleep return if 0 seq_test: movlw 0x01 call exec_cmd_w movlw 0x02 call exec_cmd_w movlw 0x60 call exec_cmd_w movlw 0x02 call exec_cmd_w movlw 0x60 call exec_cmd_w movlw 0x03 call exec_cmd_w goto debug_stop endif if 0 ; RECEIVE_OCTET+NAK, RECEIVE_OCTET+ACK テスト seq_test: movlw 0x01 call exec_cmd_w movlw 0x02 call exec_cmd_w movlw 0x04 call exec_cmd_w movlw 0x07 call exec_cmd_w movlw 0x02 call exec_cmd_w movlw 0x04 call exec_cmd_w movlw 0x06 call exec_cmd_w movlw 0x03 call exec_cmd_w goto debug_stop endif debug_stop: sleep org 0x2100 EE_BRG data .16 EE_BRGH data 0 end