K.I2007/12/06Index概要いろいろやってみる受信割込み割込みハンドラが実行されない?波形を確認してみる考えを整理してみるGPIO割込みならやっぱりRX割込みが変いろいろ悩むもう一度整理してみよう。概要タクトスイッチで操作するコントローラは良く作るんだけど、PCからもコントロールするようにしたい。タクトスイッチは、GPIO割込みで、設定、操作。シリアルは、受信割込みで、設定、操作が出来るようにする。それ以外では、SLEEPで消費電力を抑える。感じにしようと思ったんだけど、PSoCのUARTを真面目に使ったことがなかったので、いろいろ引っ掛かってしまった。[top]いろいろやってみるデバッグしながら書いたものなので纏まりが無いし、間違いもありそうだけど、記録として残しておこう。受信割込み最初、標準のUART_1_bCmdCheckとか使ってプログラムを書いてみる。RXは割込みになってるはずだから大丈夫と思ったんだけど。}シリアルインターフェースに全く反応しない。割込みが掛ってないのかなぁ。割込みハンドラを書かないとダメなのかなぁ。いうことで、受信割込みハンドラを書いてみることにしました1。_rx_handlerとして、mainに以下のような、RX割込みハンドラを追加してみた。LED_1_Invert();}で割込み許可されてるはずなのに、割込みハンドラに飛んでこない。GPIO割込みは掛ってるし、割込みハンドラはLEDを点滅させるだけなので、こんなの動かないわけが無いんだけど。retiまるで割込み許可されていないような感じだ。試しに直接割込みフラグをEnableにしてみたが、ダメ。enable波形を確認してみる実際に波形が来てないんじゃないだろうか?ということで、ロジックアナライザのDV1-100でシリアルインターフェースの信号をみてみる。今回は、FT232Rを初めて使ったので、結構疑っていたんだけど。操作アプリのDigiView2で波形確認。TX,RXともに問題なし波形は記録しませんでしたが。考えを整理してみるrx_handlerは単純なLED点滅だけ。_rx_handlerここまで、UARTのRXが設定されているDCB03の割込み処理には問題が無いように見える。GPIO割込みならRXにデータが入力されていないのでは?TX,RXともに、ロジアナで波形を確認した。ボーレートも問題なし。Port1_6→GIO6→SysClkSyncでRI0[2]→DCB03のRX端子に接続これはちゃんと接続されてるPort1_6のI/O設定は、Hi-Z状態(入力)、InterruptはDisable。UART割込みは別に許可してるんだから、関係ないよなぁ。FallingEdgeに変更してみようあれ、RX割込み掛るようになった。!Sleep状態からはデジタルモジュールからの割込みは掛らないということか。SLEEPからのWakeUpはGPIO割込みじゃないとダメなのかな。Sleepなしに設定してみたと思ったけど、気のせいかなぁ。RX割込みが変GPIO割込みでWakeするようにしてみると、キー入力から20ms弱でLEDが反転し、さらに20ms弱でまた反転するRX割込みでキーコード+CRLFを返すようにしてみた。今度は、RX割込みが掛りっぱなしになった。NULL,CR,LFを繰返している→つまりNULLコードを受信している?本当は、RX割込みが終わったら、またスリープ状態に戻って欲しいんだけど。そもそも、キー入力から何故2回RX割込みが入るんだろう。それに、ループバックした時にRX割込みが掛りっぱなしになるのは何故か。20ms弱の時間はかなり長いけど、いったい何だろう?2回目の割込みは何故発生するんだろう?いろいろ悩むキーコードとCRLFを返すようにすると、RX割込みが掛りっぱなしになるのは何故か。RX自体は変化していないから、RX割込みは掛からないはず。NULL,CR,LFのデータ出力は、rx_handlerが実行されているためだろう。rx-handlerの出力したデータをターミナルソフトがループバックしてるのでは?しかしターミナルソフトを終了しても、割込み掛りっぱなしは終わらない。それにキーコードCRLFを出力しない時はRX割込みが掛りっぱなしになることは無いのは何故かやはりキーコードが戻っているのでは?しかしRXは全く変化していないし、それともLEDが変化してるからか?でもPort2_7は割込みDisableになっているリピートで連続してキー入力すると35ms間隔ぐらいになるが、その場合、2回目のLED反転の前に、次のキー入力がされる。すると、最初のキー入力の2回目のLED反転はキャンセルされるように見える。最後のキー入力から、20ms弱でLEDが反転し、さらに20ms弱後にLEDが反転する。反転前に、次のキー入力があった場合、最初のキー入力はキャンセルされる。スリープ状態から、Port1_6の立下りで割込みが掛ってシステムが起動する。次にRX割込みで、rx_handlerが起動する。あれ、スリープの起動時間はどれくらいだろう。起動してからRXはちゃんと受信出来るんだろうか?それで、またスリープ状態に戻る。スリープに戻るのにまた時間が掛かるはず。スリープ状態になってもLEDの状態は保持されるので、変化する理由にはならないな〜。試しにスリープしないでやってみようか。SLEEPの代わりに100msのWaitを入れてみる。結果は、あまり変わらなかった。あれ?そもそも、1秒ぐらいにしてみるとどうなるのかな?それもあまり変わらない。結局SLEEPはほとんど関係ないみたいだ。すれば、2回目の割込みはいったい何だ??2回目の割込みを掛らないようにする方法は無いかなぁ。interruptsで割込みを禁止して、1秒後に割込み許可してみる。→変わらないぞ???割込み禁止したっきりにしても同じ。結局、UARTのRX割込みということではなく、単にGPIO割込みに見える。それなら何故、rx_handlerが実行されるんだろう?うーん。これだったら、むしろGPIO割込みでRX読んだ方が良いんじゃないだろうか?gpio_handlerで、RX読むとするとPort1_6が0の場合は、RXとすれば出来るかなぁ。邪魔をしていたのはあっ、つまりRX割込みの前にGPIO割込みがあるのか。GPIO割込みでもLEDを反転してるから、2回反転するのは当然なんだ!GPIO割込みでは、タクトスイッチ以外は無視しなきゃダメだな〜(考えれば当たり前なんだけど、追加したので忘れてた。)20ms掛っていたのは、GPIO割込みのチャタ処理の所為か〜。キーコードNULL、CRLFが無限に出力されるのは何故だろう。出力すると、入力が無くてもRXで割込みが掛っちゃうんだろうか?仮にそうだとすると、データがNULLで出力されるのも分かる。いうことで、以下のようにしたらとりあえず考えていたように動いた。gpio割込みで、RXが0ならば何もしない。RX割込みでRXデータがNULLの時は何もしない。mainでは、処理が終わったらSLEEP状態にする。これだとNULは受け取れないのでバイナリデータで支障がでるかな。最初にNULLが無ければ大丈夫かも。それにスリープからの起動に時間が掛かるためか反応が鈍い文字によって変わる。a,c,e,..が遅く、b,d,f,...が速い。0x41,0x43,0x45は遅く、0x40,0x42,0x44は速い。最初のビット0が0だと速い。スタートビット0で、SLEEPから目覚めて、最初のビット0が1だと認識出来ない?のかな??もしかすると、GPIO割込みでRXが1だとタクトスイッチ処理で喰われちゃうのかな?それならばとgpio割込みで、RXが0、或はタクトスイッチが変化しなければ何もしない、としてみた。文字によって反応が鈍くなることもなくなった。→やっぱりGPIO処理で喰われてたんだなぁ。TX出力時にRX割込みが掛っちゃうというのは、なんか勘違いしてるのかもしれないけどとりあえず良しとしよう。標準のルーチンを使おうここまで来ると、今回はバイナリデータを扱わないんだから、標準のルーチンで良さそうに思えてきた。分析されてるようにRXCmdBufferをEnableにした時だけ実行されるようになってるらしい。試しに、_rx_handlerへのljmpを、lcallに変更してみる。キー入力があると、そのまま暴走状態になる。Cコンパイラは割込みルーチンの最後に自動的にretiを入れちゃう3んだった。codeってあるけど、これはアセンブラで書けってことか。今回はバイナリ使わないので、標準で良いや。CRコードが2回必要?でも何故かReturnを2回送らないとコマンドを認識しない。SLEEPしないと正しく動作する。SLEEPすると何が起こるんだろう。スリープから目覚める(GPIO割込み)コマンド文字列受信→RXバッファに入れる(RX割込み)CmdCheckスリープスリープから目覚める(GPIO割込み)CRコード受信→RXバッファに入れる(RX割込み)CmdCheck→コマンド処理(文字列送信、CRLF送信)スリープこれなら、問題ないはずだ。考えてみるとSLEEPから目覚めた後、CRコード受信の後にCmdCheckが行われる保障はない。RX受信処理の方が時間が掛かるのかな。すると、スリープから目覚める(GPIO割込み)CmdCheckコマンド文字列受信→RXバッファに入れる(RX割込み)スリープスリープから目覚める(GPIO割込み)CmdCheckCRコード受信→RXバッファに入れる(RX割込み)スリープスリープから目覚める(GPIO割込み)CmdCheck→コマンド処理(文字列送信、CRLF送信)CRコード受信→RXバッファに入れる(RX割込み)スリープということで、2回目のCRでコマンド処理されているのかも。スリープが無い時は、CmdCheckは無限ループなので、次のループで処理されることになる。CmdCheckをメインループの最後に持ってきてみる。動いたが、コマンド文字列送信時に表示にへんなゴミが出る。コマンド文字列送信時には何も処理されないはずなので、ゴミが出るわけはないんだけど。次のコマンド文字列受信時に、CRLFが送信されている。コマンド文字列送信とCRLF送信後に、スリープしてるはずなのに、CRLF送信前にスリープしている感じだ。いうのは、送信用バッファにデータを入れるだけで、実際の送信はすぐに行われないのかもしれない。送信完了までSLEEPしないようにそうだとすると送信完了を確認してからSLEEPすれば良いことになる。UART_bReadTxStatus()の結果で、UART_TX_COMPLETE、UART_TX_BUFFER_EMPTYをチェックすれば良いのか。Completeあれ、戻ってこない。TXバッファが空になるまで待つというのはどうだろう。Completeうーん、文字化けの仕方は変わったけど、最初と大差ないなぁ。次のコマンド文字列受信時に、LFが出力されている。TXバッファが空になるのを、もう1回待ってみる。TXバッファのチェックってどうなってるんだ?スリープ前に、数10msの待ち時間を入れてみるとちゃんと動いた。Registorに残ってるってことなのかな。//sleepあっ動いた。あれ、でもSLEEPしてないや。COMPLETEはクリアされるUART_TX_COMPLETEが1になることは無いってことなのかな?それは、ちょっと変だな。何か間違ってるのか?以下のようにしても無限ループにならないし。Registorの記述を確認する。read.あぁ、読むとリセットされるんだ。//sleepうーん。直ったかな?LCDを付けて気が付いたけど、これだとコマンド入力後、CR入力までスリープしてないな〜。この場合は以下のようになる。スリープから目覚める(GPIO割込み)CmdCheckコマンド文字列受信→RXバッファに入れる(RX割込み)CRが来るまで、CmdCheckを繰返すCRコード受信→RXバッファに入れる(RX割込み)応答を返すTX完了したらスリープCOMPLETEフラグはクリアされちゃうから、こうなるのか。何かTXから出力しないとSLEEPしないことになる。あぁ、ちょっとマズイなぁ。COMPLETEフラグがクリアされなければ、簡単なのになぁ。問題点としては、データ送信後にSLEEPすると、CRLF送信前にスリープしてしまう。TXバッファが空になるまで待って、SLEEPするようにしてもLF送信前にスリープに入ってしまう。TX_COMPLETEでSLEEPすれば良いが、TX_COMPLETEはクリアされてしまうのでデータ送信時以外では不都合がある。スリープさせる方法として、以下のような3つの手段が考えられる。→送信フラグと条件分けが必要どれも、いまいちスッキリしない感じだけど、これぐらいしか思いつかない。まとめタクトスイッチGPIO割込み、UART割込み、スリープを併用する場合、UARTは、RXCmdBufferを有効にしておく→標準ルーチンを使う時SLEEPさせる時は、受信割込みで起動出来ないので、GPIO割り込みを併用する。その場合、RXの変化によりWakeUpさせるだけが目的なので、RX変化でGPIO割込みが発生した場合は何も処理しないようにする。データ送信したら送信完了までSLEEPしないようにする。→送信完了の確認方法は要注意このプログラムではタクトスイッチをGPIO割込みで読み込んでいるけど、チャタリング処理とか考えるとタイマ割込みで読み込んだ方が良いと思う。スリープ中はタイマが止まるので単純には行かないため、今回は諦めた。BUFFER_EMPTY,COMPLETEプラグについては、もうちょっとうまくやる方法があるかもしれない。Registorが空じゃない場合のために1文字送信分ディレイをとるようにしている。}1後から考えると変なんだけど、この時は分かってなかったので。2しかし、DigiView4のアプリは使い辛い。イライラするので3に戻した。3これ、callで呼んで自分でretiを入れる仕様の方が自由度あるんじゃないのかなぁ。余計なお世話のような気がするけど。[top]参考PSoCのUARTに関して参考にさせて頂いたサイト。バイナリデータを扱う場合は、参考になると思う。