勝手な電子工作・・

勝手なオリジナル電子工作に関する記事を書きます

PICアセンブラ#01-タイミング

f:id:a-tomi:20180924164028j:plain

別の記事にタイミング用(時間消耗用)のルーチンを載せましたが、一部でなく全体のコーディングが知りたい方がおられますので、この際きちんと書いて、測定についても載せておきます。前の記事はこれです。 

プレゼンタイマー(PICアセンブラー版) - 勝手な電子工作・・

測定のための回路ですから簡単です。しかしタイミングのテストですのでオシレータは内部オシレータではなく外部のクリスタルを使ってみます。

f:id:a-tomi:20180924164849j:plain

上の図でクリスタルに16MHzを使います。一般的にその先は22pFを介してグラウンドに落としますが、+側につないでも同じことですね。配線の都合の良い方で大丈夫。

そして、例えば次のコーディングをします。ここでは、タイミング用のルーチンはいつも同じなので、自分で作ったマクロ、Cblock(ファイル)、サブルーチンを.incファイルとしてIncludeしていますが、そこに直接中身を書いても同じことです。後ろにそれぞれのincファイル内容も示します。

ところで、このコーディングの中のinclude文の後ろには<>でファイル名が書かれていますが、それが表示されないようです。やむを得ず{}を書いておきますから、そこを<>に置き換えてください。すみません。


;Utime-test-V00-01.asm					As of Sept.24, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;										;
; 	Testing time-consuming routines						;
;	        All rights reserved. 2018(C) Akira Tominaga			;
;										;
;	  Function								;
;		Timing measurement with logic analyzer			      ;
;		 								;
;	  Input/Output for 12F1822 or 16F1823					;
;		RA0 LED output (on =H) 						;
;		RA1 Timing signals						;
;		RA4 and RA5 for Xtal Oscillator (HS:High speed)			;
;										;
;	  Remarks								;
;		1. Clock = High speed Xtal (16MHz)	 		   ;
;			Hence 1 step = 0.250 micro seconds			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	list		p=12F1822      ; list directive to define processor
	#include	{p12F1822.inc}; processor specific variable definitions
   __CONFIG _CONFIG1, _FOSC_HS & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
   __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_OFF & _STVREN_OFF & _BORV_19 & _LVP_OFF
;
	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Macro definitions						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Device dependent Macros	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DEVset	macro	
	BANKSEL	OSCCON		; Bank=1
	movlw	B'00000000'	; HS 16MHz Xtal oscillator
;	movlw	B'01111010'	; Comment for 16MHz internal oscillator
	movwf	OSCCON
;
;	BANKSEL	INTCON		; Interrupt Con (in all banks hence comment)
	clrf	INTCON		; Disable all interrupts
;
; PORTA initialization
	BANKSEL	PORTA		; Bank=0
	clrf	PORTA
	BANKSEL	LATA		; Bank=2
	clrf	LATA
	BANKSEL	ANSELA		; Bank=3
	clrf	ANSELA		; No use of ADC
	BANKSEL	ADCON0		; Bank=1
	clrf	ADCON0		; No use of ADC
;
	BANKSEL	TRISA		; Bank=1
	movlw	B'11111100'	; RA0 and RA1 are output
	movwf	TRISA
;
;	BANKSEL	OPTION_REG	; Bank=1
	bcf	OPTION_REG,7	; Enable weak pull-up
	BANKSEL	WPUA		; Bank=4
	movlw	B'00001100'	; Weak Pull-up for RA2 and 3
	movwf	WPUA		;  
;
	clrf	BSR		; Bank=0		
	movlw	B'11111100'	; Initialize PORT
	movwf	PORTA
	goto	$+1
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	General purpose macros	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	#include {at-Mtime.inc}	 
	#include {at-Mdebug.inc}	 
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Files and Equations					;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Files				;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	cblock	H'20'		; H'20' to H'6F', 80bytes for 12F1822,etc.
; For application
	LoopC			; Loop counter
	endc
;
; For utilities	
	#include {at-Ctime.inc}	
	#include {at-Cdebug.inc}	
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Equations			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;******************************** ** Comments for real connections
; 	For PORTA		* ** to secure device independence
;******************************** ** Change when PORTs changed **
;LED	equ	0
;Tsig	equ	1		; Test signal
;
;********************************
;	For logical PORTled	* ** Change when PORTled changed **
;********************************
PORTled	equ	PORTA		; PORT for LED
LED	equ	0		; LED bit
;
;;********************************
;	For logical PORTtst	* ** Change when PORTtst changed **
;********************************
PORTtst	equ	PORTA		; PORT for test
Tsig	equ	1		; Test signal bit for measurement
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Values			;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Ten	equ	D'10'
Five	equ	5
Three	equ	3
Two	equ	2
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Flags Byte		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Equ's for utilities	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	#include {at-Edebug.inc}	
;
	page
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Initializing						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	org	0
	goto	Startp		; Go to start entry
	org	4		; This is Interrupt entry
	retfie			; If here, then return
;
Startp	clrf	Flags		; Clear debugging flags
	DEVset			; Define ports and set initial values
;
	LEDon			; Show that I am awake
	Millin	D'100'		; 
	LEDoff			; 
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Main program 						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mainp	equ	$
;
; 1 micro sec x 3 
	movlw	Three
	movwf	LoopC
Mic1x3	bsf	PORTtst,Tsig
	goto	$+1		; 0.5 micro sec
	nop			; 0.25/0.75 micro sec
	bcf	PORTtst,Tsig
	decfsz	LoopC,F		; 0.25 micro sec
	goto	Mic1x3		; 0.75 micro sec
;
; 3 micro sec x 1 (test Mic2n 1)
Mic3t 	bsf	PORTtst,Tsig
	Mic2n	1		; 2.0
	goto	$+1		; /2.5 micro sec
	nop			; /2.75 micro sec
	bcf	PORTtst,Tsig
	Mic2n	1		; 2.0
	goto	$+1		; /2.5 micro sec
	nop			; /2.75 micro sec
;
; 5 micro sec x 1 (test Mic2n 2)
Mic5t	bsf	PORTtst,Tsig
	Mic2n	2		; 4.0
	goto	$+1		; /4.5 micro sec
	nop			; /4.75 micro sec
	bcf	PORTtst,Tsig
	Mic2n	2		; 4.0
	goto	$+1		; /4.5 micro sec
	nop			; /4.75 micro sec
;
; 10 micro sec x 1 (test Mic2p5n x 3)
Mic10t	bsf	PORTtst,Tsig
	Mic2p5n	3		; 7.5
	Mic2n	1		; 9.5
	nop			; 9.75
	bcf	PORTtst,Tsig
	Mic2p5n	3		; 7.5
	Mic2n	1		; 9.5
	nop			; 9.75
;
; 11 micro sec x 1 	(test Mic5n x 2)
Mic11t	bsf	PORTtst,Tsig
	Mic5n	2		; 10
	goto	$+1		; /10.5
	nop			; /10.75
	bcf	PORTtst,Tsig
	Mic5n	2		; 10
	goto	$+1		; /10.5
	nop			; /10.75
;	
; 51 micro sec x 1 	(test Mic50n x 1)
Mic51t	bsf	PORTtst,Tsig
	Mic50n	1		; 50
	goto	$+1		; /50.5
	nop			; /50.75
	bcf	PORTtst,Tsig
	Mic50n	1		; 50
	goto	$+1		; /50.5
	nop			; /50.75
;
; 101 micro sec x 1 	(test Mic50n x 2)
Mic101t	bsf	PORTtst,Tsig
	Mic50n	2		; 100
	goto	$+1		; /100.5
	nop			; /100.75
	bcf	PORTtst,Tsig
	Mic50n	2		; 100
	goto	$+1		; /100.5
	nop			; /100.75
;
; End of timing test
	Secn	1		; wait for 1 sec
	goto 	Mainp		; and loop
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Subroutines						;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Utility subroutines	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
	#include {at-Rtime.inc}	
	#include {at-Rdebug.inc}	
;
	end

Include命令にはタグと同じ<>が入りますから、ここへコードを載せるのに少し苦労してしまいました^^;それでもわかりません。しかたがないので、<>をすべて{}で置き換えて入れてありますので、ご注意ください。

このプログラムを実行して、ロジックアナライザーで測定をすると、タイミングはぴったりになっていることがわかります。最初のアウトプットの箇所です。

f:id:a-tomi:20180924171203j:plain

次に各ファイル(マクロat-Mtime.inc, Cブロックat-Ctime.inc, サブルーチンat-Rtime.inc)を示します。

まずマクロです。

;at-Mtime.inc - Time macros   by Akira Tominaga V08.01
; Mic,Mic2n,Mic2p5n,Mic5n,Mic50n,Millin,Mill100n,Secn,Minn
; As of Sept.16, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Constant time consuming 		;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic	macro			; Consume 1 μS only
	goto	$+1
	goto	$+1
	endm
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;	
;	Time macros with number to multiply	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2n	macro	mic2p		; Consume 2μS x n
	movlw	mic2p
	call	Mic2r
	endm
;
Mic2p5n	macro 	mic25p		; Consume 2.5μS x n
	movlw	mic25p
	call	Mic25r
	endm
;
Mic5n	macro	mic5p		; Consume 5μS x n
	movlw	mic5p
	call	Mic25r
	movlw	mic5p
	call	Mic25r
	endm
;
Mic50n	macro	mic50p		; Consume 50μS x n
	movlw	mic50p
	call	Mic50r
	endm
;
Millin	macro	millip		; Consume 1mS x n
	movlw	millip
	call 	Millir
	endm
;
Mil100n	macro	mil100p		; Consume 100mS x n
	movlw	mil100p
	call 	Mil100r
	endm
; 
Secn	macro	secp		; Consume Second x n
	movlw	secp
	call	Secr
	endm
;
Minn	macro	minp		; Consume Minute x n
	movlw	minp
	call	Minr
	endm
;

 次にCブロックです。endcが済んだ後にcblockを書くと、前のcblockで使われた

次のデータアドレスから始まります。cblockとendcの間には余計なことを書けませんから、書きたいときはそのようにするわけです。つまりincludeの場合だけではなくいつでもそれができます。

;Ctime.inc - Constants for Time macros V08.01  Sept 17, 2018
	cblock
	Mic25c
	Mic50c
	Millic
	Mil100c
	Secc
	Minc
	endc
;  Remarks: Do not change the sequences from Mic25c to Minc,
;  to share the bytes with other sequential-usage purposes.
;

次にサブルーチンです。

;Rtime - Time consuming routines by Akira Toninaga V08-01
;     	As of Sept. 16, 2018
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Timing subrooutines for general purposes;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.0 micro S x n	(Mic2n)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic2r	movwf	Mic25c		; + Wset + call = 1 micro sec 
;
Mic2l	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic2li		; else go out (2nd time 1.75 mic sec)
	return		
;
Mic2li	goto	$+1		;            (2nd time 2.25 mic sec)
	nop			;	     (2nd time 2.5 mic sec)
	goto	Mic2l		; go back    (2nd time 3 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 	Make 2.5 micro S x n (Mic2p5n)	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mic25r	movwf	Mic25c		; + Wset + call = 1 micro sec 
	nop			; 1.25 micro sec
;
Mic25l	nop			; 1.5 micro sec (2nd time 4 mic sec)
	decfsz	Mic25c,F	; If exhausted, 1 micro S hereafter
	goto	Mic25li		; else go out (2nd time 2.25 mic sec)
	return		
;
Mic25li	Mic			;	      (2nd time 3.25 mic sec)
	goto	Mic25l		; go back    (2nd time 3.75 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	50 Microseconds	x n	Mic50n 	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Mic50r	movwf	Mic50c	 	; set # of 50 microsecs (1 micro sec to here)
	nop			; 1.25 micro sec up to here
;
Mic50l	Mic2p5n	D'19'		; + 47.5 = 48.75 mic sec (2nd time 98.75 mic sec)
	nop			; + 0.25 = 49 micro sec (2nd time 99 mic sec)
; 
	decfsz	Mic50c,F	; If exhausted then 1 mic S hereafter
	goto	Mic50li		; else go out (2nd time 49.75 mic sec)
	return
;
;
Mic50li	Mic			; 	  (2nd time 50.75 mic sec)
	goto	Mic50l		; go back (2nd time 51.25 mic sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Milliseconds x n	Millin	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Millir	movwf	Millic 		; set # of 1 mil secs (1 mic S up to here)
	nop			; 1.25 micro sec
;
Millil	Mic50n	D'19'		; + 50 mic x 19 = 951.25 mic S (2nd, 1951.25) 
	Mic2p5n	D'19'		; + 47.5 mic = 998.75 micro S  (2nd, 1998.75)
	nop			; +0.25 mic = 999 micro sec    (2nd, 1999)
;
	decfsz	Millic,F	; If  exhausted then 1 micro sec hereafter
	goto	Millili		; else go out (2nd, 999.75 mic S)
	return
;
Millili	Mic			; 		(2nd time 1000.75 mic S)
	goto	Millil		; go back (2nd time 1001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	100 Milliseconds x n	Mil100n ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Mil100r	movwf	Mil100c		;set # of 100 ms(1 micr sec up to here)
	nop			; 1.25 micro sec
;
Milhl	Millin	D'99'		;+1ms x 99 = 99001.25 micS (2nd,199001.25mic)
	Mic50n	D'19'		; + 950 mic = 99951.25 micS(2nd.199951.25mic)
	Mic2p5n	D'19'		; + 47.5 mic = 99998.75micS(2nd,199998.75mic)
	nop			; + 0.25 mic = 99999 mic S (2nd,199999 micS)
;
	decfsz	Mil100c,F	; If exhausted then 1 micro sec hereafter
	goto	Milhli		; else go out (2nd time, 99999.75 mic S)
	return
;
Milhli	Mic			;  	    	(2nd time, 100000.75 mic S)
	goto	Milhl		; 		(2nd time, 100001.25 mic S)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Seconds x n	   	Secn	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
Secr	movwf	Secc 		; set # of seconds ( 1 mic sec up to here)
	nop			; 1.25 micro sec
;
Secl	Mil100n	D'9'		; 
	Millin	D'99'		; + 999 milli sec = 999001.25 micro sec
;
	Mic50n	D'19'		; + 950 mic = 999951.25 micro sec
	Mic2p5n	D'19'		; + 47.5 mic = 999998.75 micro sec
	nop			; + 0.25 mic = 999999 micro sec
;
	decfsz	Secc,F		; If exhausted then 1 micro sec hereafter
	goto	Secli		; else, go out 
	return
;
Secli	Mic
	goto	Secl		; (Second time, Sec + 1.25 micro sec)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	Minutes	x n	 	Minn	;
;	 Overhead ignored, that is only	;
;	 751.25 Mic S even when 100 Min	;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
Minr	movwf	Minc		;set # of minutes from parameter
;
Minl	Secn	D'60'		; 1 Seconds x 60
	decfsz	Minc,F
	goto	Minl
	return
;

内部にタグのマークがあるコーディングでしたため、うまく表示するのがたいへんで結局あきらめて別文字を入れました。すみません。何かやりかたがあるのでしょうね、その知識がなくてすみません。後で調べてみます。

それはそうと、コーディング中にあるLEDonとLEDoffのマクロ命令ですが、これらはデバッグ用マクロの塊にしている、at-Mdebug.incの中で定義しています。これを開くと、読み手は混乱するでしょうから、該当のマクロだけをここに書いておきます。


    LEDon	macro
	goto	$+1
	bsf	PORTled,LED
	goto	$+1
	endm
;
LEDoff	macro
	goto	$+1
	bcf	PORTled,LED
	goto	$+1
	endm
;

なぜgoto $+1があるかというと、ここでクロック2サイクルを消耗させるためです。PICでは同一ポートへのアクセスの間で2サイクルの間をとらないとIOが正しく動きません。このマクロの直前に何が書かれるかわからないわけで、同じPORTへの更新がないとは限りません。それでも大丈夫なように、PORT更新の前と後にそれぞれCPUクロック2サイクルを消耗させるのです。nop命令2個でもよいですが、そうすると全体でプログラムメモリーを4つ使うため、この命令で2つに減らすものです。

また、なぜPORT名を直接指定しないかといえば、このマクロはどのPICモデルでも共通に使いたいわけですし、そもそも、どのポートにLEDをつけるかというのも、配線の都合などで自由にしておきたいものです。ですから、論理的なポート名PORTledを定義し、プログラムの本体では PORTled equ PORTAとするもの。つまり「デバイスインデペンス」を確保するためです。このようなアセンブラーの組み方は、保守や変更を極めて容易にします。どのコンピュータでもプロのコーディングでは定石となっている、数あるテクニックの1つといえます。

 (c)2018 Akira Tominaga, All rights reserved.