C++によるRXマイコンCANドライバー(その4)

不具合修正

不具合を修正してブラッシュアップした。

  • リモートフレームを受信しない不具合を修正
  • 複数メールボックス割り込みの修正
  • 拡張 ID 受信の不具合修正

通常モードでは、メールボックスのフラグ設定により、受信するメールボックスが決定する仕様のようだ・・・

  • メールボックスの「RTR」が「1」なら、リモートフレームを受信
  • メールボックスの「RTR」が「0」なら、データフレームを受信
  • メールボックスの「IDE」が「1」なら、拡張 ID フレームを受信
  • メールボックスの「IDE」が「0」なら、標準 ID フレームを受信

最低でも4つのメールボックスで「待ち」状態にしないと、全てを受信できない・・
また、先のバージョンでは、メールボックスに対する割り込みフラグが正しく設定されていないようだったので、それも修正した。
※割り込み受信処理中にも受信が可能なように、8つのメールボックスをアクティブにしている。

Start CAN sample for 'RX64M' 120[MHz]
CAN command version: 0.86
CAN0: SPEED: 1000000 [bps], BRP: 3, TSEG1: 12, TSEG2: 7, SJW: 4
    RX Interrupt level: 1, TX Interrupt level: 1
CAN1: SPEED: 1000000 [bps], BRP: 3, TSEG1: 12, TSEG2: 7, SJW: 4
    RX Interrupt level: 1, TX Interrupt level: 1
#
# ch 1
# send 0x123
# map
R      1 S:x0000123 (291)
ID = 1 / Total = 1, Records = 0, Df = 0, Rf = 1
# send_loop 50
# map
D      1 S:x0000079 (121)
D      1 S:x00002B2 (690)
D      1 S:x00001C8 (456)

...

D      1 S:x000014E (334)
D      1 S:x000028C (652)
R      1 S:x0000123 (291)
D      1 S:x00002CB (715)
D      1 S:x00002BD (701)
D      1 S:x000000C (12)

...

D      1 S:x00000DB (219)
ID = 49 / Total = 51, Records = 204, Df = 48, Rf = 1
#
# dump 0x123
R      1 S:x0000123 (291)
R: ID: std 0x123 (291)
(0):
TS: 47248
# dump 219
D      1 S:x00000DB (219)
D: ID: std 0x0DB (219)
(2): D8 68
TS: 22193

リモートフレーム、データフレームの扱いについて、理解したので、表示も修正した。
※send 時、ID だけ設定するとリモートフレームを送信するようになっている。

RX66T の CAN ポート設定

RX66T では、CAN は1チャネルのみだが、候補が7番まであるので、それに伴って、port_map クラスを修正した。

        static bool sub_can_(option opt, bool enable)
        {
            uint8_t sel = enable ? 0b10000 : 0;
            switch(opt) {
            case option::FIRST:
                // PE0/CRX0 (22/144) 1ST
                // PD7/CTX0 (23/144)
                PORTE::PMR.B0 = 0;
                PORTD::PMR.B7 = 0;
                MPC::PE0PFS.PSEL = sel;
                MPC::PD7PFS.PSEL = sel;
                PORTE::PMR.B0 = enable;
                PORTD::PMR.B7 = enable;
                break;
            case option::SECOND:
                // PF3/CRX0 (31/144) 2ND
                // PF2/CTX0 (32/144)
                PORTF::PMR.B3 = 0;
                PORTF::PMR.B2 = 0;
                MPC::PF3PFS.PSEL = sel;
                MPC::PF3PFS.PSEL = sel;
                PORTF::PMR.B3 = enable;
                PORTF::PMR.B2 = enable;
                break;
            case option::THIRD:
                // PB6/CRX0 (40/144) 3RD
                // PB5/CTX0 (41/144)
                PORTB::PMR.B6 = 0;
                PORTB::PMR.B5 = 0;
                MPC::PB6PFS.PSEL = sel;
                MPC::PB5PFS.PSEL = sel;
                PORTB::PMR.B6 = enable;
                PORTB::PMR.B5 = enable;
                break;
            case option::FOURTH:
                // PA7/CRX0 (52/144) 4TH
                // PA6/CTX0 (53/144)
                PORTA::PMR.B7 = 0;
                PORTA::PMR.B6 = 0;
                MPC::PA7PFS.PSEL = sel;
                MPC::PA6PFS.PSEL = sel;
                PORTA::PMR.B7 = enable;
                PORTA::PMR.B6 = enable;
                break;
            case option::FIFTH:
                // PA1/CRX0 (58/144) 5TH
                // PA0/CTX0 (59/144)
                PORTA::PMR.B1 = 0;
                PORTA::PMR.B0 = 0;
                MPC::PA1PFS.PSEL = sel;
                MPC::PA0PFS.PSEL = sel;
                PORTA::PMR.B1 = enable;
                PORTA::PMR.B0 = enable;
                break;
            case option::_6TH:
                // PC6/CRX0 (62/144) 6TH
                // PC5/CTX0 (63/144)
                PORTC::PMR.B6 = 0;
                PORTC::PMR.B5 = 0;
                MPC::PC6PFS.PSEL = sel;
                MPC::PC5PFS.PSEL = sel;
                PORTC::PMR.B6 = enable;
                PORTC::PMR.B5 = enable;
                break;
            case option::_7TH:
                // P23/CTX0 (96/144) 7TH
                // P22/CRX0 (97/144)
                PORT2::PMR.B3 = 0;
                PORT2::PMR.B2 = 0;
                MPC::P23PFS.PSEL = sel;
                MPC::P22PFS.PSEL = sel;
                PORT2::PMR.B3 = enable;
                PORT2::PMR.B2 = enable;
                break;
            default:
                return false;
            }
            return true;
        }

有効な ID だけ通すフィルター

can_io クラスでは、フィルター機能を使っていない。
RX マイコンの CAN では、フィルターの設定が面倒で、数に制限がある為、実際のアプリでは、適応するのが難しいかもしれない。

ハードウェアーの機能を使えば、処理負荷を軽減できるものの、実用性が怪しい、また、異なるハードウェアー(RSCAN)などで、コードの再利用が難しくなる。

C++ では、特定の ID だけ通す(通さない)フィルターを簡単に実装出来る。
今回「boost::unordered_set」を使った。
※「std::unorderd_set」よりバイナリーが小さくなる。

まず、通すリストを構築する。

    // 有効な ID だけ通すフィルター
    typedef boost::unordered_set<uint32_t> VALID;
    VALID   valid_{ 0x123, 0x200, 0x300, 0xaaa, 15, 21, 33 };

非常に簡単だw

次に、メインループで、受信したフレームをディスパッチする際に、上記フィルターがヒットするか確認する。

        while(can1_.get_recv_num() > 0) {
            auto frm = can1_.get_recv_frame();
            if(valid_.find(frm.get_id()) != valid_.end()) {
                utils::format("\nCAN1:\n");
                CAN::list(frm, "  ");
            }
        }

この場合、CAN1 に受信したフレームで、「有効」な ID だけ表示する。

# send 0x123 0
CAN1:
  D: ID: std 0x123 (291)
  (1): 00
  TS: 29604
#
# send 0x1 1 2 3
# send 200 5 6 7
# send 0x200 5 6 7
#
CAN1:
  D: ID: std 0x200 (512)
  (3): 05 06 07
  TS: 41568
#

「unorderd_set」は、ハッシュを使って効率よく探すので、探す ID が多くても、検索にかかる負荷は小さくて済むものと思う。
また、「通す ID」を追加したり、削除したりも簡単に出来る。

今回はここまで。