なりなり日記

Appleと折りたたみ自転車(BROMPTON / Tern Vektron S10 / BESV PSF1)の情報を中心に発信中!

【PSoC入門】タイマーとUSBUARTによる割り込み


スポンサーリンク

こんにちは、なりなりです(^ ^)

今日は、PSoCのタイマーコンポーネントとUSB UARTコンポーネントを使った割り込みを勉強します。


https://ja.wikipedia.org/wiki/割り込み_(コンピュータ)
割り込みについての一般的知識はWikiでも割と親切に解説されています。


http://www.cypress.com/file/44246/download

http://www.cypress.com/file/144666/download

PSoCの割り込みに付いてはCypressの公式ドキュメントが有りましたので、これに従って勉強します。


回路はこの様にしました。

これによって、

  • タイマーコンポーネントによる割り込みを使ったLEDの点滅
  • USBUARTによる割り込み使ったLEDの点灯

の2つを同時に確認します。


Timer割り込みによるLEDの点滅を確認

まずは、タイマー割り込みを確認します。

/***************************
*  Place your includes, defines and code here
*****************************/
/* `#START isr_1_intc` */

/* Timer component header file */
#include "Timer_1.h"
/* LED1 pin component header file */
#include "LED_1.h"

/* `#END` */

Generated_Souce下にあるisr_1.cの頭の方でTimer_1とLED_1のヘッダーをインクルードを追記して

CY_ISR(isr_1_Interrupt)
{
   #ifdef isr_1_INTERRUPT_INTERRUPT_CALLBACK
       isr_1_Interrupt_InterruptCallback();
   #endif /* isr_1_INTERRUPT_INTERRUPT_CALLBACK */

   /*  Place your Interrupt code here. */
   /* `#START isr_1_Interrupt` */

   /* Read Timer status register to bring the interrupt line low */
   Timer_1_ReadStatusRegister();
   /* Toggle the LED */
   LED_1_Write(~LED_1_Read());

   /* `#END` */
}

isr_1のISR(Interrupt Service Routine、割り込みが生じた時に実行される部分)、CY_ISR(isr_1_Interrupt)の中にTime_1のステータス読み出しと反転コマンドを追記します。

インクルードファイル名が間違っていたり、インクルードを忘れているのにCY_ISRにコマンドを追記したりすると、ビルドをしなくてもPSoC Creatorががアラーム(×マーク)を出してくれます。とても親切なIDEですね。

int main(void)
{
   CyGlobalIntEnable; /* Enable global interrupts. */

   /* Place your initialization/startup code here (e.g. MyInst_Start()) */
   isr_1_Start();
   Timer_1_Start();

   for(;;)
   {
       /* Place your application code here. */
   }
}

main.cでisr_1とTimer_1をスタートさせる記述を追記してビルドすれば完成!

評価ボードをプログラムすると、1秒おきにLEDが点滅することが確認出来ます。


タイマー割り込みを調べているうちに、教科書として使っている「ARM PSoCで作るMyスペシャル・マイコン」で出て来て訳の分からなかった、SysTickに再度ぶち当たったので調べてみると

https://www.aps-web.jp/academy/cm/20/
どうやら、ARM Cortex-M3内部に搭載されているタイマーらしく、CPUの周辺(マイコン内)のタイマーを使わなくてもタイマー割り込みが使えるというものだそうです。

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0432cj/ch05s01s01.html
「SysTick」はCortex-M0にも搭載されている様なので、PSoC 5LPだけでなく4でも使えますから、安心して使って良さそう。


USBUARTからの割り込みを追加する

1秒おきにLEDが点滅している状態で、USBUARTを使ってPCから指示した時間だけ、LEDが点灯したままになる動きを追加してみましょう!

USBUARTの割り込みをどのように使うのか、調べても見つけられないのですが、

USBFS_EP_X_ISR - triggered at the end of a transfer directed to endpoints 1-8 (where X is the endpoint number from 1 to 8). For IN endpoint, it means that the data loaded into endpoint buffer is read by the host. For OUT endpoint it means that data is available in the endpoint buffer. These are mandatory for component operation.

USBFSコンポーネントのInterruptの説明にはこのように書かれており、翻訳すると

USBFS_EP_X_ISR - エンドポイント1-8(Xは1-8のエンドポイント番号)への転送終了時にトリガされます。 INエンドポイントの場合、エンドポイント・バッファーにロードされたデータがホストによって読み取られることを意味します。 OUTエンドポイントの場合は、データがエンドポイント・バッファーで使用可能であることを意味します。これらはコンポーネントの操作に必須です。

となりますから、EP1の設定をしてみます。

http://www.kumikomi.net/archives/2004/01/02seri.php?page=15
EP(エンドポイント)って何ぞや?という説明はこちら。何となく分かりますね。

しかしまあ、知識がどんどん拡がっていくというか、発散していくというか、覚えるべきことが沢山だ(^_^;)


USBUARTコンポーネントを置いた直後には割り込みに関するアトリビュートが見えないので、Device DescriptorタブでAdd Configurationを押してConfiguration Descriptorを表示、Endpoint Descriptorの中にあるEP1のIN/OUT、Transfer Typeを設定します。



Direction ? Input or Output. USB transfers are host centric; therefore, IN refers to transfers to the host; OUT refers to transfers from the host.

IN/OUTの説明はこの様にされており、ホストはPCでしょうから、今回はOUTなのでしょうね。


https://www.renesas.com/ja-jp/solutions/key-technology/connectivity-wired/usb/about-usb/usb1-1/usb1-c.html

Transfer Modeについては、こちらに詳しく書かれていました。これは、PSoCではなくUSBに関する知識ですね。

今回はINTで良いでしょう。



で、EP1の割り込み処理は何処に書けばいいのかというと、USBUART_1の下にUSBUART_1_episr.c(USBUARTのEPのISR)というものが有るので、この中なのでしょう。

/********************************
* Custom Declarations
********************************/
/* `#START CUSTOM_DECLARATIONS` Place your declaration here */
/* LED1 pin component header file */

/* `#END` */

ファイルを開くと、頭の方にこの様な記述が有ります。

isr_1.cと文言が異なるのが気になりますが、declaration(宣言)というくらいだから、#STARTと#ENDの間の行に、必要なヘッダをインクルードしたり、関数を定義したりするのだと思うので、まずはLED_1.hをインクルードしておきます。

#if (USBUART_1_EP1_ISR_ACTIVE)
   /******************************
   * Function Name: USBUART_1_EP_1_ISR
   ******************************
   *
   *  Endpoint 1 Interrupt Service Routine
   *
   ********************************/
   CY_ISR(USBUART_1_EP_1_ISR)
   {

   #ifdef USBUART_1_EP_1_ISR_ENTRY_CALLBACK
       USBUART_1_EP_1_ISR_EntryCallback();
   #endif /* (USBUART_1_EP_1_ISR_ENTRY_CALLBACK) */

       /* `#START EP1_USER_CODE` Place your code here */

       /* `#END` */

EP1の処理は、ここの#STARTと#ENDの間の行に書くのでしょう。

今回は、数字nを受け取ったらn(sec)の間LEDを点灯させた後に消灯させます。

   uint16 count, wait = 0;
   uint8 buffer[128];

   count =USBUART_1_GetEPCount(1);
   if(count != 0) /* Check for input data from PC */
   {
       // USBUART_1_GetAll(buffer);            // Input data from PC
       USBUART_1_ReadOutEP(1, buffer, count);
       sscanf((char *)buffer, "%d", (int *)&wait);
       USBUART_1_EnableOutEP(1);

       LED_1_Write(1); // LED Terminal ON
       CyDelay(1000*wait);
   }

この様なコードを挿入してみました(sscanfを使うために、stdio.hのインクルードが必要)。

しかし、LEDはカウンター割り込みで定期的に点滅するだけで、PCから数値を入力して(Pythonを使用)も状況が変わりませんでした。

ここでデバッグ機能で動作を解明しようとしたのですが、USBUART接続とデバッグポート接続が同時に出来ませんでした。残念ながら、USBを使ったUART通信をさせながらデバッグすることができないのです。

いろいろ調べてみたものの、USBUARTを使った割り込みを確認出来るサンプルも見つけらず、今回は、断念することにしました。

良いところまで行ってると思うのですが(^◇^;)

実プロジェクトで使う様なら代理店に相談してみますし、また何か分かったらご報告します。