ESP8266でBトレ(第5回 ハードウェア編その5 位相同期 前編)

先週オシロが届いたので、ウレシくてガチャガチャいじくってました。夜おそくにコードがもじゃもじゃの怪しげな基板を前に、不気味な笑いを浮かべながらオシロのプローブを突き立てようとしていると、ちょっとマッドサイエンティストになった気分です。 f:id:cacao1:20151212172823j:plain

これがそのオシロ DS5032E 中国製です。おじさんオシロは初めて使いましたが、すごく便利です。中国にはこんなにいいものがあるというのに、わざわざ日本まで爆買いにくる理由がまったくワカリマセン。

位相同期に挑戦してみる

さて、前回、位相が同期していないとどうなるかと、位相を同期しないで問題を解決する方法について説明しましたので、流れとして今回は位相同期する話ですよね、え~、どうしよう、できるかな? いきおいで手をつけてしまったので、いけるところまで行ってみます(これができないとゾーンコントローラー方式が実現できませんし...)。おじさんは普段はお金やモノを数えるソフトを書いてます(ました)が、ハードやマイコンソフトはアマチュア(というよりシロウト)ですので、ツッコミどころにはよろしくつっこんで下さい。

位相同期に必要なこと

位相同期(隣のセクションのPWMと位相を合わせる)には次の事柄をクリアすることが必要です。

  1. 自分のPWMの位相を意図したように変更できること
  2. 隣のセクションのPWMの位相がわかること

調べてみたら1つ目はわりと簡単でした。SDKのPWM用のカウンタをリスタートさせる関数がArduinoからも使えますので、これを好きなタイミング(割り込みとか)で呼び出してやれば実現できます。 PWMの波形のパターンにはいろいろあるようですが、analogWrite関数の場合はカウント開始時に出力がHIGHから始まり、アップダウンカウンタではないようです。 f:id:cacao1:20151212191203j:plain

ググって調べました

f:id:cacao1:20151212181924j:plain

(ソース追えないので波形で見ました)

2つ目はちょっとくふうが必要です。というのは、隣のセクションの波形そのものを知ることができないからです。しかし、列車が隣のセクションと自分のセクションにまたがっている間に自分のフィーダーにかかる電圧(波形)は、自分のフィーダーと隣のフィーダーの波形の論理和になるはずです。これに、次の2つの前提条件 (1)隣のセクションと自分のセクションのPWM周波数は(ほぼ)同じであること、(2)隣のセクションと自分のセクションのDutyは同一であること、を考慮すれば、となりのセクションの位相はわかるはずです(下図をご覧ください)。 f:id:cacao1:20151212201634j:plain

やりかた

1つめは、コードの適切な部分で以下を呼び出すかコピペするだけです(core_esp8266_wiring_pwm.c)

void pwm_start_timer(){
    timer1_disable();
    timer1_attachInterrupt(pwm_timer_isr);
    timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
    timer1_write(1);
}

2つめは、フィーダー線から引っ張り出した線に検出回路をつないで、検出回路の出力でESP8266に割り込みをかけてやることで実現します。回路とソフトそれぞれについて説明しますが、説明が長くなるのを避けるため、隣のセクションのことを「あなた」自分のセクションのことを「わたし」と書きます。

回路の説明

回路では「あなただけがON」になっている期間を検出するようにします。まず、フィーダー線から取り出した信号(あなたと私の合成波形)をダイオードブリッジで極性を揃え、コンパレーターでロジックレベルにします(図中のFEEDER)。 f:id:cacao1:20151212191508j:plain 次に、そこから「わたし」を取り除くための信号を作ります。これにはESP8266からのPWM出力を使います。ESP8266のPWMとBD6231Fの出力のタイミングを見ると、立ち上がりで10~20us、立下りで100usほどずれがあります。 f:id:cacao1:20151212182805j:plain そこで、立ち上がりはそのまま利用しつつ、立ち下り用を100usほど引き延ばした信号を作ってORをとればよさそうです。引き延ばしにはワンショットマルチHC123を使いました。これとPWM信号のORを取りますが、そのままだと、もともとの信号と引き延ばした信号とのつなぎ目でスパイクがでるため、もともとの信号のほうはCR回路で少し遅延させています。これを反転させて使用します(図中のPWMEXTENDED)。 これら二つの信号のANDをとれば、あなただけが電圧を出している期間にのみONになる信号ができます(図中のONLYYOU)

ソフトの説明

この部分の今回試したコードを載せます。上記で生成したONLYYOU信号と、わたしのPWM信号とを入力情報として、わたしのPWM信号をあなたのPWM信号の位相にあわせています。試行錯誤しながら書いたのであかぬけてませんがお許しください(スマートなロジックがあれば教えてください)。 実験では割り込み用にGPIO13、自分のPWM信号を取得するためのAnalog出力としてGPIO14を使いましたのでそのような記述になっていますが、本番ではGPIO13はフィーダー用に使っていますのでそのままでは使えません、また、Analog出力もいつも同じ端子ではなく、同期の都度、対象のポートに切り替える必要がありますのでその機構が必要です。さらに、どこかに問題があるらしく、たいてい10分くらいでこけます。このへんは次回以降なんとかします(するつもりです)。

//setup()の中
    attachInterrupt(13, sync,  CHANGE);//割り込みを設定する

volatile long up = 0;//割り込み発生回数の調査用
volatile long dn = 0;//〃
volatile short adj = 0;//タイミング調整用(実行中に変化させながら様子を見たところ、120くらいがちょうどよいようです)
bool resetWithFALLING = false;
//割り込み処理(位相同期)
void sync() {
    if (rest > 0) {//ちょっと間引き
        rest--;
        return;
    }
    detachInterrupt(13);//再入を防ぐため割り込みをやめる
    Feeder *f = Feeders->get(0);
    short duty = f->getAnalogValue();
    int isRAISING = digitalRead(13) == 1;
    if (isRAISING) {
        up++;
        if (digitalRead(14) == HIGH) {//me delay
            resetWithFALLING = true;
        }
        else {
            timer1_disable();
            delayMicroseconds(1000 - duty - adj);
            timer1_write(1);
            timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
            rest = 5;
        }
    }
    else {//FALLING
        dn++;
        if (resetWithFALLING) {
            timer1_disable();
            timer1_write(1);
            timer1_enable(TIM_DIV1, TIM_EDGE, TIM_SINGLE);
            resetWithFALLING = false;
        }
    }
    attachInterrupt(13, sync, CHANGE);//割り込みを許可する
}

volatile short rest = 0;
//loop()かonTimer()の中
    rest = 0;//割り込み間引き用カウンタをクリアする

で、動くの?

ビデオはこちらです。

youtu.be

一応、位相同期の効果は確認いただけると思います。これで落ちなくなれば(^^;;)、ゾーンコントローラー方式も実用化できそうです。 波形も載せておきます。

youtu.be

はまったところ

最初、2台の基板で同じ電源をつかっていたのですが、どれだけ位相を合わせても、境界通過時にDutyが変化してしまいました。もしやと思って別々の電源からの供給にしたところ、Dutyの変化が抑えられました。モータードライバ側から見た回路の条件が違うのでしょうか?

後編の予告

ゾーンコントローラのPWM出力は6つあるので、今回確認した回路をどう組み込むか考える必要があります。また、同期が必要なPWM出力の番号と、同期開始、終了のタイミングはサーバーから指示してやる必要がありますので、そのあたりも検討しようと思います。春節前に送ってもらえるように回路の設計を終わりたいと思ってましたが、今のペースだとちょっと無理カモ...