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のシミュレータ機能を使ってデバッグをしてみます。(続く)



コメント