| |
RAマイコンでFSPを用いると、CAN通信も簡単にできます。
レポートNO.0206 で作成したLチカのプロジェクトを改造して、使ってみます。
最初にCANのスタックを追加するため「Stacks」タブを開きます。
「New Stack」をクリックして、「Connectivity」->「CAN FD (r_canfd)」を選択します。
すると初っ端から以下のエラーが発生します。
「g_canfd0 CAN FD (r_canfd): Requires CANFD to be enabled on the Clokcs tab.」
CAN機能の動作に必要なクロックの設定がされてませんよ!、というエラーです。
常識的に考えれば、スタックを追加した時点で推奨条件のクロックが自動設定されるべきでしょう。
クロックを設定するため、「Clocks」タブを開きます。
CANにクロックを供給する設定の「CANFDCLK」がDisabledになっているので、「Src: PLL」に切り替えます。
CAFDCLKが40MHzに設定されます。
それでは、追加したCANのスタックについて設定します。
「Common」->「Global Error Interrupt」は、エラー発生時の割り込みに関する設定です。
今回はエラーに対して処理を行わないので、初期値のままにしておきます。
CANメッセージを受信する方法には、「メッセージボックス」を使う方法と「受信FIFOバッファ」を使う方法があります。
メッセージ方法は、CAN ID、メッセージフォーマット、DLCなどの値を予め設定しておき、そのメッセージのみ受信できます。
受信FIFOバッファは、とりあえずすべてのメッセージを受信対象としますが、CAN IDやDLC、メッセージフォーマット等でフィルタリングして受信条件を絞ることもできます。
今回は受信FIFOバッファでメッセージを受信します。
Channel 0を使用しますので、「Reception」->「FIFOs」->「FIFO 0」->「Enable」がEnabledになっていることを確認します。
「Depth」は最小の4stagesに変更します。自動車の車載におけるCANメッセージは最新の値を使うのが基本です。古い値をバッファしておいても意味がない程度では済まなく、間違った制御をして人命を危険に晒すことになります。
※ただし例えばフリーズフレームデータなどのイベント的な内容に関するメッセージは残す必要があります。
CANの通信速度を設定します。RENESASマイコンにおけるCAN通信機能の最大の障壁は、この通信速度設定でしょう。
RL78マイコン等ではTqという概念で設定する必要があり、この概念が非常に難解です。
しかしFSPでは、一般的な指標である bps にて数値を指定することができます。
今回は500kbpsで通信しますので、「Module g_canfd0 CAN FD (r_canfd)」->「Bitrate」->「Automatic」->「Nominal Rate (bps)」が初期値の500000 になっていることを確認します。
CANメッセージの受信には割り込みを使用します。
送信においても、なぜか割り込みを有効にする必要があります。
タイマー等の割り込みよりも優先順位を上げておく必要があるため、「Interrupts」->「Channel Interrupt Priority Level」を変更します。今回は、Priority 5 にしました。
送信に必要な送信メッセージボックスは、Channel 0を使用するため、「Transmit Interrupts」->「TXMB 0」にチェックを入れます。
最後に、CAN通信で使用するピンの設定を行います。
「Pins」タブを開いて、「Connectivity:CANFD」->「CANFD0」を開き、「Operation Mode」をEnabled に変更します。
CRX0 に PB05、CTX0 に PB04 を設定します。
CANメッセージの送信は、今回は定期送信で行いますのでタイマーを追加します。タイマーは、Channel 1を使用します。
タイマーの使い方は、レポートNo.0204 などと同じです。
今回は20ms周期で送信を行います。
割り込みの優先度は、CANの割り込み機能に影響させず、かつ送信周期の精度を上げるために、今回はとりあえず Priority 6 としました。
以上で設定完了です。コード生成をして完了です。
次にhal_entry.cのコードを追記修正します。
最初に受信メッセージのフィルタリングを設定する構造体配列を追加します。
この辺りはFSPのマニュアルに記載されていますので、それを参考にします。
「Acceptance Filter List (AFL) Array」を、hal_entry.c のグローバル変数等の宣言部分にドラッグ&ドロップします。
すると、空の構造体配列が追加されます。
構造体の中身は、「AFL Entry」をドラッグ&ドロップして貼り付けます。
無駄な二度手間だと思いますが、リリースまでにルネサス社内で誰も何も言わなかったのでしょうか?
日本人では考えられない配慮のなさです。
.id は、受信するメッセージを指定します。
メッセージボックスでは、この値が一致したメッセージのみ格納されます。
.mask は、メッセージのフィルタリングの有効範囲を指定します。
.mask_id_mode や .mask_frame_type は、.idで設定した .frame_type や .id_mode をフィルタリングの対象にするかの設定です。1で有効、0で無効となります。
.mask_id は、.idで設定した .id の有効範囲を設定します。0を設定すればフィルタが無効となり、すべてのIDを受信します。0x1FFFFFFF であれば、.id の値のみ受信します。0x1FFFFF00と指定した場合、.id & 0x1FFFFF00 の範囲の値が受信対象となります。例えば.id = 0xCC10AA 、.mask_id = 0x1FFFFF00と設定した場合、0xCC1000 〜 0xCC10FF が受信範囲となります。
今回はすべてのIDを受信対象とするため、.mask_id = 0 とします。
といった説明の詳細がFSPのマニュアルを読んでもどこにも書いてありません。
コメントの短いメッセージだけ読んで、後は自分で考えて理解しろ、ということなのでしょう。
.destination は、使用するメッセージボックスとFIFOバッファのChannelを指定します。
.minimum_dlc は、受信対象とするDLCの最小値を設定します。
.id の中で設定されるべき項目だと思いますが、なぜここにあるのでしょうか?
.rx_buffer は、使用するメッセージボックスを指定します。今回は使用しないので、初期値のCANFD_RX_MB_NONEのままにしておきます。使用する場合は、CANFD_RX_MB_0 などに書き換えます。
.fifo_select_flags は、使用するFIFOバッファを指定します。今回は FIFO 0 を使用しますので、初期値のCANFD_RX_FIFO_0 のままにしておきます。
宣言部分です。CANメッセージの送受信で使用するメッセージ用の構造体 g_can_tx_frame、g_can_rx_frame をグローバル構造体として宣言します。送信メッセージのデータとして使用する変数 count_can_msg も宣言しておきます。
グローバル宣言部分(AFL含む)
hal_entry関数内には、CANを有効にするR_CANFD_Open関数と、CANの定期送信に使用するタイマー関数のR_GPT_Open、R_GPT_Startを追加しています。
hal_entry関数
CANメッセージの受信処理です。空の割り込み関数 canfd0_callback をドラッグ&ドロップで貼り付けて、処理内容を書きます。
この割り込みは受信以外でも共通で発生するため、最初に受信完了の割り込みかどうかを判断します。戻り値として使用されている引数構造体のevent に、割り込み要因が格納されています。CAN_EVENT_RX_COMPLETE が受信完了割り込みを指しますので、この値で判定します。
次に受信メッセージを、グローバル構造体 g_can_rx_freme に格納します。
受信したメッセージが格納されているFIFOバッファのアドレスがframeに格納されているため、
memcpyでデータをコピーします。
R_CANFD_Read関数を使いたいところですが、FIFOバッファには対応していないようです。
FSPのマニュアルに記載されているサンプルプログラムでも memcpy が使用されています。
memcpy については、カーニハンリッチーの本にも記載されていると思います。
次は、CAN ID の判定を行います。今回は CAN ID = 0xFE0010 を受信したときに処理を行うようにするため、そのように記載します。今回は、データの1バイト目が0xFFの場合はLチカON、0x00の場合はLチカOFFとするため、そのように処理を書きます。
Lチカの処理内容については、レポートNO.0206 を参照してください。
canfd0_callback CAN割り込み関数
定期送信は、今回追加したタイマー1を使用して行います。
最初に、CAN機能がメッセージを送信中かどうかを判定します。これを判断する関数がFSPにないため、レジスタを直接参照します。RAマイコンにおいてレジスタを直接操作する方法については、レポートNo.0034 などを参照してください。
CFDC0STS の TRMSTS の値を参照します。通常であれば送信処理は一瞬で終わるため、今回の処理においてTRMSTS が 1になることは正常な条件下ではありません。1になるときは、何か不具合や問題があるときです。
次に送信するCANメッセージを設定します。
g_can_tx_frame はグローバル変数(構造体)として宣言していますので、
変わらない値は1度設定すれば良いのですが、今回は分かりやすいように毎回設定しています。
id_modeは、メッセージタイプが11bit標準CANなのか、29bit拡張CANなのかを指定します。
optionsは、基本的にCAN FDを使用するときのみに指定します。今回は普通のCANを使用するため、設定不要です。
1バイト目のdata[0]には、LED_0 の点灯状態を出力します。
7バイト目のdata[6]には、0〜255の範囲で送信ごとにカウントアップさせた値を格納します。
8バイト目のdata[7]には、7バイト目をビット反転させた値を格納します。
メッセージごとに異なる値を入れることで、送信側の処理がフリーズしている、送信側がAck信号を受信できずに同じメッセージ送信をリトライしている等の異常な状態であるかが判断できるようになります。ホンダさんは昔からこれやってますね。
最後に、R_CANFD_Write関数を使用して送信します。今回は送信メッセージボックスのChannel 0を使用するので、CANFD_TX_MB_0 を指定します。
タイマー割込み関数(CANメッセージ定期送信)
レジスタの説明は、ハードウェアマニュアルに記載されています。
送信中であるかの判定は、TRMSTS で確認します。
以上でコードの追記修正は完了です。
プロジェクトをビルドして、デバッグでマイコンを動作をさせます。CANメッセージの送受信は相手側も必要ですので、ツールを使って動作を確認します。
|