2013年11月26日火曜日

STM32F1 ピン変化割り込み

STM32F1のピン変化割り込み EXTIの初期化方法について

今回は僕のボードの関係でPD1の立ち上がりエッジで割り込みが入るように設定する

クロックの供給

AFIOとGPIOのクロックを有効化する
一般的な有効化と同じ手順
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,   ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,  ENABLE);

今回はUART5 RXを使うためにGPIODを
JTAGを無効化するためにAFIOを 
それぞれクロックを供給していたので追加のコードは必要なかった
/*
  JTAGを無効化するにはAFIOを初期化して
  AFIO->MAPR = _BV(26);
  として26bitを立ててやればJTAGとSWJの両方を無効化できる
*/


GPIOの初期化

これも一般的な初期化の方法と同じ
GPIO_InitTypeDef GPIO_InitStructure;
で構造体を確保し
GPIO_InitStructure.GPIO_Pin = _BV(1);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOD, &GPIO_InitStructure);
でPD1を入力モードにした
IPUでもIPDでも問題ないはず

EXTIの有効化

GPIO_EXTILineConfig関数を使う
第一引数にポートを 第二引数にピンを指定する
これは一般的なGPIOAや_BV(0)といった指定方法ができない
GPIO_PortSourceGPIOAやGPIO_PinSource0というマクロを使う
今回はGPIODのピン1を使うので
GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource1);
という感じ
/*
  ヘッダファイルを見てみるとGPIO_PortSourceGPIOAは ((uint8_t)0x00) が Bは0x01 Cは0x02
  GPIO_PinSource0は ((uint8_t)0x00) が 1は0x01 2は0x02
  という感じで指定されている

  一般的なGPIOAやGPIOBはペリフェラルのポインタが
  _BVは #define _BV(n) ( 1 << (n) ) という指定でビットシフトしている
  そのため基本的にGPIO_PortSourceとGPIOxの互換性は全くない ピン指定も同じ
*/


EXTIの初期化

EXTI_Init関数を使う
EXTI_InitTypeDefポインタを引数にする
中身は 
    EXTI_Line
    EXTI_LineCmd
    EXTI_Mode
    EXTI_Trigger
の4個

LineはEXTI_Line0からEXTI_Line19の20個から選択
ピン0がLine0 ピン15がLine15という感じで割り付けられている
また16,17,18,19はそれぞれ電圧計国やRTCのアラーム等に設定されている

LineCmdは有効化するか否かをENABLE/DISABLEで選択
Modeは割り込みかイベントを選択 それぞれEXTI_Mode_InterruptとEXTI_Mode_Event
Triggerはどちらのエッジを使うか 
    EXTI_Trigger_Risingで立ち上がり
    EXTI_Trigger_Fallingで立ち下がり
    EXTI_Trigger_Rising_Fallingで両方
という感じ

今回はピン1の立ち上がりエッジで割り込み という設定なので
EXTI_Line1 ENABLE EXTI_Mode_Interrupt EXTI_Trigger_Rising
で初期化する

// PB1は立ち上がりで PC1は立ち下がりで とかの割り込みはどうするんだろう?

NVICの設定

NVICの設定は一般的な設定と同じ
ここは省略する
NVICのチャンネルはEXTI1_IRQn等を設定する

割り込みハンドラ

割り込みで呼び出される関数
void EXTI1_IRQHandler(void)
となる
中で EXTI_ClearITPendingBit(EXTI_Line1); でペンディングビットをクリアする必要がある
EXTI_GetITStatusを使ってLine1のペンディングビットを確認することができるけど EXTI1_IRQHandlerはLine1割り込みしか呼ばれないはずなのでGetで確認は不要のはず



上記の手順でEXTI割り込みが使えるようになる
しかし、ピン変化割り込みハンドラが呼ばれても、どのラインの割り込みか はわかるが
どのポートが割り込み操作のトリガになったかは判別できない気がする
例えばPA1とPB1の両方に割り込みを設定した場合、Px1が動いた と言うのはわかるんだが、それがAなのかBなのかは判断できない

あとPA1は立ち上がり PB1は立ち下がり とかだとRising_Fallingにして、ハンドラで確認する必要があるのか?

気が向いた時にでも調べておく必要がある

2013年11月20日水曜日

RC-S620/S

いまさらですが FeliCaリーダライタのRC-S620/Sを使ってみました
コレはだいぶ前に買っていて、作ってみたいものも有ったのですが
ズルズルと放置されていました

コレにアクセスするためのAPIはSonyがArduino用に公開していますが
C++のライブラリのため、C言語環境で使いたい時はライブラリを書かなくてはなりません
幸いC++をCに移植するのはC#よりもはるかに簡単なので
とりあえず移植して試してみました

なお、RC-S620/S自体はスイッチサイエンスで販売されています
モジュールの制御方法は法人向けの技術情報ページに記載されています
http://www.sony.co.jp/Products/felica/business/tech-support/index.html
一番下にRC-S620Sの製品情報とコマンドリファレンスの簡易版があります

Arduino向けライブラリは
http://blog.felicalauncher.com/sdk_for_air/?page_id=2699
から規約に同意することでダウンロードできます


STBeeにコードを書いて実行するとIDm等を表示することができます

モジュール自体はユニバーサル基板の裏側にFFCの変換基板と3.3Vレギュレータと共に固定されています

このモジュール自体は5Vと3.3Vの両電源に対応していますが、5Vの範囲がUSBの供給電圧レベルよりも狭いため、念の為に3.3Vにしてから供給しています

今回はIDmを使用した非常に簡易的なカードキーとして使おうと思ったため、ID獲得以上のことはしていませんが
ライブラリの動作確認時にケータイ電話へWebページURLを送信できることも確認しています

なお、FeliCaのIDは比較的簡単に偽装できるため、カードキーとして使う場合にIDm単体を使うことは推奨されていません
ですが今回はとりあえず遊びなので、IDmを使おうと思います


このモジュールはSony製でSonyが日本語情報を公開しているため、非常に簡単に使用することができます
うまく使えば色々と応用できそうなので、興味がある人は試してみてください

2013年11月15日金曜日

GTK

GTKというものを始めてみました
これはLinux等で使えるGUIアプリケーションを作るためのツールキットのようなもので
用意された関数等を呼ぶとGUIアプリが作れるというものです

今回はUbuntu LTS 日本語Remix上に入れたGTK2.0を使いました
UbuntuはWin7x64上のOracle VM VirtualBoxか、Mac 10.8上のParallels8のどちらでも動作を確認しています


GTKのインストールは
$ sudo apt-get install libgtk2.0-dev


ビルドする場合は
$ gcc source.c `pkg-config --cflags --libs gtk+-2.0`
です

pkg-configの前と最後はシングルクォーテーションではなくグレイヴアクセントであることに注意してください
この記号はJISキーボードであればシフトキーを押しながらアットマークキーを USキーボードならESCキーの下のあたりにある波ダッシュキーを押すことにより入力できます


エディタはViを使いましたが、基本的に使いやすいものを使っても大丈夫です

GTKアプリはgtk/gtk.hをインクルードしておく必要があります
CbackButtonClickedとCreateButton関数は放置するとして
main関数は一般的なCUIアプリと同様です
int argcとchar ** argvが引数です

まずローカル変数としてはGtkWidgetポインタ型のwindowという変数を宣言しておきます
これはFILE *fp等と同じように扱います
この変数(が指し示すメモリ)にGUIの様々な設定が入りますが、普段は変数の中身を気にすることは無いでしょう(設定は関数経由で行われる)

次に gtk_init 関数があり、これはargcとargvのポインタを渡します
argcとargvは値渡しではなく参照渡しであることに注意です

次に gtk_window_new 関数でメインのウィンドウを作ります
引数はGTK_WINDOW_TOPLEVELで、ポップアップウィンドウなどではこれが変わります
戻り値を変数windowに入れておきます

次に gtk_widget_set_size_request 関数でウィンドウの大きさを設定します
第一引数に対象のGtkWidgetポインタを 第二引数と第三引数にそれぞれ横解像度と縦解像度を与えます

次にCreateButton関数を読んでいますが、これはボタンを作成するためのサブルーチンです
ウィンドウと同じく GtkWidget *button 変数を作り、gtk_button_new_with_label関数でボタンの雛形を作成します
gtk_button_new...関数の引数はボタンに表示される文字列を与えます

次にgtk_container_add関数を使い、ウィンドウと関連付けをします

最後にg_signal_connect関数でボタンがクリックされた際に呼び出される関数を指定子ます
イベント"clicked"を指定し、関数はCbackButtonClickedです
第四引数にはコールバック関数に与える引数を設定できますが、今回はNULLとしておきます

感覚的にはgtk_container_addよりもg_signal_connectを先にしたほうがいいかもしれません

CbackButtonClecked関数の中身は gtk_main_quit 関数を読んでいるだけです

GtkWindget *buttonは任意のタイミングで破棄して問題ないようです


main関数に戻り
次は g_signal_connect ですが、これはウィンドウが閉じられた際にプログラムを終了するために設定します
これをしておかないとウィンドウを閉じたのにプログラムは終了しない といったことになりかねません
イベント"destroy"でgtk_main_quit関数を呼ぶように設定します

最後に gtk_widget_show_all でウィンドウを表示します
gtk_widget_show という関数もありますが _allを付けない場合はボタンなどが表示されないので注意してください

あとは gtk_main() 関数を呼び出してループに突っ込みます
gtk_main_quit はgtk_main()で呼んだループを終了させる役目があります
gtk_mainを抜けだすとmain関数に戻り、その後は何も処理を書いていないのでreturn(0)で正常終了します

これを上記コマンドでビルドするとa.outというプログラムが作成されます
a.outアイコンをダブルクリックするか、端末でa.outを起動すると上記画面に表示されているボタンが1個あるだけのプログラムが表示されます
☓印をクリックして閉じてもいいですし、ボタンをクリックして終了してもいいです


このコードはGTKの基本的な使い方を学べると思います
ボタンが2つ有るウィンドウ等を作る場合は更に複雑になりますが、基本的に上記の手順で作成することができます


OSをLinuxに限定せず、Windows等を使っていいのならC#等のGUIアプリを作る方法はたくさんありますが、今回はLinux上のGTKを使ってみました