JR-100のビデオ出力信号をNTSC規格になるべく従うよう整形すべく、PICマイコンを使って何とかしようという企画の4回目。前回までで開発環境とデバッグ用のプログラムを作るところまではできました。今回はいよいよPICのプログラムを作っていきます。かなり正確な時間のパルス幅を作る必要があるのと、PICのMIPS値が最大でも8MIPSと余裕がなさそうなことから、アセンブラで記述しています。
まずプログラムに行く前に回路図を少し修正します。
修正のポイントは、PICのインサーキットデバッグをするために、同期信号の入力ピンをRA0からRA2に変更したことと、PICkit3の接続用のポートを設けたところ、最後の加算回路に計算用に入れておいた75Ωの抵抗を削除したことです。インサーキットデバッグについてはShigehiro Kimuraさんの記事(⇒MPLABXとPICKit3でPICをデバッグしてみる)を参考にさせていただきました。PIC16F1705の場合のPICkit3との接続は以下のようにします。
PICkit3のピン番号 | PIC16F1705のピン番号 | ピンの意味 |
---|---|---|
1 | 4 | RA3/MCLR |
2 | 1 | VDD |
3 | 14 | GND |
4 | 13 | RA0/ICSPDAT |
5 | 12 | RA1/ICSPCLK |
6 | 使わない | 使わない |
RA0をデバッグ用に使うため、同期信号の入力を空いているRA2に変更しました。
さてプログラムですがJR-100のNTSC信号を標準化(2)で考えたアルゴリズムをそのまま実装しています。外付け水晶発振子を3.579545MHzのものと8MHzのもので試すため、パラメータのいずれかをコメントアウトして使います。
当初はタイマー2,4,6割り込みをフル活用して同期信号の開始時点を決定していたのですが、割り込み発生時の振り分け処理に多くの命令サイクルを消費してしまうのが厳しいことと、割り込みが発生してから割り込み処理ルーチンに飛んでくるまでの時間(命令サイクル数)が不確定であることから、すべてループを使って適当な時間の待ち時間を発生させるようにしています。なお同期信号を生成している時間以外は何もすることがないので、メインループはただの無限ループです。
; PIC16F1705 Configuration Bit Settings ; Assembly source line config statements #include "p16f1705.inc" ; 3.579545MHz水晶発振子を使用する場合 ; __CONFIG _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON ; __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_ON & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_ON ; COUNT110us EQU d'10' ; COUNT047us EQU d'5' ; COUNT578us EQU d'68' ; 8MHz水晶発振子を使用する場合 __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_ON & _CP_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_ON & _FCMEN_ON __CONFIG _CONFIG2, _WRT_OFF & _PPS1WAY_ON & _ZCDDIS_ON & _PLLEN_ON & _STVREN_ON & _BORV_LO & _LPBOR_OFF & _LVP_ON COUNT110us EQU d'28' COUNT047us EQU d'12' ; 8MHz COUNT578us EQU d'153' ; 3.579545MHz ; VSYNCMODE: 同期信号の検出状態 ; 0: 垂直同期信号未検出 (初期状態) ; 1: 垂直同期信号を検出したが、映像信号も送出している。 ; 2: 垂直同期信号を検出し、映像信号はまだ送出していない。 VSYNCMODE EQU 0x70 ; LINE: フレーム番号 ; 0~2: 垂直同期パルス ; 3~16: 垂直ブランキング後縁 (3~5: 後置等化パルス) ; 17~39: 上部余白期間 ; 40~231: 映像期間 ; 232~252: 下部余白期間 ; 253~255: 垂直ブランキング前縁 (前置等化パルス) LINE EQU 0x71 LOOPCOUNTER EQU 0x72 RES_VECT CODE 0x0000 GOTO START ; 割り込み処理ルーチン ISR CODE 0x0004 ; 割り込み処理 ; BSR==0であることを前提とする。 MOVLB d'7' BTFSS IOCAF,IOCAF2 RETFIE MOVLB d'0' MOVFW VSYNCMODE SUBLW h'01' ; Z=1ならVSYNCMODE=1, C=1ならVSYNCMODE=0, C=0ならVSYNCMODE=2 BTFSC STATUS, Z GOTO VSYNCMODE1 BTFSC STATUS, C GOTO VSYNCMODE0 ; 256回目の立ち下がりエッジを検出する。 VSYNCMODE2 INCFSZ LINE,1 BRA VSYNCMODE2__SKIP MOVLW h'01' MOVWF VSYNCMODE MOVLW d'255' MOVWF LINE VSYNCMODE2__SKIP MOVLB d'7' BCF IOCAF,IOCAF2 MOVLB d'0' RETFIE ; 水平同期のパルス幅が9.05μs、垂直同期のパルス幅は500.7μsである。 ; そこでマージンを含めて11μsの同期信号の状態がLowなら垂直同期と判定する。 VSYNCMODE0 MOVLW COUNT110us MOVWF LOOPCOUNTER VSYNCMODE0__LOOP DECFSZ LOOPCOUNTER,1 BRA VSYNCMODE0__LOOP NOP ; このときのRA2の値がHIGHならHSYNC、LOWならVSYNC BTFSS PORTA,RA2 BRA VSYNC_MODE0__SKIP ; VSYNC検出 MOVLW h'02' MOVWF VSYNCMODE MOVLW d'9' MOVWF LINE VSYNC_MODE0__SKIP MOVLB d'7' BCF IOCAF,IOCAF2 RETFIE ; ライン番号に従って適切な幅の同期パルスを生成する。 VSYNCMODE1 INCFSZ LINE,1 BRA GENERATE_HSYNC GENERATE_VSYNC MOVLB d'7' BCF IOCAP,IOCAP2 ; line0 MOVLB d'0' BCF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE0_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE0_1 NOP BSF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE0_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE0_2 ; line1 BCF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE1_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE1_1 NOP BSF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE1_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE1_2 ; line2 BCF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE2_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE2_1 NOP BSF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE2_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE2_2 ; line3 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE3_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE3_1 BSF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE3_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE3_2 NOP ; line4 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE4_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE4_1 BSF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE4_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE4_2 NOP ; line5 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE5_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE5_1 BSF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE5_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE5_2 NOP ; line6 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE6_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE6_1 BSF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE6_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE6_2 NOP ; line7 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE7_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE7_1 BSF PORTC,RC0 MOVLW COUNT578us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE7_2 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE7_2 NOP ; line8 BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE8_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE8_1 BSF PORTC,RC0 MOVLW d'8' MOVWF LINE MOVLB d'7' BCF IOCAF,IOCAF2 BSF IOCAP,IOCAP2 MOVLB d'0' RETFIE GENERATE_HSYNC NOP BCF PORTC,RC0 MOVLW COUNT047us MOVWF LOOPCOUNTER GENERATE_VSYNC__LINE_1 DECFSZ LOOPCOUNTER,1 BRA GENERATE_VSYNC__LINE_1 BSF PORTC,RC0 MOVLB d'7' BCF IOCAF,IOCAF2 MOVLB d'0' RETFIE MAIN_PROG CODE START ; 初期化 - 割り込み MOVLB d'0' BSF INTCON,PEIE BSF INTCON,IOCIE ; ポートA MOVLB d'1' BSF TRISA,TRISA2 MOVLB d'3' CLRF ANSELA MOVLB d'7' BSF IOCAP,IOCAP2 ; ポートC MOVLB d'1' BCF TRISC,TRISC0 MOVLB d'3' CLRF ANSELC CLRF VSYNCMODE MOVLB d'0' ; 以降の処理はすべてBank0のメモリに対して行う。 BSF PORTC, RC0 ; 同期信号の初期状態はHigh BSF INTCON,GIE LOOP NOP ; 割り込み間隔の安定化のために必要 BRA LOOP END
いきなり実機で実行したくなる気持ちを抑え、まずはこのプログラムをMPLAB X IDEのシミュレータ機能を使ってデバッグをしてみます。(続く)
コメント