Windows IoT CoreのSPI通信APIでLチカ

How to use MCP23S08(SPI-GPIO expander) for Windows IoT Core
前回はI2C方式のIOエキスパンダーのWindows IoT Coreプログラミングを紹介しましたが、今回はSPI方式のIOエキスパンダー(MCP23S08)の使用例を紹介したいと思います。

ブレッドボードによる配線図と、写真によるイメージはこちらの通りです。Raspberry PiのSPI0ピンから出力される信号によって、上半分の右8ピンで入出力を拡張することができます。

続いてプログラミング。Windows IoT CoreにはSPI通信のためのAPIも用意されているので、これを使ってみます。このICではGPIO出力は3バイト単位で信号を送信することで操作が行えます。はじめの1バイトは操作コード(書き込みモードなら0x40、読み込みモードなら0x41。いずれもハードウェア操作の信号はなし)、次のバイトはレジスタアドレス(GPIOなら0x09)、最後のバイトはオン・オフのビット配列となります。今回は単純なGPIO操作なので、はじめに「0x40, 0x00, 0x00」の信号を送信することで、すべてのピンを出力モードとして初期化しています。

以上を踏まえたソースコードがこちらになります。今回も同様にバックグラウンドで動作し、4つのLEDがランダムで点灯します。
spiapi.cs
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Windows.ApplicationModel.Background;
using Windows.Devices.Enumeration;
using Windows.Devices.Spi;

namespace SpiApiTest
{
    public sealed class StartupTask : IBackgroundTask
    {
        private BackgroundTaskDeferral deferral;

        private SpiDevice SPIAccel;

        private byte[] sendbytes = new byte[] { 0x40, 0x09, 0x00 };
        private void SendGpio(byte bits)
        {
            sendbytes[2] = bits;
            SPIAccel.Write(sendbytes);
        }

        private void SendCommand(params byte[] args)
        {
            SPIAccel.Write(args);
        }

        private async void Start()
        {
            try {
                var settings = new SpiConnectionSettings(0);
                settings.ClockFrequency = 5000000;
                settings.Mode = SpiMode.Mode0;

                string aqs = SpiDevice.GetDeviceSelector("SPI0");
                var dis = await DeviceInformation.FindAllAsync(aqs);
                SPIAccel = await SpiDevice.FromIdAsync(dis[0].Id, settings);
                if (SPIAccel == null) {
                    Debug.WriteLine(string.Format(
                        "SPI Controller {0} is currently in use by " +
                        "another application. Please ensure that no other applications are using SPI.",
                        dis[0].Id));
                    return;
                }

                SendCommand(0x40, 0x00, 0x00);

                Random r = new Random();
                while (true) {
                    byte bits = 0x0;
                    for (int i = 0; i < 4; i++) {
                        if (r.Next(0, 2) == 1) bits |= (byte)(1 << i);
                    }
                    SendGpio(bits);

                    await Task.Delay(500);
                }
            } catch (Exception ex) {
                Debug.WriteLine("SPI Initialization failed. Exception: " + ex.Message);
            }
        }

        public void Run(IBackgroundTaskInstance taskInstance)
        {
            deferral = taskInstance.GetDeferral();

            Start();
        }
    }
}
2016/10/06