エプソンのLCDコントローラーS1D13781評価ボードをラズパイで動かす(1)

S5U13781R01C100」はエプソンが開発したLCDコントローラIC「S1D13781」を搭載した評価ボードです。

このボードの特徴はLCD用の40pinコネクタと50pinコネクタを両方備えており、単一のボードで複数のメーカーのLCDに対応できることがあげられます。また、日本語のドキュメントに加え、ライブラリーのソースが充実しているため、開発の敷居が低いのも利点です。

一方で、搭載ICのビデオRAMは384KBと、480x272のフルカラーRGBがぎりぎりで格納できる容量のため、それ以上の解像度の液晶や、表示中の画面の後ろで別の画面を作成するダブルバッファ(メーカーではPIP機能と表記)を実装するには色数を下げることでメモリーを確保しなければならず、連続した写真を表示するなどのリッチな画像処理にはやや不向きです。

S5U13781R01C100は、秋月電子や共立電子ともにArduino Due用と表記したうえで販売しており、実際にArduino Dueをセットにしたキットも販売しています。シリコンハウス共立での価格は約9000円でした。
今回はこの評価ボードをWindows IoT CoreとRaspberry Piを使って制御してみることにします。

このボードのピンは位置はArduinoにぴったりはまるような設計になっていますが、このボードとのデータのやりとりは実質的にSPI通信なので、適切な命令さえ送れば、Raspberry Piでも難なく動きます。まずはこちらの画像を参考に、電源とGPIO端子を繋げてみてください。コントローラーは裏から見た図です。LCDバックライトへの過電流を防ぐため、表面のDIPスイッチの確認(1番は電源で、2~4はスイッチの数だけ20~60mAの電流がバックライトに流れるようになる)を忘れずに。
データ送受信の肝となるピンのWindows IoT Coreにおける制御プログラムはこのようになります。低レベルGPIOコントローラーであるLightningProviderについては同ブログの「Windows IoT Coreで赤外線リモコンの信号を受信する」をご参照ください。あとはデータシートに沿って描画命令を送受信するだけですが、次回では、どのように画像を表示すれば良いかを具体的に解説していきたいと思います。
spi.cs
public async void Begin()
{
    // SPI通信の設定
    var settings = new SpiConnectionSettings(0);
    settings.ClockFrequency = 24000000;
    settings.Mode = SpiMode.Mode0;
    settings.DataBitLength = 8;

    // GPIOピンの初期化
    if (LightningProvider.IsLightningEnabled) {
        LowLevelDevicesController.DefaultProvider = LightningProvider.GetAggregateProvider();

        var cs = await SpiController.GetControllersAsync(LightningSpiProvider.GetSpiProvider());
        var controller = cs[0];
        SPI = controller.GetDevice(settings);

        var gpc = await GpioController.GetControllersAsync(LightningGpioProvider.GetGpioProvider());
        CsPin = gpc[0].OpenPin(CsPinNo);
    } else {
        string aqs = SpiDevice.GetDeviceSelector("SPI0");
        var dis = DeviceInformation.FindAllAsync(aqs).GetResults();
        if(dis.Count > 0) {
            SPI = await SpiDevice.FromIdAsync(dis[0].Id, settings);
            CsPin = GpioController.GetDefault().OpenPin(CsPinNo);
        }
    }
    if (CsPin != null) {
        CsPin.SetDriveMode(GpioPinDriveMode.Output);
        InitRegs();
    }
}

private void RegWrite(RegIndex regIndex, ushort regValue)
{
    if (CsPin == null) return;

    // 信号送信の開始を伝える
    CsPin.Write(GpioPinValue.Low);

    // SPI信号を送信
    SPI.Write(new byte[]{
        (byte)SPIBIT.SPIWRITE_8BIT, //command
        0x06, //address bits 18:16
        0x08, //address bits 15:8
        (byte)regIndex, // address bits 7:0
        (byte)(regValue & 0x00FF), //data bits 7:0
        (byte)(regValue >> 8) //data bits 15:8
    });

    // 送信の終了を伝える
    CsPin.Write(GpioPinValue.High);
}

private ushort RegRead(RegIndex regIndex)
{
    if (CsPin == null) return 0x00;

    CsPin.Write(GpioPinValue.Low);

    SPI.Write(new byte[]{
        (byte)SPIBIT.SPIREAD_8BIT, //command
        0x06, //address bits 18:16
        0x08, //address bits 15:8
        (byte)regIndex, // address bits 7:0
    });

    // 送信結果のデータは3バイトで0番目は常にダミー値が入る
    byte[] res = new byte[3];
    SPI.Read(res);

    CsPin.Write(GpioPinValue.High);

    return (ushort)(res[1] | (res[2] << 8));
}
2016/12/16