SNSへはこちら

CH559マイコンをいじってみよう(2) - クロック設定(や愚痴)

続いて、大事な大事なクロックについてやっていきましょう。

このマイコンは内蔵クロックがあるので、これだけで十分かと思います。ですのでこれをいじっていきます。まずは前提条件から定めていきましょう。

前提

  • 内部12MHzを使用
    • 外部クリスタルつけるのは面倒くさいし。
    • 個人的には、このマイコンは手軽さが売りだと思っているので、これでサクッと行くのがいいかも
  • USB CLK は 48MHz を維持
    • 他のマイコンと同じように、Full-Speed の4倍クロックが必要っぽい雰囲気。
  • できるだけ速いシステムクロックに設定する

「できるだけ速い」というのは後述の通りあんまり速くなりませんが、ひとまず構成を考える素材であるという解釈にします。

構成

データシートによると、クロックは FoscFpllFusb4xFsysがあります。それぞれについて見ていきましょう。データシート上のブロック図はこちら。

これだけでなんとなく分かる気がしますが、とりあえず解説しておきましょう。

まず、Fosc は内部 CLK か XTAL かを選べます。外部 XTAL の場合は然るべきピンに接続します。今回は内部 CLK の 12MHz で行きたいと思います。
この Fosc は PLL に入力され、24MHz〜350MHz の範囲に逓倍可能です。8051 コアという、半ば化石 MCU で PLL がついているなんて太っ腹(確か PSoC にもありましたっけ)。逓倍するファクターが PLL_CFG レジスタの MASK_PLL_MULT ビットになります。ビット幅は5なので、0〜31 の範囲で選べます。この出力が Fpll ですね。

つづいて、Fpll は分岐して USB clock dividersystem clock divider に入力されます。
まずは USB の方。こちらは MASK_USB_4X_DIV (ビット幅は3)で分周されます。んで、こちらがおそらく見た限り記述無いのですが、full-speed(12MHz動作)を保証するために、クロック名からして48MHzに揃えねばならないはずです。これがUSBクロック Fusb4x だと思います。

ではその後の Fsys の方は更に続きます。まず MASK_SYS_CK_DIV で分周されますが、こちらのビット幅は5です。一部ペリフェラルに対してその供給クロックとして直結されているのもありますが、それ以外(基本的にはE8051にもともと搭載されていない、多機能なペリフェラル)は16 or 8bit幅の分周比を設定可能となっています。

なお拡張されたペリフェラルは現代のマイコンのようにクロック有効化/無効化の機能があります。クロックゲーティングにより消費電力を減らすことが可能みたいですね〜。なおデフォルトでペリフェラルクロックは有効になっています。

設定値の検討

では実際のクロックを、データシートの電気的特性も参照しながら照らし合わせていきましょう。

デフォルトの値

内蔵発振を利用した場合、最速クロックは以下のような感じになるはずです。

CLK Value Max
Fosc 12MHz 12.18MHz
Fpll 288MHz 350MHz
Fusb4x 48MHz ---
Fsys 12MHz 56MHz

この Value の値を設定する際、、各設定値は以下のようになります。

Divisor Value(Dec) Value(2進数)
MASK_PLL_MULT 24 11000
MASK_USB_4X_DIV 6 110
MASK_SYS_CK_DIV 24 11000

こう整理しちゃえばあとは楽ちんですね。ただの割り算ですし。

...そういえばこの値、普段から参考にしているこちらの Qiita 記事に記述がありましたね。答え合わせが出来た気持ちです。

設定の検討

まずPLLの最大周波数である350MHzをクロック源の12MHzで割ると27.16666...になります。また、USBで48MHzという値にせねばならないことを考慮すると、MASK_PLL_MULT24が最適と分かります。なるほど。現状維持ですね。

続いてMASK_SYS_CK_DIV を検討します。同様に288MHzをFsys Maxの56MHzで割ると5.14くらいとなります。よってMASK_SYS_CK_DIV6と設定すると48MHzという最大クロックで動くことになります。

以上を書き込んでみましょう。ただクロック設定にはセーフモードに入るなど、特別な処理が必要なので、そのへんのルーチンはデータシートを参考にします。コードは以下で、やたらシンプル。

void clock_init(void) { // 48Mhz for System Clock
    SAFE_MOD = 0x55;
    SAFE_MOD = 0xAA; // Enter safe mode

    CLOCK_CFG &= ~0x1F;
    CLOCK_CFG |= 6;

    SAFE_MOD = 0; // Exit safe mode
}

よく分かりませんので憶測ですが、セーフモードってこのクロック設定用レジスタをバッファリングしているのですかね?セーフモードから抜ける時にバッファの値がレジスタに書き込まれる、もしくはその後クロックが安定するまで待ち時間が存在する、そんな仕様な気がします。
セーフモードに入ってから何もしなくても、「13〜23クロックはセーフモード状態を維持する」なんて適当なことが書いてあります。すぐさま抜けるために適当な値を書いているのが今回です。

次回はタイマーやりますかね。ここまで実用的なものが出てませんので、クロックとタイマーでLチカなんてどうすか。

ついでにこのマイコン特有(元の 8051 コアに比べて)の PWM 等もやりましょう。

データシートの不満(難点)

生産性のないことを雑に綴っておきます。人によっては不快に感じるかも知れませんのでスルー推奨です。申し訳ありませんがこの場で感情を吐かせてください。
一生懸命に公式の英語データシートを読もうとした人なら分かってくれると信じて...

  • 英語がわけわからない
    • 能動・受動の不一致(これ非常に致命的)
    • 動詞の原形多すぎる(分詞構文、過去分詞、三単現のsをつけた表現とするべき)
      • 特にレジスタ説明の表で"Set~~."と書いてある説明は何?このレジスタはセットされるのユーザーがセットする必要があるの?
    • and や or が無くすべてカンマで繋がっている箇所あり、見づらい
  • Typo
    • コピペのせいでSPI1とあるべきがSPI0に
    • as, at もそう。英文解釈に支障をきたす
    • 記述に一部ビット幅が合っていない。察する能力が必要
  • 構成
    • PDF のしおり機能がざっくりとしか機能していない
      • 各ペリフェラルで、レジスタごとの箇所にジャンプできない
    • 各ペリフェラルで、レジスタ説明順がセクション冒頭のレジスタ一覧と順番が逆
    • 単純な説明不足
      • 例えばクロック分周比の設定で "0000b means 10000b." って言われても...「分周比なのに0は流石に無効なので、16分周とします」という意図が分かる表現にしてほしい。
      • 他にも割り込みフラグで "0: interrupt." って言われてもなぁ。"0: Some interrupt(s) occurring." ってはっきり書いてくれないとわかりにくくて困る。脳みそ friendly では無い。
      • SLEEP_CTRL の説明。"1=off" って「ペリフェラルがオフ」なのか「スリープ機能がオフ」なのか、ややこしい。
        実際に1を書き込むとペリフェラルクロックは無効に... つまり前者だった

...代わりに良い英語訳をしたデータシートを見つけました。それがこちら非常に素晴らしい