たまには使った IC についての記事投稿とかをします。
今回は、LED ドライバ IC である、TM1627 を使ってみました。使用目的は 7セグLED の駆動のためです。
下の秋月電子の説明では最大7個(7 digits)の 7セグLED が使用可能とありますが、回路構成を考えるとアノードコモンのものを用いると最大 10個(10 digits)使用可能と考えられます。
また、マトリクス上のキー入力検出(パラ→シリ変換)にも対応していますが、今回はよくわからないので割愛します。タイトルのカッコは「今後やるかもしれん」という意味合いがあります(本当か??)
特長
なんといっても安いことが特長です(1個70円)。そして
- 電流値を内部で制御してくれるので、抵抗器が不要
- 3ピンで最大10桁の7セグを制御できる
- ダイナミック点灯は IC が高速に行ってくれるから考慮が要らない
- たった3ピンで制御可能なので、ピン数の節約になる
ことがメリットでしょう。一方デメリットもあって、
- 通信方式が独特(I2C っぽかったり SPI っぽかったりするが、どちらでもない)なため、自分で波形をパタパタさせる必要がある
- dp(小数点) は別途制御しなければならない
- データシートが中国語しか無いので翻訳が面倒(筆者は第2外国語としてドイツ語を履修)
- 通信に必要なウェイトが大きく、結果動作が遅くなっている
ということです。特に通信方式は若干面倒くさいです。
データシートの言語と通信方式が面倒だったので記事にしたためた次第です。
データシートのめもみたいなもの
仕様やピンの役割等を知りたい時にいちいち中国語を翻訳にかけるのは面倒なことこの上ないので、とりあえず「これさえあれば 7セグLED を点灯できるだろう」という内容をまとめた PDF を用意しました。どうぞ。
なお、アノードコモンの LED を用いた際のめもであることをご注意あれ。
TM1627使用メモ
取り敢えずこれで内部のレジスタ構成、コマンドの理解はできるでしょう。
通信方式
厄介なところです。他の似ている TM16xx シリーズでは1バイト送出後に9クロック目を入れて ACK の返答を確認せねばならなかったりするものがありますが、この TM1627 には ACK 確認はありません。
また、データの送受信を行う DIO ピンですが、これは双方向にデータのやり取りができるように(というより、信号が衝突しないように)、オープンドレイン とする必要があります。
以上を含めて、ハマり注意ポイントを列挙しておきましょう。
- どことなく I2C に近いが、STB(SPI の CS#)があったり、ACK 確認がなかったり、アドレス + R/W の送出がなかったりと、微妙に I2C とは違う
- スタートコンディション・ストップコンディションはしっかりやろう。
- LSB Firstです。
- コマンド間のウェイトでは CLK を下げること無く High に保つ必要がある。これでだいぶハマった。
- DIO ピンのみオープンドレイン。IC 内部でプルアップされているので、外部抵抗不要。
- その他の CLK, STB は全て通常のプッシュプルで OK。
- K1, K2 はガン無視で OK。
通信のための擬似コード
ご参考にどうぞ。というか僕がオレオレライブラリを用いて動かしているのですが、そのままのコードを貼り付けます。十分読めると思いますが。
また、何処にどのデータを書けば良いのか?についてはデータシートを参考にしてください。
#include <stm32f3xx.h>
#include <gpio.hpp>
#include <new>
static char buf_stb[sizeof(Gpio)];
static char buf_dio[sizeof(Gpio)];
static char buf_clk[sizeof(Gpio)];
static Gpio *stb; // #18, GPIOA8
static Gpio *dio; // #19, GPIOA9
static Gpio *clk; // #20, GPIOA10
namespace serial {
void init() {
GpioConfig cfg;
cfg.mode = GpioConfig::PinMode::GPIO_OUTPUT;
cfg.outputtype = GpioConfig::PinOutputType::OD;
stb = new(buf_stb) Gpio(GPIOA, 8, GpioConfig::PinMode::GPIO_OUTPUT);
dio = new(buf_dio) Gpio(GPIOA, 9, cfg);
clk = new(buf_clk) Gpio(GPIOA, 10, GpioConfig::PinMode::GPIO_OUTPUT);
*stb = 1;
*dio = 0;
*clk = 1;
}
static void wait() {
for(volatile int i = 0; i < 10; i++);
}
static void startCondition() {
*stb = 0;
wait();
*clk = 0;
wait();
}
static void stopCondition() {
*clk = 1;
wait();
*stb = 1;
wait();
}
static void stbPulse() {
*stb = 1;
wait();
*stb = 0;
wait();
}
static void sendBit(bool bit) {
*clk = 0;
*dio = bit;
wait();
*clk = 1;
wait();
}
void sendByte(uint8_t data) {
for(int i=0; i<8; i++) {
sendBit(data & 0x01);
data >>= 1;
}
}
void sendLEDData(uint8_t *array) {
startCondition();
sendByte(0x03);
stbPulse();
sendByte(0x40);
stbPulse();
sendByte(0xC0);
for(int i=0; i<14; i++) {
if( array != nullptr ) {
sendByte(array[i]);
}else{
sendByte(0x00);
}
}
stbPulse();
sendByte(0x8A);
stopCondition();
}
}
動作させた例
スイッチを使ってインクリメント、デクリメントの例をやってみました。こんな感じに動きます。
おもしろい pic.twitter.com/ghHwaV9094
— しまじゃき (@obknt) October 6, 2019
終わりに
独自の通信方式を使っているということだけあって、データシートの波形をしっかり読んで、しっかりそれに従うのが大事だと知りました。
色々と適当な判断をしたせいでハマりにハマり、かなり時間を溶かしてしまいました。悲しい。
コメント
TM1627の解説サイトが見当たら無い中、中国語データシートを読み解いて頂きとても参考になり感謝しております。おかげ様でAVRのアセンブラを使って信号パタパタさせて無事7セグLEDを表示させることができました。ただアノードコモンのLEDだとおっしゃる通り小数点の取り扱いが難しいのが欠点。あと固定アドレスモードでもアドレスとデータの出力にSTBをLに保つ必要があるところで躓きました。自動アドレスインクリメントの設定にしてデータを1件送るのと違いが無いのではないかと思いましたが。
お役に立てたようで良かったです!(コメント承認遅れましてすみません)
やはり言語が違うと読解力が落ちますよね...独特の通信波形ということも相まって、僕も思い込みにより上手くいかなくて苦しんでましたので。
AVRでもパタパタ出来たということで、大変嬉しく思います。
このようなハマり所を克服してしまえばとても便利な石ですよね。重宝しています。