
センサを接続するためのADC(Analog-to-Digital Converter)とDAC(Digital-to-Analog Converter)各1チャネル、Bluetooth通信モジュールとの間で通信を行うUART(Universal Asynchronous Receiver Transmitter)ポート1チャンネルを使用できる汎用的なファームウエアを作成します。これだけだと、MCU内のリソース(部品やIOポート)は、まだ殆ど使われずに余っていますので、後で色々な回路を追加できます。
Cypress社のPSoCは、一般的なMCU(Microcontroller)と異なり、各種のディジタル回路、アナログ回路をチップ内に組み立て、IOピンに配線接続することができ、さらに、その回路構成やパラメータをプログラムにより変更することもできます。つまり、回路を構築するためのMCUです。これ1個で、殆どのコンピュータ周辺回路が組めるため、沢山のアナログおよびディジタル部品を集める必要がありません。PSoCシリーズのうち、今回使用しているPSoC1のCPUコア(M8C)は、整数演算能力はそこそこ高いのですが、メモリが少なく、浮動小数点演算(実数演算)もできません。外部から受け取った命令のデコードや回路を制御するためにCPUを使用し、通信や信号処理は、なるべくチップ内に組み立てた周辺回路で実行するようにします。
取りかかる前に、BluetoothモジュールのRBT-001の取扱説明書も読んでおいてください。コマンドを覚える必要はありません。取り扱い注意の他、Bluetoothの概要およびRBT-001に与えるコマンドのフォーマットと送信タイミングだけ解れば十分です。
プロジェクトの作成
- PSoC Designer を起動
- メニューより、File - New Project...を選択
- 下記のように入力してOKボタンをクリック。プロジェクト名、保存先、ワークスペース名は任意の名前でよい
- プロジェクトが作成されると、リソース(回路ブロックや配線)やパラメータリストが表示される。
- プロジェクトは、最初に設定した、保存先\ワークスペース名\ のディレクトリに、プロジェクト名.appというファイルに保存されている。.appファイルを開くことによって、PSoC Designerを起動することもできる。
- 後で割り込みを追加できるように設定をします(本例題では、設定しなくても動作しますが)
- メニューよりProject - Settings... を選択
- Project Settings画面の左欄で、Chip Editorをクリック
- Enable interrupt generation control にチェックを入れる
- OKボタンをクリック
ユーザモジュールのデータシート
対象デバイスで使用できる回路ブロック(ユーザモジュールと呼ばれる)は、右側のUser Modules欄に表示されています。ユーザモジュール名を右クリックし、表示されたメニューからDatasheet - Show in Separate Window を選択すると、ユーザモジュールのデータシートを見ることができます。データシートを見ながら、必要なユーザモジュールの配置やパラメータの設定をしていきます。
グローバルリソースの設定
PSoC Designer の左側にGlobal Resourceという欄があります。ここでは、主に、クロック、基準電位(アナログ回路のグランド電位など)などの設定を行います。クロックについては、必要な周波数を予め求めておく必要があります。そして、PSoCの内蔵システムクロック(IMO) の周波数(SysClk)を分周して必要な周波数を作り出します。ただし、周波数の分周比は、整数であるため、どんな周波数でも作れるわけではありませんので、どのようにクロックを分周するか計画しておく必要があります。
今回、PSoCに搭載予定の回路のうち、クロックを必要とするのは、UART, ADC, DAC、カウンタ、(当然、CPUも)です。ADCとDACにはいろいろな種類がありますが。今回は、最も高精度なDelSigPlusおよびDAC9を使用してみます。
- UART
- UARTのデータシートを見ると、各種の設定例が載っていて、まとめると下記の関係式のようになります。つまり、ビットレートの8倍のクロック周波数が必要です。そして、fCLKを得るために、システムクロックSysClkをN分周します。

- Bluetooth通信モジュールの説明書では、UARTのデータ転送レートの上限が、921600bpsとなっています。一方、PSoCのSysClkは、24MHzと6MHzの選択となっていますが、残念ながら、Bluetooth通信モジュールのUARTスピードの上限である、921600bpsでデータ転送を行うために必要なクロック周波数は、24MHzや6MHzの整数分周では作り出せません。最高速で通信を行う必要がある場合は、PSoCの内部クロックではなく、外部クロックを使用することになります。ここでは、やや通信速度が遅くなりますが、簡便に24MHzの内部クロック(SysClk)を13分周し、クロック周波数 = 1,846,154Hz, 転送レート = 230,769bps とします。
- ここでは、UARTで規定されているデータ転送レートの一つである、230400Hzを使用します。上記のクロックから求められるデータレートと +0.16% 程度の誤差がありますが、データシートでは、+/- 2%のクロック周波数誤差は実用上問題ないと書かれています。経験上、+/- 5%程度であれば、フレームエラーが発生しないようです。
- ADC
- DelSigPlusのデータシートには、下記の関係式が記載されています。

- 14bit精度でAD変換を行う場合の最高サンプリング周波数は、7812.5Hzと記載されています。最高サンプリング速度で、14bit精度(デシメーションレート = 256)にすることを想定して、上式からクロック周波数を求めると、8MHz = SysClk/3 となります。このクロックは、スイッチトキャパシタと呼ばれるアナログ回路およびデシメーションフィルタと呼ばれるディジタルフィルタのクロック(オーバサンプリングレート相当)を発生させる基準タイミングになります(詳しくは、大学院のミクストシグナルLSI工学で扱います)。CY8C28445は、専用のデシメーションフィルタを内蔵しているため、CPUの負荷がありませんが、他の方式のADCを使う場合は、CPUを使用するため、CPUクロックもサンプリング周波数に関係しているので注意が必要です。
- DAC
- DAC9は、ナイキストレートDAC、即ち、アップデートクロック周波数(出力更新周波数)= クロック周波数です。データシートを見ると、アップデートクロック周波数は最大125kHzですが、ここでは、ADCのサンプリングレートと同じ速度で動作させることにします。ADCのサンプリングレートは、SysClk/(3*4*256) としましたので、DACのクロック周波数は、SysClk周波数/3072とすればよいことになります。
PSoCには、SysClk (= 24MHz), CPU Clock を元にして、分周クロック VC1, VC2, VC3 の3種類のクロックを設定できます。以上の考察をまとめると、次の表のようなクロック設計ができます。ただし、VC1, VC2, VC3などの分周器では、3072分周のような長い周期は作れませんので、分周器で12分周までを行い、さらに8ビットカウンタを別途用意して256分周を行います。CPUクロックの周波数は、低くするほど消費電力を抑えられますが、低すぎると、他の処理をしている間に、ADCの変換結果を取りこぼす可能性がありますので、先ずは、SysClk/2かSysClk/4ぐらいにしておき、後で調整してください。
Clock | Divider | Frequency | Drived Circuit |
SysClk | - | 24M | - |
VC1 | SysClk/3 | 8MHz | ADC |
VC2 | VC1/4 | 2MHzHz | counter(さらに256分周してDACに供給) |
VC3 | SysClk/13 | 1,846kHz | UART |
ADCやDACを使う場合は、LSB当たりの電圧VLSBを何Vにするか決めるため、基準電圧Vrefという値を与える必要があります。ADCとDACの最大電圧 = 2Vref となるように回路が構成されるため、N bitの符号なし整数で数値を表す場合、次式の関係が得られます。

通常、Vrefの必要精度または必要とする入力電圧範囲 2Vrefに合わせて、Vrefの電圧を設定しますが、ここでは、特に目標仕様がないため、とりあえず、Vref = VBG としておきます。VBG は、バンドギャップリファレンスと呼ばれ、電源電圧や温度に依存しないバンドギャップリファレンス回路によって生成されます。この回路の仕組みについては、大学院のミクストシグナルLSI工学で扱います。
電位に関して、もう一つ決める必要があります。AGND(アナロググラウンド)です。この電圧は、PSoC内のアナログ回路の基準(0V)となります。アナログ回路で交流信号を扱うためには、正負の電圧が必要です。このため、ディジタルグランド電位を0Vにしてしまうと、マイナス値の信号を扱えなくなるので、バイアスを加えておく必要があります。ここでは、VDD/2を基準としましょう (VDDはPSoCの電源電圧を表す)。AGNDとVrefは、まとめてRef Muxのパラメータ項目で設定します。AGNDが電源電圧の変化によって変わっては困るような場合は、VBGまたは2VBGを選んでもよいでしょう。
以上の考察に基づき、Global Resource欄を下記のように設定してください。

UARTの設定
PSoCでは、多くのマイコンで使用されているUARTやI2Cなどの各種の通信規格の中から必要なものを組み合わせて実装できますが、BluetoothモジュールRBT-001のデータ通信ポートは、UARTのみとなっているため、PSoC側にも、UARTの送受信器を搭載します。
- 左側のUser Modules欄でDigital Comm - UART を右クリックして、メニューでPlaceを選択する
- レイアウト画面のブロックの2個の色が変わるが、拡大すると片方がTX(送信モジュール)で、もう一方がRX(受信モジュール)になったことが分かる
- 右側の Workspace Explorer で Tobacco 以下を展開すると、UART_1 があるのが分かる。複数配置すると、順次UART_2, UART_3 のように番号が増えていく。後で、このUART_1というモジュールのインスタンスに対して、ファームウエアから設定を行っていく(UARTではなくUART_1に対してプログラム操作を行うという意味)。
- 画面の拡大や移動は、上部のツールバーを使う方法と、CTRL + クリック、CTRL + Shift + クリック、ALT + ドラッグといった操作法がある。
- リソース画面の上半分のブロックがディジタルブロックで、下半分がアナログブロックとなっていて、機能を実装することにより消費されたブロックが色づけされるようになっている。
- 以下の手順で、RXを10番ピン(P1[7]ポート)、TXを11番ピン(P1[5]ポート)に接続する
- 左のPinout欄で、P1[7]を展開する
- Select = GlobalInOdd_7, Drive = High Z, Interrupt = DisableInt を選択
- 左のPinout欄で、P1[5]を展開する
- Select = GlobalInOdd_7, Drive = Strong, Interrupt = DisableInt を選択
- 設定したポートがMCU内部のグローバル配線に接続された様子がレイアウト画面に表示される
- UART_1ブロックの上側横配線の左端の四角をクリックするとセレクタの画面が表示される
- GIO_7のグローバル配線に接続可能な横配線を探し、セレクタをクリックする
- GlobalInOdd_7 を選択してCloseボタンをクリック
- UARTブロックの下側横配線の右端の四角をクリックするとセレクタとドライバの画面が表示される
- GOO_5のグローバル配線に接続可能な横配線を探し、ドライバをクリックする
- GlobalOutOdd_5 を選択してCloseボタンをクリック
- GIO_7 - RI0[3], GOO_5 - RO0[1] が接続された様子がレイアウト画面に表示される
- UART_1のブロックをクリック
- 左側のParameters欄で、以下のように設定する
- UART_1ブロックの入力、出力、クロック端子に配線された様子がレイアウト画面に表示される
レイアウト画面または右側のWorkspace Explorer欄でUART_1をクリックするとParameters欄に UART_1 のParameter設定が表示されるので、下記のように設定してください。

重要なパラメータについてのみ説明します。
- Clock
- グローバルリソースで決定したように、VC3 = SysClk/13 をクロックに使用します。この設定を行うと、レイアウト画面のTXブロックのクロック端子に"3"という数字が表示されます。これは、クロック端子にVC3がつながったことを意味しています。
- RXBufferSize
- 受信用バッファメモリの大きさです。スマートフォンから送信するコマンドの長さは、一定ではないので、少し大きめで、127Byteにしておきます。
- CommandTerminater
- 受信データの行終了を表す文字コード(10進数表記)です。13はCR(キャリッジリターン)に相当します。スマートフォン側で送信データの最後にCRの文字コード(0x0d)を追加して送ります。
- Parram_Delimiter(デリミタ)
- 受信データに含まれる単語の区切り文字コード(10進数表記)を表します。32はスペースです。区切りを入れておくと、頭から何ビット目を読むなどという計算をしなくてよいため、命令の解読が簡単になります。
カウンタの設定
DACのクロックを作るために、VC2 = VC1/4 = SysClk/3/4 = SysClk/12 を使用し、さらに、8ビットカウンターで256分周します。0からカウントするので、Period = 255、デューティ比を0.5とするため、カウント値 < 128 の条件で判定を行います。このため、Compare Value 128, CompareType = Less Than としてあります。以上で、ADCのサンプリング周波数と同じ、7812.5Hzのクロックが得られます。

- User Modules欄で、Counters - Counter8 を右クリックしてPlace
- 配線は後で行う
DACの設定
DACは信号波形を出力したり、センサやヒータに加える電流や電圧を制御したりといった様々な用途に使用することができます。9bit入力のDACを配置します。DACには、電圧出力DACと電流出力DACがあります。ここでは、9bit入力の電圧出力型のDACをPlaceし、下記のようにパラメータ設定をしてください。AnalogBusは、DACのブロックの横に走っているアナログ信号出力用の(アナログ出力バッファが付いている)配線です。Global Parametersの設定で、VDD/2を中心として、正負に信号を変化させることを想定していたので、入力整数のDataFormatは、ここでは、正負の値を扱いやすい2の補数表現(TwosComplement)を使用します。
[参考] Javaには、符号なし整数というのはないので(charで代用?)、ADCやDACは2の補数表現にしておいたほうが、扱いやすいと思います。

配線は、以下の手順で行います。
- 左側のUser Modules欄でDACs - DAC9 を右クリックして、メニューでPlaceを選択する
- 出力端子(ブロックの右側)つながっているAnalogOutBufをクリックして、メニューからPort_0_5を選択
- Port_0_5 (P0[5])に配線が接続される。アナログ出力は接続できるポートに制約がある
- クロック入力端子につながっているセレクタをクリックして、メニューからAnalogClock_0_Selectを選ぶ
- セレクタの入力配線をたどると、さらにセレクタがあるので、クリックしてメニューから、DBC00(アナログ回路のクロック用のバス配線の一つ)を選択すると、カウンタ出力と配線がつながる
- カウンタを配置した位置によっては、配線がつながらないかもしれない。その場合は、セレクタをクリックして選択する配線を変えるか、カウンタの配置を変更する。ユーザモジュールの配置替えは、回路ブロックをドラッグすることにより行える
ADCの設定
DelSigPlusというADCを使用します。このADCは、デルタ-シグマ型(またはオーバーサンプリング型)と呼ばれる高精度タイプのADCです。微小信号を検出するセンサ回路の他、無線通信、ディジタルオーディオなど、高精度信号処理の主流となっている方式です。
- User Modules欄で、ADCs - DelSigPlusを右クリックしてPlace
- Select Multi User Module画面で、14bit Resolution相当のDS2256回路構成を選んで、OKボタンをクリックする。これは、2次ノイスジェーピング, 256倍オーバーサンプリングの構成を意味している
- 入力端子は、後で設定するので何でもよい
- 出力は、デフォルトでCPUに送られるため設定する必要はない
- クロック入力端子に接続されたセレクタをクリックして、リストからVC1を選ぶ
DelSigPlus_1およびDigInv_1のパラメータを下記のように設定してください。このADCは差動入力が可能なのですが、ここではマイナス入力を使用しないので、NegInputGainをDisconnectedにしています。NegInputは仮にACC00にしてありますが、実際には接続されません。DataFormatは、AD変換したディジタル値の表現法です。ここでも、2の補数で表すことにします。
PGAの設定
センサを用いて高精度または高感度な計測をしたい場合、変換ビット数の大きい高精度なADCがあればよいのですが、現実のADCはアナログ回路の誤差が避けられないため、有効ビット数 ENOB(Effective Number Of Bits)があまり大きくありません。このため、ADCのに接続されるセンサの信号が小さい場合には増幅し、大きい場合には減衰させて、ADCの入力電圧範囲(2x基準電圧)にちょうど収まるような振幅にしておかないと、高精度な計測ができません。ADCの入力信号の増幅または減衰を制御するために、PGA(Programmable Gain Amplifier)という増幅回路を繋いでおきます。
- User Modules欄より、Amplifiers - PGA をPlace。
- ADCと同じ列に配置されなかった場合は、ドラッグしてADCの列に移動(他の列でもよいのだが、配線がややこしい)
- 入力端子付近(ブロック左側)をクリックして、メニューから、AnalogColumnMUXBusSwitch_0を選択
- SelSigPlus ブロックの入力端子付近をクリックして、メニューからACC00を選択(ACCはアナログ連続時間回路の意味)
- PGAのブロックとADCのブロックが接続される
PGA_1のパラメータを以下のように設定します。Referenceは、基準電位です。DACやADCなど、他の回路と一致させるため、AGNDを選択します。Gainは、スマートフォンから命令によって設定する予定ですが、ここでは、初期値として、1.000倍(= 0dB)を与えておきます。

RefMuxの設定
PSoCの外部に回路を設ける場合、基準電位(AGND)を合わせておかないと、ADCの入力に直流電圧オフセットがかかってしまうので、AGNDを外部に出力する必要があります。PSoC内の基準電圧を外部配線に出力するためには、アナログマルチプレクサ(アナログセレクタ)RefMux を使用します。
- User Modules欄より、MUXs - RefMux をPlace。
- DACと同じ列に配置された場合は、ドラッグして左から4列目に移動。DACの列は、既にアナログ出力配線がDACに使用されている
- 出力端子(ブロックの右側)に接続されているAnalogOutBus_3をクリックし、リストからPort_0_2を選ぶ
- ポートP0[0]に配線が接続されたことを確認
パラメータの設定は、Reference Select のみです。AGND以外の基準電圧も出力できるので、2つのPSoCでADCの基準電圧を合わせたいような場合にも、RefMuxを使用します。

LEDの設定
ADCの動作をLEDで知らせるため、ユーザモジュール欄から、Misc Digital - LED を1個配置し、下記のパラメータ設定をしておきます。また、LEDを空きポートに付けておくと、デバッグの際に何かと便利です。マイコンのデバッグのため、ブレークポイントの代わりにLEDを点灯させるというのも一つの手法です。

SleepTimerの設定
Bluetooth無線モジュールの起動を待ってから、コマンドを送信するための待ち時間を作るため、SleepTimerを用意します。ユーザモジュール欄から、Misc Digital - SleepTimerを1個配置します。このユーザモジュールは、回路ブロックを消費しませんので、レイアウトの上には表示されませんが、Workspace Explorer欄に、SleepTimer_1というインスタンス名で配置されます。名称がSleepTimerとなっていますが、CPUはSleepしません。

IOポートの設定
最後にポート設定を確認します。どのピンを使用しているか回路図と見比べて、チェックしてください。LEDをドライブするためには、Drive(ドライブ強度)をStrongにする必要があります。ドライブ強度は、接続するものによって変わるので、使用するポートだけ注意するひつようがあります。Strongは、出力値が論理値のH/Lのどちらかで、ハイインピーダンス状態がないという意味です。ON/OFFスイッチを接続する場合は、Pull UpかPull Down、アナログ信号や基準電圧は、入力出力にかかわらず、High Z Analogです。Selectは、接続先を選択するパラメータです。デフォルトではStdCPUとなっていますが、これはCPUに対してデータの入出力を行うという意味です。その他は、内部の配線へと接続されます。
下記に、IOポート設定と全体のレイアウトを示します。必要なユーザモジュールと配線が行われているかチェックしてください。

データフォーマット
スマートフォンからPSoCへ命令が送られ、PSoCは、命令を解読して実行し、その結果のメッセージまたはセンサの測定データをPSoCからスマートフォンに送るということを想定して、簡単な通信データのフォーマットを決めてみます。

- MCUへの命令
- 命令とパラメータは任意長さの文字列で表し、命令、パラメータ1, 2の間はSPC(スペース)で区切ります。行の最後にデリミタのCR(キャリジリターン)を置くことにします。このフォーマットは、PSoCのUART受信時のデフォルトフォーマットですが、PSoCのUARTパラメータで変更することができます。

- 命令は下記のように決めます。PGAの利得は、小数点表記(数値ではなく文字列として)送ることにします。PSoCの仕様上、連続可変ではなく11段階の変更となりますが、ファームウエア内で11段階に丸めることにします。DACの入力値は、HEX表記(整数ではなく文字列)で送ることにします。スマートフォンアプリでは、ボタンとコマンドライン入力のどちらからでも、下記の命令を送信できるようにします。
コマンドリスト
命令文字列 | 第1パラメータ | 第2パラメータ | 命令内容 |
meas | なし | なし | 連続測定 |
sample | なし | なし | 1点測定 |
set | gain | 0.06〜48.0(11段階) | PGAの利得を実数(培)で設定 |
set | dac | -256〜255 | DACの入力を10進法整数で設定 |
stop | なし | なし | 測定停止 |
reset | なし | なし | 回路設定を初期化 (PGA gain = 1.00, DAC = 0) |
- MCUからの応答
- データとメッセージを見分けるために2種類の開始デリミタまたはヘッダーを置くことにします。メッセージやエラーコード番号を取り決めて、対応するコードを送ってもよいのですが、頻繁に送るものではないので、メッセージ内容をそのまま文字列で送ることにします。
- ADCの変換結果などのデータは、文字列で表せば、符号の有無、整数/浮動小数点にかかわらず、同じ変数型で表現できるため、計測を含むシステムでは便利なのですが、多くの数値を連続して送る場合、数値を文字列で表すと、16進数を使用しても、1Byte(0 - 255)の通信データに対して、0 〜 15までの値しか表せないため、データ通信量が無駄に大きくなってしまうという欠点があります。
- ここでは、一度に送るデータ数が多くないため(スマートフォンの受信バッファとして1024Byteを想定)、測定結果はHEX表現の文字列で送信することにします。ADCの出力は、14bit(3.5Byte)ですが、UARTおよびBluetoothは1Byte(8bit)/1フレームで送受信するため、1測定データに対して、4Byteを割り当てます。
- データの終了(フッター)は、CR(キャリッジリターン) + LF(ラインフィード) としておきます。予め一度に送信するデータ数を取り決めておけば、受信側では、データの終了位置を検出する必要はないのですが、データの長さが一定でない場合は、ヘッダーとフッターがあったほうが便利です。フッターの値はデータを表す0~9, A~Fと重ならなければ何でもよいのですが、測定値をバイナリ形式で送る場合には、受信側ではデータ値が予測できないため、デリミタの値にも注意が必要です。

- ADCの出力データ形式
- ADCの出力データは、2の補数と符号無しが選択できますが、AGNDに対して、負電圧を測る可能性がある場合は、2の補数を使用すると負電圧が負の整数に対応するので便利です。ところが、受信側で文字列として受け取り、符号付き整数に変換されるとややこしい問題が起こります。簡単な対処法として、2の補数からオフセットバイナリ形式に変換して、負数を無くしてから送ることにします。受け取った後で、オフセット値を減算します。14bitの補数からオフセットバイナリ表現を求める場合には、2の補数 + 213 のようになります。受信したbyte整数を、文字列に変換しない場合は、問題ありません。ただし、PSoCは、ビッグエンディアンなので、short, int に変換する際には、注意が必要です。
通信データのフォーマットが決まったところで、ADCのサンプリング周波数とデータ通信速度の関係について考察をしておく必要があります。ADCのサンプリング速度は7812.5sample/sに設定しました。ADCのデータは、ヘッダーとフッターを含めると1回7Byte = 56bit + 2bit(UARTが使用) で送られます。従って、通信速度は、7812.5Hz x 58 = 453,125bps 以上が必要となります。今回の設定で使用している、230,400bps のUARTでは、通信速度が不足です。ヘッダーとフッターのオーバヘッドを減らすには、複数データを一度に送ります。例えば、2データを1回に送ると、ヘッダーとフッターを含め、1回当たり、11Byte = 56bit + 2bit, 送信頻度は、7812.5Hz/2 = 3906.25kHz, 通信速度 = 351,562.5Hzとなります。さらに、バイナリ形式でデータを送ると、データビット数が半分になり、通信速度は、226,562.5Hzとなり、全データを転送可能となります。ただし、後で示すプログラムでは、送信回数を減らすのではなく、データを間引いて送信することにより、必要通信速度を下げています。送信データを間引くと、PSoC側で時間平均などの処理が可能になります(ただし、CPUに余力がある場合)。後述のPSoCファームウエアの例では、送信データの間引き数を調整する仕組みを入れてありますので、確認してください。
ソースプログラムの記述とコンパイル
PSoC Designer右側のWorkspace Explorer欄で、Tobacco - Source Files - main.c をダブルクリックすると、C言語のエディタが開きます。右側のWorkspace Explorer欄には、配置されたユーザモジュールのリストが表示されていますので、ユーザモジュール名を右クリックしてデータシートを開くと、ユーザモジュールを制御するAPI関数の説明と、C言語およびアセンブリ言語のサンプルコードが表示されます。殆どは、このサンプルコードをコピペして、変数名等を少し修正すれば、すぐ使えます。APIは、ハイレベルAPIとローレベルAPIに分かれていますが、殆どの場合、高機能なハイレベルAPI関数だけで簡単に書くことができます。
回路パラメータの設定は、各ユーザモジュール用のレジスタにアクセスすることで変更や確認ができます。主なレジスタ操作のためのコマンドとビットマスク(レジスタ操作用の定数)がAPIに用意されており、直接レジスタを触らなくても使えるようになっていますが、回路設計ができる人ならば、標準的な設定以外でユーザモジュールを利用したり、一部の回路パラメータをプログラム中で切り替えたい場合もでてきます。ユーザモジュールのデータシートの一番最後に、レジスタの説明が書かれています。
では、試しに、Tobacco の main.c に、UARTのデータシートのサンプルコードをコピペして、コンパイルしてみましょう。UARTを配置すると、UART_1 のようにUARTのインスタンス名が付けられます。一方、サンプルのほうは、元 のUART のままですので、関数名および定数名がUARTとなっている部分を UART_1 に修正する必要があります。下に修正後の例を示します。このサンプルでは、クロックにVC1〜VC3(分周回路)を使用せずに、Counter8(8bitカウンタ)を使用していますが、Tobaccoでは、UARTのクロッキングにはカウンタを使用せず、VC3をクロックに使用する設定になっているので、Counter8_WritePeriod(155);以下の3行はコメントアウトしておきます。
UARTのデータシートに付いているサンプルコード(回路に合わせて少し変更)について説明しておきます。この例は、PSoCファームウエアの典型的パターンです。他のユーザモジュールでも、ほぼ同じような書き方になります。UARTの設定は、送信側と受信側で合わせておく必要があります。設定項目は、通信速度、データビット数、パリティビット付加、ストップビット数になります。Bluetooth モジュールの説明書で工場出荷時の設定を確認してください。
[参考] UARTのデータフレームのについて調べておいてください。データビットは、7bitと8bitの場合がありますが、MCUや組み込みシステムでは、通常、8bitデータです。データが7bitだとすごく扱いにくいですね。パリティを付けると1bitの誤り検出ができるのですが、この方法ではエラーの位置は特定できないので、パリティを付けることは少ないようです。ストップビットは、1bitと2bitの場合がありますが、組み込み系では1bitが使われるようです。理論上は、1bitだとフレームエラー(送信側と受信側で1フレームの周期がずれる)が検出できない可能性はありますが、十分高精度なクロックを使えば、フレームエラーは起こらないはずです。ここでは、8-N-1(8bit data, No parity, 1 stop bit)を使用します。
- strPtr: UARTは、1Byteずつ送受信するので、char型のポインタを受信バッファとして用意する
- UART_1_CmdReset(): UART_1の初期化
- UART_1_IntCntl(): 受信割り込みを許可する(受信を検知するために必要です)
- カウンタは使用しないのでコメントアウト
- UART_1_Start: UART回路の動作開始関数。UART_1_PARITY_NONEは、APIに定義されているパリティ設定レジスタのビットマスク
- [NOTE] ユーザモジュールは、各モジュール用のStart関数で開始させないと動作しません。
- M8C_EnableGInt: グローバル割り込みの許可(裏で割り込みを使用するAPI関数があるため、プログラム上で割り込みを使わない場合でも許可でよいと思います)
- UAR_1_CPutString: 文字列定数をTXに送信する
- while(1): 受信待ちの無限ループ
- [NOTE] MCUのプログラムは、OSの上で動作しているわけではないので、電源が切られるまでプログラムが終了しないようにする必要があります。このため、初期設定が終わったら、無限ループの中でIOや周辺回路からの割り込みを待つような構造になります。
- UART_1_bCmdCheck(): デリミタを含むデータ(1行分のデータ)を受信したことを確認します
- UART_1_szGetParam(): RXバッファから単語デリミタまでを読み出して、charポインタに代入します
- UART_1_PutString(strPtr): Null終端文字列をTXに送信(ここでは、受信した単語のエコーを返している)
- [参考] バイナリデータを送る場合は、1Byteの場合は、UART_1_PutCgar(1Byteをchar * にキャスト), またはUART_Write(intなど2Byte以上をchar * にキャスト)を使用
- while(strPtr = UART_1_szGetParam()): RXバッファが読み出せなくなるまで単語単位で繰り返し読む
- UART_1_CmdReset(): RXバッファをクリアして、次の受信に備える
void main(void)
{
char * strPtr; // Parameter pointer
UART_1_CmdReset(); // Initialize receive buffer
UART_1_IntCntl(UART_1_ENABLE_RX_INT); // Enable RX interrupts
UART_1_Start(UART_1_PARITY_NONE); // Enable UART
M8C_EnableGInt; // Turn on interrupts
UART_1_CPutString("\r\nWelcome to PSoC UART \r\n");
while(1) {
if(UART_1_bCmdCheck()) { // Wait for command
if(strPtr = UART_1_szGetParam()) { // More than delimiter
UART_1_CPutString("Command =>");
UART_1_PutString(strPtr); // Print out command
UART_1_CPutString("<\r\nParamaters:\r\n");
// loop on each parameter
while(strPtr = UART_1_szGetParam()) {
UART_1_CPutString(" <");
UART_1_PutString(strPtr); // Send each parameter
UART_1_CPutString(">\r\n");
}
}
UART_1_CmdReset(); // Reset command buffer
}
}
}
練習のため、上記のコードをビルドしてみましょう。一般のMCUと異なり、まだハードウエア機能が定義されていませんので、C言語で書いた部分だけではコンパイルできません。最初は、Generateボタンでハードウエアの定義を含む、プロジェクト全体をビルドします(時間がかかります)。2回目からは、回路部分の変更がなければ、CompileボタンでC言語部分をコンパイルできます。サンプルコードにバグは無いはずですので、下のOutputタブを開いて、
0 error(s) 0 warning(s)
となることを確認してください。ここで、エラーが出る場合は、回路の設定のほうにミスがある可能性があります。Tobacco[Chip]タブを開いて、回路を修正してください。

もう一つの典型例として、DelSigPlasのデータシートにあるサンプルコードを少し変更した例について説明しておきます。
- DelSigPlus_Start(DelSigPlus_HIGHPOWER): DelSigPlusのStrat関数
- DelSigPlus_HIGHPOWERは、アナログ回路ブロックの消費電力設定レジスタのビットマスクを表す定数。消費電力を下げたい場合は、DelSigPlus_LOWPOWERに、性能を上げたい場合は、DelSigPlus_MIDPOWERかDelSigPlus_HIGHPOWERにする。データシートには説明が書かれていないが、消費電力は、周波数特性、SR(ステップ応答の速さ)、PSRR、雑音密度など、アナログ性能全般に効く。詳しくは、大学院のミクストシグナルLSIで説明する。HIGHPOWERでは、LOWPOWERの場合よりも周波数特性(GBP)が一桁程度高いようだ。
- DelSigPlus_StartAD(): 回路の動作開始ではなく、サンプリングの開始命令
- DelSig(デルタシグマ型)ADCは、1サンプル毎の処理ではなく、高速にアナログ値のサンプリングを行い、データ列から正確なディジタル値を算出する方式のため、一度スタートすれば、連続的にサンプリングを続ける使い方をする。サンプリングを止めるための、DelSigPlus_StopAD()という関数も用意されている。
- DelSigPlus_fIsDataAvailable(): 1サンプル分のAD変換が完了したかどうかをチェックする関数
- DelSigPlus_iGetDataClearFlag(): AD変換の結果レジスタからデータを取り出す関数。データを読んだあと、自動的にデータ使用可能フラグをクリアして、次の結果読み出しに備える
void main(void)
{
M8C_EnableGInt; // Global Interrupt
DelSigPlus_1_Start(DelSigPlus_1_HIGHPOWER); // Analog power
DelSigPlus_1_StartAD(); // Start sampleing
while (1) {
if ( DelSigPlus_1_fIsDataAvailable() ) { // Check the data buffer
// Read the buffer and send to UART port as a 2byte integer
UART_1_Write(DelSigPlus_1_iGetDataClearFlag(), 2);
}
}
}
Tobacco 用のファームウエアの記述例を、以下にリンクしますので、ダウンロードして、main.cにコピペまたは上書きしてください。ソースファイルの位置は、Tobacco\Tobacco\Tobbaco\main.c です。PSoCの高機能なAPIを使用したシンプルな記述なので、PSoCのデータシートを参照しながら読めば、すぐに理解できると思います。記述内容を把握したら、Generateを実行してください。
PSoCファームウエアの例

ファームウエアの大まかな流れ
回路ブロックをスタートさせた後、Bluetoothモジュール(RBT-001)の設定を行っています。RBT-001のコマンドについては、取扱説明書をよく読んで、ファームウエアで設定した内容を理解しておいてください。スマートフォンからのコマンドと見分ける手間がかかりため、イベントフィルタにより、RBT-001がメッセージを出さないように設定してあります。本来は、RBT-001のメッセージを受け取って、エラー処理を行うことにより、信頼性を高めるようにします。余力があれば、挑戦してみてください。また、Bluetoothデバイス名を Tobacco-D と設定しています。この名前は、スマートフォン側に通知され、どのデバイスと通信しているのかを見分けることができますので、自分の好きな名前に、変更してみてください。データ長やチェックサム(誤り検出用の1Byteデータ。計算法はRBT-001の説明書を参照)の値が誤っていると、コマンドがRBT-001に受理されませんので、変更は注意深く行ってください。
ファームウエアの書き込み
0 error(s) 0 warning(s) でGenerateが完了したら、次のような手順でPSoCにプログラムを書き込みます。
- PSoC miniProgから電源が供給されるので、基板の電源は切っておいてかまわない
- PSoC MiniProgの向きを間違えないように注意して、5pinピンヘッダーに接続する
- PSoC Designerのメニューより、Program - Program Part...を選択
- Program Part画面(PSoC Programmer)が起動する
- 下図のように設定して、矢印ボタン(書き込み)をクリック
- 電源を入れているときは、Acquire Mode をResetにすること。
- 下のステータス表示欄に、PASSと表示されれば書き込み成功です。

動作確認とキャリブレーションデータの取得
RBT-001は、電源投入時に、UARTポートからコマンドを受付け、設定内容を不揮発性メモリに保存しますが、設定が反映されるのはRBT-001の再起動後です。つまり、電源投入前に、MCUとRBT-001のUART設定を一致させておく必要があります。説明書によると、工場出荷時のUARTの通信速度は、9600bpsに設定されているので、9600bps以外の通信速度で使用する場合は、Bluetoothモジュールの設定時と通信時で、PSoCのUART通信速度を変更できるようにしておく必要があるということです(例えば、DIPスイッチなどで手動変更)。しかし、初回しか必要ないスイッチを基板に置くのは無駄なので、RBT-001をUSBでPCに接続して、PCからBluetoothモジュールのほうの設定を変更するための基板を実験室に用意してあります。市販のUART-USB変換モジュール(例:秋月電子通商 FT232RL USBシリアル変換キット)などを利用して、簡単に自作することもできます。
変換モジュールとBluetoothモジュールの接続向きに注意して、PCに接続したら、ターミナルソフトで、0x0252230100760503(UART Speed = 38,400bps)を書き込みます。または、Bluetoothモジュールのメーカサイト(マイクロテクニカ)から、命令書き込みソフトをダウンロードしておくと、Bluetoothモジュールに各種コマンドを簡単に送ることができます。
製作した基板の動作確認は、以下のような手順で行うことができます。
- 電源電圧とAGND電位の確認
- VSS(電源のマイナス側)とAGND(アナロググランド)出力端子の間およびVSSとVDD(レギュレータの出力)の間の電圧を、桁数多めのディジタルマルチメータで測定する
- PSoCのグローバルパラメータ設定で、リファレンス電圧が、VDD/2 +/- VBG を選んだので、下記のような電位関係になるはず。DACの出力範囲およびADCの入力範囲は、AGNDを中心として、+/-VBGの範囲となる
- 消費電力の確認
- 測定用の直流電源器を用意し、VDD配線 - マルチメータ(電流測定モード) - 直流電源器を接続し、5Vラインから供給される電流値を測定する。レギュレータの供給能力(150mA)より小さいことを確認
- スマートフォンからPSoCを連続測定(Continuous)にしたときと、測定停止(Stop)にしたときの電流を確認する。測定停止にしても、クロックは動いているので、大きくは違わないはず
- DACの確認
- スマートフォンアプリのコマンド欄に、reset と入力し、Commandボタンをタッチ(2回Returnキーをたたいてもよい)すると、DACのディジタル入力値 = 0になる
- ディジタルマルチメータでDACの出力ピンとAGNDの出力ピンの間の電圧を測定する。通常、10mV程度のオフセットがあるでので、記録しておく
- スマートフォンの入力欄に set adc 255 を入力し、Commandボタンをタッチ(2回Returnキーをたたいてもよい)、DACのディジタル入力値を最大にする。255以上の値を入力した場合は、ファームウエア側で、255に読み替えている
- DACの出力電圧を記録しておく。
- 同様にして、set adc -255 のコマンドを送信し、DACの出力電圧を測定、記録しておく。AGNDに対して、-1.2V〜-1.3V ぐらいの電圧がでるはず
- ADCの確認
- スマートフォンアプリのコマンド欄に、reset と入力し、Commandボタンをタッチ(2回Returnキーをたたいてもよい)すると、ADCの入力に繋がっているPGAの利得 = 1.00倍となる
- ADCの入力をAGNDに接続したときの、スマートフォンのシングル測定結果を何度か記録し平均する
- ADCの入力端子とAGNDの間に、計測用の直流電源器で1.00Vを加えたときの、スマートフォンのシングル測定結果を何度か記録し平均する
- 同様に、ADCの入力端子とAGNDの間に、-1.0Vを加えて、測定を行う
- 測定結果を記録しておき、正確な電圧値が必要なアプリケーションを作成する際に、オフセットと利得誤差に対する補正を行う
- 補正データの利用法
- DACとADCのオフセットおよび利得誤差の較正データは、正確な測定値が必要なアプリケーションで必要となる。非線形誤差が問題となる場合は、較正テーブル(オフセットとゲインエラーだけでなく途中の値)も測定する
- 補正はスマートフォンアプリとPSoCのファームウエアのどちらでも実行することができるが、誤差には個体差があるため、ファームウエアやスマートフォンアプリに較正データを書き込むことはできず、別ファイルから読み込む必要がある
- 製品開発の場合は、PSoC基板側にマイクロSDカードのモジュールを付けるか、PSoC内のフラッシュメモリに補正値を記録することになる。PSoCには、プログラムメモリの一部を使用してEEPROMエミュレーション行うためのユーザモジュールが用意されており、スマートフォンから、較正データをPSoCに書き込むこともできるので、これを利用すれば、基板サイズの小型化に有効である

お問い合わせはこちらまで: kitagawa@is.t.kanazawa-u.ac.jp
© Kanazawa Univ., 2013