SSブログ

BLE Beacon Observer のユーザインターフェースを作る [PSoC]このエントリーを含むはてなブックマーク#

CY8CKIT-145-40XX

PSoC Advent Calendar 2016の7日目の記事です。

以前の記事で、 BLE Beacon を検出するアプリケーションを作成しました。 このアプリケーションでは、検出結果を UART から出力していましたので、出力を見るための PC が必要でした。

そこで、今回の記事では、 CY8CKIT-145-40XX に搭載された PSoC 4 S-Series、 CapSense ボタン、そして LED によるユーザインターフェイスを作成します。 ユーザインターフェイスが出来上がったら、この基板の裏側に搭載された EZ-BLE PRoC Module と組み合わせて、独立した BLE Beacon 検出アプリケーションに仕立てましょう。

回路図

回路図

回路図は、このようになっています。 これまでの記事に比べて、多くのコンポーネントが並んでいます。 それぞれのコンポーネントの設定は、後で述べるとして、最初にクロックの設定から見ていきます。


クロックの設定

このアプリケーションでは、 CapSense ボタンを使用するために SYSCLK の周波数を可能な限り高くします。 IMO を最大周波数である 48NHz に設定し、そのまま CPU で使用します。

このアプリケーションでは、低速クロックは使用しませんので、 "Low Frequency Clock" タブの設定はデフォルトのままです。

CapSense コンポーネント

Basic タブ

CY8CKIT-145-40XX 基板のすべての静電容量センサを使用するため、 CapSense には、3個のボタンと5極のスライダ1個を取り扱わせます。

この基板のパターンは、相互容量 (CSX) 方式を前提として作られていますが、ここでは 自己容量 (CSD) 方式を使用します。 そのため、 CSX の TX パターンは不要になりますが、この電位がフラフラしていると静電容量の検出に悪影響を与えます。 そこで、 TX パターンにつながる P1[3]/P2[6] 端子は、いずれも回路図で GND に固定しています。

このアプリケーションでは、面倒なチューニングは行わない方針で、 "CSD tuning mode" を "SmartSense (Full Auto-Tune)" に設定しています。 また、 "Finger capacitance" は、目分量でいずれも 0.3pF に設定しています。 たぶん、こんなもんでしょう。


Advanced - Generalタブ

SmartSense を使う事を前提にしているので、設定すべき項目は、ほとんどありません。 あとで、もし、ノイズに困ったら、フィルタなどを入れてみましょう。


Advanced - CSD Settingsタブ

このタブで変更するのは、 "Modulation clock frequency" だけです。 "Modulation clock" は、センサの静電容量を計算するのに使われるクロックで、この周波数が高ければ高いほど反応速度を早くすることが出来ます。 ここに、設定可能な最大周波数である 48000kHz (48MHz) を設定します。 これは、 SYSCLK に設定したクロックの周波数です。

その他、 "Enable Compensation IDAC" がチェックされています。 この機能を使うと、見かけの感度が上がるので、タッチ検出に余裕が出ます。

EZI2C コンポーネント

EZI2C Basic タブ

EZI2C コンポーネントは、 BLE Observer として使われる EZ-BLE PRoC Module との通信を行う I2C スレーブデバイスです。 "EZI2C Basic" タブでは、通信のプロトコルが定義されます。 以下のようなパラメータが設定されています。


項目備考
Data rate (kbps)400クロック信号SCLの最大周波数を示します
Number of addresses1この EZI2C コンポーネントが応答すべきスレーブアドレスの個数を示します
Primary slave address (7-bits)0x08この EZI2C コンポーネントのスレーブアドレスを示します
Sub-address size (bits)16EZI2C コンポーネントがデータを格納する仮想レジスタのアドレスのビット数を示します

UART コンポーネント

UART Basic タブ

"UART Basic" タブの設定は、前回の記事で使ったものと同じです。


UART Advanced タブ

"UART Advanced" タブの設定も、前回の記事で使ったものと同じです。

LED 出力コンポーネント

Pin_LED_top の設定

上側に配置された LED に使われている GPIO 出力の設定は、このようになっています。 LED は、 Active-LOW の設定で使用されるため、 LOW 出力の時には電流を流しますが、 HIGH 出力の時には電流を流しません。


Pin_LED_bot の設定

下側に配置された LED の設定も同様です。

PWM_BUZ コンポーネント

PWM タブ

PWM_BUZ は、 2kHz のブザー音を出すように設定されます。 ですが、ファームウェアでは、今のところ使われていません。 こんど実装しましょう。

端子の設定

端子の設定

それぞれの端子の割り当ては、このようになっています。 EZI2C の信号線は EZ-BLE PRoC Module と、 UART の信号線は KitProg2 と、接続されます。


CY8CKIT-145-40XX のブロック図

評価ボード CY8CKIT-145-40XX の内部配線は、このようになっています。 EZI2C の信号線 SCL/SDA は、 EZ-BLE PRoC にもつながっていますが、同時に KitProg2 にも接続されています。 そのため、できあがったアプリケーションは、 KitProg2 からも動作を確認する事が出来ます。

PSoC 4000SEZ-BLE PRoC の間には、 UART の信号線 TX/RX も接続されています。 しかしながら、これらの信号線は未実装の0Ω抵抗を追加すると使えるようになるものです。 このため、このアプリケーションでの使用はあきらめたのでした。

ファームウェア

ファームウェア

ファームウェアは、以下のようになりました。 ちょっと、短めです。

#include "project.h"
#include <stdio.h>

// I2C の送受信に使われるバッファ
struct I2cBuffer {
    uint8       temp;       // [RW] 温度データ
    uint8       humid;      // [RW] 湿度データ
    int8        rssi;       // [RW] RSSIデータ
    uint8       id;         // [RW] データのID番号
    uint8       newid;      // [RO] 見つけたいID番号
};

volatile struct I2cBuffer   i2cBuffer;  // バッファの実体

#define     RW_BOUNDARY     (4)         // RW領域のバイト数

EZI2C は、 RAM 上に仮想レジスタ領域を作り、 I2C のプロトコルをアクセスするという仕組みです。 そこで、最初に仮想レジスタ領域を宣言します。

アドレスラベル読み書き用途
0TEMPR/W温度データを受け取る
1HUMIDR/W湿度データを受け取る
2RSSIR/WRSSIデータを受け取る
3IDR/WID番号を受け取る
4NEWIDRID番号の変更を伝える

ここでは、5バイトのレジスタ領域が宣言され、頭から4バイトの部分が書き込み可能になっています。 書き込み可能領域の長さを示しているのが RW_BOUNDARY です。 ここでいう書き込み可能は、 I2C バスから書き込む事が出来るという意味で、どのレジスタも PSoC 4000S のファームウェアからは自由に読み書きできます。

これらのレジスタのなかで PSoC 4000S から発信されるのは、 ID 番号の変更要求 (NEWID) だけです。 EZ-BLE PRoC Module は、このレジスタから値を読み出して、次の「スキャン」で探す ID 番号として使います。

int main(void) {
    // 割り込みを許可する
    CyGlobalIntEnable;

    // UARTを起動する
    UART_Start();
        
    // EZI2C を起動する
    EZI2C_Start();
    EZI2C_EzI2CSetBuffer1(
        sizeof i2cBuffer,
        RW_BOUNDARY,
        (uint8*)&i2cBuffer
    );

    // CapSense を起動する
    CapSense_Start();
    CapSense_ScanAllWidgets();

    // 初期メッセージを表示する
    UART_UartPutString("Beacon Observer\r\n");

宣言がおわったら、すぐに main() 関数が始まります。 割り込みの許可と UART の初期化に続いて、 EZI2C の起動をおこないます。 EZI2C の初期化では、 EZI2C_EzI2CSetBuffer1() 関数に三つの引数を与えます。 それぞれ、仮想レジスタの長さ、読み書き可能レジスタの長さ、仮想レジスタのアドレスです。 外部から書き込みを行わせる場合には、二番目の引数の値を適切に設定する必要があります。

次に CapSense コンポーネントの初期化を行います。 CapSense_Start() に続いて CapSense_ScanAllWidgets() でセンサの初期スキャンを始めます。

    // メインループ
    for(;;) {
        // CapSense 関連の処理
        if (!CapSense_IsBusy()) {
            // CapSense の Scan がおわったら、
            // 各 Widget の状態を更新する
            CapSense_ProcessAllWidgets();
            
            // TOP ボタンで着目 ID を切り替える
            if (CapSense_IsWidgetActive(CapSense_BUTTON0_WDGT_ID)) {
                // ボタン0は、 ID=1 に関連付けられる
                i2cBuffer.newid = 1;
                Pin_LED_top_Write(0xFF - 0x01);     // TOPはLED0のみ点灯
                Pin_LED_bot_Write(0xff);            // BOTはすべて消灯
            } else if (CapSense_IsWidgetActive(CapSense_BUTTON1_WDGT_ID)) {
                // ボタン1は、 ID=2 に関連付けられる
                i2cBuffer.newid = 2;
                Pin_LED_top_Write(0xFF - 0x02);     // TOPはLED1のみ点灯
                Pin_LED_bot_Write(0xff);            // BOTはすべて消灯
            } else if (CapSense_IsWidgetActive(CapSense_BUTTON2_WDGT_ID)) {
                // ボタン2は、 ID=3 に関連付けられる
                i2cBuffer.newid = 3;
                Pin_LED_top_Write(0xFF - 0x04);     // TOPはLED2のみ点灯
                Pin_LED_bot_Write(0xff);            // BOTはすべて消灯
            } else {
                // その他の場合は現状維持
            }
            
            // 次の Scan を開始する
            CapSense_ScanAllWidgets();
        }

メインループは、ふたつの部分から構成されています。 前半は、 CapSense コンポーネントの処理です。 CapSense のスキャンが終わると CapSense_IsBusy() が false を返し、各センサの静電容量が求まった事を示します。 ここで、 CapSense_ProcessAllWidgets() を呼び出すと、それぞれの Widget について、タッチの有無やスライダでの指の位置などが計算されます。

基板上方にある三つのボタンは、 ID番号をそれぞれ 1, 2, 3 に変更するために使用されます。 ボタンのタッチを検出したら、フィードバックとして上方の LED の点灯パターンを変更し、 EZI2C の仮想レジスタ NEWID を変更します。

タッチされたボタンに関する処理がおわったら、ふたたび CapSense_ScanAllWidgets() を呼び出して、次のスキャンを開始します。

        
        // EZI2Cへの WRITE 動作の処理
        if (EZI2C_EzI2CGetActivity() & EZI2C_EZI2C_STATUS_WRITE1) {
            // WRITE 操作でレジスタが変更されたら、
            // RSSI の値によって LED バーの長さを変える
            if (i2cBuffer.rssi > 0) {
                Pin_LED_bot_Write(0xFF - 0x1F);     // LEDを5個点灯
            } else if (i2cBuffer.rssi > -60) {
                Pin_LED_bot_Write(0xFF - 0x0F);     // LEDを4個点灯
            } else if (i2cBuffer.rssi > -70) {
                Pin_LED_bot_Write(0xFF - 0x07);     // LEDを3個点灯
            } else if (i2cBuffer.rssi > -80) {
                Pin_LED_bot_Write(0xFF - 0x03);     // LEDを2個点灯
            } else if (i2cBuffer.rssi > -90) {
                Pin_LED_bot_Write(0xFF - 0x01);     // LEDを1個点灯
            } else {
                Pin_LED_bot_Write(0xff);            // 全消灯
            }
            // UART に受信結果を表示する
            {
                char buffer[64];    // UART出力のバッファ
                int16 t, h;         // 温度と湿度を格納する変数
                // 温度と湿度を1/10単位の整数で計算する
                t = ((17572L * i2cBuffer.temp) / 256 - 4685 + 5) / 10;
                h = ((12500L * i2cBuffer.humid) / 256 - 600 + 5) / 10;
                // Reportパケットの内容を表示する
                sprintf(buffer, "ID=%d TEMP=%d.%d HUMID=%d.%d RSSI=%d\r\n",
                    i2cBuffer.id, t/10, t%10, h/10, h%10, i2cBuffer.rssi);
                UART_UartPutString(buffer);
            }
        }        
    }
}

後半は、 EZI2C への書き込み処理です。 EZI2C に書き込み動作が行われると、 EZI2C_EzI2CGetActivity() が返す状態コードの EZI2C_EZI2C_STATUS_WRITE1 がセットされます。 これを検出して、書き込み通信後の処理を開始します。

書き込まれたデータの中で着目しているのは、 RSSI の値です。 この値の大小によって、下方の LED の点灯個数を変更します。 LED の個数で電波強度を表そうという動きです。

書き込み通信が行われた時、 UART への送信も行っています。 送信内容は、前の記事で表示していたものと同じです。 これで、 EZI2C が書き込み通信を受信したかどうかが判断できます。

実行結果

書き込みテスト

まずは、 I2C から書き込みを行ってみます。 PSoC Creator と一緒にインストールされた Beidge Control Panel を起動し、 KitProg2 と接続します。 そして、コマンド w 08 00 00 12 34 56 78 9A p を送ります。 このコマンドで、仮想レジスタのアドレス 0000 に5バイトのデータを書き込みます。 すると、コンソールに w 08+ 00+ 00+ 12+ 34+ 56+ 78+ 9A- p が返ってきます。 数字の最後の + は ACK をあらわし、 - は NAK をあらわします。 5バイト目のデータだけ NAK が返っているのは、5バイト目が書き込み不可のレジスタだからです。

これに対して、 UART は ID=120 TEMP=-34.-4 HUMID=19.4 RSSI=86 を返しました。 温度と湿度のデータは意味がありませんが、 RSSI=86($56) ID=120($78) になっているのが確認できます。 同時に下方の LED が点灯しました。

さらに w 08 00 00 23 45 67 89 p を送ると UART の出力が変わりました。


読み出しテスト

さらに I2C から読み出しを行ってみます。 コマンド r 08 x x x x x p を送るとコンソールに r 08+ 23+ 45+ 67+ 89+ 00+ p が返ってきました。 これは、さきほど I2C に書き込みを行った値です。

ここで、 BTN0 をタッチしてから、読み出しコマンドを送ると r 08+ 23+ 45+ 67+ 89+ 01+ p が返ってきました。 最後のバイト "01" が、タッチをしたことによって新たに設定された NEWID の値です。 同様に BTN1 をタッチすると "02" が返ってきました。

どうやら、ユーザインターフェイスが出来たようなので、次は BLE Beacon Observer を I2C に対応させてユーザインターフェイスと結合します。

プロジェクトアーカイブ

この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できます。

参考サイト

CY8CKIT-145-40XX PSoC® 4000S CapSense Prototyping Kit
今回の記事で使用したハードウェアです。 PSoC 4000S だけを使いました。

参考商品

PSoC 4 BLE

PSoC 4 BLE

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス

nice!(0)  コメント(0)  トラックバック(0)  このエントリーを含むはてなブックマーク#

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

トラックバックの受付は締め切りました

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。