ArduinoでCAN通信(その2:拡張IDでフィルタ、マスク)

「ArduinoでCAN通信」の次は、拡張IDを使いCANコントローラMCP2515でハード的にフィルタ、マスクを行う機能を追加することになります。

オリジナルのソースには、フィルタ、マスクに関して次のような記述があります。
//-------
// P258_N1.ino
//
    // フィルタ、マスク設定 SID 11bit
    CANSetSidFilter0(0x0000);
    CANSetSidFilter1(0x0000);
    CANSetSidFilter2(0x0000);
    CANSetSidFilter3(0x0000);
    CANSetSidFilter4(0x0000);
    CANSetSidFilter5(0x0000);
    CANSetSidMask0(0x0000);
    CANSetSidMask1(0x0000);

    CANSetFilterRxB0(3);            // RXB0でフィルタ、マスクは使用しない
    CANSetFilterRxB1(3);            // RXB1でフィルタ、マスクは使用しない
//-------------

これの意味を調べてみると
・これは標準ID用です。(拡張ID用は作らねばならない)
・フィルターは0から5まで6個設定ができる
・マスク(スルーさせる部分)は2個設定ができる
・フィルタ、マスク共、0x0000 という、0を設定するとフィルタしない、マスクしないという意味
・フィルタ、マスクをRxB0、RxB1で使う:0、標準IDとして使う:1、拡張IDとして使う:2、使わない:3

さらに、これらのプログラム構成を調べると、
// ------
// CAN2515.h 内にマクロが記述されています
//
// フィルタSID設定 (注:0だけ表示、5まであります)
#define CANSetSidFilter0(sid) CANSetSidFilteMask(RXF0SIDH, sid)
//
// マスクSID設定
#define CANSetSidMask0(sid) CANSetSidFilteMask(RXM0SIDH, sid)
#define CANSetSidMask1(sid) CANSetSidFilteMask(RXM1SIDH, sid)
// ------

そしてマクロを実行するプログラム本体は
// ------
// --------------------------------------------------------------------
// CAN SID フィルタ、マスク設定 (兼用ルーチン)
// --------------------------------------------------------------------
// CAN2515.h 内
//
void CANSetSidFilteMask(byte adrs, word sid) {
    CANWriteReg(adrs, (byte)(sid>>3));            // HIGH
    CANWriteReg(adrs + 1, (byte)((sid & 0x07)<<5));        // LOW
}

CANWriteREG() というのはSPIを使ってMCP2515指定アドレスにByteデータを書き込む部分ですので、フィルタ、マスクを書き込むルーチンを拡張ID用で作れば良いということのようです。

// --------
// CAN2515.h に追加した記述
//
// フィルタEID設定
#define CANSetEidFilter0(eid) CANSetEidFilteMask(RXF0SIDH, eid)
#define CANSetEidFilter1(eid) CANSetEidFilteMask(RXF1SIDH, eid)
#define CANSetEidFilter2(eid) CANSetEidFilteMask(RXF2SIDH, eid)
#define CANSetEidFilter3(eid) CANSetEidFilteMask(RXF3SIDH, eid)
#define CANSetEidFilter4(eid) CANSetEidFilteMask(RXF4SIDH, eid)
#define CANSetEidFilter5(eid) CANSetEidFilteMask(RXF5SIDH, eid)
//
// マスクEID設定
#define CANSetEidMask0(eid) CANSetEidFilteMask(RXM0SIDH, eid)
#define CANSetEidMask1(eid) CANSetEidFilteMask(RXM1SIDH, eid)
//
// -------------------
// プロトタイプ
void CANSetEidFilteMask(byte adrs, long eid);
// -------------------------------------------------------------------- 
// CAN EID フィルタ、マスク設定(兼用ルーチン)
// --------------------------------------------------------------------
void CANSetEidFilteMask(byte adrs, long eid) { 
  word canid;                                                   // 抽出2バイト値
  byte bSIDH;                                                   // フィルタ標準ID上位
  byte bSIDL;                                                   // フィルタ標準ID下位
  byte bEID8;                                                   // フィルタ拡張ID上位
  byte bEID0;                                                   // フィルタ拡張ID下位

  canid = (word)(eid & 0x0FFFF);       // 拡張IDの下位側2バイトをcanidに抽出する
 
  bEID0 = (byte)(canid & 0xFF);          // canid の下位1バイトがフィルタ拡張ID下位
  bEID8 = (byte)(canid >> 8);              //  同上の上位1バイトがフィルタ拡張ID上位
  canid = (word)(eid >> 16);                // 拡張IDから上位2バイト分の標準ID部分を
                                                   // canidに抽出する
  bSIDL = (byte)(canid & 0x03);          // フィルタ標準ID下位に抽出したcanid の
                                                   // 下位2ビット(EID17,EID16)を代入する
  bSIDL += (byte)((canid & 0x1C) << 3 );    // 同上のb4,b3,b2の3ビットを3ビット
                                                   // 上方シフトして加える(SID2,1,0)
  bSIDL |= 0x08;                                 // 拡張IDを示すEXIDEビット(b3)を立てる
  bSIDH = (byte)(canid >> 5);              // フィルタ拡張ID上位は 抽出していた値を
                                                   // 5ビット右シフトして代入する
  CANWriteReg(adrs, bSIDH);                     // MCP2515 には、SIDH,SIDL,EID8,EID0 の
  CANWriteReg(adrs + 1, bSIDL);               // 順にアドレスが並んでいるので
  CANWriteReg(adrs + 2, bEID8);               // 順に書き込む
  CANWriteReg(adrs + 3, bEID0);
}
// ------------------

これを作るに当たり、先に参考にしたseeedのソースをまた参考にしました。
元となったソースでは、標準IDか拡張IDかを判定するフラグによって処理を分岐させるように作ってあります。汎用的に使われる機器の場合はそのような作りが好ましいと思えます。

忘備録として、フィルタIDバッファと拡張IDデータの関係を図で記載します。
表内のSIDは標準ID、EIDは拡張ID用のビットです。

RXFnSIDH フィルタn標準ID 上位(n=0,1,2,3,4,5)
(アドレス:0x00,0x04,0x08,0x10,0x14,0x18)
b7b6b5b4b3b2b1b0
SID10SID9SID8SID7SID6SID5SID4SID3

RXFnSIDL フィルタn標準ID 下位(n=0,1,2,3,4,5)
(アドレス:0x01,0x05,0x09,0x11,0x15,0x19)
b7b6b5b4b3b2b1b0
SID2SID1SID0-EXIDE-EID17EID16
EXIDE は拡張ID許可ビットで、0:標準ID、1:拡張ID を示します。

RXFnEIDH フィルタn拡張ID 上位(n=0,1,2,3,4,5)
(アドレス:0x02,0x06,0x0A,0x12,0x16,0x1A)
b7b6b5b4b3b2b1b0
EID15EID14EID13EID12EID11EID10EID9EID8

RXFnEIDL フィルタn拡張ID 下位(n=0,1,2,3,4,5)
(アドレス:0x03,0x07,0x0B,0x13,0x17,0x1B)
b7b6b5b4b3b2b1b0
EID7EID6EID5EID4EID3EID2EID1EID0


このフィルタバッファに拡張IDデータを入れるわけだが
拡張IDには、連なる4バイトにデータが下図のように並んでいる。

b7b6b5b4b3b2b1b0
---SID10SID9SID8SID7SID6

b7b6b5b4b3b2b1b0
SID5SID4SID3SID2SID1SID0EID17EID16

b7b6b5b4b3b2b1b0
EID15EID14EID13EID12EID11EID10EID9EID8

b7b6b5b4b3b2b1b0
EID7EID6EID5EID4EID3EID2EID1EID0

このような配置なので、先のようなCAN EID フィルタ、マスク設定ルーチンになる。


次にメインのunoソースを変えます
// -----------
// N258_N1.uno
//
// SID用フィリタ、マスク部をコメントアウト(省略)
//
  // フィルタ、マスク設定 EID 29bit
  CANSetEidFilter0(0x18F00200);   //J1939 sim 'VSS' 6Byteが、km/hr
  CANSetEidFilter1(0x18F00400);   //J1939 sim 'RPM' 5Byteの64倍が、r/min
  CANSetEidFilter2(0x18FEEE00);   //J1939 sim 'ECT' 1Byteの-40オフセットが、℃
  CANSetEidFilter3(0x00000000);
  CANSetEidFilter4(0x00000000);
  CANSetEidFilter5(0x00000000);
  CANSetEidMask0(0x7FFFFFFF);     //全てのビットを立てるとフィルタの全一致
  CANSetEidMask1(0x7FFFFFFF);     //(同上)

  CANSetFilterRxB0(0);            // RXB0でフィルタ、マスクを使用する
  CANSetFilterRxB1(0);            // RXB1でフィルタ、マスクを使用する
// -----------

3個の拡張IDを通すようなフィルタ、マスクにしました。

フィルタを通ってきた3種のデータの後に数値を表示させてみました。

// -------------------------
// N258_N1.uno
//
    //CANデータを処理し、数値を追加
    if(msg2 == 0x18F00200){
      sprintf(StrBuf, "-VSS:%d(km/hr)", MsgBuf[11]);
      PUTSTR(StrBuf);
    }
    if(msg2 == 0x18F00400){
      sprintf(StrBuf, "-RPM:%d(r/min)", (word)(MsgBuf[10]*64));
      PUTSTR(StrBuf);
    }
    if(msg2 == 0x18FEEE00){
      sprintf(StrBuf, "-ECT:%d(deg)", (word)(MsgBuf[6]-40));
      PUTSTR(StrBuf);
    }
// ----------------------------

【拡張IDフィルタを使った処理結果、シリアルモニタ】
Arduino_CAN_12.jpg

回転数rpmは0.1秒間隔くらいで送られてきています。
これぐらいのデータ量ならばArduinoで難なく処理できているということでしょう。

さて、計画していたことは
【今後のお勉強課題】
1.ID識別で、続くデータを処理する機能のテスト(取りあえずシリアル通信を受けたPCで処理)
2.この機能をArduinoマイコンに実装
3.Arduinoマイコン(実体はMCP2515)でCAN IDによるフィルタ機能の実装(実機で使えるように)
4.BlueToothによる通信と(当初はWindowsPCへ)、Androidタブレットまたはスマホでの表示

1.2.を飛ばして3.ができてしまいました。

お次は4.の前半・BlueToothによる結果の伝送です。





コメントの投稿

非公開コメント

プロフィール

haiga

Author:haiga
私のブログへようこそ!
電気オンチが始めた自作オーディオです
2010/3/17 電子工作をプラスしました。

自作オーディオの楽しみ共有のため、私が作ったパーツ提供をしてます。質問や要望を遠慮なくコメント欄に書き込んでください。

FC2カウンター
その日1回目にアクセスいただいた方の総カウントです
最新記事
最新コメント
最新トラックバック
カテゴリ
月別アーカイブ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード