これは、PSoC Advent Calendar 2019の10日目に突っ込まれた記事です。
LCD表示器にはバックライトがある
前回の記事では、**Groveのスターターキットに入っていたGrove LCD RGB Backlight**というボードを使いました。
今回も、このボードを使って実験を行います。
このボードは、**Grove LCD RGB Backlight**という名前からもわかるようにバックライトを内蔵しています。ところが、どうやって使うんだか例によって回路図が無いのでわかりません。やっぱり、プログラム例を見るしかないのか。
LEDドライバ
で、基板を眺めていて、裏側にI2Cバスに直接つながっているチップがいると気が付きました。
この写真では全く見えませんが、マーキングの"9632"の文字を手掛かりに**NXPのPCA9632**というLEDドライバであるらしいことが分かりました。
前回の記事で判明したI2CのSlaveアドレスとも符合します。
8bit | 7bit | デバイス |
---|---|---|
7C | 3E | LCD Controller |
C4 | 62 | LED Driver |
E0 | 70 | LED Driver |
このLEDドライバには、二つのアドレスが見えています。
これらのうち、0xC4が通常使用されるSlaveアドレスです。
一方、0xE0の方は、"LED All Call I2C-bus Address"と呼ばれるもので、モード設定によって無効にすることもできます。
このLEDドライバには、ほかにもサブアドレスが3種類設定できるなど機能が多いのですが、すべてvolatileとなっています。同一I2Cバスに**PCA9632を複数接続しても、個別に設定することができずに困ってしまうんじゃないのかな。
ちなみに、PCA9632**には10ピンパッケージのものもあり、増えた2ピンを使ってSlaveアドレスを変更できることができます。複数つなげるときには、こちらを使えば良いのでしょう。
I2C Masterを直接操作する
今回は、前回のプロジェクトを拡張して対応してみます。まず、回路図は、前回と同じです。
LEDドライバを制御する便利なコンポーネントは存在しないので、すべてソフトウェアで操作します。ソフトウェアは、こんなになりました。
# include "project.h"
# define LED_ADDRESS (0xC4)
# define REG_MODE1 (0x00)
# define REG_PWM (0x02)
# define REG_LEDOUT (0x08)
# define REG_CONTINUOUS (0x80)
# define MODE1_ENABLE (0x00)
# define MODE1_DISABLE (0x10)
# define LEDOUT_ENABLE (0xAA)
# define LEDOUT_DISABLE (0x00)
# define BUFF_SIZE (16)
static uint8_t buff[BUFF_SIZE];
void SendBuffer(uint32_t size) {
I2CM_I2CMasterWriteBuf(
LED_ADDRESS >> 1,
buff,
size,
I2CM_I2C_MODE_COMPLETE_XFER
);
while (!(I2CM_I2CMasterStatus() & I2CM_I2C_MSTAT_WR_CMPLT)) {
// Wait until I2C Master finishes transaction
}
}
int main(void) {
CyGlobalIntEnable; /* Enable global interrupts. */
I2CM_Start();
// Setup LCD display
I2C_LCD_Start();
I2C_LCD_PrintString("Hello, World!");
// Setup Backlight LED
buff[0] = REG_MODE1;
buff[1] = MODE1_ENABLE;
SendBuffer(2);
buff[0] = REG_LEDOUT;
buff[1] = LEDOUT_ENABLE;
SendBuffer(2);
buff[0] = REG_CONTINUOUS | REG_PWM;
buff[1] = 0x33;
buff[2] = 0x33;
buff[3] = 0x88;
SendBuffer(4);
for (;;) {
/* Place your application code here. */
}
}
LCDディスプレイに文字を表示させてから、LEDドライバにコマンドを送り、 MODE1, LEDOUT, PWM の順にレジスタに値を書き込んでいきます。これで、バックライトがピンクに点灯します。
I2Cバスにコマンドを送信する関数 SendBuffer() を定義しているので、多少はマシなはずですが、大したことやってるわけでもないのに、長いです。
この先、可読性を考えるのであれば、MODE1レジスタを書き換える関数やら、LEDOUTレジスタを書き換える関数やら、PWMレジスタを書き換える関数やら、色んなものが考えられますが、ベタにmain.cに書くべきものじゃありません。ぜひとも、ライブラリ化したいところです。
LEDドライバを制御するコンポーネント
ということで、コンポーネントを作っちゃいました。
このコンポーネントは、Character LCD with I2C Interfaceと同じように指定されたI2C Masterを介して**PCA9632**を制御するソフトウェアコンポーネントです。
ただし、凝った設定画面は作っていないので、かなり質素です。
二つのパラメータ、Slaveアドレスと操作対象となるI2C Masterコンポーネントのインスタンス名が設定されます。
API
提供しているAPI関数は、以下の通りです。
API | 概要 |
---|---|
void I2C_LED_Init(void) | コンポーネントの初期設定を行います。 |
void I2C_LED_Enable(void) | LEDドライバの動作を開始します。 |
void I2C_LED_Disable(void) | LEDドライバの動作を停止します。 |
void I2C_LED_Start(void) | コンポーネントの使用を開始します。 |
void I2C_LED_Stop(void) | コンポーネントの使用を終了します。 |
void I2C_LED_WriteMode1(uint8 mode1) | MODE1レジスタに値を書き込みます。 |
void I2C_LED_WriteLedout(uint8 ledout) | LEDOUTレジスタに値を書き込みます。 |
void I2C_LED_WritePWM(uint8 pwm0, uint8 pwm1, uint8 pwm2, uint8 pwm3) | PWMレジスタに値を書き込みます。 |
これらの関数を使って、**PCA9632**を制御します。ほかにも色々と細かい設定はできるのですが、バックライトとしてはこのくらいで十分でしょう。
メインルーチン
コンポーネントを使って、メインルーチンを書き直しました。
# include "project.h"
int main(void) {
CyGlobalIntEnable; /* Enable global interrupts. */
I2CM_Start();
// Setup LCD display
I2C_LCD_Start();
I2C_LCD_PrintString("Hello, World!");
// Setup Backlight LED
I2C_LED_Start();
I2C_LED_WritePWM(0x33, 0x33, 0x88, 0x00);
for (;;) {
/* Place your application code here. */
}
}
"main.c"は、すっかり簡素になりました。このプログラムでも、コンポーネントを作成しない場合と同じようにピンク色になります。
GitHub リポジトリ
関連サイト
32-bit ArmR CortexR-M0 PSoCR 4
PSoCR 4 BLE (Bluetooth Smart)
スイッチサイエンスのスターターキットのページ
関連記事
CY8CKIT-042-BLE-A でLチカ
CY8CKIT-042-BLE-A でLCD表示
CY8CKIT-042-BLE-A でバックライト点灯
CY8CKIT-042-BLE-A で気圧を表示
CY8CKIT-042-BLE-A で気圧を送信