MBR3 で、静電容量センサの実験 (2) [PSoC]
MBR3 で作った静電容量ボタンは、静電容量センサに触れたときに ON/OFF します。 センサの感度をもっと高くすると、近づいただけで ON/OFF できる「近接センサ」に利用できます。
MBR3 を近接センサに設定する
近接センサの実験をするために、新しいプロジェクトを作成しました。 ここでは、 "Design002" というプロジェクトを作成しています。
静電容量センサを近接センサ (Proximity sensor) として使用するには、 EZ-Click 2.0 の "CapSense sensor configuration" タブで、設定をおこないます。 まず、 "Number of proximity sensors" で、近接センサに使用する静電容量センサの数を "1" に設定します。
すると、 "Proximity sensors" セクションが現れます。 このタブで、以下の設定を行います。
- "Proximity sensors" セクションの "Pin" カラムを "CS0/PS0" に設定します。
- "Sensor" カラムのセンサ名を "BTN0" に変更します。
- "Buttons" セクションの "CS1/PS1/GPO0/SH" で "Enable" カラムをチェックします。
- 同じく "Sensor" カラムのセンサ名を "BTN1" に変更します。
他の部分は、デフォルトのままにしておきます。 前回と同様に "Save Project" でプロジェクトを保存し、 "Select Target Device" で接続相手を探し、 "Apply Current Configuration" で設定を書き込みます。 これで、 "BTN0" が近接センサとして、 "BTN1" が静電容量ボタンとして動作するようになります。
近接センサの動作を確認する
近接センサの動作は、前回と同様に "CapSense output" タブで確認する事ができます。 "Button" に "BTN0" を選択すると、近接センサの動作が現れます。 指を近づけると、センサが反応を始め、5センチメートルの距離で "Button status" が "Proximity" に変化して接近を検出したことを知らせます。 さらに指を近づけて、静電容量センサに触れると、 "Button status" は "On" に変化します。
静電容量ボタンとの違いについて
近接センサも静電容量ボタンと同じように静電容量の変化をとらえて、接近を検出しています。 それでは、静電容量ボタンと近接センサの違いは、どこにあるのでしょうか。 比較するために、 "BTN1" の動作もグラフにしてみました。
- Base line の値が大きい
静電容量ボタンの Base line は、約1530です。 これに対して近接センサの Base line は、約52660です。 つまり、30倍以上の違いがある事がわかります。
- Raw count の振れ幅が大きい
静電容量ボタンに触れた時、 Raw count は300ほど高くなります。 これに対して、近接センサに触れた時、 Raw count は5000ほど高くなります。
これらの差は、静電容量センサのいわゆる「感度」による違いです。 「感度」は、単位容量に対する Raw count の差として定義されます。 近接センサの感度が30倍高いので、指を触れていない時の静電容量の Raw count も30倍大きくなっています。 結果として、 Base line が30倍大きな値になったというわけです。
振れ幅の差も「感度」が影響したものです。 指が触れた時に増加する静電容量に対する Raw count の増分も感度が高くなれば大きくなります。 近接センサは、 Raw count の振れ幅が大きいことで、近接状態の検知と接触状態の検知を行う事ができます。
アプリケーションで使うには
近接センサの状態を一般的なアプリケーションで利用する場合も、 I2C インターフェイスを介してレジスタにアクセスし、状態を知ることができます。 具体的には、アドレス 0xAE の下位1ビットが "BTN0" 近接センサの状態を示しています。
参考文献
- CY3280-MBR3 CapSense® MBR3 Evaluation Kit
MBR3 の具体的な使い方は、このキットに関連した文書として提供されています。 特に "CY3280-MBR3 User Guide" が、キットを使わない場合でも役に立ちます。
- CY8CMBR3102, CY8CMBR3106S, CY8CMBR3108, CY8CMBR3110, CY8CMBR3116 CapSense® Express™ Controllers Registers TRM
I2C でアクセス可能なレジスタが解説されています。 MBR3 では、ここで記述されているレジスタに対するアクセスによって、すべての動作を規定しています。
- CY8CMBR3xxx CapSense® Design Guide
この記事では、被覆導線を利用して実験を行うための簡易ボタンを作成しました。 本格的に静電容量ボタンを使いたい場合には、この文書を参照して作成します。
MBR3 で、静電容量センサの実験 (1) [PSoC]
さきごろ、 CapSense MBR3 というシリーズのチップが発表されました。 MBR は、 "Mechanical Button Replacement" つまり、「機械式ボタンを置き換えよう」という意味を持っています。 では、さっそく使ってみますか。
実験に使った回路図
今回使用する実験基板は、このような回路になっています。 左側にあるのは、 MiniProg3 を接続するための5ピンコネクタです。 ここから電源を取り入れ、さらに I2C で通信を行います。 右側にあるのが、静電容量ボタンのセンサです。 単に抵抗を介して電極がつながっているだけですが、これだけの構造で静電容量の変化を検出し、ボタンとして動作します。
MBR3 の設定方法
MBR3 は、プログラムを開発する必要がありません。 その代わりに、 I2C を介して動作を設定する事ができます。 設定に必要なのは、 EZ-Click 2.0 というアプリケーションと、電気的に I2C の信号をやり取りするための USB-I2C Bridge というハードウェアです。 EZ-Click 2.0 が対応する USB-I2C Bridge には、以下のようなものがあります。
- CY3240-I2USB
- CY3280-MBR3 CapSense® MBR3 Evaluation Kit
- CY8CKIT-002 PSoC® MiniProg3 Program and Debug Kit
この他に多少の改造が必要になりますが、 CY8CKIT-042 PSoC® 4 Pioneer Kit などに搭載されている KitProg の USB-I2C Bridge 機能を使用する事もできます。 また、現在のところ、 USB-Serial Bridge Controller には対応していません。 この記事では、 MiniProg3 を使って、設定を行っていきます。
EZ-Click 2.0 で静電容量ボタンを設定する
EZ-Click 2.0 を起動したら、最初に設定ファイルの作成場所を指定します。 メニューから "File"→"New Project..." を選択して、 "New Project" ダイアログを呼び出します。
このダイアログでは、プロジェクト名("Project Name")、プロジェクトの配置場所("Project Path")、そして使用するデバイス("Target Device")を指定します。 ここでは、 CY8CMBR3102-SX1I を使用する "Design001" というプロジェクトを作成しています。
"CapSense sensor configuration" タブでは、ふたつのボタンをイネーブルします。 "Enable" カラムのふたつのチェックボックスにチェックを入れるだけで、静電容量ボタンが動作するようになります。 ここでは、ボタンの名前を回路図の名前に合わせて "BTN0" と "BTN1" に変更しています。 他の設定は、デフォルトのままにしておきます。
プロジェクトが完成したので、 "Save Project" でプロジェクトを保存します。
ここで、 MBR3 に MiniProg3 を接続し、さらに PC に接続します。 そして、 "Select Target Device" で接続相手の MBR3 を探しにいきます。
"Select I2C Target" ダイアログが開いたら、 "Ports" で "MiniProg3" を選択します。 そして、 "Power" で MiniProg3 から供給する電源電圧を指定します。 ここでは、 5.0V の電源を供給します。 さらに、 "I2C Speed" で、 I2C インターフェイスで使用するクロックの周波数を指定します。 ここでは、 400kHz で通信を行います。
ここまで設定できたら、 "Devices" に通信可能なデバイスの一覧が現れますので、目当てのデバイスを選択します。 この例では、デバイスは一つだけ見つかりました。
これで準備完了です。 "Apply Current Configuration" で MBR3 に設定を書き込むと、すぐに静電容量ボタンの動作が始まります。
静電容量ボタンの確認
静電容量ボタンの動作の確認も、 EZ-Click 2.0 から行います。
- CapSense output タブを開きます。
- "Select view" で "Button output" を選びます。
- "Button" で ボタン "BTN0" または "BTN1" を選びます。
- "Graph" で "Raw count vs Base Line" を選びます。
- "Start" ボタンをクリックします。
これで、グラフが表示されるようになります。 ここでは、 "Raw count" と "Base Line" という二つの二つの値が表示されています。 "Raw count" は、静電容量センサがとらえた容量値を表しています。 また、 "Base Line" は、「静電容量センサに指が触れていない時の推定容量値」を表しています。 静電容量センサに指が触れると、これらの値が乖離(かいり)して、指が触れた事を検知するという仕組みです。
グラフの上の方にある "Button status" は、「MBR3 が、指が触れたと判断しているか」を On/Off で示します。 また、 Cp (pF) は、「静電容量センサに指が触れていない時の推定容量値」をピコファラッド単位で計算した値です。
アプリケーションで使うには
実際のアプリケーションでは、 "Button status" で表示されているボタンの状態だけを知りたい場合がほとんどであろうと思われます。 その場合、 I2C インターフェイスを介してレジスタを読み出す事で、ボタンの状態を知ることが出来ます。 具体的には、アドレス 0xAA の下位2ビットが、ふたつのボタンの状態を表しています。
他には、ボタンの状態を MBR3 の出力端子により直接知らせる機能もあります。 この機能を使うためには、 EZ-Click 2.0 で、今回とは違う設定を使用する必要があります。
参考文献
- CY3280-MBR3 CapSense® MBR3 Evaluation Kit
MBR3 の具体的な使い方は、このキットに関連した文書として提供されています。 特に "CY3280-MBR3 User Guide" が、キットを使わない場合でも役に立ちます。
- CY8CMBR3102, CY8CMBR3106S, CY8CMBR3108, CY8CMBR3110, CY8CMBR3116 CapSense® Express™ Controllers Registers TRM
I2C でアクセス可能なレジスタが解説されています。 MBR3 では、ここで記述されているレジスタに対するアクセスによって、すべての動作を規定しています。
- CY8CMBR3xxx CapSense® Design Guide
この記事では、被覆導線を利用して実験を行うための簡易ボタンを作成しました。 本格的に静電容量ボタンを使いたい場合には、この文書を参照して作成します。
PSoC 3 で、かけ算器を作った [PSoC]
全国一千万人のデータパスファンの皆様、お待たせいたしました。 すっかり、公開を忘れていましたが、ついに、かけ算器までたどり着きました。 といっても、まだまだ、チューニングが必要ですね。 ひとまず、公開。
かけ算器の考え方
以前、「PSoC 3 で、16ビット演算器を作った」で定数倍のかけ算器を作りました。 このデータフローでは、アキュムレータのデータをシフトしながら、時々、データレジスタの値を足しこむことで、10倍の値を生成していました。 この「データレジスタの値を足しこむ」タイミングを制御すると、任意の倍数の「かけ算器」に改造することができます。
そのタイミングの制御の方法ですが、三つ目のデータパスを追加してシフトレジスタとして使い、その MSB の値にしたがって、データレジスタの値を足すか足さないかを決定します。 dp1 の A0 をシフトレジスタとして使用し、 dp0 の D0 レジスタに入った値を10倍にして dp0 の A0 に求める計算を行っています。
実際には、 dp1 に8ビットの値を入れてかけ算を行うため、かけ算の手順は、 STEP1 から STEP8 までが必要です。 このデータフローでは、下位4ビットの STEP5 から STEP8 までを記述しています。
シフトレジスタ部分の構成
シフトレジスタ dp1 で使用する機能そのものは、 dp0 の機能と揃えました。 そのため、ステートマシンと機能コードデコーダは、 dp0 と dp1 で同じものが使えます。
Verilog の記述
Verilog 記述は、一つの Verilog ファイルに三つのデータパスを記述しているので、かなり長くなってしまいました。 また、 dp0 で使用される機能コードの最下位ビットには、 dp1 の MSB を直接取り入れて、機能コードデコーダを簡略化しています。
//`#start header` -- edit after this line, do not edit this line // ======================================== // // Copyright noritan.org, 2013 // All Rights Reserved // UNPUBLISHED, LICENSED SOFTWARE. // // CONFIDENTIAL AND PROPRIETARY INFORMATION // WHICH IS THE PROPERTY OF NORITAN.ORG. // // ======================================== `include "cypress.v" //`#end` -- edit above this line, do not edit this line // Generated on 06/08/2013 at 16:32 // Component: Multiply16 module Multiply16 ( output drq, input clock, input en, input reset ); //`#start body` -- edit after this line, do not edit this line // State code declaration localparam ST_IDLE = 4'b0000; localparam ST_GET = 4'b0001; localparam ST_STEP1 = 4'b1000; localparam ST_STEP2 = 4'b1001; localparam ST_STEP3 = 4'b1010; localparam ST_STEP4 = 4'b1011; localparam ST_STEP5 = 4'b1100; localparam ST_STEP6 = 4'b1101; localparam ST_STEP7 = 4'b1110; localparam ST_STEP8 = 4'b1111; localparam ST_WAIT = 4'b0011; localparam ST_PUT = 4'b0010; // MSB part of Datapath function localparam CS_IDLE = 2'b00; localparam CS_CLEAR = 2'b01; localparam CS_SL = 2'b10; localparam CS_ADD = 2'b11; // Wire declaration wire[3:0] state; // State code wire f0_empty; // DP1.F0 is EMPTY wire[1:0] f1_full; // DP0.F1 is FULL wire[1:0] so; // Shift out of DP0_A wire[1:0] co; // Carry out of DP0_A wire dp1_msb; // MSB of DP1 // Pseudo register reg[1:0] addr; // MSB part of Datapath function reg d0_load; // LOAD D0 from F0 reg f1_load; // LOAD F1 // State machine behavior reg [3:0] state_reg; always @(posedge reset or posedge clock) begin if (reset) begin state_reg <= ST_IDLE; end else casez (state) ST_IDLE: if (en & ~f0_empty) begin state_reg <= ST_GET; end ST_GET: state_reg <= ST_STEP1; ST_STEP1: state_reg <= ST_STEP2; ST_STEP2: state_reg <= ST_STEP3; ST_STEP3: state_reg <= ST_STEP4; ST_STEP4: state_reg <= ST_STEP5; ST_STEP5: state_reg <= ST_STEP6; ST_STEP6: state_reg <= ST_STEP7; ST_STEP7: state_reg <= ST_STEP8; ST_STEP8: state_reg <= ST_WAIT; ST_WAIT: if (~f1_full[1] & ~f1_full[0]) begin state_reg <= ST_PUT; end /*ST_PUT*/ default: state_reg <= ST_IDLE; endcase end assign state = state_reg; // Internal control signals always @(state) begin casez (state) ST_IDLE: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b0; end ST_GET: begin addr = CS_CLEAR; d0_load = 1'b1; f1_load = 1'b0; end ST_STEP1, ST_STEP2, ST_STEP3, ST_STEP4, ST_STEP5, ST_STEP6, ST_STEP7: begin addr = CS_SL; d0_load = 1'b0; f1_load = 1'b0; end ST_STEP8: begin addr = CS_ADD; d0_load = 1'b0; f1_load = 1'b0; end ST_WAIT: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b0; end /*ST_PUT*/ default: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b1; end endcase end reg drq_reg; always @(posedge clock) begin casez (state) ST_PUT: drq_reg <= 1'b1; default: drq_reg <= 1'b0; endcase end assign drq = drq_reg; cy_psoc3_dp16 #(.cy_dpconfig_a( { `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE0 : Do nothing*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM1: IDLE1 : Do nothing*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM2: CLEAR0 : A0 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM3: CLEAR1 : A0 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0<= ALU <= (A0 + D0) << 1;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + D0);*/ 8'hFF, 8'h00, /*CFG9: */ 8'hFF, 8'hFF, /*CFG11-10: */ `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, `SC_SI_A_DEFSI, /*CFG13-12: */ `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, 1'h0, `SC_FIFO1_ALU, `SC_FIFO0_BUS, `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, `SC_FB_NOCHN, `SC_CMP1_NOCHN, `SC_CMP0_NOCHN, /*CFG15-14: */ 10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, `SC_WRK16CAT_DSBL /*CFG17-16: */ } ), .cy_dpconfig_b( { `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE0 : Do nothing*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM1: IDLE1 : Do nothing*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM2: CLEAR0 : A0, A1 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM3: CLEAR1 : A0, A1 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0 <= ALU <= (A0 + A1) << 1;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + A1);*/ 8'hFF, 8'h00, /*CFG9: */ 8'hFF, 8'hFF, /*CFG11-10: */ `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, `SC_CI_A_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, `SC_SI_A_CHAIN, /*CFG13-12: */ `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, 1'h0, `SC_FIFO1_ALU, `SC_FIFO0_BUS, `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, `SC_FB_NOCHN, `SC_CMP1_NOCHN, `SC_CMP0_NOCHN, /*CFG15-14: */ 10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, `SC_WRK16CAT_DSBL /*CFG17-16: */ } )) dp0( /* input */ .reset(reset), /* input */ .clk(clock), /* input [02:00] */ .cs_addr({addr[1:0], dp1_msb}), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(f1_load), /* input */ .d0_load(d0_load), /* input */ .d1_load(1'b0), /* output [01:00] */ .ce0(), /* output [01:00] */ .cl0(), /* output [01:00] */ .z0(), /* output [01:00] */ .ff0(), /* output [01:00] */ .ce1(), /* output [01:00] */ .cl1(), /* output [01:00] */ .z1(), /* output [01:00] */ .ff1(), /* output [01:00] */ .ov_msb(), /* output [01:00] */ .co_msb(), /* output [01:00] */ .cmsb(), /* output [01:00] */ .so(), /* output [01:00] */ .f0_bus_stat(), /* output [01:00] */ .f0_blk_stat(), /* output [01:00] */ .f1_bus_stat(), /* output [01:00] */ .f1_blk_stat(f1_full[1:0]) ); cy_psoc3_dp8 #(.cy_dpconfig_a( { `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE0 : Do nothing*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM1: IDLE1 : Do nothing*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM2: CLEAR0 : A0 <= F0;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC___F0, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM3: CLEAR1 : A0 <= F0;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= (A0 << 1);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0 <= (A0 << 1);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= A0;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= A0;*/ 8'hFF, 8'h00, /*CFG9: */ 8'hFF, 8'hFF, /*CFG11-10: */ `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, `SC_SI_A_DEFSI, /*CFG13-12: */ `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, 1'h0, `SC_FIFO1_BUS, `SC_FIFO0_BUS, `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, `SC_FB_NOCHN, `SC_CMP1_NOCHN, `SC_CMP0_NOCHN, /*CFG15-14: */ 10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, `SC_WRK16CAT_DSBL /*CFG17-16: */ } )) dp1( /* input */ .reset(reset), /* input */ .clk(clock), /* input [02:00] */ .cs_addr({addr[1:0], 1'b0}), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(1'b0), /* input */ .d0_load(1'b0), /* input */ .d1_load(1'b0), /* output */ .ce0(), /* output */ .cl0(), /* output */ .z0(), /* output */ .ff0(), /* output */ .ce1(), /* output */ .cl1(), /* output */ .z1(), /* output */ .ff1(), /* output */ .ov_msb(), /* output */ .co_msb(), /* output */ .cmsb(), /* output */ .so(dp1_msb), /* output */ .f0_bus_stat(), /* output */ .f0_blk_stat(f0_empty), /* output */ .f1_bus_stat(), /* output */ .f1_blk_stat() ); //`#end` -- edit above this line, do not edit this line endmodule //`#start footer` -- edit after this line, do not edit this line //`#end` -- edit above this line, do not edit this line
かけ算器の使い方
これまでのかけ算器は、 dp0 の FIFO にデータが入ったら、それをトリガにして計算を開始していました。 今回は、 dp1 の FIFO への書き込みをトリガにしています。 そのため、かけ算器に値を書き込むときには、 dp0 への書き込みの後、 dp1 への書き込みをおこないます。
for (i = 0; i < N_BATCH; i++) { CY_SET_REG16(Multiply16_INPUT_PTR, alub[i]); CY_SET_REG8(Multiply16_MULTIPLIER_PTR, alua[i]); }
かけ算の結果は、前回の「PSoC 3 で、 DMA 対応倍増器を作った」と同様に DMA で自動的に取り出されます。 プログラムの部分は、前回同様、計算結果を自動的に検証して、検証結果を LCD に表示させるようにしています。
プロジェクトアーカイブ
この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
CY8CKIT-049 Prototyping Kit で簡単に Bootloader を呼び出す [PSoC]
PSoC 42xx シリーズを使って、簡単に工作を楽しめる PSoC 42xx Prototyping Kit (CY8CKIT-049) が提供されています。 このボードは、 Bootloader という仕組みを使って、ユーザが作成したアプリケーションを導入する事ができます。 この記事では、この基板で Bootloader を使う際の「チョットイイ小技」をご紹介します。
Bootloader でアプリケーションを導入する仕組み
この基板は、 CY8C4245AXI-483 (PSoC 4) を搭載した大きい基板と CY7C65211-24LTXI (USB-Serial) を搭載した小さい基板で構成されており、この写真のように二つに切り離して使うことができます。 小さい基板は、 PC の USB 端子に接続する事で、 UART シリアルインターフェイスとして働きます。 さらに、小さい基板と大きい基板の間は、電源と UART の RX/TX の計4本の配線で接続されています。 大きい基板の PSoC 4 に搭載されている Bootloader プログラムは、この UART シリアルインターフェイスを介して、 PC からアプリケーションを受信し、 Flash ROM の内容を書き換えます。
このように Flash ROM を書き換えるためには、 Bootloader が動作している状態で PC との通信を開始しなくてはなりません。 ところが、ユーザが作成したアプリケーションは、 Flash ROM を書き換えるために作られている訳ではありませんので、 Flash ROM を書き換える仕掛けを持っているとは限りません。 アプリケーションを書き換えるためには、何とかして Bootloader を呼び出さなくてはならないのです。 さて、困った。
Bootloader を呼び出す標準的な方法
Bootloader を呼び出す方法は、標準では一つだけ用意されています。 それは、 SW1 を押しながら、 PSoC 4 にリセットをかける事です。 この基板には、リセット・スイッチは搭載されてないため、基板を無改造で使用する場合には、電源を再投入することによるパワー・オン・リセットによる方法しかありません。 さらに、 PSoC 4 の電源は小さい基板を介して USB コネクタの VBUS に接続されています。 このような事情により「Bootloader を呼び出すには、 SW1 を押しながら USB コネクタに抜き差しする。」というのが、標準的な手順になっています。
ところが、この方法には問題があります。 それは、 USB コネクタの信頼性です。 小さい基板は、 USB コネクタを基板パターンで作成しています。 そのため、ちょっと荷重をかけると、 USB コネクタの VBUS が切れてしまうのです。 つまり、 SW1 を押すだけでも VBUS が切れてしまいます。 これでは、パワー・オン・リセットをかけるどころではありません。
ふたつの基板を切り離して配線で接続すると、 SW1 を押しても USB コネクタに力がかからないようになります。 これで、 SW1 を押しながら、小さい基板を抜き差しして、確実に Bootloader を呼び出す事ができます。 これでも良いのですが、小さい基板を抜き差しする事によって、シリアルインターフェイスが途切れてしまう事態は避けられません。 もっと、簡単で確実な方法はないものでしょうか。
サイプレス公式 BLOG で紹介された手法
実は、すでに Bootloader 呼び出す手間を減らすための手法が考案されていて、公式 BLOG で紹介されています。 キーは、この回路です。
この Timer コンポーネントには、 "reload" "start" "stop" の三つの制御端子が追加されて、すべての端子が SW1 に接続されています。 「あれっ? "start" と "stop" に同じ信号が入ったら、動かないんじゃないの?」 ごもっともです。 秘密は、それぞれの端子の「モード」にあります。
Input | Mode |
---|---|
reload | Falling edge |
start | Falling edge |
stop | Rising edge |
それぞれの制御端子のモードは、この表のように設定されています。 まず、 Timer を起動したときには、カウンタは止まっています。 そこから SW1 を押すと、 SW1 には立ち下がりエッジが発生します。 立ち下がりエッジでは、 "reload" と "start" イベントが働きますので、ダウンカウンタに初期値が設定され、カウントが始まります。 しばらく SW1 が押されたままになっていると、ダウンカウンタがゼロに達して、割り込みを発生させます。 この時の時間は、 Timer に接続されたクロックの周波数とダウンカウンタの初期値によります。 この例では、 12kHz のクロックを 24000 回数えているので、2秒の設定になっています。
ダウンカウンタがゼロになる前に SW1 が離されると、 SW1 に立ち上がりエッジが発生します。 そのため、 "stop" イベントが働き、ダウンカウンタは停止し、割り込みは発生しません。
割り込みサービスルーチンでは、 Bootloadable を経由して Bootloader を呼び出すコードが記述されています。 こうして、 SW1 を2秒以上押し続けると Bootloader を呼び出す仕掛けが出来ました。
リソースがもったいないじゃないか
この仕掛けは、記述するコードの量が、ごく少ないので簡単に実装できますが、ハードウェアタイマを一つ占有してしまうので、もったいない感があります。 ここは、ソフトウェアで実装して、必要なハードウェアリソースを少なくしましょう。
クロックを使った周期割り込みタイマ
一つ目の実装で使うのは、 Interrupt コンポーネントにクロックを直結したタイマです。 PSoC 3 や PsoC 5LP では、本当にクロックを直結する事が出来たのですが、 PSoC 4 では、このようにフリップフロップを使わなくてはなりません。 これは、内部配線の都合でクロックとロジック信号を明確に区別する必要があるためです。 200Hz のクロックをフリップフロップで2分周したので、1秒間に100回割り込みが発生します。
// PIT 割り込みサービスルーチン CY_ISR(int_Pit_isr) { LedMachine(); BootMachine(); }
割り込みサービスルーチンは、このようになっています。 呼び出されているふたつの関数は、前回まで PSoC 40xx の Bootloader を実験していた時に使用していたものと同じです。
// Bootloader への移行を確認するステートマシン // 移行確認時間を3秒とする #define BOOT_VALIDATION (3*INT_FREQ) uint32 boot_count = 0; void BootMachine(void) { if (SW1_Read()) { // SW1 が RELEASE されている boot_count = 0; } else { // SW1 が PUSH されている if (++boot_count >= BOOT_VALIDATION) { // 確認期間を超えて SW1 が押され続けた Bootloadable_Load(); } } }
実は、前回までの記事で作成した Bootloadable application には、ブートに入るための仕掛けが、すでに入っていたのでした。 ここでの実装では、 SW1 を3秒間押し続けると Bootloader が呼び出されるようになっています。
// PIT 割り込みの初期設定 int_Pit_StartEx(int_Pit_isr);
初期設定も簡単です。 Interrupt コンポーネントに割り込みサービスルーチンを登録して、おしまいです。
// UART の起動 // これが無いと Bootloader 移行直後の接続がうまくいかない UART_Start(); // 割り込み許可 CyGlobalIntEnable;
最後に割り込みを許可するのですが、一つだけ、やらなくてはならない事がありました。 それは、 UART コンポーネントを起動する事です。 このアプリケーションでは、 UART は、いっさい使っていません。 それでも、 UART の起動が必要な理由は、 USB-Serial に接続されている端子 P4[0] および P4[1] を不定にしないためです。
何度か Bootloadable アプリケーションをプログラムして試してみたのですが、 Bootloadable アプリケーションでは、少なくとも TX 端子 (P4[1]) を High にしておかないと、うまく Bootloader を呼び出す事が出来なくなってしまいました。 ここでは、 UART コンポーネントを配置してしまって、これらの端子の状態を確定させています。
SysTick を使った実装
二つ目は、 SysTick を使った実装です。 一つ目の周期割り込みでは、クロックの周期がそのまま割り込み周期になっていましたが、 SysTick の場合には、コードで周期を明記する必要があります。
// Systick 周期の定数 #define SYSTICK_PERIOD (24000000/INT_FREQ)
PSoC 42xx をデフォルトの状態で使用しているので、 SYS_CLK は、 24MHz です。 よって、 SysTick に与える分周比は、このように計算できます。
// SysTick 割り込みサービスルーチン CY_ISR(SysTick_isr) { LedMachine(); BootMachine(); }
割り込みサービスルーチンは、周期割り込みを使った場合とまったく同じです。
// SysTick 割り込みサービスルーチンの初期設定 CyIntSetSysVector(SysTick_IRQn + 16, SysTick_isr); // SysTick 割り込み周期の設定 SysTick_Config(SYSTICK_PERIOD);
初期設定部分も、「PSoC 40xx で SysTick を使ってみる」で使ったものと同じです。
ウォッチドッグ・タイマを使った実装
一番大きく異なっているのは、ウォッチドッグ・タイマを使った場合の実装です。 コンポーネントの使い方は同じですが、「PSoC 40xx でウォッチドッグ・タイマを使ってみる」で紹介したものとは、コードがかなり異なっています。
// Watchdog 周期の定数 #define WDT_PERIOD (32768/INT_FREQ)
まず、割り込み周期の計算方法が異なっています。 これは、 PSoC 42xx に内蔵されている ILO クロックの周波数が、標準で 32768Hz であるためです。
// Watchdog 割り込みサービスルーチン CY_ISR(int_Wdt_isr) { CySysWdtClearInterrupt(CY_SYS_WDT_COUNTER0_INT); LedMachine(); BootMachine(); }
割り込みサービスルーチンも異なっています。 まず、割り込みフラグをクリアする時にクリアすべきカウンタを指定しています。 これは、 PSoC 42xx のウォッチドッグ・タイマが三つの16ビットカウンタで構成されているためです。 三つのカウンタは、設定により、並列に動作させる事も、カスケードに接続して長周期タイマとして使用する事もできます。 ここでは、16ビットのカウンタひとつで十分なので、 COUNTER0 だけを使っています。
さらに、 PSoC 40xx に内蔵されていたウォッチドッグ・タイマは、フリーランニングタイマでしたが、 PSoC 42xx に内蔵されているものは、リロード機能付きのタイマです。 そのため、次に期待される割り込み時刻を再設定する必要がなく、コードが簡単になっています。
// Watchdog 割り込みの初期設定 int_Wdt_StartEx(int_Wdt_isr); // Watchdog 割り込み周期の設定 CySysWdtUnlock(); CySysWdtWriteMode(CY_SYS_WDT_COUNTER0, CY_SYS_WDT_MODE_INT); CySysWdtWriteMatch(CY_SYS_WDT_COUNTER0, WDT_PERIOD); CySysWdtWriteClearOnMatch(CY_SYS_WDT_COUNTER0, 1); CySysWdtEnable(CY_SYS_WDT_COUNTER0_MASK); CySysWdtLock();
初期設定部分は、大幅に複雑になっています。 これは、先に述べたように、ウォッチドッグ・タイマが三つのカウンタで構成されているため、それぞれの設定を行う必要があるためです。 また、このウォッチドッグ・タイマは、安全のため、ウォッチドッグ・タイマにロックを掛ないと設定が変更できないようになっています。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できるようになります。 今回は、一つのプロジェクトに三つの機能を盛り込んでしまい、以下のマクロ宣言でどの機能を有効にするかを決める方法をとっています。
// 3種類のタイマから周期タイマを選ぶ #define PIT (0) // Periodit Interrupt Timer #define WDT (1) // WatchDog Timer #define SYSTICK (0) // SysTick Timer
参考文書
- PSoC® 4: PSoC 4200 Family Datasheet
- PSoC 42xx シリーズのデータシートです。 電気的な特性に関しては、いちばん詳しい情報が掲載されています。
- PSoC 4100 and 4200 Family: PSoC® 4 Architecture Technical Reference Manual (TRM)
- PSoC 41xx シリーズと PSoC 42xx シリーズの内部構造を開設した文書です。 ウォッチドッグ・タイマについても、この文書に書かれていますが、あまり理解しやすいとはいえません。
- AN90799 - PSoC® 4 Interrupts
- PSoC 4 の割り込みについて書かれた文書です。 この中でウォッチドッグ・タイマが解説されていますが、やっぱり、物足りないですね。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 40xx でウォッチドッグ・タイマを使ってみる [PSoC]
前回の記事では、専用タイマモジュールである TCPWM を使わずに SysTick を使って周期的なタイマを実現しました。 今回は、もうひとつのタイマ Watchdog Timer (WDT: ウォッチドッグ・タイマ)を使って周期的なタイマを実現します。
ウォッチドッグ・タイマの役割
ウォッチドッグ・タイマのそもそもの役割は、プログラムが動作しているかどうかを確認する事です。 ユーザが書いたプログラムは、定期的にウォッチドッグ・タイマに「生きてるよ」と知らせます。 もちろん、声をかけるのではなく、ウォッチドッグ・タイマのレジスタに特定の値を書きこむ事で、プログラムが生きている事を通知します。
ウォッチドッグ・タイマは、プログラムからの「生きてるよ」通知を監視していて、ある一定の時間を超えて通知が来なくなったら、「プログラムが暴走を始めた」と判断してリセットをかけます。 すると、リセットをかけられたプログラムは、再び、正常な動作をするようになるという仕組みです。
ウォッチドッグ・タイマは、内蔵低速発振器 (Internal Low-speed Oscillator: ILO) で駆動される16ビットのタイマを持っていて、このタイマで割り込みを発生させます。 ILO の発振周波数は、標準値で 40kHz なので、ウォッチドッグ・タイマが発生する割り込み間隔は、1.6秒ほどです。 実際には、割り込みまでの時間を設定する仕組みも入っていますので、「最大1.6秒」ということになります。
ウォッチドッグ・タイマが発生した割り込みが処理されず、ふたたび割り込みを発生する状態になると、ウォッチドッグ・タイマは「暴走」を確信し、リセットをかけます。
ここまでの解説は、ウォッチドッグ・タイマの本来の使い方です。 もし、割り込みが発生したところで、確実に割り込み処理を行ったとすると、周期的に動作するタイマとして動作させる事ができます。
ILO クロックの周波数は、いくつだろう?
この記事を書いている時点では、PSoC 40xx シリーズのデータシートによると、 ILO の発振周波数は、標準値で 40kHz となっています。 ところが、 Architecture Technical Reference Manual や Registers Technical Reference Manual と呼ばれる文書では、 32kHz が標準となっています。 確認したところ 40kHz の方が正しい値のようです。
ただし、 ILO の発振周波数の仕様は、 20kHz から 80kHz とかなり広範囲にわたっています。 そのため、 32kHz と書いてあっても誤差範囲内に入ってしまいます。 あまり、信用しすぎないようにした方がよさそうです。
WDT を扱うコンポーネント
PSoC Creator のコンポーネント・カタログを探しても、ウォッチドッグ・タイマのコンポーネントはありません。 では、どうやってウォッチドッグ・タイマを使うかというと、 Global Signal Reference コンポーネントで取り扱います。
Global Signal Reference コンポーネントを回路図上に配置すると、一緒に Interrupt コンポーネントが付いてきます。 Global Signal Reference コンポーネントは、デフォルトの状態でウォッチドッグ・タイマの割り込み信号である WDT 信号が出力されます。 これだけで、ウォッチドッグ・タイマの割り込みを受け付ける仕組みが出来上がります。
ウォッチドッグ・タイマのコード
ウォッチドッグ・タイマは、コンポーネントとして提供されるわけではないので、初期設定などをコードとして書かなくてはなりません。 初期設定は、このようになっています。
- ウォッチドッグ割り込みを受けとる Interrupt コンポーネントを初期設定する。
- 割り込みまでのカウント数を MATCH レジスタに書き込む。
- ウォッチドッグ割り込みを許可する。
- ウォッチドッグ・タイマを起動する。
この後、全体の割り込みを許可すると、 MATCH レジスタに設定した時間が経過した後、ウォッチドッグ割り込みが発生します。
このファームウェアでは、前回の SysTick モジュールと同様、1秒間に100回割り込みが発生するように設定しています。 ただし、使用するクロックが、 40kHz ですので、割り込み間隔カウント数の計算部分が異なっています。
割り込み処理ルーチンは、 TCPWM や SysTick を使用する場合と少々異なっています。 これは、ウォッチドッグ・タイマが、フリーランニングタイマという種類に分類されるからです。 たとえば、 SysTick を使う場合、カウンタがある値に一致したら、カウンタの値が自動的にリロードされます。 そのため、特別にタイマを操作する必要はありません。
ところが、フリーランニングカウンタの場合、カウンタ値が一致してもリロードは行われません。 また、カウンタの値をソフトウェアから書き換える事もできません。 そのため、周期的なタイマとして使う場合には、次に割り込みを発生させるべきカウンタ値を MATCH レジスタに書き込んで、割り込み周期を規定します。
その他、ウォッチドッグ割り込みに関連する割り込みフラグを確実にクリアする必要があります。 これも、ウォッチドッグ・タイマがコンポーネントとして提供されていないがゆえに必要な操作です。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できるようになります。 これまで同様、 LED の点滅パターンを少々変更しています。
参考文書
- PSoC® 4: PSoC 4000 Family Datasheet: Programmable System-on-Chip (PSoC®)
- PSoC 40xx シリーズのデータシートです。 電気的な特性に関しては、いちばん詳しい情報が掲載されています。
- PSoC 4000 Family: PSoC® 4 Architecture Technical Reference Manual (TRM)
- PSoC 40xx シリーズの内部構造を開設した文書です。 ウォッチドッグ・タイマについても、この文書に書かれていますが、あまり理解しやすいとはいえません。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 40xx で SysTick を使ってみる [PSoC]
前回の記事では、 PSoC 40xx シリーズに Bootloader を導入してみました。 Bootloadable として準備したのは、 PWM を使用して LED を駆動し、 CPU をフルに使って押しボタンの状態を監視していました。 PSoC 40xx シリーズは、用意されているリソースが少ないので、このような使い方は、かなり贅沢です。 今回は、 "SysTick" と呼ばれる周期タイマを使って、 LED の駆動と押しボタンの監視を行わせます。
SysTick って何だっけ?
SysTick は、 CPUである ARM Cortex-M0 に近い場所にある周期タイマで、他の Cortex-M0 搭載プロセッサでも内蔵されています。 SysTick は、もちろん PSoC Creator からも使う事ができます。 ただし、残念な事にコンポーネントとして提供されているわけえはないので、普通のマイコンで割り込みを扱う時と同じように、すべてプログラムから制御してやる必要があります。 SysTick を使うために必要なのは、以下のステップです。
- SysTick 割り込みに対応する割り込みベクタに割り込みサービスルーチン (Interrupt Service Routine; ISR) を割り当てます。
- SysTick の周期を設定します。
- 割り込みを許可します。
これだけで、 SysTick が周期割り込みとして作用します。 それぞれのステップは、 PSoC Creator の API 関数またはマクロで定義されているので非常に簡単です。 ここでは、 CPU が 12MHz クロックで動作していることを前提として、1秒当たりの割り込み回数 SYSTICK_FREQ から1周期のクロック数 SYSTICK_PERIOD を計算させています。
ここで紹介するファームウェアでは、すべての処理を ISR の中で行っています。 そのため、 main 関数には無限ループのみ残っています。 CPU は、ほぼ遊んでいますので、お好きな処理を加えてやってください。
割り込み処理ルーチンに実装した二つのステートマシン
SysTick により周期的に呼び出す処理内容は、このように二つのステートマシン BootMachine と LedMachine で構成されています。
BootMachine では、押しボタンの監視を行っています。 このステートマシンでは、押しボタンが押され続けた時間を boot_count という変数で計測していきます。 そして、 BOOT_VALIDATION で決められた長さに達したら、 API 関数 Bootloadable_Load を使って、 Bootloader を呼び出します。 BOOT_VALIDATION の長さは、2秒に設定しています。
LedMachine では、 LED の駆動を行っています。 led_state という変数を使用して、赤を2回、緑を2回点滅させるパターンを繰り返させています。 このステートマシンの周期 LED_PERIOD は、2秒に設定しています。
Bootloadable の書き込み
Bootloadable プロジェクトをビルドしたところ、 5856 バイトと前回のプロジェクトよりも若干小さくなりました。 理由は、深く追い求めてはいません。
Bootloadable の書き込みは、前回と同様に I2C インターフェイスを介して行います。 前回の Bootloadable を書込んでいたら、押しボタンを2秒以上押し、Bootloader を呼び出してから Bootloader Host アプリケーションで CYACD ファイルを書込みます。 前回から、 LED の点滅パターンが変化したのがわかるでしょうか。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できるようになります。
参考文書
- Using the SysTick Timer in PSoC® 4 – KBA91374
- PSoC 4 で SysTick を使う方法について述べています。 コンポーネントにしてくれれば、もっとありがたいのですが。
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
PSoC 40xx に Bootloader を導入してみた [PSoC]
PSoC に 40xx シリーズなるものが出てきました。 本当に使えるんだろうかていうぐらい内部リソースを削られてしまっています。 そんなリソースの無い PSoC 40xx シリーズで、 Bootloader は使えるのか、また、使う意味が有るのだろうか検証してみます。
PSoC 40xx のメモリ容量
PSoC 40xx シリーズには、いくつか種類が有ります。 現在のところ、 CY8C4013 と CY8C4014 という番号にサフィックスが付いた型番になっています。 Flash ROM のサイズは、 CY8C4013 が 8kB で、 CY8C4014 が 16kB になっています。 Bootloader が使用可能であるかを検証するためには、 8kB の CY8C4013 で試さなくてはならないでしょう。 ここでは、8ピン SOIC の CY8C4013SXI-410 を題材に使います。
Bootloader で使用可能な通信インターフェイス
Bootloader に対応したプロジェクトの作成手順は、 PSoC 3 等の他の PSoC と同様です。 PSoC Creator で Application Type を指定してプロジェクトを作成し、 Bootloader または Bootloadable コンポーネントを配置するだけです。 問題になりそうなのは、 Bootloader で使用する通信線をどこに確保するか、 Bootloader を入れたら Bootloadable アプリケーションが入る隙間が無くなるんじゃないかという点です。
PSoC 40xx シリーズでは、リソースを大胆に削ってしまったおかげで、使用可能な通信線は I2C しか残されていません。 そのため、自分で通信プロトコルを記述する以外では、 I2C のほかに選択肢がありません。 そのため、 Bootloader では、必然的に I2C を選ぶことになります。
コンポーネントとしては、ソフトウェア UART も存在しますが、この UART は、送信専用であるため、送受信の機能が必要な Bootloader には使用できません。 あきらめて、 I2C を使う事にしましょう。
Bootloader プロジェクト
通信線が決まった所で、 Bootloader プロジェクトを作成します。 Application Type に Bootloader を指定してプロジェクトを作成したら、 I2C コンポーネントと Bootloader コンポーネントを配置します。
Bootloader コンポーネントで通信に使用するコンポーネントに I2C を選択したら、他はデフォルトのままにしておきます。
8ピン SOIC の場合、端子数が極端に限られてくるため、 I2C を選んだ時点で SWD によるデバッグをあきらめざるをえません。 CYDWR ファイルで、デバッグ端子の特性を GPIO するのをお忘れなく。
他には、 Bootloader を呼び出すためのスイッチと状態を表示させるための LED 端子とそれを駆動する PWM を配置しました。
ソースコードには、リセット直後にスイッチが0.1秒以上の間押されていたら Bootloader を呼び出すコードを記述しました。 スイッチが押されていない場合には、可能であれば Bootloadable を呼び出します。
ソースコードの最初の方では、 I2C のポート "SCL" と "SDA" をプルアップ付きポートに設定しています。 これで、外付けプルアップ抵抗を省略する事ができます。 ところで、この設定は有効なのだろうか?
プロジェクトをビルドしたところ、 "Debug" 設定のままでは Flash ROM の消費量が 8kiB を 184 バイトほど超えてしまいました。
そこで、 "Release" 設定で試したところ、消費量はで 4608 バイトとなりました。 どうやら、この CY8C4013 で Bootloader を使用する時には、 "Release" 設定を使用しなくてはならないようです。
Bootloadable プロジェクト
Bootloader プロジェクトが出来たら、次は、 Bootloadable プロジェクトを作成します。 これも、 Bootloader と同様に Application Type に Bootloadable を指定してプロジェクトを作成した後、 I2C コンポーネントと Bootloadable コンポーネントを配置します。
I2C コンポーネントは、配置はしましたが、アプリケーションでは使用しません。 Bootloadable コンポーネントでは、先ほどビルドした Bootloader プロジェクトの HEX ファイルおよび ELF ファイルを指定して、 Bootloader 側の情報を読み取らせます。
他には、 Bootloader を呼び出すためのスイッチと状態を表示させる LED 端子と駆動用 PWM を配置してあります。 見ためではわかりませんが、 LED の点灯パターンは、 Bootloader のパターンから変更しているので、 LED の点灯パターンを見て、現在の状態を判断する事ができます。
Bootloadable のソースコードでは、2秒以上スイッチが押されたら Bootloader を呼び出すコードを記述しました。 これで、リセットや電源遮断をすることなく、簡単に Bootloader を呼び出す事ができます。
ビルドをすると、Flash ROM の消費量は 5912 バイトとなりました。 この容量には、 Bootloader の部分も含みますので、 Bootloadable の正味消費量は 1304 バイトです。 これなら、もっと色々な事ができそうです。
Bootloadable の書き込み
Bootloadable がビルドできたら、 Bootloader Host アプリケーションを使って Bootloadable をプログラムします。 今回は、 I2C インターフェイスを使用するので、 USB-I2C ブリッジが必要です。 てもとに適当な USB-I2C ブリッジが無いので MiniProg3 で書き込みます。
あれ? MiniProg3 が使えるんだったら、 Bootloader なんて必要ないんだな。
プロジェクトアーカイブ
この記事で作成したプロジェクトは、このファイルの拡張子を "zip" に変更すると再現できるようになります。
参考文書
- AN86526 - PSoC® 4 I2C Bootloader
- PSoC 4 で I2C インターフェイスを使用した Bootloader を使う方法について解説しています。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC Creator でも GitHub がしたい (4) [PSoC]
前回まで、 GuiHub にプロジェクトを登録したり取り出したりする手順について考えました。 Git は、リビジョン管理ツールですから、当然、プロジェクトを変更したうえで、 GitHub に再度登録する機能もあります。
プロジェクトを変更する
プロジェクトの開発を想定して、まず、プロジェクトを変更します。 ある種のリビジョン管理ツールでは、一度に一人だけがプロジェクトを変更できるようにするため、リポジトリを「ロック」してから変更をおこないます。 Git では、同時に複数の人がリポジトリを変更する事を許可しているので、リポジトリを「ロック」する必要がありません。 PSoC Creator でプロジェクトを開いて、そのまま変更します。 ここでは、 PWM を2出力に変更し、ソースコード main.c も少々変更しました。 変更が終わったら、プロジェクトのすべてのファイルを Save し、 Build します。
ローカルリポジトリに Commit
プロジェクトの変更が終わったら、 Git Gui でリポジトリを開きます。 Open Rescent Repository のリストから選ぶか、 Open Existing Repository でローカルリポジトリの場所を指定します。
Git Gui でリポジトリを開いたままにしていた場合には、 Rescan ボタンをクリックして、変更されたファイルを探しにいきます。
いずれの場合も、 Unstaged Changes に変更されたファイルが並びます。 リポジトリを作成した時と同様に、すべてのファイルが必要な訳ではありません。 そのため、ここから必要なファイルを選びます。
ここで変更されたファイルを一つ一つ選択していっても良いのですが、もっと便利な方法があります。 メニュー "Commit"→"Stage Changed Files To Commit" を選択して、変更されたファイルを一括で選びます。 このメニューアイテムは、 Unstages Changes に並んだファイルを Staged Changes に移動するものですが、このあと追加のダイアログが現れます。
このダイアログでは、「未管理のファイル 52 個を管理するか」を聞いています。 ここで候補として挙げられた 52 個のファイルは、 Git の管理に入っていないが、ワークスペースに存在するファイルです。 主に、 PSoC Creator によって、新たに作成されたファイルが、これに相当します。
今回の場合、 PSoC Creator で必要となるすべてのファイルは、リポジトリの作成時に管理するように指定しましたので、他のファイルを新たに管理下に置く必要はありません。 「いいえ」をクリックして、既存のファイルだけを選択します。
ファイルが選択されて Staged Changes に並んだら、次はコメントを書きます。 GitGui では、 Commit するときのコメントは必須になっています。 コメントを書込んだら、 Commit ボタンをクリックして、ローカルリポジトリに登録します。 正常に登録されたら、ダイアログが出てきますので、 Close で閉じます。
GitHub に Push
Commit では、ローカルリポジトリに登録されます。 これをリモートリポジトリである GitHub に登録するのが Push です。 Push ボタンをクリックします。
Push は、ローカルリポジトリの変更箇所をリモートリポジトリに登録します。 次のダイアログでは、リポジトリの送り元と送り先を指定します。 送り元の "master" は、ローカルリポジトリに先ほど Commit した版を表します。 送り先の "origin" は、 GitHub のリモートリポジトリに付けた名前です。
Push をクリックすると、ローカルリポジトリの内容が GitHub に転送されます。
Push が終わったら、転送の詳細を示すダイアログが表示されます。 Success が表示されたら、転送成功です。
メニュー "Repository"→"Visualize All Branch History" を選択すると、リポジトリに記録された履歴が表示されます。 ローカルリポジトリの "master" とリモートリポジトリの "remotes/origin/master" が、同じバージョンになっていることがわかります。
GitHub の WEB ページで確認
上で確認したリモートリポジトリの履歴は、実はローカルリポジトリにコピーされたリモートリポジトリの状態を見ているにすぎません。 本当に GitHub のリポジトリが変更されたかどうかは、 GitHub の WEB ページに直接確認した方が確実です。 そこで、 WEB ページ https://github.com/noritan/Design109_3p0_3 から、 "xx commits" と記述してあるリンクをクリックすると、リポジトリが Commit された履歴を見ることが出来ます。
すると、これまでに Commit してきた履歴が表示されます。 Git Gui から確認したのと同様に三つのバージョンが確認できます。 これで、変更後のプロジェクトが共有できるようになりました。
参考文献
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC Creator でも GitHub がしたい (3) [PSoC]
前回まで、 PSoC Creator のワークスペースを GitHub のリポジトリとして保存する方法について調べてきました。 今回は、保存したリポジトリを参照して、ローカルリポジトリにワークスペースを再現し、 PSoC Creator から使ってみます。
リポジトリの場所を確認する
まず、リポジトリの場所を示す URL をクリップボードにコピーします。 GitHub の WEB ページ(ここでは https://github.com/noritan/Design109_3p0_3 )に行き、右下あたりにある "SSH clone URL" の "copy to clipboard" ボタンをクリックします。 これで、リポジトリの場所を示す URL が、クリップボードにコピーされました。
Git Gui で、リポジトリのコピーを作る
次に新たに Git Gui を開きます。 Git Gui は、一つのリポジトリを扱う事しかできません。 そのため、別のリポジトリを操作しようとするときには、別の Git Gui を開きます。
Git Gui が開いたら、 "Clone Existing Repository" をクリックして、 GitHub に存在するリポジトリをローカルリポジトリにコピーする準備をします。
このダイアログでは、リポジトリのコピー元とコピー先を指定します。 まず、クリップボードに入っているコピー元の情報を Source Location にペーストします。 次に、 Target Directory に新たにローカルリポジトリを作成するディレクトリを指定します。
この例では、 Git がデフォルトで使用するホームディレクトリの "git" というディレクトリに "Design109_3p0_3" というリポジトリを作成しています。 指定し終わったら、 Clone ボタンをクリックして、リポジトリのコピーを開始します。
コピーが終わったら、 Git Gui のウィンドウが開きます。 まだ、リポジトリをコピーしただけの状態なので、変更箇所は一切なく、何も表示されていません。
PSoC Creator で開いてみる
ここで作成したローカルリポジトリは、ワークスペースそのものでしたので、 PSoC Creator から直接開くことが出来ます。 PSoC Creator からプロジェクトファイルを指定して開きます。
開いたプロジェクトは、そのまま Build して、プログラムもすることができます。 これで、 GitHub に登録されたプロジェクトをローカルなワークスペースで使用する事が出来るようになりました。
参考文献
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 HID Bootloader を試す (5) [PSoC]
これまで、単純に Bootloader を実装してきましたが、 MiniProg3 などを使って SWD でアクセスすると、フラッシュ ROM の内容が丸見えになってしまいます。 大事なファームウェアを保護するには、フラッシュ ROM にプロテクトをかけます。
フラッシュ ROM には、4レベルのプロテクションレベルがある
フラッシュ ROM には、 256 バイトの row 単位でプロテクトを設定できるようになっています。 それぞれの領域に設定可能なプロテクションレベルは、以下の4種類です。
プロテクションレベル | 概要 |
---|---|
U - Unprotected | 全くプロテクトがかかっていない状態です。 内蔵ファームウェアからも外部プログラマからも読み書きができます。 |
F - Factory Upgrade | 内蔵ファームウェアからの読み書きと外部プログラマからの書き込みは出来ますが、外部プログラマからの読み出しが禁止されます。 |
R - Field Upgrade | 内蔵ファームウェアからは読み書きができますが、外部プログラマからは読み書きともに禁止されます。 |
W - Full Protection | 外部プログラマからのアクセスおよび内蔵ファームウェアからの消去書き込みが禁止されます。 |
Bootloader と Bootloadable は、互いに使用方法が異なっていますので、これらの領域ごとにプロテクションレベルを考えて設定します。
Bootloader が破壊されては困る
Bootloader は、ここで想定しているシステムの要(かなめ)です。 ホストから新たな Bootloadable アプリケーションを受け付けられるのも、 Bootloader が存在すればこそです。 そこで、 Bootloader 部分には、なにがあっても破壊されない、最も強力なプロテクトをかけます。
そこで、この領域には、 "W - Full Protection" のプロテクションレベルを適用します。 このプロテクションレベルが設定されると、 Bootloader の領域は、フラッシュ ROM の一括消去以外では、破壊されなくなります。 また、外部プログラマから読み出される事もないため、情報が安全に守られます。
Bootloadable は、 Bootloader によって書き換えられる
Bootloadable の領域は、内部ファームウェアである Bootloader によって書き換えることができます。 しかし、外部プログラマからのアクセスは、情報を守るために禁止しなくてはなりません。
そこで、この領域には、 "R - Field Upgrade" のプロテクションレベルを適用します。 このプロテクションレベルが設定されると、 Bootloadable の領域は、 Bootloader からの読み書きができます。 ただし、外部プログラマからのアクセスが禁止され、外部からの読み出しおよび破壊・改ざんなどから情報を守る事ができます。
フラッシュ ROM のプロテクト設定
それぞれの領域のプロテクションレベルを決定したので、 PSoC Creator で実際に設定します。 まずは、 Bootloader が、フラッシュ ROM のどこまでの範囲に配置されるかを調べます。
Bootloader の配置アドレスを調べるには、 "Workspace Explorer" の "Results" タブから Bootloader プロジェクトの ".map" ファイルを開きます。 ここでは、 "USB_Bootloader.map" を開きます。
フラッシュ ROM は、 "CODE MEMORY" というセグメントに配置され、このファイルでは、後に "XDATA MEMORY" が続いています。 ここで作成した "USB_Bootloader" の場合、 000000H から 003759H までの範囲に配置されます。 フラッシュ ROM は、256バイトの row 単位で消去・書き込み・プロテクションレベルの設定ができます。 そのため、実際に Bootloader のために確保されるのは、 000000H から 0037FFH までの 56rows の範囲です。
プロテクションレベルは、 "USB_Bootloader.cydwr" の "Flash Security" タブで設定する事ができます。 このタブで row ごとにプロテクションレベルを設定しますが、一つずつ設定するのは大変です。
そこで、タブの上方にある一括設定ボタンを使用します。
領域 | From row | to | 設定 |
---|---|---|---|
Bootloader (0000-37FF) | 0 | 55 | W - Full Protection |
Bootloadable (3800-FFFF) | 56 | 255 | R - Field Upgrade |
上記の設定のあと Set ボタンをクリックすると、プロテクションレベルを設定できます。
デバッガからのアクセスを禁止する
フラッシュ ROM にプロテクトをかけると、確かにプログラマからのアクセスが禁止されますが、実は、もう一つ抜け道が残っています。 それは、デバッガです。 PSoC 3 がデバッガからの接続を受け付けている限り、デバッガはメモリに対してアクセスする事ができます。 "USB_Bootloader" の場合も、このままではファームウェアが丸見えです。
この状態に対処するためには、デバッガが接続できないように設定しなくてはなりません。 "USB_Bootloader.cydwr" の "System" タブで "Enable Device Protection" をチェックします。 これで、デバッガからの接続は拒否され、ファームウェアを保護する事が出来るようになります。
デバッガの接続を受け付けられないという事は、アプリケーションのデバッグも出来ないという事を意味します。 しかしながら、 Bootloadable のプロジェクトでは、デバッガを起動する事がそもそもできないので、デバッガを使ったデバッグを行う事が出来ません。 開発段階でデバッガを使う必要がある場合には、 "Enable Device Protection" の設定を元に戻すほか、 "Project"→"Build Settings..." で "Application Type" をBootloadable から Normal に変更し、回路図に配置した "Bootloadable" の Property で CY_REMOVE を "true" に設定し、ソースコードで "Bootloadable" を参照している部分を変更します。 これで、通常のアプリケーションとしてデバッグを行うことが出来ます。
Bootloadable の NVL 設定は、 Bootloader に合わせる
フラッシュ ROM にプロテクションを設定するため、 "USB_Bootloader.cydwr" の "System" タブの設定を変更してきました。 この "System" タブの設定は、ファームウェアから設定されるものではなく、 Non Volatile Latch (NVL) と呼ばれる特殊な不揮発性メモリに記録されリセット後に自動的に設定されます。 もちろん、 NVL は、一つの PSoC 3 には、一つしかありません。 そのため、 Bootloadable が実行される場合でも、 Bootloader から Bootloadable が呼び出され時にソフトウェアリセットが発生し、 Bootloader で設定した NVL の値が使用されます。 このような事情から、 Bootloadable の開発を行う場合でも、 "System" タブの設定を Bootloader で設定した値と同じにする必要があります。 設定が異なっている場合には、初期状態が違うためにポートが動作しないなどの症状が出る場合がありますので、気を付けてください。
参考文献
- AN73854 - PSoC® 3, PSoC 4, and PSoC 5LP - Introduction To Bootloaders
- AN73503 - USB HID Bootloader for PSoC® 3 and PSoC 5LP
- AN60317 - PSoC® 3 and PSoC 5LP I2C Bootloader
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC Creator でも GitHub がしたい (2) [PSoC]
前回は、 Git Gui を使用して、 PSoC Creator のプロジェクトをローカルのリポジトリに Commit しました。 今回は、いよいよ PSoC Creator プロジェクトを GitHub サーバに登録します。
GitHub でリポジトリを作成する
最初に GitHub サーバに新しいリポジトリを作成します。 GitHub の WEB ページで、 Create new repo ボタンをクリックします。
すると、 WEB ページが変化し、リポジトリの設定を行う画面に遷移します。 ここでは、 Repository name にローカルリポジトリと同じ名前を入れます。 そして、このプロジェクトの内容を示す Description を記入します。 下の方に "Initialize this repository with a README" (README を付けてリポジトリを初期設定する)というチェックボックスが有りますが、これをチェックしてしまうと、ローカルリポジトリとの整合がややこしくなるので、チェックせずにおきます。 最後に Create repository ボタンをクリックすると、リポジトリが作成されます。
リポジトリの作成直後は、中身が無い状態なので、このような画面に遷移します。 この画面で必要なのは、リポジトリの場所を示す Location です。 右にある "copy to clipboard" ボタンをクリックして、クリップボードに記憶します。
ローカルリポジトリを GitHub と関連付ける
この段階まで、ワークスペースに作成したローカルなリポジトリと、 GitHub に作成したリモートリポジトリは、全く関係のない別々のリポジトリです。 次は、これらのリポジトリを関連付けていきます。 まず、 Git Gui のメニュー "Remote"→"Add..." を選択して、ダイアログを呼び出します。
このダイアログでは、リモートリポジトリの名前と場所を入れます。 "Location:" には、 GitHub の WEB ページでクリップボードに入れておいたリポジトリの場所を入れます。 "Name:" には、 "origin" という名前を付けました。 Git では、リモートリポジトリに名前を付けることによって、ローカルリポジトリと区別しています。 "Add" をクリックすると、 ”Fetch Immediately" にチェックを入れてあるので、 GitHub のリポジトリがローカルにコピーされます。
といっても、 GitHub にリポジトリを作成する時に、あえて何もファイルを作らなかったので、コピーされる物はありません。 処理が終わったら、 "Success" と表示されます。 Close ボタンをクリックして、ダイアログを閉じます。
ローカルリポジトリをリモートに登録する
準備が出来たので、いよいよローカルリポジトリを GitHub のリポジトリに登録します。 Git Gui で Push ボタンをクリックして、ダイアログを呼び出します。
ダイアログでは、送り元であるローカルリポジトリと送り先であるリモートリポジトリを指定します。 今回は、ローカルリポジトリを示す "master" から、GitHub のリポジトリを示す "origin" に送り込みます。 Push ボタンをクリックしたら、リポジトリのコピーが始まります。
ダイアログが変わって、 "Success" と表示されたら、リポジトリの登録は完了です。 Close をクリックして、ダイアログを閉じます。
GitHub の WEB ページでリポジトリ名をクリックすると、ローカルリポジトリが登録されたのを確認する事ができます。 これで、 GitHub への登録は、完了です。
参考文献
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC Creator でも GitHub がしたい (1) [PSoC]
PSoC Creator でも GitHub が使えるようになったら、便利に違いない。 今回は、どうやったら PSoC Creator プロジェクトと GitHub が共存できるかについて考えました。
PSoC Creator には、リビジョン管理の機能が無い
PSoC Creator は、 PSoC 3/4/5LP のファームウェア開発を行うための統合開発環境 (Integrated Development Environmend; IDE) です。 ファームウェア開発をする時には、当然、プロジェクトのリビジョン管理を行うべきですが、 PSoC Creator そのものには、リビジョン管理をするための仕掛けは入っていません。 これは、プロジェクトを管理する上では、マズイ状態です。
では、どの様にプロジェクト管理を行うかというと、 "Revision Control for PSoC® Creator™ Projects - KBA86358" に記述のある通り、ユーザが用意した "Revision Control System" で、必要なファイルだけ管理する方式が推奨されています。 ところが、 PSoC Creator と併用して、リビジョン管理を行うための具体的な方法について書かれた文書は見つかりません。 そこで、この文書では、 GitHub でプロジェクトを管理する方法を具体的に手順を追って解説します。
使用するソフトウェアは、 http://git-scm.com/ で提供されている Git Gui クライアントです。 なお、この記事では、 GitHub および Git の細かい使い方については、言及していませんので、ご了承ください。
新しいリポジトリを GitHub に作るには
GitHub の WEB サイトでリポジトリを作成すると、この図のように「次に何をすべきか」という指示が表示されます。 この記事では、このうち、 "Create a new repository on the command line" の手順に従った方法を git-gui を使って操作していきます。
いつも通りにプロジェクトを作成する
最初にいつも通りにプロジェクトを作成します。 ワークスペースを作成する場所は、どこでも構いません。 ここでは、マイドキュメントの "PSoC Creator" というディレクトリにワークスペースを新たに作成しています。 将来、このワークスペースがリポジトリとして機能します。
プロジェクトが作成できたら、適当な回路図と適当なソースコードを書いて Build しておきます。 これで、リポジトリに登録すべきファイルが、準備できました。
ワークスペースをリポジトリとして仕立てる
次は、作成したワークスペースをリポジトリに仕立て上げます。 このために使用するアプリケーションが Git Gui です。 "Create New Repository" をクリックして、リポジトリの作成を開始します。
リポジトリを作成する場所をたずねるダイアログが開くので、さきほど作成したワークスペースの場所を指定します。 ここで、 "Create" をクリックすると、ワークスペース内にリポジトリとして機能するのに必要なファイルがいくつか追加されて、ワークスペースがリポジトリとして機能するようになります。
.gitignore ファイルを用意する
Git Gui の画面が開いたら、 Unstaged Changes という所に多くのファイルが並んでいます。 これらのファイルが、リポジトリに Commit すべきファイルの候補です。 ところが、必要のないものが大量に並んでいますので、必要でないものはリストされないように設定ファイルを追加します。
ここで作成するのは、 ".gitignore" という名前のテキストファイルです。 これをリポジトリの直下に置きます。 内容は、以下の通りです。
# # .gitignore file for PSoC Creator 3.0 # # Log files *.log *.rpt # Temp directry *.cydsn/codegentemp/* # Results *.cydsn/DP8051/*
"Rescan" ボタンをクリックすると、ファイルの数が、ずいぶん少なくなりました。 それでも、まだ、沢山ありますね。 "Generated_Source" ディレクトリというのは、 PSoC Creator が生成したファイルなので、本来は Commit しなくても良いはずです。 しかし、割り込みハンドラなどでは、ユーザがこれらのファイルを直接変更する場合が有ります。 このような場合、 Commit することによってユーザの変更箇所を保存しなくてはなりません。 このような事情から、 "Generated_Source" ディレクトリは、リストされるようにしています。
必要なファイルだけ Commit する
PSoC Creator は、操作中に多くのファイルを生成しますが、プロジェクトに必須なファイルと言うのは、実はほんの数個に過ぎません。 このことは、 "Revision Control for PSoC® Creator™ Projects - KBA86358" にも記述されています。 次の作業は、必須ファイルを選択して、 Commit することです。 ここでは、以下の5個のファイルを選択して、メニュー "Commit"→"Stage To Commit" を選択して、 "Staged Changes" にこれらのファイルを移動します。
- .gitignore :
先ほど作成した、 Commit すべきでないファイルを示すファイルです。
- <Project Name>.cydsn/<Project Name>.cydwr :
"Design Wide Resource" と呼ばれるファイルで、 PSoC Creator でプロジェクトのさまざまな属性を保存するために使用されます。
- <Project Name>.cydsn/<Project Name>.cyprj :
使用しているコンポーネントなど、プロジェクトに関連した情報を格納したファイルです。
- <Project Name>.cydsn/TopDesign/TopDesign.cysch :
プロジェクトで使用している、トップレベルの回路図を格納したファイルです。
- <Project Name>.cydsn/main.c :
C のソースコードが格納された、トップレベルのファイルです。
この他に、ユーザが作成したソースファイルやヘッダファイルなどが有れば、いっしょに "Staged Changes" に入れておきます。 そして、 Commit ボタンをクリックすると、リポジトリに登録されます。
メニュー "Repository"→"Visualize All Branch History" を選択すると、リポジトリに記録された履歴が表示されます。 確かに、5個のファイルが、登録されているのが、わかります。
ひとまず、ローカルなリポジトリができたので、今日はここまで。
参考文献
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 HID Bootloader を試す (4) [PSoC]
ここまで作成してきた Bootloader は、どんな場合でも、とりあえずブート用の通信が有効になります。 ブートの有無を制御できないでしょうか。
Bootloader のシーケンス
これまでの Bootloader のシーケンスでは、まず、ブート通信用のポートを開き、 Bootloader Host からの通信を待ちます。 Bootloadable が書き込まれていた場合には、既定の待ち時間が経過するまで、通信を待ち続けていました。 待ち時間は、デフォルトでは2秒でしたが、この実験では10秒に延長しています。
Bootloadable を書込んだ時に Bootloader Host の動きを観測すると、待ち時間を見ることができます。 PSoC 3 にリセットをかけた直後、 Bootloader Host の画面上のポートリストには、 "USB Human Interface Device (04B4_B71D)" が並びます。 ところが、10秒間、そのまま放っておくと、 "USB Human Interface Device (04B4_B71D)" の表示が消えて、 LED が点滅を開始します。
この動きを見て分かるように、ユーザが真に必要としている Bootloable の処理が始まるまで、10秒の待ち時間が生じてしまいます。 かといって、待ち時間を短くしてしまうと、 Bootloader Host からコマンドを送信する前に待ち時間を使い切って、書き込み動作を実行する事ができません。 USB の場合には、特に接続に手間取るので、2秒では短いと感じています。
今回の目標は、確実に Bootloader を呼び出し、かつ、 Bootloadable の起動までの時間を短くすることです。
タクトスイッチでブートに入れる
PSoC 3 のどこかにタクトスイッチが付いていれば、リセット時にタクトスイッチを操作することで Bootloadable ではなく Bootloader を呼び出す事ができます。 まずは、回路図上にタクトスイッチを接続するための Digital Input Pin を追加します。 ここでは、 P6[1] に接続されている "SW2" のタクトスイッチを使用します。 入力端子の Pull-Up 設定と P6[1] への端子割り当てをお忘れなく。
次に Bootloader コンポーネントで接続待ちを行わないように設定します。 具体的には、 Wait for command のチェックをはずします。
最後に、 "main.c" ファイルを変更して、 "SW2" が、リセット後 100ミリ秒の間、継続して押し続けられていたら、 Bootloader を呼び出すように変更します。 一方、 "SW2" スイッチが押されていない場合、ほぼ遅延なく、ユーザアプリケーションである Bootloadable プログラムが呼び出されます。 いずれの場合でも、 Bootloadable が書き込まれていない場合には、 Bootloadable が呼び出されます。
この方法では、タクトスイッチの追加が必要になってきます。 もちろん、アプリケーションで使用するスイッチを流用させることも出来ますが、その場合、機器のエンドユーザも Bootloader を呼び出すための操作が可能になってしまいます。 そのため、 Bootloader の呼び出しに複雑なシーケンスを組まなければならなくなり、ファームウェア開発が重くなる可能性もあります。
Bootloadable から Bootloader を呼び出せるようにする
上で実現した方法は、外部にタクトスイッチの実装が必要でした。 ハードウェアの追加なしに Bootloadable から Bootloader を呼び出すのが、次に述べる方法です。
まず、 Bootloadable プロジェクトの回路図で、 Bootloader を呼び出すためのタクトスイッチを配置します。 この例では、タクトスイッチと言うハードウェアを人間が操作する事をきっかけとして、 Boootloader を呼び出す動作を実現します。 実際のアプリケーションでは、ハードウェアを追加するまでも無く、 Bootloadable アプリケーションに Bootloader を呼び出す仕掛けを追加するだけで実現できます。
ファームウェアでは、メインループでタクトスイッチを監視して、2秒の間、継続して押されていたら、 API "Bootloadable_Load()" を呼び出して、 PSoC 3 のソフトウェアリセットの後、 Bootloader の通信待ちに入ります。
この方式を使うと、 Bootloader での通信待ちを行わないようにしていても、 Bootloadable を通じて、確実に Bootloader を呼び出す事ができます。 ただし、 Bootloadable からの Bootloader の呼び出しに失敗してしまうと、二度と Bootloadable を書き換えられなくなってしまいます。 そのために、 Bootloadable の開発には、細心の注意が必要になってきます。
参考文献
- AN73854 - PSoC® 3, PSoC 4, and PSoC 5LP - Introduction To Bootloaders
- AN73503 - USB HID Bootloader for PSoC® 3 and PSoC 5LP
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 HID Bootloader を試す (3) [PSoC]
Bootloader を書込んで、 Bootloadable の書き込みまでできました。 今回は、 Bootloader サイズについて考えます。
Bootloader のサイズ
Bootloader は、最初にフラッシュ ROM に書き込まれて、アプリケーションが書き込まれた後でも常駐し続けます。 常駐する時に、どのくらいのメモリ容量を占めているかを確認するために、 MAP ファイルを確認しました。
このファイルは、プロジェクトを Build する際にリンカが作成するファイルで、メモリのどの範囲を使用しているかがわかります。 この Bootloader プロジェクトの場合には、 CODE と CONST の二つのセグメントがフラッシュに配置され、合計 0x4814 (18,452) Byte の容量を消費しています。 なんと、 30% 近くの容量が、アプリケーションとは関係ない、 Bootloader で消費されているのです。 もったいない。
Bootloader が、これだけの容量を消費する理由は、他のプロトコルに比べると複雑な USB インターフェイスを使用したからです。 他のプロトコルを使えば、もっと小さくなります。 ただ、 USB を使いたいということであれば、いたしかたありません。 何とか、サイズを抑える方法を考えましょう。
コンパイルオプションで最適化する
コンパイルの結果を簡単に小さくするには、コンパイラの最適化オプションを指定します。 これまでの実験では、 Build Configuration を "Debug" にしたままで行ってきましたが、これを "Release" に変更してみます。 最適化レベルは、ライセンスを必要としない範囲で最高の "5" です。
すると、 0x37B5 (14,261) Bytes と 22% ほどの消費に抑えることができました。
外付け水晶発振子を使う
最初の Bootloader プロジェクトは、ホストから到着する USB 通信信号で PSoC の内蔵発振器の周波数を微調整していました。 これを外付けの水晶発振器を使う方式にしたらどうなるか、試してみました。 クロック設定画面で XTAL をイネーブルし、 IMO を XTAL から供給するように変更しています。
変更後のコンパイル結果が、これです。 0x3816 (14,358) Bytes と、少し増えてしまいました。 逆効果だったようです。
Bootloader の機能を削減する
これまで、 Bootloader コンポーネントの設定は、通信コンポーネントの指定以外はデフォルトの値を使っていました。 設定ダイアログのうち、右側の Optional commands の部分は、追加機能として提供されているもので、必要が無ければ Bootloader に実装しなくてもかまいません。 そこで、 Bootloader のサイズを削減する事を目的として、すべてのチェックを外してみました。
その結果、サイズは 0x36CA (14,026) Bytes まで削減できました。 この設定で、 Bootloader Host を使おうとしましたが、使用できませんでした。 これは、このツールに必要なコマンドが実装されていないためです。
Bootloader のデータシートによると、このツールを使うためには、最低限 Get flash size, Send data, Verify row の三つのコマンドが必要です。 そこで、これら三つのコマンドだけ実装して、サイズを確認してみました。
その結果、 0x375D (14,173) Bytes となりました。 ちゃんと、 Bootloader Host で、書き込みも出来ました。 ただし、 Erase All だけは、コマンドが実装されていないので実行できませんでした。 このあたりが限界でしょうか。
Bootloadable は、どうなっているのか
ところで、 Bootloadable のメモリマップは、どの様になっているのでしょうか。 "Bootloadable001" プロジェクトのメモリマップを確認したところ、 CODE と CONST の両セグメントは、 0x3800 からの領域に割り当てられていました。 この PSoC 3 の場合、 256Bytes の row 単位でフラッシュ ROM の消去を行う事ができます。 そのため、 256Bytes の区切りである 0x3800 からの 0xC800 (51,200) Bytes のフラッシュ ROM が Bootloadable 用の領域として使用されます。
参考文献
- AN73854 - PSoC® 3, PSoC 4, and PSoC 5LP - Introduction To Bootloaders
- AN73503 - USB HID Bootloader for PSoC® 3 and PSoC 5LP
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 HID Bootloader を試す (2) [PSoC]
前回は、 Bootloader プロジェクトを作成して、 PSoC 3 に書き込みました。 今回は、 Bootloadable プロジェクトを作成し、 Bootloader 機能を使ってプログラムしてみます。
Bootloadable プロジェクトを作成する
Bootloadable プロジェクトも Bootloader プロジェクトと同様に、 PSoC Creator から作成する事ができます。 前回作成したワークスペース "Design102" に、新たにプロジェクトを追加作成します。 やはり、通常のプロジェクトを作成するのとは、少し異なっています。
- プロジェクト名を明確に付ける
Bootloader プロジェクトを作成するときと同様に、プロジェクト名を明示的に指定しておく必要があります。 ここでは、 "Bootloadable001" というプロジェクト名を付けます。
- Application Type を指定する
Application Type に "Bootloadable" を指定します。 これにより、 Bootloadable 用プロジェクトのひな形が使用されて、初期プロジェクトが作成されます。
Bootloadable プロジェクトを Bootloader プロジェクトとは別のワークスペースに置いても、 Bootloadable の開発は出来ます。 しかしながら、後で説明する理由により、同じワークスペースに置いた方が扱いやすくなります。
コンポーネントを配置する
回路図が開いたら、通常のプロジェクトと同様に、必要なコンポーネントを並べていきます。 今回作成する Bootloadable プロジェクトでは、クロックを LED 端子に直結して点滅を行わせます。 必要なのは、 Bootloadable プロジェクトとしての振る舞いをさせるための Bootloadable コンポーネントと LED を点滅させるために必要な Clock コンポーネントと Digital Output Pin コンポーネントの三つです。 それぞれのインスタンス名を "Bootloadable" "Clock_2Hz" および "LED4_P6_3" に変更します。
Bootloadable コンポーネントの設定
Bootloadable プロジェクトを作成するには、このプロジェクトを取り扱う Bootloader プロジェクトのバイナリーファイルが必要です。
Bootloadable コンポーネント設定画面の Dependencies タブで、 Bootloader プロジェクトにある HEX ファイルと ELF ファイルを指定します。
具体的には USB_Bootloader.cydsn\DP8051\DP8051_Keil_951\Debug\
にファイルが有るはずです。
ここで指定したファイルは、コンポーネントの中では、相対パスとして格納されます。 そのため、同じワークスペースに双方のプロジェクトを入れてしまった方が、アーカイブなどの時に便利です。
Bootloadable では、これらのバイナリーファイルが必要になります。 したがって、既存の Bootloader に対して Bootloadable アプリケーションを作成する場合には、最低限、これらのバイナリーファイルを入手する必要があります。
クロックと出力の設定
残りのコンポーネントは、単純に LED を点滅させるために使用されます。 クロックの周波数を 2Hz に設定し、出力端子を P6[3] に関連付けるだけで、 LED4 が 2Hz で点滅するアプリケーションができあがります。 もちろん、 "main.c" に記述をする必要もありません。 設定できたら、プロジェクトを Build します。
Bootloadable をプログラムする
Build できたら、 PSoC に書き込みます。 ただし、今回は、プログラマを使わずに USB 通信線だけを使います。
CY8CKIT-030 を通信用 USB コネクタで接続します。 そして、 PSoC Creator のメニュー "Tools"→"Bootloader Host..." で、 Bootloader Host アプリケーションツールを呼び出します。 まず、 "File:" フィールドに Application File を指定します。 指定すべきファイルは、以下の場所にあります。
<Workspace Path>\Design102\Bootloadable001.cydsn\DP8051\DP8051_Keil_951\Debug\Bootloadable001.cyacd
このファイルは、 Bootloadable プロジェクトを Build した際に作成されるファイルです。
次にPorts: リストから "USB Human Interface Device (04B4_B71D)" を選択したら、 Program をクリックして、プログラムを開始します。 プログラムが書き込まれたら、自動的にリセットがかかり、 Botloadable が走り始め、 LED4 が点滅を始めます。 これで、最初の Bootloadable は、完成です。
参考文献
- AN73854 - PSoC® 3, PSoC 4, and PSoC 5LP - Introduction To Bootloaders
- AN73503 - USB HID Bootloader for PSoC® 3 and PSoC 5LP
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 HID Bootloader を試す (1) [PSoC]
PSoC 3 を題材に Bootloader の使い方を試します。 使用するハードウェアは、 CY8CKIT-030 です。
Bootloader って何だろう
通常、 PSoC のプログラミングを行う場合には、プログラマと呼ばれる専用のハードウェアが必要です。 PSoC 3 の開発を行う場合には、 MiniProg 3 と呼ばれるプログラマが使われ、プログラマを接続するための専用コネクタが基板上に装備されます。 プログラマを使う方法は、開発時には良いのですが、いったん、 PSoC が装置に組み込まれてしまうと、このコネクタにたどり着くことができません。 また、開発時にしか使わないコネクタなど、省略されてしまうこともしばしばです。
そこで、専用のコネクタを装備しなくても、どこかの既存の通信線を通じて PSoC のプログラムを行う方法があると便利です。 Bootloader は、専用のプログラマやコネクタを使わなくてもプログラムを行う事が出来る手法の一つです。
PSoC 3 で提供する Bootloader は、この図のように三つの部分から構成されます。
- Application (Bootloadable)
- ユーザが最終的に必要とするプログラムです。 このプログラムは、 Bootloader によってプログラムする事ができます。
- Bootloader
- Bootloader は、フラッシュ ROM に常駐するプログラムです。 このプログラム自体の役割は、 Bootloadable をフラッシュ ROM の残りの部分に書き込むことです。 また、システムのリセット直後に、 Bootloader として振る舞うか、 Bootloadable として振る舞うかの判断も行います。
- Application File
- Bootloader は、ホストと通信線を介して Bootloadable を受信し、フラッシュ ROM に書き込みます。 この時に使用されるフォーマットが、 Application File です。 Application File は、 PSoC Creator で簡単に作成する事ができます。
このモデルでは、 Bootloader を最初に作成して、そのあと、 Bootloadable を作成し、 Application File として配布します。 まずは、 Bootloader から作成します。
Bootloader プロジェクトを作成する
Bootloader プロジェクトを作成するには、通常通りに PSoC Creator で新規プロジェクトを作成します。 その際に、通常のプロジェクトとは、異なる設定を行います。
- プロジェクト名とワークスペース名を明確に分ける
通常、 Name: フィールドにプロジェクト名を記述すると、ワークスペース名には、そのコピーが入ります。 Bootloader を使用する場合には、通常、ひとつの Bootloader プロジェクトと複数の
Bootloadable プロジェクトを共通のワークスペースに混在させて使用します。 ここでは、 "Design102" というワークスペースに "USB_Bootloader" というプロジェクトを作成しています。 - Application Type を指定する
Application Type に "Bootloader" 指定します。 これにより、 Bootloader 用プロジェクトのひな形が使用されて、初期プロジェクトが作成されます。
指定したら、 OK をクリックして、プロジェクトを作成させます。
コンポーネントを準備する
回路図が開いたら、通常のプロジェクトと同様に、必要なコンポーネントを並べていきます。 今回作成する Bootloader プロジェクトでは、 USB の HID インターフェイスを用いて、プログラムを行うプログラムを作成します。 必要なのは、 Bootloader コンポーネントと USBFS コンポーネントです。 それぞれのインスタンス名を "Bootloader" および "USBFS" に変更します。
Bootloader コンポーネントの設定
Bootloader コンポーネントでは、 Communication component フィールドに "USBFS" を指定します。 このフィールドで指定した通信機能を使ってホストとの通信を行います。
この設定画面では、もう一つ、変更した所があります。 それは、 Wait for command time (ms) フィールドで、 10000(10秒)に変更しています。 リセット直後、 Bootloader は、このフィールドで指定された待ち時間だけ、ホストからの接続要求を待ちます。 そして、時間切れになったら、 Bootloadable を呼び出して、通常のアプリケーションとしての動作に移行します。 ここで待ち時間を初期値の2000(2秒)から増やしたのは、後の実験で、 Bootloadable への移行時間を見えやすくするためです。
USBFS の設定
USBFS コンポーネントを設定するためには、一般にかなり深い知識が必要になってきます。 ところが、 Bootloader を作成するだけであれば、ユーザが苦労をする必要はありません。 それは、すでに、 Bootloader のための設定ファイルが用意されているからです。 設定画面で Import ボタンをクリックすると、設定ファイル選択ダイアログが開きます。
ここで選択するのは、 "bootloader.root.xml" というファイルで、 PSoC Creator のインストールディレクトリ配下の以下の場所にあります。
<PSoC Creator InstallDir>\psoc\content\cycomponentlibrary\CyComponentLibrary.cylib\USBFS_v2_60\Custom\template\
USBFS コンポーネントのバージョンは、お使いのコンポーネントのバージョンに合わせてください。
これで、 Bootloader のための設定が追加されました。 まだ、 USBFS の初期設定が残されていますので、ふたつある "Device Descriptor" の上の方を選択し、 "Delete" ボタンをクリックして、削除しておきます。 これで、 USBFS コンポーネントの準備が出来ました。
クロックの設定
この Bootloader は、 USBFS を使用するために、厳密にクロックの設定を行う必要があります。 もちろん、 PSoC Creator であれば、簡単に設定できます。
Workspace Explorer から "USB_Bootloader.cydwr" を開いて、 "Clocks" タブを選択すると、このような画面が開きます。 二つばかり「赤いビックリマーク」が付いていますので、修正が必要です。 "Edit Clock..." をクリックして、クロック設定ダイアログを開きます。
クロック設定ダイアログでは、以下の4点を修正します。
- IMO
IMO の設定を "24.000MHz ±4%" に変更します。 USB の規格で要求とされているのは、 4% どころではない、もっと高精度なクロックです。 ところが、 PSoC には、接続先の USB ホストに合わせて内部クロックを自動的に調整する機能が有ります。 この機能を生かすための設定が、 "24.000MHz ±4%" なのです。
- ILO
ILO の設定を "100kHz" に変更します。 先に説明した IMO を USB ホストに合わせて調整する機能は、 ILO のタイミングで実行されます。 適切な範囲に調整するために、 ILO を "100kHz" に設定します。
- USB
USB のチェックボックスをクリックして、 USB ブロックにクロックを供給します。 与えるクロックは、 IMO のクロックをクロックダブラに通した "IMOx2 - 48.000MHz" です。
- PLL
PLL の出力周波数を "66MHz" に設定します。 USBFS コンポーネントを使用する場合、 USB に与えるクロックよりも速いクロックを "MASTER_CLK" に与える必要があります。 ここでは、 "48MHz" のクロックで十分という事になりますが、許容される最高周波数である "66MHz" を与えています。
これで、クロックの設定は、完了です。
コードを書く
コンポーネントが整ったら、次は、 "main.c" にソースコードを書きます。 ところが、ここでは、何もする必要がありません。 既に必要な記述 "CyBtLdr_Start();" が入っています。
ひとつだけ修正しなくてはならない個所が有りました。 "main()" の戻り値の型を "void" から "int" に変更しておいてください。 どうも、テンプレートの段階から間違っていたようです。
Bootloader の書き込み
Bootloader は、通常のプロジェクトと同様に、プログラマを使って書き込みます。 CY8CKIT-030 の場合には、オンボードのプログラマを使って書き込むことができます。
Bootloader との通信
書き込みが終わったら、接続してみましょう。 Bootloader と通信を行うためには、 USB コネクタを通信用のコネクタに接続しなおして、 PSoC Creator のメニュー "Tools"→"Bootloader Host..." で Bootloader Host というアプリケーションツールを呼び出します。
すると、上のスクリーンショットのように、 "USB Human Interface Device (04B4_B71D)" がポートリストに並びます。 この VID/PID は、 Bootloader の設定ファイルに記述されていたものです。 これで、 Bootloader プログラムと通信できるようになりました。
参考文献
- AN73854 - PSoC® 3, PSoC 4, and PSoC 5LP - Introduction To Bootloaders
- AN73503 - USB HID Bootloader for PSoC® 3 and PSoC 5LP
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
トランジスタ技術増刊 基板付き体験編ARM PSoCで作るMyスペシャル・マイコン 2013年 12月号 [雑誌]
- 作者:
- 出版社/メーカー: CQ出版
- 発売日: 2013/11/21
- メディア: 雑誌
開発編 ARM PSoCで作るMyスペシャル・マイコン (トライアルシリーズ)
- 作者: 圓山 宗智
- 出版社/メーカー: CQ出版
- 発売日: 2013/12/24
- メディア: 単行本
PSoC 3 で、 DMA 対応倍増器を作った [PSoC]
前回まで、 CPU から FIFO に対して読み書きをするコンポーネントを作成してきました。 今回は、 DMA を接続して、自動的に出力を受け取らせる仕組みを取り入れてみました。
題材とするコンポーネントは、10倍増器です。 コンポーネント自身には、 ST_PUT 状態の時に演算の終了を示すためにアサートされる "drq" (DMA Request) 出力を追加してあります。 この信号の立ち上がりを DMA が検出したら、 FIFO から計算結果を取り出して、 RAM に転送します。
DMA Wizard への対応
PSoC Creator で、 DMA を使うためには、かなり長文のソースコードを書かなくてはなりません。 この DMA の設定を簡単に生成するためのツールが、 DMA Wizard です。
DMA Wizard は、コンポーネントの情報、例えばレジスタのアドレスをリストに表示します。 ユーザは、提示された選択肢の中から転送元と転送先を選んで、簡単に DMA 設定コードを得る事ができます。 ただし、そのためには、コンポーネントが DMA Wizard に対応している必要があります。
DMA に対応させるために必要なのが、拡張子 "cydmacap" の付いた "DMA Capability File" です。 このファイルは、 XML 形式で記述されており、 DMA の転送元および転送先のレジスタアドレスや、そのビット長などの情報が記述されています。
今回は、拡張子 "h" の付いた API ヘッダファイルも作成しています。 DMA Wizard では、レジスタアドレスを指定しますが、何か名前を付けておいた方が理解しやすくなります。 ここでは、ヘッダファイルにマクロ定義 #define を記述することによって、名前を付けています。
DMA Capability File の記述
コンポーネントのコンテキストメニューから "Add Component Item" でダイアログを呼び出して、 "DMA Capability" を選択すると、 DMA Capability File のテンプレートが作成されます。 このテンプレートのコメント以外の部分を以下のように変更しています。
<DMACapability> <Category name="Primary" enabled="`=$EnableDMA`" bytes_in_burst="2" bytes_in_burst_is_strict="true" spoke_width="2" inc_addr="false" each_burst_req_request="true"> <Location name="`$INSTANCE_NAME`_INPUT_16BIT_PTR" enabled="true" direction="destination"/> <Location name="`$INSTANCE_NAME`_OUTPUT_16BIT_PTR" enabled="true" direction="source"/> </Category> </DMACapability>
DMA Capability File の書き方については、現在のところ、マニュアルもドキュメントもありません。 唯一、手掛かりとなるのは、ファイルとして作成されるテンプレートに記述されたコメントだけです。 以下、記入すべき項目について、列挙します。
項目名 | 属性名 | 内容 | |
---|---|---|---|
Category | Category には、レジスタへのアクセス方法に関する情報が記述されます。 レジスタのビット幅が異なるなどの複数の Category を併記することも出来ます。 | ||
name | name には、複数の Category を区別するための名前が記述されます。 DMA Wizard では、複数の Category が存在する時に限り Category を選択するリストが表示されます。 今回のように Category が一つだけの場合には、設定しても使用されません。 | ||
enabled | enabled は、 true または false の値をとります。 この値が false の時には、 DMA Wizard から認識されないので、リストに表示されなくなります。 主にコンポーネントの設定ダイアログから指定する目的で使われます。 今回の例でも、設定プロパティ EnableDMA の値を使っています。 | ||
bytes_in_burst | この値は、 DMA の一度の転送で送受信されるデータのバイト数を指定します。 今回の例では、 FIFO から2バイトずつ演算結果が出力されますので、 "2" を指定します。 | ||
bytes_in_burst_is_strict | この値は、 true または false の値をとります。 先の属性 "bytes_in_burst" で指定された値は、 DMA Wizard で変更することも出来ます。 これを変更不可能にするのが、この属性です。 この値が true の時には、属性 "bytes_in_burst" で決められた値は、 DMA Wizard では変更できません。 今回の例では、必ず2バイトの演算結果を出力しますので、 "true" を指定します。 | ||
spoke_width | この値には、レジスタの接続されるスポークのビット幅をバイト単位で指定します。 スポークのビット幅は、ハードウェアにより、接続されるブロックごとに決定されます。 今回の場合は、 UDB の FIFO に読み書きを行うため、16ビットのスポークに接続されます。 そのため、設定する値は、 "2" となります。 | ||
inc_addr | この値は、 true または false の値をとり、一回の転送の後、アドレスを増加させるかどうかを指定します。 今回の場合は、特定の FIFO レジスタに対して読み書きを行うため、アドレスは固定されます。 そのため、設定する値は、 "false" となります。 | ||
each_busrt_req_request | この値は、 true または false の値をとり、 DMA 要求が到着した時に複数回の転送を行うかどうかを指定します。 今回の場合は、2バイトの演算結果ごとに DMA 要求が到着する仕組みになっていますので、 "true" を指定します。 | ||
Location | Location には、転送元または転送先に関する情報が記述されます。 レジスタアドレスごとに一つの Location が記述されます。 | ||
name | name には、レジスタのアドレスを示す名前が記述されます。 DMA Wizard では、この名前がリストに表示されます。 この例では、 API ヘッダファイルに定義したレジスタアドレスを指定しています。 | ||
enabled | enabled は、 true または false の値をとります。 この値が false の時には、 DMA Wizard から認識されないので、リストに表示されなくなります。 この属性も、コンポーネントの設定ダイアログなどから指定する目的で使われます。 今回の例では、 "true" を指定して、常に DMA Wizard から認識されるようになっています。 | ||
direction | この値は、レジスタのアクセス方向を示します。 "source" が指定された時、このアドレスは転送元として扱われます。 また、 "destination" が指定されたら、転送先として扱われます。 さらに、 "both" が指定されたら、転送元または転送先の両方に使えるものとして扱われます。 今回の例では、レジスタに応じて、 "source" または "destination" を指定しています。 |
API ヘッダファイルの記述
API ヘッダファイルは、以下のように記述しています。
#define `$INSTANCE_NAME`_INPUT_16BIT_PTR ((reg16 *)`$INSTANCE_NAME`_dp_u0__16BIT_F0_REG) #define `$INSTANCE_NAME`_INPUT_PTR ((reg8 *)`$INSTANCE_NAME`_dp_u0__F0_REG) #define `$INSTANCE_NAME`_OUTPUT_16BIT_PTR ((reg16 *)`$INSTANCE_NAME`_dp_u0__16BIT_F1_REG) #define `$INSTANCE_NAME`_OUTPUT_PTR ((reg8 *)`$INSTANCE_NAME`_dp_u0__F1_REG)
今回作成したプロジェクトでは、入り口の FIFO のアドレスと出口の FIFO のアドレスを、 DMA からのアクセスおよび CPU からのアクセスについて別々に登録しています。 これは、 DMA からアクセスする場合には16ビットバスを、 CPU からアクセスする場合には8ビットバスを使用するという制約によります。 "16BIT" が付いた名前を DMA で使い、もう一つの方を CPU で使います。
DMA Wizard の設定
DMA Wizard 対応のコンポーネントが出来たら、 DMA Wizard で DMA 設定コードを生成させます。 DMA Wizard を起動したら、まず、プロジェクトと転送に使用する DMA コンポーネントを指定します。
次は、転送元と転送先のコンポーネントを指定します。 今回の場合には、カスタムコンポーネントの Times10 から出力された演算結果を SRAM に転送するのが目的です。 そこで、 "Source" には Times10 を、 "Destination" には SRAM を指定します。
一転送あたりのバイト数などの設定は、 DMA Capability File からコピーされてきます。 転送を繰り返して行いたいので、 Loop にチェックを入れておきます。
次は、 Transaction Descriptor の詳細を設定します。 今回のプロジェクトは、 PSoC 3 で16ビットレジスタを操作するため、 FIFO レジスタのエンディアンとコンパイラが想定するエンディアンが異なります。 そのため、 Endian の設定を "2" に変更して、16ビットアクセスができるようにしています。
"result" は、 main.c ソースコードで使用する予定の SRAM 上の配列の名前です。 この例のように、配列名を使って表現すると、わざわざ、配列の長さを数える手間が省けます。
設定項目を入力したら、コードが生成されます。 これを "main.c" ソースコードの適切な場所にコピーすると、 DMA の初期設定を行う事ができます。
テストプログラム
テストプログラムは、16ビットの範囲内で計算が実現できるすべての組み合わせをテストして、その結果を LCD モジュールに表示します。 コンセプトは、前回のプログラムと同じなのですが、今回は、 FIFO からデータを取り出す操作を CPU ではなく DMA が行っています。 以下では、 "main.c" のコードを抜粋しながら解説していきます。
uint16 result[64];
計算結果は、配列 "result" に DMA で転送されます。 DMA Wizard の設定で "Loop" にチェックを入れたので、配列の最後まで達したら、元のアドレスに戻って転送を行います。
/* Variable declarations for DMA */ uint8 DMA_Chan; uint8 DMA_TD[1]; /* DMA Configuration for DMA */ #define DMA_BYTES_PER_BURST 2 #define DMA_REQUEST_PER_BURST 1 #define DMA_SRC_BASE (CYDEV_PERIPH_BASE) #define DMA_DST_BASE (CYDEV_SRAM_BASE)
DMA Wizard で生成されるコードは、変数宣言、マクロ宣言、初期設定の三つの部分に分かれています。 この例では、まず変数宣言とマクロ宣言を行っています。 このため、変数は、グローバルな変数として宣言されることになります。
/* Initialize the DMA channel */ void DMA_Init(void) { DMA_Chan = DMA_DmaInitialize(DMA_BYTES_PER_BURST, DMA_REQUEST_PER_BURST, HI16(DMA_SRC_BASE), HI16(DMA_DST_BASE)); DMA_TD[0] = CyDmaTdAllocate(); CyDmaTdSetConfiguration(DMA_TD[0], sizeof result, DMA_TD[0], TD_SWAP_EN | TD_INC_DST_ADR); CyDmaTdSetAddress(DMA_TD[0], LO16((uint32)Times10_OUTPUT_16BIT_PTR), LO16((uint32)result)); CyDmaChSetInitialTd(DMA_Chan, DMA_TD[0]); CyDmaChEnable(DMA_Chan, 1); }
残りの初期設定部分は、関数 DMA_Init として定義しました。 詳細については、ここでは解説しません。
void main() { uint8 i; uint8 j; uint16 a; uint16 a10; volatile uint16 w = 0; CYBIT good; LCD_Start(); DMA_Init();
初期設定部分で、 LCD とDMA の初期設定を行っています。 これで、倍増器の演算が終わり次第、自動的に配列 result に結果が転送されます。
CR1_Write(1); good = 1; a = 0; for (i = 0; i < 102; i++) { for (j = 0; j < 64; j++) { CY_SET_REG16(Times10_INPUT_PTR, a + j); } for (j = 0; j < 64; j++) { a10 = (a + j) * 10; w = result[j]; if (a10 != w) { good = 0; goto escape; } } a += 64; } escape:
プログラムは、これまでと同様に倍増器の FIFO0 に16ビットの値を書込み、その演算結果を CPU で検証するという流れになっています。
これまでと異なっているのは、 FIFO0 に64個の値をまとめて書き込み、 DMA によって配列 result に出力された演算結果を64個ずつ検証している点です。 このため、プログラムは、64個の値の書き込みを102セット、つまり "0" から "6527" までの 64×102=6528 個の値を書込むようになっています。
LCD_Position(0, 0); if (good) { LCD_PrintString("GOOD"); } else { LCD_PrintString("BAD"); LCD_Position(1, 0); LCD_PrintNumber(a + j); LCD_Position(1, 8); LCD_PrintNumber(w); }
演算の検証の結果、すべて正しければ、 LCD に "GOOD" が表示されます。 もし、誤りが見つかったら、"BAD" の表示と共に FIFO0 に書き込んだ値と演算結果が表示されます。
CyDmaChDisable(DMA_Chan); a = 0; CY_SET_REG16(Times10_INPUT_PTR, a++); CY_SET_REG16(Times10_INPUT_PTR, a++); /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */ for(;;) { CY_SET_REG16(Times10_INPUT_PTR, a++); w = CY_GET_REG16(Times10_OUTPUT_PTR); } }
一通り、検証が終わったら、 DMA の動きを止めて、前回同様の CPU で書き込んで CPU で読み出すループに入ります。 DMA に対応はしましたが、 DMA 専用ではないので、これまで通りの動作をさせることができます。
プロジェクトアーカイブ
この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
PSoC 3 で、16ビット演算器を作った [PSoC]
前回まで、8ビットの演算器を作ってきましたが、10倍の倍増器などを実験していると、すぐに上限値である256を超えてしまいます。 そこで、今回は、データパスをもう一つ追加して、16ビットの演算器を作ります。
8ビットから16ビットへ
ここでは、例として16ビットの10倍増器を作ります。 データフローを見て分かるように、二組のデータパスを使って、演算を行います。 二つのデータパスには、 "_a" と "_b" のサフィックスが付いていて、順番に下位 (LSB) と上位 (MSB) を表しています。
そして、二つのデータパスの間には、繰上りを表現するための "Carry" とデータパスをまたぐビットシフトを表現するための "SIO" が配置されています。 これらのデータパスは、お互いを信号線で結ぶことから、物理的に近くに割り当てる必要があります。 PSoC Creator の論理合成では、二組のデータパスを確保する "cy_psoc3_dp16" を使うと、連続するデータパスを割り当ててくれるます。 このため、合わせて16ビットのデータパスとして使用することができるようになります。
しかしながら、二つのデータパスは、独立して設定できますので、連続したデータパスであったとしても、全く別の動作を行わせることも出来ます。
16ビット対応の設定
今回作成する10倍増器は、二つのデータパスを使いますが、それぞれのデータパスの設定は8ビットの時とほぼ同じです。 異なっているのは、上位 ("_b") 側の Carry/SIO 入力の部分です。
下位 ("_a") のデータパスの設定
上位 ("_b") のデータパスの設定
キャリー信号を下位から取り入れるために、 "CI SELA" の設定を "ARITH" から "CHAIN" に変更しています。 また、シフト信号を下位から取り入れるために、 "SI SELA" の設定を "DEFSI" から "CHAIN" に変更しています。 これで、二つの ALU が16ビットの ALU として動作するようになります。
Verilog 記述
Verilog 記述は、前回の倍増器とほぼ同じですが、データパスが二つになったために、一部の制御信号が2本になっています。
//`#start header` -- edit after this line, do not edit this line // ======================================== // // Copyright noritan.org, 2013 // All Rights Reserved // UNPUBLISHED, LICENSED SOFTWARE. // // CONFIDENTIAL AND PROPRIETARY INFORMATION // WHICH IS THE PROPERTY OF NORITAN.ORG. // // ======================================== `include "cypress.v" //`#end` -- edit above this line, do not edit this line // Generated on 05/25/2013 at 18:50 // Component: Times10 module Times10 ( input clock, input en, input reset ); //`#start body` -- edit after this line, do not edit this line // State code declaration localparam ST_IDLE = 3'b000; localparam ST_GET = 3'b001; localparam ST_STEP1 = 3'b010; localparam ST_STEP2 = 3'b011; localparam ST_STEP3 = 3'b100; localparam ST_WAIT = 3'b101; localparam ST_PUT = 3'b110; // Datapath function declaration localparam CS_IDLE = 3'b000; localparam CS_CLEAR = 3'b001; localparam CS_SL0 = 3'b100; localparam CS_SL1 = 3'b101; localparam CS_ADD0 = 3'b110; localparam CS_ADD1 = 3'b111; // Wire declaration wire[2:0] state; // State code wire[1:0] f0_empty; // F0 is EMPTY wire[1:0] f1_full; // F1 is FULL wire[1:0] so; wire[1:0] co; // Pseudo register reg[2:0] addr; // Datapath function reg d0_load; // LOAD D0 from F0 reg f1_load; // LOAD F1 // State machine behavior reg [2:0] state_reg; always @(posedge reset or posedge clock) begin if (reset) begin state_reg <= ST_IDLE; end else casez (state) ST_IDLE: if (en & ~f0_empty[1] & ~f0_empty[0]) begin state_reg <= ST_GET; end ST_GET: state_reg <= ST_STEP1; ST_STEP1: state_reg <= ST_STEP2; ST_STEP2: state_reg <= ST_STEP3; ST_STEP3: state_reg <= ST_WAIT; ST_WAIT: if (~f1_full[1] & ~f1_full[0]) begin state_reg <= ST_PUT; end /*ST_PUT*/ default: state_reg <= ST_IDLE; endcase end assign state = state_reg; // Internal control signals always @(state) begin casez (state) ST_IDLE: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b0; end ST_GET: begin addr = CS_CLEAR; d0_load = 1'b1; f1_load = 1'b0; end ST_STEP1: begin addr = CS_SL1; d0_load = 1'b0; f1_load = 1'b0; end ST_STEP2: begin addr = CS_SL0; d0_load = 1'b0; f1_load = 1'b0; end ST_STEP3: begin addr = CS_SL1; d0_load = 1'b0; f1_load = 1'b0; end ST_WAIT: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b0; end /*ST_PUT*/ default: begin addr = CS_IDLE; d0_load = 1'b0; f1_load = 1'b1; end endcase end cy_psoc3_dp16 #(.cy_dpconfig_a( { `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE : Do nothing*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM1: CLEAR : A0 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM2: */ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM3: */ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0<= ALU <= (A0 + D0) << 1;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + D0);*/ 8'hFF, 8'h00, /*CFG9: */ 8'hFF, 8'hFF, /*CFG11-10: */ `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, `SC_CI_A_ARITH, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, `SC_SI_A_DEFSI, /*CFG13-12: */ `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, 1'h0, `SC_FIFO1_ALU, `SC_FIFO0_BUS, `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, `SC_FB_NOCHN, `SC_CMP1_NOCHN, `SC_CMP0_NOCHN, /*CFG15-14: */ 10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, `SC_WRK16CAT_DSBL /*CFG17-16: */ } ), .cy_dpconfig_b( { `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM0: IDLE : Do nothing*/ `CS_ALU_OP__XOR, `CS_SRCA_A0, `CS_SRCB_A0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM1: CLEAR : A0 <= ALU <= (A0 XOR A0);*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM2: */ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC_NONE, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM3: */ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM4: SL0 : A0 <= ALU <= (A0) << 1;*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP___SL, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM5: SL1 : A0 <= ALU <= (A0 + D0) << 1;*/ `CS_ALU_OP_PASS, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM6: ADD0 : A0 <= ALU <= (A0);*/ `CS_ALU_OP__ADD, `CS_SRCA_A0, `CS_SRCB_D0, `CS_SHFT_OP_PASS, `CS_A0_SRC__ALU, `CS_A1_SRC_NONE, `CS_FEEDBACK_DSBL, `CS_CI_SEL_CFGA, `CS_SI_SEL_CFGA, `CS_CMP_SEL_CFGA, /*CFGRAM7: ADD1 : A0 <= ALU <= (A0 + D0);*/ 8'hFF, 8'h00, /*CFG9: */ 8'hFF, 8'hFF, /*CFG11-10: */ `SC_CMPB_A1_D1, `SC_CMPA_A1_D1, `SC_CI_B_ARITH, `SC_CI_A_CHAIN, `SC_C1_MASK_DSBL, `SC_C0_MASK_DSBL, `SC_A_MASK_DSBL, `SC_DEF_SI_0, `SC_SI_B_DEFSI, `SC_SI_A_CHAIN, /*CFG13-12: */ `SC_A0_SRC_ACC, `SC_SHIFT_SL, 1'h0, 1'h0, `SC_FIFO1_ALU, `SC_FIFO0_BUS, `SC_MSB_DSBL, `SC_MSB_BIT0, `SC_MSB_NOCHN, `SC_FB_NOCHN, `SC_CMP1_NOCHN, `SC_CMP0_NOCHN, /*CFG15-14: */ 10'h00, `SC_FIFO_CLK__DP,`SC_FIFO_CAP_AX, `SC_FIFO_LEVEL,`SC_FIFO__SYNC,`SC_EXTCRC_DSBL, `SC_WRK16CAT_DSBL /*CFG17-16: */ } )) dp( /* input */ .reset(reset), /* input */ .clk(clock), /* input [02:00] */ .cs_addr(addr[2:0]), /* input */ .route_si(1'b0), /* input */ .route_ci(1'b0), /* input */ .f0_load(1'b0), /* input */ .f1_load(f1_load), /* input */ .d0_load(d0_load), /* input */ .d1_load(1'b0), /* output [01:00] */ .ce0(), /* output [01:00] */ .cl0(), /* output [01:00] */ .z0(), /* output [01:00] */ .ff0(), /* output [01:00] */ .ce1(), /* output [01:00] */ .cl1(), /* output [01:00] */ .z1(), /* output [01:00] */ .ff1(), /* output [01:00] */ .ov_msb(), /* output [01:00] */ .co_msb(), /* output [01:00] */ .cmsb(), /* output [01:00] */ .so(), /* output [01:00] */ .f0_bus_stat(), /* output [01:00] */ .f0_blk_stat(f0_empty[1:0]), /* output [01:00] */ .f1_bus_stat(), /* output [01:00] */ .f1_blk_stat(f1_full[1:0]) ); //`#end` -- edit above this line, do not edit this line endmodule //`#start footer` -- edit after this line, do not edit this line //`#end` -- edit above this line, do not edit this line
FIFO は、それぞれのデータパスに8ビットずつ配置されています。 そのため、双方のデータパスの FIFO にデータが準備できた時にデータを取り出す事ができるという判断をしています。
テストプログラム
今回は、16ビットの範囲内で表現可能なすべての組み合わせを検査し、最終結果を LCD に表示するようなテストプログラムとしました。
/* ======================================== * * Copyright noritan.org, 2013 * All Rights Reserved * UNPUBLISHED, LICENSED SOFTWARE. * * CONFIDENTIAL AND PROPRIETARY INFORMATION * WHICH IS THE PROPERTY OF NORITAN.ORG. * * ======================================== */ #include <device.h> void main() { uint16 a; uint16 a10; volatile uint16 w = 0; CYBIT good; LCD_Start(); CR1_Write(1); good = 1; for (a = 0; a < 6554; a++) { CY_SET_REG16(Times10_dp_u0__F0_REG, a); a10 = a * 10; w = CY_GET_REG16(Times10_dp_u0__F1_REG); if (a10 != w) { good = 0; break; } } LCD_Position(0, 0); if (good) { LCD_PrintString("GOOD"); } else { LCD_PrintString("BAD"); LCD_Position(1, 0); LCD_PrintNumber(a); LCD_Position(1, 8); LCD_PrintNumber(w); } a = 0; CY_SET_REG16(Times10_dp_u0__F0_REG, a++); CY_SET_REG16(Times10_dp_u0__F0_REG, a++); /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */ for(;;) { CY_SET_REG16(Times10_dp_u0__F0_REG, a++); w = CY_GET_REG16(Times10_dp_u0__F1_REG); } } /* [] END OF FILE */
データを入れるための FIFO0 には、下位 (u0) 側の F0 レジスタのアドレスを指定して、16ビットのアクセスをしています。
CY_SET_REG16(Times10_dp_u0__F0_REG, a);
上位のデータパスは、下位の隣に配置されています。 そのため、上位データパスの F0 レジスタは、この次のアドレスに配置されています。 このような構造のために、下位の F0 レジスタのアドレスが、16ビットレジスタへのアドレスとして使用できるのです。
また、読み出し側のアドレス指定も同様に下位側のアドレスを指定します。
w = CY_GET_REG16(Times10_dp_u0__F1_REG);
計算結果が、すべて正しければ、 "GOOD" が表示されます。 また、計算結果が合わなかった場合には、 "BAD" の表示とともに、与えた値と計算結果が表示されて、デバッグを支援するようになっています。
プロジェクトアーカイブ
この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本
続・PSoC 3 で、倍増器を作った [PSoC]
前回は、 FIFO を応用して入ってきたデータを2倍にして返す倍増器を作りました。 今回も倍増器を作ります。 ただし、倍率が前回とは違っています。
今度は、10倍
今回は、10倍に挑戦します。
値を10倍にする仕組みをデータフローで表現しています。 足し算とシフトを駆使して、 D0 に入った値 "d" を10倍にしています。 10倍の値を得るために必要なクロック数は、5クロックに伸びました。 それぞれのステップで ALU の振る舞いを変化させて、計算を行っています。
ここでは、演算部分だけを解説します。
- STEP1
このステップでは、前回と同様、 "SL1" 操作を行います。 A0 には、 FIFO0 から取り出した値 "d" の二倍の値 "2d" が入ります。
- STEP2
このステップでは、新たに定義した "SL0" 操作を行います。 "SL1" とは違い、シフターを通す前に "D0" を加算しません。 そのため、A0 には、値 "d" の4倍の値 "4d" が入ります。
- STEP3
このステップでは、ふたたび、 "SL1" 操作を行います。 A0 に "d" を足してからシフターを通すので、A0 には、値 "d" の10倍の値 "10d" が入ります。 これで、元の値の10倍の値を得る事ができました。
以上の3ステップで、 D0 の値は10倍されます。 "SL1" と "SL0" の適用順序を変えると、違う倍率の倍増器を構成することも出来ます。
Verilog の実装のコンセプトは、前回とほぼ同じです。 ここでは省略しますが、興味があれば、プロジェクトを開いて確認してください。
データパスの実装
データパスの設定は、 "SL1" が追加されました。 また、後の戦略の都合上、 "SL0" を Reg4 に、 "SL1" を Reg5 に割り当てています。 "SL1" と "SL0" の違いは、 ALU の演算設定だけで、 ADD の部分が PASS になっています。
10倍増器の動作
10倍増器の使い方は、前回の倍増器と同じです。 そのため、テストプログラムも同じものが使えます。 ただし、倍増器のインスタンス名が変わっていますので、レジスタアクセスに使用する名前を変更する必要があります。
/* ======================================== * * Copyright noritan.org, 2013 * All Rights Reserved * UNPUBLISHED, LICENSED SOFTWARE. * * CONFIDENTIAL AND PROPRIETARY INFORMATION * WHICH IS THE PROPERTY OF NORITAN.ORG. * * ======================================== */ #include <device.h> void main() { uint8 i = 0; uint8 v[16]; volatile uint8 w = 0; CR1_Write(1); CY_SET_REG8(Times10_dp_u0__F0_REG, w++); for (i = 0; i < 16; i++) { CY_SET_REG8(Times10_dp_u0__F0_REG, w++); v[ i] = CY_GET_REG8(Times10_dp_u0__F1_REG); } LCD_Start(); LCD_Position(0, 0); for (i = 0; i < 8; i++) { LCD_PrintInt8(v[i]); } LCD_Position(1, 0); for (i = 8; i < 16; i++) { LCD_PrintInt8(v[i]); } CY_SET_REG8(Times10_dp_u0__F0_REG, i++); CY_SET_REG8(Times10_dp_u0__F0_REG, i++); /* CyGlobalIntEnable; */ /* Uncomment this line to enable global interrupts. */ for(;;) { CY_SET_REG8(Times10_dp_u0__F0_REG, i++); w = CY_GET_REG8(Times10_dp_u0__F1_REG); } } /* [] END OF FILE */
奇数倍の場合
データパスの設定 "SL0" と "SL1" を使う事によってすべての倍率に対応できるようになったかかというと、そうはいきません。 "SL0" も "SL1" も、最後にシフターを通しているので、偶数倍の値しか出てきません。
5倍増器のデータフロー
では、どうするかというと、最後の1ステップのために、シフターを通さない操作を追加します。 このデータフロー図は、5倍増器の場合です。 10倍増器の STEP3 の演算で、 "SL1" の代わりに "ADD1" が使用されています。 "ADD1" は、 A0 と D0 を加算して、シフターを通さずにそのまま A0 に格納する操作です。 この操作を使う事で、奇数倍の場合にも対応することができます。
5倍増器対応のデータパス設定
データパスは、奇数倍に対応させるために、さらに操作を追加しています。 上の5倍増器のデータフローでは、 "ADD1" のみが必要になっていましたが、ここでは、後のことを考えて、 "ADD0" という操作も追加しています。 この操作は、 D0 の加算も行わず、シフターも通さないで、 A0 を単に書き直すという操作になっています。
さあ、これで任意の値に対応する役者が揃いました。
プロジェクトアーカイブ
この記事を書くために作成したプロジェクトは、このファイルの拡張子を ZIP に変更して展開すると再現できます。
関連文献
シリーズ最強!PSoC 3ボード+デバッグ・ボード: あのPSoCが生まれ変わった!アナログもディジタルも一新 (トライアルシリーズ)
- 作者: 古平 晃洋
- 出版社/メーカー: CQ出版
- 発売日: 2012/10/23
- メディア: 単行本