ORANGE-4 で GROVE - 高精度RTC から秒の1の位を読んでみた

[ORANGE-4](http://www.picosoft.co.jp/ORANGE-4/index.html) で [GROVE - 高精度RTC](https://www.switch-science.com/products/3134) から秒の1の位を読んでみた。
(1の位を読むだけで容量がいっぱいになってしまった…)

# GROVE - 高精度RTC

**GROVE - 高精度RTC** は、PCF85063TP を搭載したリアルタイムクロックモジュールである。
SDA (データ) と SCL (クロック) の2本の信号線により、時刻情報や設定情報の読み書きが可能である。
このモジュールから1バイトを読み出すのは、以下の手順でできる。
なお、SDA および SCL はモジュール内でプルアップされており、信号の出力はオープンドレインで行う。

1. 「スタートコンディション」を送信する。  
   すなわち、SCLがHIGHの状態で、SDAをHIGHからLOWにする。
2. アクセスするデバイスのアドレス (7ビット、今回は0x51) に続いて書き込みを表す1ビットの0を送信する。  
   すなわち、値0xA2のバイトを送信する。  
   バイトの送信は、上位のビットから下位のビットの順で各ビットを送信する。  
   ビットの送信は、SCLがLOWの状態でSDAを設定し、SCLを一旦HIGHにしてLOWにすることで行う。
3. SDAをHIGHにし、SCLを一旦HIGHにしてLOWにする。  
   このとき、デバイスはSDAをLOWにしてACKを表現する。  
   以下、この操作を「ACK用のクロックを送信する」という。
4. アクセスするレジスタのアドレス (今回は秒を読み出すので 0x04) を表す1バイトを送信する。
5. ACK用のクロックを送信する。
6. 「スタートコンディション」を送信する。
7. アクセスするデバイスのアドレス (7ビット) に続いて読み込みを表す1ビットの1を送信する。  
   すなわち、値0xA3のバイトを送信する。
8. ACK用のクロックを送信する。
9. 1バイト (8ビット) 受信する。  
   バイトの受信は、上位のビットから下位のビットの順で各ビットを受信する。  
   ビットの送信は、SCLをHIGHにしてからSDAの状態を読み取り、SCLをLOWにすることで行う。
10. ACK用のクロックを送信する。  
    このとき、本来は受信した側がACKを表現するタイミングであるが、今回受信する最後のバイトを受信した後はACKではなくNACKを表現する (SDAがHIGHの状態でSCLを操作する) ことになっている。  
    よって、送信時のACKを確認しない場合、送信時と共通の処理を用いることができる。
11. 「ストップコンディション」を送信する。
    すなわち、SDAを一旦LOWにしておき、SCLをHIGHにした後でSDAをLOWからHIGHにする。

# プログラム

読み取った秒の下位4ビットを7セグメントLEDに表示する。

適当なタイミングでプログラムの実行を停止してしまうと、通信の途中でプログラムの実行が止まり、RTCの動作に支障が出る場合がある。
そのため、プログラムの実行を停止する際は、まずキーを押して通信を止め、その状態で実行を止めること。
キーの同時押しは効かないようであるが、以下の手順で実行を止めることができた。

1. 「0」キーを押す
2. 「RST」キーを押す
3. 「0」キーを離す
4. 「RST」キーを離す

容量の都合で、ポートの初期化を省略し、
[ORANGE-4のI/Oの仕様を調査してみた (暴走もあるよ) - Qiita](https://qiita.com/mikecat_mixc/items/71effbbbea1c0d0415de)
で調査した通りLOWの出力が初期値になっていること、および `in` 命令はポートが (`in` 命令の仕様に反して) デジタル出力に設定されている場合でもAレジスタに0または1を格納することを前提とする。

また、
[【GMC-4】命令の実行速度を調べる - Qiita](https://qiita.com/mikecat_mixc/items/ea820b4f2f7f96be9999)
より、ORANGE-4 がポートの状態を切り替える速度は最高でも30kHz程度であり、400kHz以下という制限には引っかからなそうであることがわかる。

以下のプログラムは、[MikeAssembler](https://mikecat.github.io/mike_assembler/) でアセンブルできる。

```
target orange4

; PORT1 - SDA
; PORT2 - SCL

	org 0x00

main_loop:
	call send_start
	ldi 0xA
	ldyi 0x2
	call comm
	ldi 0x0
	ldyi 0x4
	call comm
	call send_start
	ldi 0xA
	ldyi 0x3
	call comm
	ldi 0xF
	ldyi 0xF
	call comm

	; STOP を送信する
	; SDA を LOW にする
	ldyi 1
	ldi 0
	ioctrl
	; SCL を HIGH にする
	ldyi 2
	ldi 2
	ioctrl
	; SDA を HIGH にする
	ldyi 1
	ioctrl

	jmpf display_data_read

	; START を送信する
send_start:
	; SDA を HIGH にする
	ldyi 1
	ldi 2
	ioctrl
	; SCL を HIGH にする
	ldyi 2
	ioctrl
	; SDA を LOW にする
	ldyi 1
	ldi 0
	ioctrl
	; SCL を LOW にする
	ldyi 2
	ioctrl
	ret

	org 0x80

	; 1バイト送受信する
	; YレジスタとAレジスタに送信したい値を置いて呼び出す (受信したい場合は 0xf を置く)
	; Aレジスタが上位、Yレジスタが下位
	; 受信した値の下位が[0xf]に格納される (上位は捨てる)
comm:
	pushY
	ldyi 0xf
	st
	ldi 0
comm_loop:
	ldyi 3
comm4_loop:
	abyz
	; ビットを送信する (SDAを設定する)
	ldyi 0xf
	ld
	add
	jmpf comm4_send_one
	addyi 14 ; -2
comm4_send_one:
	addyi 3
	ay
	ldyi 1
	ioctrl
	; SCL を HIGH にする
	ldyi 2
	ldi 2
	ioctrl
	; SDA を読む
	ldyi 1
	in
	pushA
	; 読んだビットを保存する
	ldyi 0xf
	ld
	add
	st
	popA
	add
	st
	; SCL を LOW にする
	ldyi 2
	ldi 0
	ioctrl
	; ループを進める
	abyz
	addyi 0xf
	jmpf comm4_loop
	; 周回状態チェック
	cpi 0
	jmpf comm_low
	; 上位の送受信が終わった
	ldyi 0xf
	popA
	st
	ay
	jmpf comm_loop
comm_low:
	; 下位の送受信が終わった
	; SDA を HIGH にする
	ldyi 1
	ldi 2
	ioctrl
	; SCL を HIGH にする
	ldyi 2
	ioctrl
	; SCL を LOW にする
	ldi 0
	ioctrl
	ret

display_data_read:
	ldyi 0xf
	ld
	outn
pause_loop:
	ink
	jmpf main_loop
	jmpf pause_loop
```

以下は、このプログラムの ORANGE-4 のモニタ用の表現である。

```
E00:F60448AA2F608080
E10:A4F6080F60448AA3
E20:F60808FAFF6080A1
E30:80F70A282F70A1F7
E40:0FE5A182F70A2F70
E50:A180F70A2F70F61
E80:F66AF480A32AF56F
E90:94BEB33A1F70A282
EA0:F70A1F72F62AF564
EB0:F6364A280F702BFF
EC0:8AC0FD1AFF6343F8
ED0:8A182F70A2F7080F
EE0:70F61AF510F00FE9
```

# 実行結果

7セグメントLEDの表示が0～9で1秒ごとに切り替わっており、秒の1の位 (BCD表現の下位4ビット) が読み取れていると考えられる。

<iframe width="560" height="315" src="https://www.youtube.com/embed/FhugmJNjktI" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

通信の様子を[ロジックアナライザ](https://www.switch-science.com/products/7642)で見ても、秒を読み出す操作を行えていることがわかる。

![通信の様子](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/99656/03c03cb9-651d-0df8-8ac2-8433067ccfa8.png)