;--------------------------------------------------------------------- ; FM radio tuner (RDA5807M) コントローラ ; ; 2019.09.19 naka ; Ver.2 2019.10.27 naka ; Ver.2.1 2021.03.03 naka ; 1. 概要 ; RDA5807MをI2Cでつなぎ、チャンネル(周波数)設定などを行い、 ; 局名、周波数を小型LCDディスプレイに表示する。 ; ; 選局情報はPICのFlash Memoryに覚えておき次回電源オン時に復帰する。 ; ; 2. ピンアサイン ; ; (1). RA0 [in]: SW Channel Up (ICSP DAT) ; (2). RA1 [in]: SW Channel Down (ICSP CLK) ; (3). RA2 [out]: LED(デバッグ時に使用) ; (4). RA3 [in] : (VPP) ; (5). RA4 [in] : I2C SDA ; (6). RA5 [in] : I2C SCL ; ; 3. ToDo(やってもよいかと思うこと) ; ・音量コントロール ; 当初、100円位の安いアンプを繋ぎ、ボリウムはRDA5807Mの設定で ; コントロールしようと考えていた。しかしダイソーの300円USBスピーカに ; ボリウム付きアンプが載っていたので、それをそのまま利用した。 ; ・ステレオ/モノラル表示 ; RDA5807Mには受信状態によってステレオ/モノラルのフラグがある ; のでそれを表示する。 ; ・モノラル受信 ; 強制モノラル受信もできるようなので、電波状態がよくないときに ; モノラル受信モードにする。 ; ・信号レベル表示 ; 電波の信号レベルをレベルインジケータのように表示する。 ; LCDには任意の図形を登録できるので、その機能を使う。 ; ; 4. 備考 ; ・動作クロック :内蔵OSC 8MHz ; ; 5. 改版履歴 ; Ver.2.1 2021.03.03 ; 電源投入時に電池の残量を表示. ; AD変換のパラメタと処理が適切でなかったので修正. ; ; Ver.2 2019.10.27 ; VDD電圧を測定して、液晶表示のコントラストを自動調整. ; 自動調整のタイミングは、電源投入時、スイッチ操作時。 ; ;--------------------------------------------------------------------- ;--------------------------------------------------------------------- ; デバイス定義 ;--------------------------------------------------------------------- LIST P=PIC12F1501 INCLUDE "P12F1501.INC" __CONFIG _CONFIG1, _FOSC_INTOSC & _CP_OFF & _BOREN_OFF & _MCLRE_OFF & _PWRTE_ON & _WDTE_OFF & _CLKOUTEN_OFF & 0x3FFF __CONFIG _CONFIG2, _WRT_OFF & _STVREN_ON & _LVP_OFF & 0x3FFF ERRORLEVEL -302 ;アセンブル時のバンク警告メッセージ抑制 ;--------------------------------------------------------------------- ; 変数レジスタの定義 ;--------------------------------------------------------------------- WAIT1 EQU H'20' WAIT2 EQU H'21' CNT EQU H'22' TMP EQU H'23' TMP2 EQU H'24' I2CADDR EQU H'25' FREQH EQU H'26' FREQL EQU H'27' ; binH EQU H'28' binL EQU H'29' bcdH EQU H'2A' bcdM EQU H'2B' bcdL EQU H'2C' counter EQU H'2D' temp EQU H'2E' sign EQU H'2F' ACCaHI EQU H'30' ACCaLO EQU H'31' ACCbHI EQU H'32' ACCbLO EQU H'33' ACCcHI EQU H'34' ACCcLO EQU H'35' ACCdHI EQU H'36' ACCdLO EQU H'37' ; CHANNEL EQU H'70' ; どのBANKからも読み書きできる場所 ADCH EQU H'71' ADCL EQU H'72' ; ;--------------------------------------------------------------------- ; マクロ定義 ;--------------------------------------------------------------------- LCDTEXT MACRO text MOVLW HIGH text MOVWF FSR1H MOVLW LOW text MOVWF FSR1L ENDM ; ;--------------------------------------------------------------------- ; フラッシュ(不揮発記憶用) ;--------------------------------------------------------------------- ORG 380H ; HEFメモリ DW 0x000 ; Channel初期値 ; ;--------------------------------------------------------------------- ; リセットベクタ ;--------------------------------------------------------------------- ORG 00H ; リセット時の飛び込み先 GOTO MAIN ; ; ORG 04H ; 割り込み時の飛び込み先 ;--------------------------------------------------------------------- ; 割り込み処理(SW RA0,RA1の立下り割り込み) ;--------------------------------------------------------------------- INTRUPT CLRF INTCON ;全割込み禁止 CALL W20MS ; BANKSEL IOCAF BTFSC IOCAF,0 GOTO INT_UP BTFSC IOCAF,1 GOTO INT_DOWN CLRF IOCAF BANKSEL 0 GOTO INT_RET ; INT_UP ; 選局アップ BCF IOCAF,0 BANKSEL 0 BTFSC PORTA,0 ; SW low 確認 GOTO INT_RET INCF CHANNEL,F MOVF CHANNEL,W SUBLW D'10' BTFSC STATUS,Z CLRF CHANNEL ; CHANNEL = 0〜9 CALL CHSELECT BTFSS PORTA,0 GOTO $-1 GOTO INT_SET ; INT_DOWN ; 選局ダウン BCF IOCAF,1 BANKSEL 0 BTFSC PORTA,1 ; SW low 確認 GOTO INT_RET DECF CHANNEL,F MOVF CHANNEL,W SUBLW D'255' BTFSS STATUS,Z GOTO $+3 MOVLW D'9' ; CHANNEL = 0〜9 MOVWF CHANNEL CALL CHSELECT BTFSS PORTA,1 GOTO $-1 ; INT_SET CALL ERASFLSH ; CHANNEL情報をFlashに記憶 CALL WRITFLSH ; CALL W20MS ; INT_RET MOVLW B'10001000' ; 割り込み許可 GIE,IOCIE MOVWF INTCON ; RETFIE ;--------------------------------------------------------------------- ; メイン処理 ;--------------------------------------------------------------------- MAIN CALL INIT ; LCDTEXT MSGDT ; 電源オン時の起動メニュー(LCD) CALL DSPTXT ; CALL VDDCHK ; VDD測定 CALL VDD2CNT ; VDD電圧に応じてコントラスト設定 ; CALL BATTPTN ; バッテリ表示パターン登録 CALL VDDCHK ; VDD測定 CALL BATTDSP ; バッテリ表示 CALL W05S ; 表示時間分 wait 1秒 CALL W05S ; CALL READFLSH ; 前回のチャンネル情報を復帰 CALL CHSELECT ; MAIN_LP SLEEP CALL VDDCHK ; VDD測定 CALL VDD2CNT ; VDD電圧に応じてコントラスト設定 GOTO MAIN_LP ; MSGDT DT " Ver.2.1"," " ; ;--------------------------------------------------------------------- ; 初期化 ;--------------------------------------------------------------------- INIT CLRF INTCON ;全割込み禁止 ; BANKSEL PORTA CLRF PORTA BANKSEL LATA CLRF LATA BANKSEL ANSELA CLRF ANSELA ; digital I/O BANKSEL TRISA MOVLW B'00000011' ; RA0,RA1 input MOVWF TRISA BANKSEL OSCCON MOVLW B'01110010' ; 8MHz MOVWF OSCCON ; ; AD変換用設定 BANKSEL FVRCON MOVLW B'10000001' ; 7:FVR enable, 1-0:00 FVR 1.024V MOVWF FVRCON BANKSEL ADCON0 MOVLW B'01111100' ; FVR利用 MOVWF ADCON0 MOVLW B'00100000' ; 7:左詰, 1-0:00 VRPOS is connected to VDD MOVWF ADCON1 ; ; 外部割込み設定 BANKSEL OPTION_REG CLRF OPTION_REG BANKSEL IOCAP CLRF IOCAP MOVLW B'00000011' ; RA0,RA1 Negative edge interupt MOVWF IOCAN BANKSEL 0 ; CLRF CHANNEL ; 後でflashから復元された値が入る ; CALL LCDINIT ; MOVLW B'10001000' ; 割り込み許可 GIE,IOCIE MOVWF INTCON RETURN ; ;--------------------------------------------------------------------- ; 選局(CHANNEL) ;--------------------------------------------------------------------- CHSELECT MOVLW HIGH FMDATA ; 局名テーブル MOVWF FSR1H MOVLW LOW FMDATA MOVWF FSR1L ; MOVF CHANNEL,W MOVWF TMP ; BCF STATUS,C ; 18倍(テーブルサイズが18byte/局) RLF TMP,W ; 2 MOVWF TMP MOVWF TMP2 RLF TMP,F ; 4 RLF TMP,F ; 8 RLF TMP,W ; 16 ADDWF TMP2,W ADDWF FSR1L,F ; 局名テーブルに加算 CLRW ADDWFC FSR1H,F ; キャリー加算 CALL DSPTXT ; 局名表示 ; CALL GETFREQ ; 周波数取り出し CALL SETFREQ ; 周波数設定 RETURN ; GETFREQ MOVF INDF1,W MOVWF FREQH ADDFSR FSR1,1 MOVF INDF1,W MOVWF FREQL RETURN ; ; 周波数設定値の計算方法 ; 例) ; TOKYO FM 80.0MHz = 100KHz x CHAN + 76.0MHz ; CHAN= D'40' = H'28' = B'00001010,00' FMDATA ; 1局あたり18byte ; LCD 1行目 LCD 2行目 周波数 局No. DT "NACK5 "," 79.5MHz",B'00001000',B'11011000' ; 0 DT "TOKYO FM"," 80.0MHz",B'00001010',B'00011000' ; 1 DT "J-WAVE "," 81.3MHz",B'00001101',B'01011000' ; 2 DT "NHK YKH "," 81.9MHz",B'00001110',B'11011000' ; 3 DT "NHK TKO "," 82.5MHz",B'00010000',B'01011000' ; 4 DT "YOKOHAMA"," 84.7MHz",B'00010101',B'11011000' ; 5 DT "InterFM "," 89.7MHz",B'00100010',B'01011000' ; 6 DT "TBS FM "," 90.5MHz",B'00100100',B'01011000' ; 7 DT "BUNKA FM"," 91.6MHz",B'00100111',B'00011000' ; 8 DT "NIPPON "," 93.0MHz",B'00101010',B'10011000' ; 9 ; ;--------------------------------------------------------------------- ; 周波数設定 ;--------------------------------------------------------------------- SETFREQ MOVLW H'20' ; I2Cアドレス CALL I2CWSTART ; ; Reg 0x02 MOVLW B'11010000' ; DHIZ,DMUTE,MONO,BASS,RCLK,RCLK,SEEKUP,SEEK MOVWF datao CALL TX MOVLW B'00000001' ; SKMODE,CLK_MODE[2:0],RDS_EN,NEW_METHOD,SOFT_RESET,ENABLE MOVWF datao CALL TX ; ; Reg 0x03 MOVF FREQH,W ; CHAN[9:2] MOVWF datao CALL TX MOVF FREQL,W ; CHAN[1:0],DIRECT MODE, TUNE,BAND[1:0],SPACE[1:0] MOVWF datao CALL TX ; Reg 0x04 MOVLW B'00000000' ; RSVD[15:12],DE,RSVD,SOFTMUTE_EN,AFCD MOVWF datao CALL TX MOVLW B'00000000' ; MOVWF datao CALL TX ; Reg 0x05 MOVLW B'10001000' ; INT_MODE,RSVD,SEEKTH[3:0] MOVWF datao CALL TX MOVLW B'10001111' ; ,RSVD,VOLUME[3:0] MOVWF datao CALL TX ; CALL I2CSTOP ; RETURN ;--------------------------------------------------------------------- ; 文字列表示 ; 表示する文字列はLCDTEXTマクロで指定 ;--------------------------------------------------------------------- DSPTXT MOVLW D'16' MOVWF CNT CLRF TMP ; MOVLW H'80' + H'00' ; LCD1行目先頭へ CALL LCDCMD DSPTXTLP MOVF CNT,W SUBLW D'8' ; 9文字目以上は2行目に表示 BTFSS STATUS,Z GOTO DSPTXT1 MOVLW H'80' + H'40' ; LCD2行目先頭へ CALL LCDCMD DSPTXT1 MOVF INDF1,W CALL LCDDATA ; MOVWF INDF1 ADDFSR FSR1,1 INCF TMP,F DECFSZ CNT,F GOTO DSPTXTLP ; RETURN ; ; ;--------------------------------------------------------------------- ; LCD初期化(データシート通り) ;--------------------------------------------------------------------- LCDINIT CALL W20MS ; 電源が安定するまでの待ち時間 CALL W20MS ; MOVLW H'38' ; Function set CALL LCDCMD ; MOVLW H'39' ; Functino set CALL LCDCMD ; MOVLW H'14' ; Intrenal OSC frequency CALL LCDCMD ; ; ; Contrast= B'10 1000' = D'40' MOVLW H'70'+H'08' ; Contrast set CALL LCDCMD ; MOVLW H'54'+H'02' ; Power/ICON/Contrast control CALL LCDCMD ; MOVLW H'6C' ; Follower control CALL LCDCMD CALL W200MS ; MOVLW H'38' ; Function set CALL LCDCMD ; MOVLW H'0C' + H'01' ; Display ON/OFF control CALL LCDCMD ; MOVLW H'01' ; Clear Display CALL LCDCMD ; RETURN ; ;--------------------------------------------------------------------- ; VDD to LCDコントラスト ;--------------------------------------------------------------------- VDD2CNT ; MOVLW D'60' ; 2.65V で濃すぎる ; MOVLW D'50' ; 2.65V で丁度よい ; MOVLW D'40' ; 2.65V でちょっと薄い ; MOVLW D'30' ; 6ビット 0〜63 2.65Vで薄くてギリギリ ; MOVLW D'40' ; 3.15V でちょっと濃い ; MOVLW D'35' ; 3.15V で丁度よい ; MOVLW D'30' ; 3.15V でちょっと薄い ; ; 3.2V〜2.4V --> 30〜50の間 ; ; 320〜240 ; ; c = 110 - VDD(0.01V単位) / 4 BCF STATUS,C ; VDD/4 (2bitシフト) RRF ACCbHI,F RRF ACCbLO,F BCF STATUS,C RRF ACCbHI,F RRF ACCbLO,W SUBLW D'110' CALL LCDCNT RETURN ; ;--------------------------------------------------------------------- ; LCDコントラスト (W:コントラスト) ;--------------------------------------------------------------------- LCDCNT MOVWF TMP2 ; MOVLW H'39' ; Function set CALL LCDCMD ; MOVF TMP2,W ; コントラスト ANDLW H'0F' ; 下位4ビット IORLW H'70' CALL LCDCMD SWAPF TMP2,W ANDLW H'03' ; 上位2ビット IORLW H'54' CALL LCDCMD ; MOVLW H'38' ; Function set CALL LCDCMD ; RETURN ;--------------------------------------------------------------------- ; LCDコマンド (W:CMD) ;--------------------------------------------------------------------- LCDCMD MOVWF TMP ; 一時退避 ; MOVLW H'7C' ; I2Cアドレス CALL I2CWSTART MOVLW H'00' ; Command (RS=0) MOVWF datao CALL TX MOVF TMP,W MOVWF datao CALL TX CALL I2CSTOP ; MOVLW H'01' ; Clear Display SUBWF TMP,W BTFSC STATUS,Z GOTO LCDW1MS MOVLW H'02' ; Return Home SUBWF TMP,W BTFSC STATUS,Z GOTO LCDW1MS ; CALL W27US ; Normal command RETURN LCDW1MS CALL W1MS RETURN ; ;--------------------------------------------------------------------- ; LCD データ(Wレジ内容をLCDに書き込む) ;--------------------------------------------------------------------- LCDDATA MOVWF TMP ; 書き込みデータ一時退避 ; MOVLW H'7C' CALL I2CWSTART ; MOVLW H'40' ; Data (RS=1) MOVWF datao CALL TX ; MOVF TMP,W MOVWF datao CALL TX ; CALL I2CSTOP ; RETURN ; ;--------------------------------------------------------------------- ; VDD測定(結果0.01V単位 ACCbHI,ACCbLO) ;--------------------------------------------------------------------- VDDCHK ; VDDをAD変換で測定 BANKSEL ADCON0 BSF ADCON0,0 ; ADCON enable BANKSEL 0 CALL W1MS ;Acquisiton delay BANKSEL ADCON0 BSF ADCON0,ADGO ;Start conversion BTFSC ADCON0,ADGO ;Is conversion done? GOTO $-1 BANKSEL ADRESH MOVF ADRESH,W ;Read upper 2 bits MOVWF ADCH ;store in GPR space MOVF ADRESL,W ;Read lower 8 bits MOVWF ADCL ;Store in GPR space BANKSEL 0 ; ; ADC結果は左詰上位8ビットのみ利用(0〜255) ; 電圧値に変換 1.024:vdd=ADC:255 ... vdd = 1.024*255/adc ; VDD = 1.024 * 100 * 255 / ADC (0.01V単位にするため100倍) ; VDD = 26520 / ADC ; D'26520' = H'6798' MOVLW H'67' MOVWF ACCbHI MOVLW H'98' MOVWF ACCbLO ; CLRF ACCaHI MOVF ADCH,W ; AD変換結果上位8ビット MOVWF ACCaLO CALL D_divS ; ACCb/ACCa = ACCb ... ACCc RETURN ; ;--------------------------------------------------------------------- ; バッテリ表示 __[***]_ ;--------------------------------------------------------------------- BATTDSP CLRF ACCaHI ; 0.1V単位にするため VDD/10 ... ACCb/ACCa MOVLW D'10' MOVWF ACCaLO CALL D_divS ; ; VDD 0.1V単位... 0〜32位(3.2V) なのでLOのみ ; MOVLW H'80' + H'42' ; カーソル位置をLCD2行目先頭へ CALL LCDCMD MOVLW D'0' CALL LCDDATA ; MOVLW D'20' ; 2V CALL BATTCELL ; MOVLW D'25' ; 2.5V CALL BATTCELL ; MOVLW D'30' ; 3V CALL BATTCELL ; MOVLW D'2' CALL LCDDATA ; MOVLW ' ' CALL LCDDATA ; RETURN ; ;--------------------------------------------------------------------- ; バッテリ セル表示(Wレジに閾電位 30,25,20) ;--------------------------------------------------------------------- BATTCELL SUBWF ACCbLO,W BTFSC STATUS,C GOTO $+3 MOVLW D'1' GOTO $+2 MOVLW D'3' CALL LCDDATA RETURN ; ;--------------------------------------------------------------------- ; バッテリ表示用パターン登録 ;--------------------------------------------------------------------- BATTPTN MOVLW HIGH BATTDT ; バッテリパターン MOVWF FSR1H MOVLW LOW BATTDT MOVWF FSR1L ; MOVLW D'32' ; 8x4 MOVWF CNT MOVLW H'40' ; CGRAMアドレス CALL LCDCMD BATTPTNLP MOVF INDF1,W CALL LCDDATA MOVLW D'1' ADDWF FSR1L,F BTFSC STATUS,C INCF FSR1H,F DECFSZ CNT,F GOTO BATTPTNLP ; BATTDT DT B'00000011' DT B'00000010' DT B'00000010' DT B'00000010' DT B'00000010' DT B'00000010' DT B'00000010' DT B'00000011' ; DT B'00011111' DT B'00000000' DT B'00000000' DT B'00000000' DT B'00000000' DT B'00000000' DT B'00000000' DT B'00011111' ; DT B'00011000' DT B'00001000' DT B'00001110' DT B'00000010' DT B'00000010' DT B'00001110' DT B'00001000' DT B'00011000' ; DT B'00011111' DT B'00000000' DT B'00011111' DT B'00011111' DT B'00011111' DT B'00011111' DT B'00000000' DT B'00011111' ; ;--------------------------------------------------------------------- ; ウェイト色々 ;--------------------------------------------------------------------- W27US MOVLW D'18' MOVWF WAIT1 W27USLP DECFSZ WAIT1,F GOTO W27USLP RETURN ; W1MS MOVLW D'221' MOVWF WAIT1 W1MSLP GOTO $+1 GOTO $+1 GOTO $+1 DECFSZ WAIT1,F GOTO W1MSLP GOTO $+1 GOTO $+1 GOTO $+1 RETURN ; W20MS MOVLW D'20' MOVWF WAIT2 W20MSLP CALL W1MS DECFSZ WAIT2,F GOTO W20MSLP RETURN ; W200MS MOVLW D'200' MOVWF WAIT2 W200MSLP CALL W1MS DECFSZ WAIT2,F GOTO W200MSLP RETURN ; W05S MOVLW D'100' MOVWF WAIT2 W05SLP CALL W1MS CALL W1MS CALL W1MS CALL W1MS CALL W1MS DECFSZ WAIT2,F GOTO W05SLP RETURN ; ;--------------------------------------------------------------------- ; 16ビット割り算 ;--------------------------------------------------------------------- TRUE equ 1 MSB equ 7 ;******************************************************************* SIGNED equ TRUE ; Set This To 'TRUE' if the routines ; ; for Multiplication & Division needs ; ; to be assembled as Signed Integer ; ; Routines. If 'FALSE' the above two ; ; routines ( D_mpy & D_div ) use ; ; unsigned arithmetic. ;******************************************************************* ; Double Precision Divide ( 16/16 -> 16 ) ; ; ( ACCb/ACCa -> ACCb with remainder in ACCc ) : 16 bit output ; with Quotiont in ACCb (ACCbHI,ACCbLO) and Remainder in ACCc (ACCcHI,ACCcLO). ; ; NOTE : Before calling this routine, the user should make sure that ; the Numerator(ACCb) is greater than Denominator(ACCa). If ; the case is not true, the user should scale either Numerator ; or Denominator or both such that Numerator is greater than ; the Denominator. ; ; D_divS ; IF SIGNED CALL S_SIGN ENDIF ; call setup clrf ACCcHI clrf ACCcLO dloop bcf STATUS,C rlf ACCdLO, F rlf ACCdHI, F rlf ACCcLO, F rlf ACCcHI, F movf ACCaHI,W subwf ACCcHI,W ;check if a>c btfss STATUS,Z goto nochk movf ACCaLO,W subwf ACCcLO,W ;if msb equal then check lsb nochk btfss STATUS,C ;carry set if c>a goto nogo movf ACCaLO,W ;c-a into c subwf ACCcLO, F btfss STATUS,C decf ACCcHI, F movf ACCaHI,W subwf ACCcHI, F bsf STATUS,C ;shift a 1 into b (result) nogo rlf ACCbLO, F rlf ACCbHI, F decfsz temp, F ;loop untill all bits checked goto dloop ; IF SIGNED btfss sign,MSB ; check sign if negative retlw 0 goto neg_B ; negate ACCa ( -ACCa -> ACCa ) ELSE retlw 0 ENDIF ; ;******************************************************************* ; setup movlw .16 ; for 16 shifts movwf temp movf ACCbHI,W ;move ACCb to ACCd movwf ACCdHI movf ACCbLO,W movwf ACCdLO clrf ACCbHI clrf ACCbLO retlw 0 ; ;******************************************************************* ; neg_A comf ACCaLO, F ; negate ACCa ( -ACCa -> ACCa ) incf ACCaLO, F btfsc STATUS,Z decf ACCaHI, F comf ACCaHI, F retlw 0 ; neg_B comf ACCbLO, F ; negate ACCb ( -ACCb -> ACCb ) incf ACCbLO, F btfsc STATUS,Z decf ACCbHI, F comf ACCbHI, F retlw 0 ; ;******************************************************************* ; Assemble this section only if Signed Arithmetic Needed ; IF SIGNED ; S_SIGN movf ACCaHI,W xorwf ACCbHI,W movwf sign btfss ACCbHI,MSB ; if MSB set go & negate ACCb goto chek_A ; comf ACCbLO,F ; negate ACCb incf ACCbLO,F btfsc STATUS,Z decf ACCbHI,F comf ACCbHI,F ; chek_A btfss ACCaHI,MSB ; if MSB set go & negate ACCa retlw 0 goto neg_A ; ENDIF ; ;--------------------------------------------------------------------- ; I2Cアクセスルーチン ; 流用元:Microchip Applicatin Note : AN982 ; Interfacing I2C Serial EEPROMs to PIC10 and PIC12 Drivers ;--------------------------------------------------------------------- ;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ; ; Filename: i2c_routines.inc ; Date: March 21, 2005 ; File Version: 1.0 ; Assembled using: MPLAB IDE 7.00.00.0 ; ; Author: Chris Parris ; Company: Microchip Technology, Inc. ; ;*******************RAM register definitions********************** #define STARTRAM 0x40 ; Start RAM at address 0x40 cblock STARTRAM buffer ; Transfer/Receive bit buffer datai ; Data input byte buffer datao ; Data output byte buffer bitcount ; Bit loop counter bytecount ; Byte loop counter addressH ; Word address pointer addressL ; Word address pointer loops ; Delay loop counter loops2 ; Delay loop counter pollcnt ; Polling loop counter endc ;*******************Bit definitions******************************* SDA equ 4 ; I2C data pin, PORTA pin GP4 SCL equ 5 ; I2C clock pin, PORTA pin GP5 DO equ 0 ; TX/RX buffer output bit DI equ 1 ; TX/RX buffer input bit ACKB equ 2 ; ACK/NO ACK select bit ;*******************Delay Macros********************************** ; Each macro delay for 1 inst. cycle less than ; required, as the instruction immediately ; before the macro call provides 1 inst. cycle. ;***************************************************************** THIGH macro ; Clock high time delay (5 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) nop ; 0.5us endm THDSTA macro ; Start condition hold time delay (5 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) nop ; 0.5us endm TSUSTA macro ; Start condition setup time delay (5 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) nop ; 0.5us endm TSUSTO macro ; Stop condition setup time delay (5 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) nop ; 0.5us endm TAA macro ; Output valid from clock delay (4 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) goto $+1 ; 2-inst. cycle delay (1 us) nop ; 0.5us endm ;------------------------------------------------------------------- ; I2Cアクセス ;------------------------------------------------------------------- I2CWSTART MOVWF I2CADDR ; I2Cアドレス退避 movlw .8 movwf bytecount ; Initialize counter to 16 bytes txbyte call BSTART ; Generate start bit ; Now send the control byte ; for a write, to set address movf I2CADDR,W ; I2Cアドレス movwf datao ; Copy control byte to buffer call TX ; Output control byte to device ; Next, the address pointer RETURN I2CSTOP CALL NOACK call BSTOP ; Generate stop bit RETURN ; I2CRSTART IORLW H'01' MOVWF I2CADDR ; I2Cアドレス退避 movlw .8 movwf bytecount ; Initialize counter to 16 bytes rxbytec call BSTART ; Generate start bit ; Now send the control byte ; for a write, to set address movf I2CADDR,W movwf datao ; Copy control byte to buffer call TX ; Output control byte to device clrf datao ; 0x00アドレス call TX ; Output address to device call BSTART ; Generate another start bit ; to switch to read mode movf I2CADDR,W movwf datao ; Copy control byte to buffer call TX ; Output control byte to device ; Finally, read the data byte RETURN ;*******************Start bit subroutine************************** ; This routine generates a Start condition ; (high-to-low transition of SDA while SCL ; is still high. ;***************************************************************** BSTART bsf PORTA,SCL ; Make sure SCL is high TSUSTA ; Start condition setup time delay BANKSEL 1 BCF TRISA,SDA ; Configure SDA to be an output BANKSEL 0 bcf PORTA,SDA ; Pull SDA low to initiate ; Start condition THDSTA ; Start condition hold time delay bcf PORTA,SCL ; Bring SCL low in preparation ; for data transfer BANKSEL 1 BSF TRISA,SDA ; Configure SDA to be an input BANKSEL 0 retlw 0 ;*******************Stop bit subroutine*************************** ; This routine generates a Stop condition ; (low-to-high transition of SDA while SCL ; is still high. ;***************************************************************** BSTOP BANKSEL 1 BCF TRISA,SDA ; Configure SDA to be an output BANKSEL 0 bcf PORTA,SDA ; Pull SDA low bsf PORTA,SCL ; Make sure SCL is high TSUSTO ; Stop condition setup time delay BANKSEL 1 BSF TRISA,SDA ; Configure SDA to be an input BANKSEL 0 retlw 0 ;*******************Bit output subroutine************************* ; This routine outputs bit 'DO' in 'buffer' to ; the serial EEPROM device. ;***************************************************************** BITOUT bcf PORTA,SCL ; Make sure SCL is low btfss buffer,DO ; Check for state of bit to xmit goto bitlow ; If bit is low, pull SDA low clockout ; If bit is high, leave SDA high bsf PORTA,SCL ; Bring SCL high to begin transfer THIGH ; Clock high time delay bcf PORTA,SCL ; Bring SCL low again BANKSEL 1 BSF TRISA,SDA ; Configure SDA to be an input BANKSEL 0 retlw 0 bitlow BANKSEL 1 BCF TRISA,SDA ; Configure SDA to be an output BANKSEL 0 bcf PORTA,SDA ; Pull SDA low goto clockout ;*******************Bit input subroutine************************** ; This routine inputs a bit of data from the ; serial EEPROM device, and stores it in bit ; 'DO' of 'buffer'. ;***************************************************************** BITIN bcf PORTA,SCL ; Make sure SCL is low BANKSEL 1 BSF TRISA,SDA ; Configure SDA to be an input BANKSEL 0 bsf buffer,DI ; Assume input bit is high bsf PORTA,SCL ; Bring SCL high to begin transfer TAA ; Output valid from clock delay btfss PORTA,SDA ; Check for state of SDA bit bcf buffer,DI ; If SDA is low, set bit low bcf PORTA,SCL ; Bring SCL low again retlw 0 ;*******************Data transmit subroutine********************** ; This routine transmits the byte of data ; stored in 'datao' to the serial EEPROM ; device. Instructions are also in place ; to check for an ACK bit, if desired. ; Just replace the 'goto' instruction, ; or create an 'ackfailed' label, to provide ; the functionality. ;***************************************************************** TX movlw .8 movwf bitcount ; Initialize loop counter to 8 txlp bsf buffer,DO ; Assume output bit is high btfss datao,7 ; Check state of next output bit bcf buffer,DO ; If low, set buffer bit low call BITOUT ; Call routine to output bit rlf datao,F ; Rotate datao left for next bit decfsz bitcount,F ; Decrement counter, check if done goto txlp ; Keep looping ; call BITIN ; Call routine to read ACK bit CALL ACK retlw 0 ;*******************Data receive subroutine*********************** ; This routine reads in one byte of data from ; the serial EEPROM device, and stores it in ; 'datai'. It then responds with either an ; ACK or a NO ACK bit, depending on the value ; of 'ACKB' in 'buffer'. ;***************************************************************** RX clrf datai ; Clear input buffer movlw .8 movwf bitcount ; Initialize loop counter to 8 bcf STATUS,C ; make sure carry bit is low rxlp rlf datai,F ; Rotate datai 1 bit left call BITIN ; Read a bit btfsc buffer,DI bsf datai,0 ; Set bit 0 if necessary decfsz bitcount,F ; 8 bits done? goto rxlp ; If not, do another RETLW 0 ACK bcf buffer,DO ; If ACKB = 1, send ACK (DO = 0) call BITOUT ; Send bit retlw 0 NOACK bsf buffer,DO ; If ACKB = 1, send ACK (DO = 0) call BITOUT ; Send bit retlw 0 ; ;--------------------------------------------------------------------- ; flashメモリから読み出す ; W:アドレス ; 0:0x0380 Channel情報 → H'70' ;--------------------------------------------------------------------- READFLSH ; This code block will read 1 word of program ; memory at the memory address: PROG_ADDR_HI : PROG_ADDR_LO ; data will be returned in the variables;PROG_DATA_HI, PROG_DATA_LO BANKSEL PMADRL ; Select Bank for PMCON registers MOVLW H'03' ; 0x0380 から読み出す MOVWF PMADRH ; Store MSB of address MOVLW H'80' ; MOVWF PMADRL ; Store LSB of address BCF PMCON1,CFGS ; Do not select Configuration Space BSF PMCON1,RD ; Initiate read NOP ; Ignored (Figure 10-2) NOP ; Ignored (Figure 10-2) MOVF PMDATL,W ; Get LSB of word MOVWF CHANNEL ; Store in user location BANKSEL 0 RETURN ; ;--------------------------------------------------------------------- ; flashメモリ消去 ; 0x380H 〜 0x38FH (16バイト) ;--------------------------------------------------------------------- ERASFLSH ; This row erase routine assumes the following: ; 1. A valid address within the erase row is loaded in ADDRH:ADDRL ; 2. ADDRH and ADDRL are located in shared data memory 0x70 - 0x7F (common RAM) BCF INTCON,GIE ; Disable ints so required sequences will execute properly BANKSEL PMADRL MOVLW H'03' MOVWF PMADRH MOVLW H'80' MOVWF PMADRL BCF PMCON1,CFGS ; Not configuration space BSF PMCON1,FREE ; Specify an erase operation BSF PMCON1,WREN ; Enable writes MOVLW 55h ; Start of required sequence to initiate erase MOVWF PMCON2 ; Write 55h MOVLW 0AAh ; MOVWF PMCON2 ; Write AAh BSF PMCON1,WR ; Set WR bit to begin erase NOP ; NOP instructions are forced as processor starts NOP ; row erase of program memory. ; ; The processor stalls until the erase process is complete ; after erase processor continues with 3rd instruction BCF PMCON1,WREN ; Disable writes BSF INTCON,GIE ; Enable interrupts BANKSEL 0 RETURN ; ;--------------------------------------------------------------------- ; flashメモリ書き込み ; 0x70H〜0x7FH → 0x380H 〜 0x38FH (16ワード) ;--------------------------------------------------------------------- DATA_ADDR EQU H'70' WRITFLSH ; This write routine assumes the following: ; 1. 32 bytes of data are loaded, starting at the address in DATA_ADDR ; 2. Each word of data to be written is made up of two adjacent bytes in DATA_ADDR, ; stored in little endian format ; 3. A valid starting address (the least significant bits = 00000) is loaded in ADDRH:ADDRL ; 4. ADDRH and ADDRL are located in shared data memory 0x70 - 0x7F (common RAM) BCF INTCON,GIE ; Disable ints so required sequences will execute properly BANKSEL PMADRH ; Bank 3 MOVLW H'03' MOVWF PMADRH ; MOVLW H'80' MOVWF PMADRL ; MOVLW LOW DATA_ADDR ; Load initial data address MOVWF FSR0L ; MOVLW HIGH DATA_ADDR ; Load initial data address MOVWF FSR0H ; BCF PMCON1,CFGS ; Not configuration space BSF PMCON1,WREN ; Enable writes BSF PMCON1,LWLO ; Only Load Write Latches LOOP MOVIW FSR0++ ; Load first data byte into lower MOVWF PMDATL ; MOVIW FSR0++ ; Load second data byte into upper MOVWF PMDATH ; MOVF PMADRL,W ; Check if lower bits of address are '00000' XORLW 0x01 ANDLW 0x01 BTFSC STATUS,Z ; Exit if last of 16 words, GOTO START_WRITE ; MOVLW 55h ; Start of required write sequence: MOVWF PMCON2 ; Write 55h MOVLW 0AAh ; MOVWF PMCON2 ; Write AAh BSF PMCON1,WR ; Set WR bit to begin write NOP ; NOP instructions are forced as processor ; loads program memory write latches NOP ; INCF PMADRL,F ; Still loading latches Increment address GOTO LOOP ; Write next latches START_WRITE BCF PMCON1,LWLO ; No more loading latches - Actually start Flash program ; memory write MOVLW 55h ; Start of required write sequence: MOVWF PMCON2 ; Write 55h MOVLW 0AAh ; MOVWF PMCON2 ; Write AAh BSF PMCON1,WR ; Set WR bit to begin write NOP ; NOP instructions are forced as processor writes ; all the program memory write latches simultaneously NOP ; to program memory. ; After NOPs, the processor ; stalls until the self-write process in complete ; after write processor continues with 3rd instruction BCF PMCON1,WREN ; Disable writes BSF INTCON,GIE ; Enable interrupts BANKSEL 0 RETURN ; ;--------------------------------------------------------------------- END ;--------------------------------------------------------------------- ; 終わり ;---------------------------------------------------------------------