ORANGE-4には、3本のI/Oピンを制御できる命令がある。
今回は、これらのI/Oについて挙動を調べてみた。
今回対象とするファームウェアのバージョンは1.09である。
免責
今回は、仕様に無い挙動や、仕様に反する使い方を扱う。
そのため、ファームウェアのバージョンやそれまでの操作、個体差、環境などによって挙動が変わる可能性が考えられる。
この記事の内容を参考にした、または参考にしなかった結果生じた一切の損害について、筆者は責任を負わない。
I/Oの仕様
ORANGE-4には、PORT1、PORT2、PORT3の3本のI/Oピンがある。
また、これらの操作用の以下の命令がある。
(マニュアル「必ずわかるORANGE-4機械語プログラミング」(2020/3/23版) に基づく)
機械語 | ニモニック | 動作 (仕様) |
---|---|---|
F70 | ioctrl | Aレジスタの値により、Yレジスタで指定したポートの設定を行う。 A=0 : デジタル出力 A=2 : デジタル入力 |
F71 | out | Yレジスタで指定したポートに、Aレジスタの値(0または1)を出力する。 ポートはioctrl命令でデジタル出力の設定をしておく必要がある。 |
F72 | in | Aレジスタに、Yレジスタで指定したポートの状態を読み込む。 ポートはioctrl命令でデジタル入力の設定をしておく必要がある。 |
調査方法
ソフトウェア
パラメータをキーを用いて自由に指定してioctrl命令、out命令、in命令を実行できる以下のプログラムを用意した。
以下のプログラムは、MikeAssemblerでアセンブルできる。
また、先頭のtarget orange4
を取ればORANGE-4 IDEでもアセンブルできる。
target orange4
; 操作方法
; 1. コマンドを選択する (状態を2進LEDに表示する)
; 0 : ioctrl
; 1 : out
; 2 : in
; その他 : 無効 (無視)
; 2. ポートを選択する (0-f)
; 3. パラメータを選択する (0-f) (ioctrl, out のとき)
; 読み込んだ値を7セグメントLEDに表示する (in のとき)
org 0x00
ay
scall 0
ldi 0
ldyi 0xE
st
ldyi 0xF
st
main_loop:
; 2進LEDを消灯する
scall 0xD
; モード選択
call key_input
cpi 0
jmpf not_ioctrl
; 0 : ioctrl
ldyi 0
scall 1
; ポートを選択する
call key_input
outn
ldyi 6
scall 1
; パラメータを選択する
ay
call key_input
; コマンドを実行する
ioctrl
scall 0
jmpf main_loop
org 0x80
not_ioctrl:
cpi 1
jmpf not_out
; 1 : out
ldyi 1
scall 1
; ポートを選択する
call key_input
outn
ldyi 6
scall 1
; パラメータを選択する
ay
call key_input
; コマンドを実行する
out
scall 0
jmpf main_loop
not_out:
cpi 2
jmpf main_loop
; 2 : in
ldyi 2
scall 1
; ポートを選択する
call key_input
outn
ldyi 6
scall 1
; コマンドを実行する
ay
in
outn
jmpf main_loop
key_input:
ink
jmpf key_input
; キー入力後、チャタリング対策で待つ
abyz
ldi 0
scall 0xC
abyz
key_release_wait:
ink
jmpf key_released
jmpf key_release_wait
key_released:
; キー入力後、チャタリング対策で待つ
abyz
ldi 0
scall 0xC
abyz
ret
このプログラムの機械語のORANGE-4のモニター向け表現は、以下のようになった。
E00:3E080AE4AF4EDF60
E10:BCC0F80A0E1F60BC
E20:1A6E13F60BCF70E0
E30:F0B
E80:C1FA1A1E1F60BC1A
E90:6E13F60BCF71E0F0
EA0:BC2F0BA2E1F60BC1
EB0:A6E13F721F0B0FBC
EC0:280EC20FCDFC6280
ED0:EC2F61
ハードウェア
調査対象のポートから、GNDとVDDそれぞれに20kΩ(公称値)の抵抗を接続し、GNDからポートの電圧を測定する。
測定される電圧から、ポートの状態を以下のように判定する。
電圧 | 状態 |
---|---|
3.3V付近 | HIGHを出力 |
1.65V付近より高く、3.3V付近より低い | プルアップ |
1.65V付近 | ハイインピーダンス |
0V付近より高く、1.65V付近より低い | プルダウン |
0V付近 | LOWを出力 |
調査
リセット時の状態
電源投入直後は、3ポートとも「LOWを出力」となっていた。
プログラムを実行してポートの状態を変更した後、RSTボタンによりプログラムの実行を止めた時は、ポートの状態は維持された。
RESETボタンによるリセットを行うと、ポートの状態は「LOWを出力」に戻った。
ポートの選択
ioctrl命令では、Yレジスタの値によって以下のポートの状態が変わった。
Yレジスタの値 | 状態が変わったポート |
---|---|
1 | PORT1 |
2 | PORT2 |
3 | PORT3 |
0,4,5,6,7,8,9,A,B,C,D,E,F | なし |
out命令では、Yレジスタの値によって以下のポートの状態が変わった。
Yレジスタの値 | 状態が変わったポート |
---|---|
1 | PORT1 |
2 | PORT2 |
3 | PORT3 |
0,4,5,6,7,8,9,A,B,C,D,E,F | なし |
in命令においては、PORT1、PORT2、PORT3全てにHIGHを入力した状態で実行した結果、
Yレジスタが1,2,3の時はAレジスタの値が1となり、それ以外の時はAレジスタの値が0となった。
よって、ioctrl命令やout命令と同様に、Yレジスタの値1,2,3がそれぞれPORT1,PORT2,PORT3に対応すると推測できる。
ポートの設定
リセット後、PORT1について、ioctrl命令によるポートの設定を行った。
Aレジスタの値として0~Fを昇順に試した結果、命令実行後のポートの状態は以下のようになった。
Aレジスタの値 | ポートの状態 |
---|---|
0,1,F | LOWを出力 |
2,3,4,5,6,7,8,9,A,B,C,D,E | ハイインピーダンス |
また、リセット後、Aレジスタの値として3~Fを昇順に試した結果、ポートの状態は「LOWを出力」のまま変わらなかった。
さらに、リセット後、PORT1をデジタル入力に設定(Aレジスタの値=2)した後、Aレジスタの値として1を用いると、ポートの状態は「ハイインピーダンス」のまま変わらなかった。
したがって、Aレジスタの値が0,2,F以外の場合、ポートの状態は変わらないと推測できる。
仕様にあるAレジスタの値0,2でポートの設定を行った場合、その後もioctrl命令でポートの設定を変更したり、out命令でポートの出力を設定したりできる。
一方、Aレジスタの値Fでポートの設定を行った場合、ioctrl命令やout命令を用いても反応せず、ポートの状態は「LOWを出力」のままとなった。
一旦RSTボタンでプログラムの実行を止めて再実行しても、反応は復活しなかった。
この設定を行う前のポートの状態が「デジタル入力」「デジタル出力、0を出力」「デジタル出力、1を出力」のどれであっても、この現象が見られた。
また、あるポートがこの設定により反応しなくなっても、他のポートはこの設定をしない限り反応は維持されるようだった。
したがって、ioctrl命令実行時のAレジスタの値とポートの設定は以下のようになっていると考えられる。
Aレジスタの値 | ポートの設定 |
---|---|
0 | デジタル出力 |
2 | デジタル入力 (ハイインピーダンス) |
F | ポートを無効化し、LOWを出力するように固定 |
その他 | 変更なし |
ポートへの出力
ioctrl命令でPORT1をデジタル出力に設定した後、Aレジスタの値として0~Fを昇順に用い、out命令をPORT1について実行したところ、ポートの状態は以下のようになった。
Aレジスタの値 | ポートの状態 |
---|---|
0 | LOWを出力 |
1~F | HIGHを出力 |
さらに、Aレジスタの値0でout命令を実行した後、Aレジスタの値2~Fそれぞれについてout命令を実行 (それぞれの実行の前にAレジスタの値0でout命令を実行) すると、全てポートの状態は「HIGHを出力」となった。
したがって、ポートがデジタル出力に設定されている場合、out命令におけるAレジスタの値とポートの状態の関係は以下のようになっていると考えられる。
Aレジスタの値 | ポートの状態 |
---|---|
0 | LOWを出力 |
1~F | HIGHを出力 |
ioctrl命令でPORT1をデジタル入力に設定した後、Aレジスタの値として0~Fを昇順に用い、out命令をPORT1について実行したところ、ポートの状態は全て「ハイインピーダンス」のまま変わらなかった。
さらに、PORT1について以下のような操作を行うと、PORT1の状態は以下のようになった。
操作 | 操作の詳細 | ポートの状態 |
---|---|---|
プログラムの実行を開始 | - | LOWを出力 |
デジタル出力に設定 | ioctrl, A=0 | LOWを出力 |
0を出力 | out, A=0 | LOWを出力 |
デジタル入力に設定 | ioctrl, A=2 | ハイインピーダンス |
1を出力 | out, A=1 | ハイインピーダンス |
デジタル出力に設定 | ioctrl, A=0 | HIGHを出力 |
デジタル入力に設定 | ioctrl, A=2 | ハイインピーダンス |
0を出力 | out, A=0 | ハイインピーダンス |
デジタル出力に設定 | ioctrl, A=0 | LOWを出力 |
よって、デジタル入力に設定してある状態でのout命令による操作も保存され、デジタル出力に設定した際に反映されるようである。
さらに、デジタル出力に設定した状態で、さらにAレジスタの値0でioctrl命令を実行(デジタル出力に設定)しても、ポートの状態は変わらない(HIGHの出力も維持される)ようだった。
ポートからの入力
「ポートの選択」での実験結果より、PORT1、PORT2、PORT3をデジタル入力に設定した状態では、HIGHはAレジスタの値1として読み込まれ、無効なポートはAレジスタの値0として読み込まれることがわかっている。
また、PORT1で実験をすると、LOWはレジスタの値0として読み込まれることがわかった。
ポートをデジタル出力に設定した場合、1を出力している状態ではAレジスタの値1、0を出力している状態ではAレジスタの値0が読み込まれた。
Aレジスタの値2でout命令を実行した後でも、Aレジスタの値1が読み込まれた。
ポートを無効化(Aレジスタの値Fでioctrl命令を実行)した場合も、Aレジスタの値0が読み込まれた。
よって、in命令はポートの設定によらず、HIGHをAレジスタの値1、LOWをAレジスタの値0として読み込むようであることがわかった。
結論
ORANGE-4 (ファームウェアのバージョンは1.09) は、I/O関係について以下のような挙動をするらしいことがわかった。
ポートの選択 (共通)
Yレジスタの値 | ポート |
---|---|
1 | PORT1 |
2 | PORT2 |
3 | PORT3 |
その他 | 無効 |
ioctrl命令
ioctrl命令は、選択したポートの状態をAレジスタの値によって以下のように設定する。
Aレジスタの値 | ポートの設定 |
---|---|
0 | デジタル出力 |
2 | デジタル入力 |
F | LOWの出力に固定し、以降のioctrl命令やout命令を無視 |
その他 | 変化なし |
リセット(電源投入・RESETボタン)時は、デジタル出力に設定したような状態になっている。
RSTボタンによりプログラムの実行を止めても、状態の設定は維持される。
デジタル入力は、ハイインピーダンスのみ(プルアップ・プルダウンなし)のようである。
out命令
out命令は、選択したポートの出力をAレジスタの値によって以下のように設定する。
Aレジスタの値 | 出力 |
---|---|
0 | LOW |
非0 | HIGH |
出力の設定はポートがデジタル入力に設定されている時でも有効であり、設定後ポートをデジタル出力に設定すると設定した値が出力される。
in命令
in命令は、選択したポートの状態を以下のようにAレジスタの値に反映する。
ポートの状態 | Aレジスタの値 |
---|---|
LOW | 0 |
HIGH | 1 |
この関係は、ポートがデジタル出力に設定されている場合でも同様である。(出力している値が読み込まれる)
無効なポートを選択した場合は、Aレジスタの値は0となる。
ポートの物理仕様
ORANGE-4のサイトに載っている回路図より、ポートとマイコンのピンの対応は以下のようになっている。
ポート | ピン番号 | ピン名 |
---|---|---|
PORT1 | 10 | OSC2 |
PORT2 | 14 | RB5 |
PORT3 | 7 | RB3 |
使われているマイコン PIC32MX120F032B のデータシートを参照すると、この中で5VトレラントになっているのはPORT2 (RB5) だけであることがわかる。
ORANGE-4の暴走再び
今回のプログラムによる検証中も、前回のXorshiftのプログラムの実行時に見られた暴走現象が度々発生した。
今回の暴走はキー入力時に発生することがあり、発生すると以下の症状が見られた。
- キー操作を受け付けない (数字キーだけでなく、RSTキーも)
- 2進LEDが通常より明るく点灯する
- 押したキーによって2進LEDが点灯することがある (例えば、Cキーを押すとLED3が点灯する)
検証のためにプログラムを削っていったところ、以下のプログラムを実行し、RSTキーで実行を止めると、別の不都合が発生することがわかった。
(「発生することがある」ではなく、100%に近い確率で発生するようである)
target orange4
; ORANGE-4 Ver 1.09 暴走テスト
; 1. このプログラムをアセンブルし、モニターから入力する
; 2. モニターを終了する (qコマンド)
; 3. 1→RUNで実行する
; 4. RSTで止める
; 5. ビープ音が繰り返し鳴り、キー入力を受け付けなくなる
; ※モニターを終了せずにgコマンドで実行した場合、RSTを押しても不都合は起きない
; ※モニターを経由せず、キーでプログラムを打ち込んで実行しても不都合が起きる
org 0x00
ay
scall 0
main_loop:
; 2進LEDを消灯する
ldi 0
ldyi 0xE
st
ldyi 0xF
st
scall 0xD
; モード選択
ldi 1
cpi 1
jmpf main_loop
; 1 : out
ldyi 0
scall 1
; ポートを選択する
ldi 1
outn
ldyi 1
scall 1
; コマンドを実行する
scall 0
jmpf main_loop
E00:3E080AE4AF4ED81C
E10:1F03A0E1811A1E1E
E20:0F03
このプログラムを実行し、RSTキーで実行を止めると、以下の現象が発生した。
- 約134BPMで「ピッ」という短い音が鳴り続ける
- キー操作を受け付けなくなる
- 前述の暴走とは異なり、キーを押しても2進LEDは点灯しない
このような暴走現象が発生する詳しい条件は、まだよくわかっていない。