RXマイコン、ポート・マップ・ピン情報を追加

ポート・マップ候補機能

  • C++フレームワークでは、各ペリフェラルを扱う場合、どのポートを選択するかを、簡潔に扱う為に、「ポート・マップ候補機能」を導入しています
  • 今まで、「候補」がどのポートを選択するかを知る為、各ソースコードを参照するようにとアナウンスしていました
  • それを、少しだけ便利にする為、単純に、候補とポートの関係を表にして、各MPUのルートにある、README.md ファイルに集約するようにしました
  • これは、ソースコードの修正とは、異なり、単なるドキュメントの更新なんだけど、分量がかなり多く、又、ピン番号も同時に記入してあるので、それなりに大掛かりな作業でした
  • ピン番号は、良く使うであろう、パッケージだけに絞り、(例えば、64 ピン、100 ピン、144 ピンなど)全てを網羅している訳では無いのだけど・・・
  • パッケージとピン番号の正確性は、ミスもあるかと思うので、実際に配線する前に確認が必要です

各CPUの特徴とリンクなど

現在サポートされ、動作確認済みデバイス:

シリーズ MinV MaxV MHz コア FPU TFU DFPU 動作確認 rx_prog リンカーファイル
RX110 1.8 3.6 32 RXv1 R5F51103/4/5
RX111 1.8 3.6 32 RXv1 R5F51115/6/7
RX113 1.8 3.6 32 RXv1 R5F51136/8
RX130 1.8 5.5 32 RXv1 R5F51305/6
RX140 1.8 5.5 48 RXv2 Yes R5F51403/5/6
RX13T 2.7 5.5 32 RXv1 Yes R5F513T3/5
RX210 1.62 5.5 32 RXv1 R5F52108/B
RX220 1.62 5.5 32 RXv1 R5F52206
RX231 1.8 5.5 54 RXv2 Yes R5F52316/7/8
RX23T 2.7 5.5 40 RXv2 Yes R5F523T5
RX24T 2.7 5.5 80 RXv2 Yes R5F524T8/A
RX24U 2.7 5.5 80 RXv2 Yes R5F524UB/E
RX261 1.6 5.5 64 RXv3 Yes R5F52618
RX26T 2.7 5.5 120 RXv3 Yes V2 R5F526TF
RX621 2.7 3.6 100 RXv1 Yes R5F56218
RX62N 2.7 3.6 100 RXv1 Yes R5F562N7/8
RX631 2.7 3.6 100 RXv1 Yes R5F5631F
RX63N 2.7 3.6 100 RXv1 Yes R5F563NE
RX63T 3.3 5 100 RXv1 Yes R5F563T6
RX64M 2.7 3.6 120 RXv2 Yes R5F564MF/G/J/L
RX71M 2.7 3.6 240 RXv2 Yes R5F571MF/G/J/L
RX651 2.7 3.6 120 RXv2 Yes R5F5651E
RX65N 2.7 3.6 120 RXv2 Yes R5F565NE
RX66N 2.7 3.6 120 RXv3 Yes V1 Yes R5F566ND/N
RX660 2.7 5.5 120 RXv3 Yes R5F56609
RX671 2.7 5.5 120 RXv3 Yes R5F5671C/E
RX72N 2.7 3.6 240 RXv3 Yes V1 Yes R5F572ND/N
RX72M 2.7 3.6 240 RXv3 Yes V1 Yes R5F572MD/N
RX66T 2.7 5.5 160 RXv3 Yes R5F566TA/E/F/K
RX72T 2.7 5.5 200 RXv3 Yes V1 R5F572TF/K

基本的な候補の使い方など

「候補」は以下のようになっています:

    enum class ORDER : uint8_t {
        BYPASS,         ///< ポートマップの設定をバイパスする場合

        FIRST,          ///< 第1候補
        SECOND,         ///< 第2候補
        THIRD,          ///< 第3候補
        FOURTH,         ///< 第4候補
        FIFTH,          ///< 第5候補
        SIXTH,          ///< 第6候補
        SEVENTH,        ///< 第7候補
        EIGHTH,         ///< 第8候補
        NINTH,          ///< 第9候補
        TENTH,          ///< 第10候補
        ELEVENTH,       ///< 第11候補
        TWELVETH,       ///< 第12候補

        USER,           ///< ユーザー設定

        LOCAL0,         ///< 独自の特殊な設定0
        LOCAL1,         ///< 独自の特殊な設定1
    };
  • 現在、ポート候補は、グループ設定の場合と、単独ポートの場合が混在しています
  • たとえば、SCI、CAN、RSPI、IICA などはグループ指定、MTU、TPU、GPT、GPTW、QSPI などは単独で指定可能になっています
  • なので、SCI などで、グループを超えて設定(TXD を FIRST、RXD を SECOND みたいな)事は出来ないです
  • グループ指定は、複数あるポートを一括して行うものです
  • 一般的に、グループ候補の場合、近接するポートを選んでいるので、通常それで困る場合は無いと思います
  • 急遽、ペリフェラルの機能が必要になり、余っているポートをかき集めたり、改造を最小限にする為に、異なる候補を選択するしか無い場合はあるかと思います
  • そのような場合は、「USER」設定を使って、独自に設定する必要があります

SCI ポート候補の選択例

  • 例として RX231、LFQFP64 パッケージの場合
  • SCI5 を使いたい場合

Github RX231 ルート

Port map order / ポートマップ候補

LFQFP64

Peripheral FIRST SECOND THIRD FOURTH
SCI5 / RXD PA2 (--) PA3 (43) PC2 (32) PC2 (32)
SCI5 / TXD PA4 (42) PA4 (42) PC3 (31) PC3 (31)

候補の選択と管理

  • 「Port map order / ポートマップ候補、LFQFP64」の表から、「SCI5 / RXD, SCI5 / TXD」の欄を見ます
  • 実際のハードを吟味して、SECOND の RXD/PA3 (43)、TXD/PA4 (42) が使えそうと判断します
  • SCI の入出力では、「sci_io.hpp」のテンプレートクラスを使います
  • 以下のコードのように、「SECOND」を指定して、sci_io のテンプレートを typedef して型を定義します
  • それの実態を定義して、初期化するだけで、使えるようになります
  • new しても構いませんが、固定されたハードウェアーで、動的にクラスを生成する必要性が無いので、static に宣言します
  • 出来るだけ、new を使わない方法を選択する事が寛容です
  • static に宣言すれば、必要なメモリは、C++ コンパイラが適切に領域を設定して配置してくれます
  • C++ では、static と宣言しても良いのですが、main 関数があるソースに、無名の名前空間で囲んで定義するのが一般的です
  • sci_io クラスでは、定義に、受信、送信バッファの型を伴って定義します
  • バッファは、固定長のリングバッファを使います、「fixed_fifo」テンプレートクラス
  • 以下の例では、それぞれ、512 バイト、256 バイトの大きさで定義しています
#include "common/renesas.hpp"
#include "common/fixed_fifo.hpp"
#include "common/sci_io.hpp"

namespace {
    typedef utils::fixed_fifo<char, 512> RXB;  // RX (受信) バッファの定義
    typedef utils::fixed_fifo<char, 256> TXB;  // TX (送信) バッファの定義
    typedef device::sci_io<device::SCI5, RXB, TXB, device::port_map_order::SECOND> SCI5_IO;

    SCI5_IO sci5_io_;
}
  • もし、あーやっぱり、「RXD/PA3 (43)、TXD/PA4 (42)」じゃなく、「RXD/PC2 (32)、TXD/PC3 (31)」の方が、都合が良いとなれば
  • 候補を、「SECOND」から「THIRD」にするだけです
  • 他は変更する必要がありません
    typedef device::sci_io<device::SCI5, RXB, TXB, device::port_map_order::THIRD> SCI5_IO;

標準入出力の設定

  • 一般的な gcc を使った、組み込みアプリケーションでは、標準入出力とのインターフェースを設定する必要があります
  • この C++ フレームワークでは、syscall.c をリンクする事で、インターフェースを有効にする事が出来ます
  • SCI5 のインスタンスをこの標準入出力と繋げる場合、以下のように定義します
extern "C" {

    // syscalls.c から呼ばれる、標準出力(stdout, stderr)
    void sci_putch(char ch)
    {
        sci5_io_.putch(ch);
    }

    void sci_puts(const char* str)
    {
        sci5_io_.puts(str);
    }

    // syscalls.c から呼ばれる、標準入力(stdin)
    char sci_getch(void)
    {
        return sci5_io_.getch();
    }

    uint16_t sci_length()
    {
        return sci5_io_.recv_length();
    }
}
  • この定義で、SCI5 での入出力は、標準入出力とリンクされます
  • printf や scanf などで入出力を行えます
  • C++ では、C 言語の関数は使わないので、format クラス、input クラスの用意があります

初期化

  • SCI の初期化は簡単で、ボーレート、割り込みレベル、プロトコルを選択するだけです
// 起動時、1度行って、マスタークロックをブーストして下さい
    SYSTEM_IO::boost_master_clock();

    {  // SCI の開始
        constexpr uint32_t baud = 115200;  // ボーレート(任意の整数値を指定可能)
        static_assert(SCI5_IO::probe_baud(baud), "Failed baud rate accuracy test");  // 許容誤差(3%)を超える場合、コンパイルエラー
        auto intr = device::ICU::LEVEL::_2;     // 割り込みレベル(NONE を指定すると、ポーリング動作になる)
        if(!sci5_io_.start(baud, intr)) {  // 標準では、8ビット、1ストップビットを自動選択
            halt_();
        }
// 通信プロトコルを設定する場合は、通信プロトコルのタイプを指定する事が出来る。
// sci_io.hpp PROTOCOL enum class のタイプを参照
//      sci_.start(baud, intr, SCI::PROTOCOL::B8_E_1S);
    }
  • これで、入出力が行える準備が整います
  • 後は、標準入出力を使って、データ通信を行います
    {  // SCI の設定レポート表示
        utils::format("SCI5 PCLK: %u [Hz]\n") % SCI5_IO::sci_type::PCLK;
        utils::format("SCI5 Baud rate (set): %u [BPS]\n") % sci5_io_.get_baud_rate();
        float rate = 1.0f - static_cast<float>(sci5_io_.get_baud_rate()) / sci5_io_.get_baud_rate(true);
        rate *= 100.0f;
        utils::format("  Baud rate (real): %u (%3.2f [%%])\n") % sci5_io_.get_baud_rate(true) % rate;
        utils::format("  SEMR_BRME: %s\n") % utils::str::get_bool_text(SCI5_IO::sci_type::SEMR_BRME);
        utils::format("  SEMR_BGDM: %s\n") % utils::str::get_bool_text(SCI5_IO::sci_type::SEMR_BGDM);
    }

独自ポート設定(ORDER::USER)

  • 以下の例は、候補として「USER」を行う場合の方法です
  • SCI5: TXD/PA3, RXD/PC3 を利用する例です
  • この設定は、初期化 (sci5io.start) を行う前に設定する必要があります(初期化時に、設定された関数が呼ばれます)
  • 又、C++ のランタイムをリンクする必要があります(Makefile に supc++ ライブラリを追加してください)
  • 独自設定の場合、特別なレジスター郡へのアクセスがあるので、独自関数が呼ばれる前に、書き込み保護が解除された状態になっています
    typedef device::sci_io<device::SCI5, RXB, TXB, device::port_map_order::USER> SCI5_IO;
        device::port_map::set_user_func( [=](device::peripheral per, bool ena) {
            // SCI5: TXD/PA3, RXD/PC3 の場合
            using namespace device;

            // セレクターのビット列は、MPC の解説を参照して下さい
            uint8_t sel = ena ? 0b0'1010 : 0;
            MPC::PA3PFS.PSEL = sel;
            PORTA::PMR.B3 = ena;
            MPC::PC3PFS.PSEL = sel;
            PORTC::PMR.B3 = ena;

            return true;
        }
        );

Makefile への C++ ランタイムライブラリの追加:

USER_LIBS   =   supc++
  • この例ではラムダ式を使って簡潔に行っています
  • 詳しくは、「std::function ラムダ式」などで検索して、使い方を参照して下さい
  • これらのサンプルは、「SCI_sample/main.cpp」に具体的なコードが示されていますので参考にしてください
  • ポートの機能設定は、ハードウェアーマニュアルの MPC の解説を参照して下さい
  • MPC に、機能を設定するビット列には特別な意味があります、間違えると、正しく動作しません
  • ポートの独自設定は、設定を合格とする為「true」で戻る必要があります

まとめ

  • 今回の更新は、ドキュメントの追加程度ですが、github に色々な情報を集約するのに都合が良いものでした
  • マークダウンの表は、そこそこ見やすいものなので、多少利便性が向上したものと思います
  • 又、ポートマップの仕組み、具体的な独自設定の方法などをさらに詳しく示しました