ポート・マップ候補機能
- 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 を使いたい場合
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 に色々な情報を集約するのに都合が良いものでした
- マークダウンの表は、そこそこ見やすいものなので、多少利便性が向上したものと思います
- 又、ポートマップの仕組み、具体的な独自設定の方法などをさらに詳しく示しました