R8C/Tinyマイコン基板
掃除をしていると、RenesasのR8C/Tinyのマイコン基板が出てきました。
R8Cは、RenesasのH8とM16Cの合体で作られたマイコン。
H8はHitachi、M16CはMitsubishiの流れをくんでいます
が、CPUがM16CでMC68000のサブセットのようです。
11月に横浜で開催されているETでの販売促進で配布されて
いたものを貰ったはずですが、いつ頃だったのか不明。
オークス電子のM16C Basicは、自費購入していたので
似たCPUを利用してのアセンブリ言語理解に使います。
オークス電子のM16Cには、拡張基板がなかったので万能基板に
必要な部品を半田付けして使っています。
どちらのマイコン基板もオークス電子の製品ですが、R8C/Tinyの方は
周辺(タイマー、A/Dコンバータ)がH8系列になっています。
R8C/Tinyの方は、もう1枚、マルチプロセッサ基板に入れてあり
こちらのマイコンと互換でした。
R8C/Tinyは、開発環境としてHEWを利用しますが、自分には
HEWは使い難くTM(Tool Manager)を使って、アセンブリ言語
の勉強をします。
マイコンのプログラムの入門定番と言えば、自分の中では
Knight RiderのKnight2000のLED点滅なので、これをテーマ
にファームウエアを作成していきました。
基板上にはLEDが2個だけなので、踏切の点滅をエミュレートします。
使うLEDは、下の写真でマークした2LED。
回路図で、この2LEDが、どこのポートに配置されているのか確認。
ポート3のビット2、3にアサインされています。
この情報から、ポート3のビット2、3を出力に設定し
点灯は論理値の0を出力、消灯は論理値の1を出力だと
わかります。
R8C/Tinyは、メモリマップドI/Oを採用しているので
SFR(Special Function Register)エリアから該当の
アドレスを拾い出します。
DDR(Data Direction Register)が$E7、DR(Data Register)が$E5と
わかります。R8C/Tinyのアセンブラでは、擬似命令の「.equ」を
利用するようで、サンプルコードから次のようにアサイン。
P3 .equ 0E5h
P3D .equ 0E7h
ポートの方向を設定する必要があるので、入出力の指定を
調べると、出力では論理値を1に、入力では論理値を0と
なっていました。最初は、消灯として初期化。
INIT:
; port 3 data
mov.b #0FFh,P3
; port 3 data direction
mov.b #0FFh,P3D
;
rts
点灯、消灯にはビットの論理演算を使えばよいので簡単。
サブルーチンにしておきます。
; P3_3 P3_2 turn off LEDs
P32_00
bset #2,P3
bset #3,P3
rts
; P3_3 turn off , P3_2 turn on
P32_01
bset #2,P3
bclr #3,P3
rts
; P3_3 turn on , P3_2 turn off
P32_10
bset #2,P3
bclr #3,P3
rts
; P3_3 P3_2 turn on LEDs
P32_11
bclr #2,P3
bclr #3,P3
rts
タイマー割込みで、カウンタ値をインクリメントして
点滅を制御するようにしておきます。
; ? WFLAG = ON
btst #0,WFLAG
jz MAINLPE
; clear
mov.b #0,WFLAG
; get counter
mov.b SCNT,R1H
; compare
MAIN0:
cmp.b #0,R1H
jnz MAIN1
jsr P32_00
jmp MAIN4
MAIN1:
cmp.b #1,R1H
jnz MAIN2
jsr P32_01
jmp MAIN4
MAIN2:
cmp.b #2,R1H
jnz MAIN3
jsr P32_10
jmp MAIN4
MAIN3:
cmp.b #3,R1H
jnz MAIN4
jsr P32_11
; increment
MAIN4:
inc.b SCNT
and.b #3,SCNT
;
MAINLPE:
jmp MAIN
フラグ、カウンタ等はバイトかワードで確保しておく
必要があるので、擬似命令で指定。
.org 0400h
WFLAG: .blkb 1
SCNT: .blkb 1
初期化をまとめると、以下。
INIT:
; port 3 data
mov.b #0FFh,P3
; port 3 data direction
mov.b #0FFh,P3D
; clear
xor.b R0L,R0L
; store
mov.b R0L,WFLAG
mov.b R0L,SCNT
;
rts
R8C/Tinyのアセンブラでは、ROM、RAMのエリアを
sectionという単位で管理しています。属性には
以下があります。
section名は任意でよいので、次のように記述します。
.section FARM,CODE
;
.glb Start
.glb Main
;
.org 0C000h
Start:
;***** set interruptstack *****
ldc #intstack,ISP
;***** set Processor mode *****
bset PRC1
mov.b #00000000b,PM0
mov.b #00000000b,PM1
bclr PRC1
;***** set System clock *****
bset PRC0
mov.b #C_CM0,CM0 ; enable 20MHz
mov.b #C_CM1,CM1 ; no divided
bclr PRC0
;***** initialize I/O *****
jsr.a INIT
MAIN:
;
jmp MAIN
;+++++ sub routines +++++
INIT:
; port 3 data
mov.b #0FFh,P3
; port 3 data direction
mov.b #0FFh,P3D
; clear
xor.b R0L,R0L
; store
mov.b R0L,WFLAG
mov.b R0L,SCNT
;
rts
.section SRAMAREA,DATA
.org 0400h
WFLAG: .blkb 1
SCNT: .blkb 1
.end
割込みを利用するときには、固定エリアと可変エリアの
Vector指定となるので、利用する割込みだけを宣言して
使います。
LEDの点滅に戻って、テーブル参照法でパターンを引いて
それを出力することを考えます。2処理を考えて対応。
テーブル(表)に値を格納
LEDの点滅は、次のように考えました。
○ 点灯 ● 消灯
●● → ●○ → ○○ → ○● → ●●
パターンで考えると、次の4つになります。
00
01
11
10
P33、P32にパターンを配置すればよいので
PTBLに、2進数で格納するコードを作成。
INIT_TBL:
; store
push.w A0
; set pointer
mova PTBL,A0
; 00
mov.b #00000000b,0:8[A0]
; 01
mov.b #00000100b,1:8[A0]
; 11
mov.b #00001100b,2:8[A0]
; 10
mov.b #00001000b,3:8[A0]
; resume
pop.w A0
;
rts
レジスタA0は、アドレスに関係する処理を
担当するので、ポインタに使います。
オフセットを用意して、ベースアドレスから
どれだけ離れているかを指定して対応。
4バイトの領域を確保。
PTBL: .blkb 4
パターンを引き出して印加
ポートにパターンをそのまま出力すれば、LEDの点滅に
もっていけるので、状態変数を用意し、その値がオフ
セットになるように細工。
DISPLAY:
; store
pushm R0,A0
; set pointer
mova PTBL,A0
; get index
mov.b IDX,R0L
; clear
mov.b #0,R0H
; calculate
add.w R0,A0
; get value
mov.b [A0],R0L
; impress
mov.b R0L,P3
; resume
popm R0,A0
;
rts
IDXは1バイトでよいので、領域を確保しておきます。
IDX: .blkb 1
IDXの値は、タイマー割込みを使いインクリメントして
4になったなら、0に戻すようにします。
タイマー割込みからは、イベントフラグで通知。
MLOOP:
; judge
btst #0,FLAGS
jeq MLOOP1
; clear
bclr #0,FLAGS
; impress
jsr DISPLAY
; increment
inc.b IDX
; compare
mov.b IDX,R1
cmp.b 4,R1
jne MLOOP1
; clear
mov.b #0,IDX
MLOOP1:
jmp MLOOP
(under construction)
目次
前
次