ワンコインデコーダXをはじめとするDCCデコーダのプログラムトラック(設定線路)での挙動について、ソースコードの観点から少しマニアックな解説をします。
DCCを始めたばかりの方が必ず一度はぶつかる壁が、「なぜモーターを繋がないとCV値が読み込めない(エラーになる)のか?」という疑問です。
実はこの謎を解くカギは、デコーダのプログラムファイル motor_ctrl.c の中に書かれた、DCC規格特有の「力技な通信の仕組み」に隠されています。
そもそも、コマンドステーションから線路へ流れるDCC信号は、テレビのリモコンなどと同じ「一方通行」の通信です。線路にはプラスとマイナスの2本の線しかなく、デコーダ側からコマンドステーションへ「私のCV3の値は10です」といったデータを送り返すための通信線(TX線)は存在しません。
では、コマンドステーションはどうやってデコーダのCV値を「読み取って」いるのでしょうか?
実は直接数値を読み取っているのではなく、「CV3の値は1ですか?」「CV3の値は2ですか?」と順番に質問(パケットを送信)し、デコーダが「YES」と答えた時の数値を画面に表示しているのです。
通信線を持たないデコーダが、どうやってコマンドステーションに「YES(= Ack:Acknowledge)」と返事をするのか。ここがDCC最大の物理的ハックです。
「一瞬だけモーターを全力で回して、線路の電流をドカッと消費する」
NMRA(全米鉄道模型協会)のDCC規格では、「60mA以上の電流を、5ミリ秒(0.005秒)以上消費すること」が「YES(Ack)」の合図として定められています。コマンドステーションは、質問を投げた直後に線路に流れるアンペア数をじっと監視し、この電流の跳ね上がり(サージ)を検知して返事を受け取っています。
ワンコインデコーダXのソースコード(motor_ctrl.c)の中に、まさにこの「YESの返事をする」ための関数 Send_Ack() が定義されています。
void Send_Ack(void) {
// 質問を受け取った後、規定のタイミングまで少し待つ
uint16_t pre_wait = TIM2->CNT;
while ((uint16_t)(TIM2->CNT - pre_wait) < 5000);
// 【ハック部分】
// モーターの前進ピンに、一瞬だけマイコンの最大パワー(mp+1)を出力する!
#ifdef HAS_MOTOR_OUTPUT
uint32_t mp = TIM1->ATRLR;
SET_MOTOR_FWD(mp+1);
SET_MOTOR_REV(0);
#endif
// ※この後、約6ミリ秒後にモーター出力をOFFに戻す処理が続きます
} このコードが実行されると、マイコンは一瞬だけモーターにフルパワーの電圧をかけます。しかし、通電時間がわずか数ミリ秒と短すぎるため、ギアや車輪が回り出す前に通電が終わり、人間の目には「モーターから『チッ』あるいは『プッ』という微かな音がしただけ(車体は動かない)」ように見えます。
しかし電気的には、コマンドステーションがしっかり検知できるだけの「60mA以上の大電流スパイク」が発生しているのです
これで疑問は氷解したはずです。
もしモーターを繋がずに、LED(室内灯など)だけを配線した状態でプログラムトラックに乗せた場合、Send_Ack() が実行されてピンからフルパワーが出力されても、LEDが消費する電流はせいぜい10〜20mA程度です。
これでは規格である「60mA以上の大電流スパイク」に届かないため、コマンドステーションのアンペア計は反応できず、「(デコーダは一生懸命YESと叫んでいるのに)声が小さすぎてコマンドステーションに聞こえていない」という状態になります。これが「読み込みエラー」の正体です。
テクニック: X や Xplusでモーターを繋がない状態で車両に搭載したい場合は、モーター端子に一時的に「100Ω〜150Ω程度のダミー抵抗」を繋ぐことで、強制的に60mA以上の電流を消費させ、Ackを読ませることができます。
(ただし、マイコンの出力は10mA程度しか流せません。100Ω〜150Ω程度のダミー抵抗を繋ぐとマイコンが壊れます。)