こんにちは、ルネサスマイコン(RXマイコン中心ですが)でTCP/IP関連をいろいろ実験しておりますシェルティと申します。
TCP/IPですが、複雑怪奇な仕様であり、スクラッチ開発となると相当な難易度ですね。
実験/研究レベルならスクラッチ開発もありかもしれませんが、量産製品に適用となると、
第一にネットワーク関連ソフトを組み込みマイコン向けに製品化しているソフトウェアハウス製のものがおすすめです。
例えば、図研エルミック殿やデータテクノロジー殿、ユビキタス殿などの組み込み用TCP/IPが有名です。
ルネサス製でも組み込み用TCP/IP M3S-T4-Tinyというのが有償製品として提供されています。(SH2A用の無償ダウンロードもあるようです)
http://japan.renesas.com/mw/t4
第二に組み込み用OSに内包されているTCP/IP機能を使うのも良いです。
(ここでいう組み込み用OSはリアルタイムOSではなく、組み込み用Linuxを指します)
第三にuIPやlwIP等のオープンソース系のコードを頑張って量産製品に適用する道です。
第四にスクラッチ開発でTCP/IPを手作りする道です。
第三・第四の道は技術力に自信が有る場合におすすめですね。
安く仕上げられるというメリットも捨てがたいと思います。
-------
さて、uIPで大きいデータ転送に弱い件ですが、uIPのTCP処理の実装に問題があります。
lwIPでも私が調査した限り同様の問題を含んでいます。
組み込み用TCP/IP M3S-T4-TinyもRXマイコン用パッケージにて、最近ソースコードが公開されたので中の実装を確認したところ、
uIPやlwIPよりはマシですが、もう一段の改善が必要といったところです。
各TCP/IPを比較すると以下の通りです。
uIP or lwIP : TCPの送信アルゴリズムが貧弱。データ送信1回につき1個のACKが戻ってくることを期待している。
多くの一般的なTCP/IPはTCPデータ受信時は2個データを受信する or 1個データ受信し200ms経過後タイムアウトしACKを返す実装になっている。
その結果、毎回タイムアウトが発生し1秒に5回のデータ転送しか実現出来ない。
組み込み用TCP/IP M3S-T4-Tiny : TCPの送信アルゴリズムが少し貧弱。データ送信は2個セットでACKが戻ってくることを期待している。
その結果ACKがすぐ戻ってくるネットワーク環境(LAN)においては転送速度に問題は発生しないが、
ACKがすぐに戻ってこないネットワーク環境(WAN)においては転送速度がACKが返ってくる時間に律速する。
ACKが返ってくるまで200msかかる(東京-北米西海岸等)通信をする場合は、uIP or lwIPと変わらない程度の通信速度に落ちる。
※ローカル環境ではSH7216@200MHz で、TCP送受信が60Mbps程度出せることを確認しました。(RX62N@100MHz では30Mbps程度確認)
-----
これは組み込み用TCP/IPが多くの場合、RAM容量に制限の多いマイコンでの動作を期待しているため、
送信用/受信用のバッファを多く持たないことに起因します。
TCPの規格上、お互いに受信用のバッファサイズ(受信ウィンドウと呼ばれます)を常にTCPヘッダの特定16bitエリア(0xffff=最大64KB)に載せて
通知し合っているわけですが、上述したTCP/IPたちはここにTCPパケット1個分(=1460バイト)の容量を設定しているのです。
#組み込み用TCP/IP M3S-T4-Tinyではここが可変になっていて柔軟にチューニングが効くようにはなっています。
その上、送信アルゴリズムも上述した通り貧弱ですのでいずれにしても大きなデータ通信には向きません。
長くなりました。
結論ですが、量産製品にTCP/IP機能を付ける目的であれば、有償のTCP/IP製品をお求めになるのが良いかと思います。
とにかくまず実験して感触を掴んでみたい/通信速度が気になる/LANでしか通信しない、ということであれば、
SH2A用の組み込み用TCP/IP M3S-T4-Tinyを使って実験されるのが良いかと思います。
ただ、ソフトは無償ダウンロードがありますが、SH7216の評価ボードとE10Aエミュレータが必要となり、ちょっと実験してみるのには敷居が高そうですね。
(TCP/IP処理部分はSH7670でも動作するでしょうけれど、サンプル全体がSH7216用に作られているため、
Etherドライバ付近とボード周りの設定プログラム、スタートアップ等を調整してあげる必要はありそうです)
もちろん、せっかくuIPをSH7670に移植されたのですから、大きなデータ通信については目をつむり、そのまま使用し続ける案も十分に有りと思います。
以上です。
すみません、少し書き漏れました。
一般的なTCP送信アルゴリズムは、「通信相手の受信ウィンドウサイズに空きがあればACKが返ってこなくてもお構いなしに送信する」です。
このように実装するためには、通信相手の受信ウィンドウサイズの最大値(0xffff=64KB)の容量の送信バッファが必要です。
しかも、通信相手が複数同時に居る場合は通信相手の数分だけ64KBの送信バッファが要ります。もちろん受信ウィンドウも要ります。
従って、多くの(オープンソース系)組み込み用TCP/IPは多くのマイコンで動作させることを優先し、
バッファサイズを制限し通信速度を犠牲にしたのだと思います。
組み込みソフトを専業でやっているソフトウェアハウスのTCP/IPの場合、この辺りが柔軟に設定できるものがあると聞きますので
本格的に量産製品を作られる場合は一度ソフトウェアハウスに相談してみるのが良いかと思います。
シェルティ さん
回答ありがとうございます、
なにか、今一番必要なことを教えられた気分です、なるほど
要約すると、組み込み用の多くのTCP/IP機能は組み込み用に特化するため
大容量、高速通信を犠牲にして作成されているということでしょうか
できればUIPでも動作している環境ですので、なにか設定を変更するなどすれば
高速になることも期待したりもしたのですが、基本的なところの設計が違うということなのでしょうか、
このプロジェクトはまだ量産の段階ではありませんので
その段階になりましたら、さしせまってきたらソフトウェアハウスに相談してみたいと思います。
その前に
が結構早い?
組み込み用TCP/IP M3S-T4-Tinyというのが有償製品として提供されています。(SH2A用の無償ダウンロードもあるようです)
これ今日ダウンロードしましてインストールさせていただきました。(SH2A用の無償ダウンロードもあるようです)
これからはこれを使用することに切り替えたいと思います。
シェルティ さん有益な情報ありがとうございました。
IKUZOさん
私の情報が少しでも役に立てたようで嬉しいです
私は組み込み用TCP/IP M3S-T4-Tinyに関してはそこそこ詳しくなってきましたので、
通信速度性能測定などで思ったように性能が出ない、等ありましたらご連絡ください。
アドバイスできることがあるかもしれません。
#IKUZOさんがSH7670に移植されたuIPもとても良いと思います。設定で通信速度改善出来ないかuIPのコードを見てみます。何か分かったら連絡します。
ほんとうに心強い思いです、自分一人で悩んでいたところで、かふぇルネから助けられた思いです
「TCP/IPですが、複雑怪奇な仕様であり」とありましたが、この言葉にはなぐさめられました、苦労してきましたから
シェルティ さん、これからもよろしくお願いします。
シェルティ さんお世話になります
an_r20an0050jj_sh2a_t4_v106r00\sample のフォルダ
Ether.hws でコンパイルすると下記エラー発生なのですが
何かdefine する必要がありますか?
Phase: SH C/C++ Compiler, File: SH C/C++ Compiler, dependency scan error
C:\Dev\BASE\T4\sh2a\an_r20an0050jj_sh2a_t4_v106r00\sample\src\t4\lib\r_t4_itcpip.h(75) : DC201 (E) A header file does not exist 'stdint.h'
C:\Dev\BASE\T4\sh2a\an_r20an0050jj_sh2a_t4_v106r00\sample\src\t4\lib\r_stdint.h(25) : DC201 (E) A header file does not exist 'stdint.h'
申し訳ありません
エラーのようなものは出ることには出ますが
ビルドはできました、H8S等もやってみましたが
正常に出来ました、
これから導入いたします。
エラーの出ているヘッダファイルの中に include 'stdint.h' と書いてありませんか。
その 'stdint.h' が見つからないと言うエラーだと思う。
IKUZOさん、リカルドさん
こんにちは、シェルティです。
エラーについて少し調べてみました。
エラーはDependencyのチェックのエラーで、コンパイルのエラーではないですね。
Cコンパイラのプリプロセッサが動く前に#includeで指定されているファイルの有無をチェックしており、
#ifdef で括られた部分のヘッダファイル「stdint.h」が無いというエラーが出力されていました。
以下のコードの「★ここでDependencyエラー検出」というところでエラーが出てますね。
#if defined(__RX)#include "stdint.h" // ★ここでDependencyエラー検出#else#include "r_stdint.h"#endif
T4ライブラリはルネサスマイコン全般で使えるようにしてあるようで、
ヘッダファイル(r_t4_itcpip.h)では種々マイコンのプリデファインマクロとITRONの使用有無のマクロで
標準型定義が切り分けられているようです。
__RXはRXコンパイラがコンパイル時に自動的に定義してくれるマクロ名ですね。
以上です
リカルドさんシェルティ さん
__RX #define があれば#include "stdint.h"を探しに行くというような内容で
sh2a用で使用するので__RXはないはずですが、コンパイラ(プリプロセッサ)が
一応はチェックするようで
Dependencyエラー検出なのでしょう
#if defined(__RX)
//#include "stdint.h" // ★ここでDependencyエラー検出
#else
#include "r_stdint.h"
#endif
こうしてやればエラーは一応でません
他の箇所も同様にしました
内容を精査したところどうも7216用なので
7670のドライバがレジスタ構成も異なり
それを調整するのに手間取りそうです
typedefの定義も特徴的なものに変更いたしました
まだまだこれからです
SH2A用のT4ライブラリに付属しているサンプルはIKUZOさんが仰るとおりSH7216用ですね。
私はT4ライブラリに付属しているSH7216のEtherドライバのコードをSH7670に移植しその上でT4ライブラリを動作確認したことがあります。
このときのEtherドライバのソースコードの差分を調べたので参考にしてください。
思ったより差分はなく、iodefine.hのレジスタアクセス方法の違いを合わせて変更してあげるだけで移植が出来ております。
(この掲示板、表を書けるみたいなので使ってみます。変になったらすみません)
シェルティ さん ありがとうございます
ソースコードの差分どうりです、ほとんどのところはLONGを消すことでコンパイラはOKでした
ただベクタ関連でしょうか違うところが
SH7216
// INTC.IPR19.BIT._EDMAC = EINT0_INT_LV; //EINT0 priority level コンパイラNG
SH7670
INTC.IPR12.BIT._ETC=EINT0_INT_LV;//EINT0 priority levelこれが替わりに?
// 153 E-DMAC EINT0
void INT_EDMAC_EINT0(void){
lan_recv_handler();
}
// 171 ETC EINT0
void INT_ETC_EINT0(void)
{
unsigned long stat_edmac;
unsigned long stat_EtherC;
パソコンからpingコールして割り込みが入るかテストしたのですが
SH7670サンプルコードの組み合わせphy,etherでは割り込みが入るのですが
SH7216サンプルコードの組み合わせphy,ethでは不能?なので(たぶん?もう一度やってみても良いが)
少し考えました
t4_driver.cのところの
lan_readをSH7670サンプルコードのlan_recvに渡し
lan_writeをSH7670サンプルコードのlan_sendに渡したらと思いましたが
t4ライブラリが完全にphy,eth層と別であればうまくいくと思ったのですが
SH7670サンプルコードの組み合わせphy,etherと
SH7216サンプルコードの組み合わせphy,ethでは基本的な構造上の違いがあるのでしょうか?
コンパイルが通ったとのことで良かったです。
あとはご指摘通り割り込み周りの差分ですね。
(一度に案内できず、すみません)
SH7216もSH7670もEther関連は基本構造は同じですね。
ご推察の通り t4_driver.c にはEtherドライバからの割り込みを受け付ける lan_recv_handler()が有ります。
また、T4ライブラリからのR/Wや初期化を受け付けるlan_read()、lan_write()、tcpudp_act_cyc()等の
T4ライブラリのユーザ定義関数があります。
t4_driver.c はT4ライブラリとEtherドライバの橋渡し的な存在ですね。
まず割り込みコントローラの設定でレジスタ定義が異なるので以下のように変更します。(左側:SH7216、右側SH7670)
これはIKUZOさんが試された通り、SH7670の場合、INTC.IPR12.BIT._ETCを使用するように変更です。
次にlan_recv_handler()です。(左側:SH7216、右側SH7670)
これはコードが整理できていなくて差分が出ているだけです。続くlan_recv_handler()の呼び出し元の
intprg.c の差分と合わせてご参照ください。
大事なのは、EDMACのEESRレジスタをクリアしてあげることです。そうしないと次の割り込みが入りません。
(このレジスタは少し変わっていて、'1' を書いたらクリアされるタイプです)
次にintprg.c の差分です。(上画像の左側がSH7216のEther割り込みの入口、下画像の右側がSH7670のEther割り込みの入口)
こちらもサンプルコード切り貼りなので整理出来てなくてすみません。
実行していることは、SH7216もSH7670も同じで、「割り込み受付→割り込みフラグクリア→_process_tcpip()呼び出し」のセットです。
SH7216サンプルコードの組み合わせphy,ethを用いた差分他設定ありがとうございます
こちらでも同時にSH7670サンプルコードの組み合わせphy,etherをt4_driver.c に組み込んでテストしました
t4ライブラリが完全にphy,eth層と別であるということマニュアルに記されていまして
どんなドライバでも接続可能ということでしたので
マニュアルのとうりに設定をしているうちに
C:\Dev\BASE\T4\sh2a\test2\test2>ping 192.168.0.3
192.168.0.3 に ping を送信しています 32 バイトのデータ:
192.168.0.3 からの応答: バイト数 =32 時間 =1ms TTL=80
192.168.0.3 からの応答: バイト数 =32 時間 <1ms TTL=80
192.168.0.3 の ping 統計:
パケット数: 送信 = 4、受信 = 4、損失 = 0 (0% の損失)、
ラウンド トリップの概算時間 (ミリ秒):
最小 = 0ms、最大 = 1ms、平均 = 0ms
C:\Dev\BASE\T4\sh2a\test2\test2>
PINGが通りました、これができたということで、一応成功ということで
ひとつ
SH7216サンプルコードの組み合わせphy,ethと比較して
どちらが良いと思われますか?
おお、pingが通りましたね。おめでとうございます。
SH7670とSH7216のphy, ehterのサンプルコードですが、SH7216のものをおススメします。
改めて以下2点のアプリケーションノートのコードを開いて確認してみました。
気になったのでついでに色々調べてルネサスマイコンのEtherドライバの系譜をまとめてみました。
SH7216グループ アプリケーションノート Ethernetを使用したユーザプログラムモードフラッシュ書き換え動作例R01AN0289JJ0211
SH7670グループ イーサネット送信設定例R01AN0302JJ0101
SH7670のether.c は、送信用のコードと受信用のコードが分かれていて、割り込み関数も中身が空っぽで、
TCP/IPと結合するのに苦労すると思います。<Etherドライバ世代1>
SH7216のeth.c は上記問題がなく一通り実装されていてTCP/IPとインタフェースを合わせれば使えそう、という印象です。
SH2A用のT4のサンプルもこれをほとんど流用していますね。
それから、SH7216のeth.c はRX62Nの従来のEtherドライバのコードと同一ですね。<Etherドライバ世代2>
次に最新のRX62N/RX63N用のEtherドライバは現在T4のサンプルに取り込まれているようで、以下アプリケーションノートに含まれています。
RXファミリ 組み込み用TCP/IP M3S-T4-Tinyを用いたサンプルプログラムFirmware Integration TechnologyR20AN0312JJ0100
→\an_r20an0312jj0100_rx_t4_connectivity\workspace\reference\rx62n_rx63n_ether_driver
こちらは、LANケーブル活線挿抜に対応したり、Etherドライバ内でのデータコピーを省いたりかなり進歩した、という印象です。<Etherドライバ世代3>
さらにさらに、最近はソフトウェアのモジュール化が進んできたのか、
RXマイコンで「FIT(Firmware Integration Technology)」というのが出てきており、
その一環でRX用のEtherドライバがモジュール化されていました。(まだRX64Mしか対応していませんが)
RXファミリ イーサネットモジュール Firmware Integration TechnologyR01AN2009JJ0100
これが現在のルネサスのEtherドライバの最終形のようです。<Etherドライバ世代4>
以下、FITの説明を読むと、BSP(Board Support Package)上に積み木のようにFITモジュールを組み立てていく感じですね。
http://japan.renesas.com/products/mpumcu/rx/child/fit.jsp
これまでアプリケーションノートのコードをくっつけるのが面倒だったのが解消されますね。
横道に逸れてしまいました。
ひとまずSH7216のEtherドライバをおススメしましたが、
もし余力があるのであれば、<Etherドライバ世代4>のEtherドライバをSH7216 or SH7670に再移植すると
転送レート/CPU負荷率共にグっと向上すると思います。
iodefine.h の交換と target フォルダの中身をSH7216 or SH7670用に作ってあげると良いかと思います。
ちなみに、<Etherドライバ世代2>のデータコピー関数(_eth_fifoRead()と_eth_fifoWrite())は
最下層で1バイトずつforループでデータコピーするかなり残念な仕様ですね。
長文失礼しました
シェルティです、すみません訂正です。
<Etherドライバ世代4>はRXマイコン用のBSPが前提のコードが有り
これをSH7216 or SH7670に移植するのは少し骨が折れそうです。
<Etherドライバ世代3>であればiodefine.h の差分だけ何とかしてあげれば
RXマイコン用→SH7216 or SH7670用に移植が出来そうな印象を受けました。
シェルティ さん、なるほどこれから苦労しそうということですね
一応変更したところですが、自己流に改造してしまったというところですが
///////////////////////////////////////////////////////////////////////
//etherから呼び出す
t4_H lan_read( t4_B **buf )
t4_H return_code;
return_code=(t4_H)lan_recv(lan_buf); //etherからデータを受信する
if(return_code > 0){
//有効なデータを読み込んだ
*buf = (t4_B*)lan_buf;
t4_stat.t4_rec_cnt++;
t4_stat.t4_rec_byte+=return_code;
}else{//有効なデータは受信しなかった
return_code = -1;
return return_code;
//etherから呼び出す end
t4_H lan_write( t4_B *header , t4_H header_len, t4_B *data , t4_H data_len)
if (header_len+data_len > 1514 || header_len+data_len <= 0){
return -5; // Return code "-5" notifies "data transmission fail" to T4.
memcpy(lan_buf, header, header_len);
memcpy(lan_buf + header_len, data, data_len);
//etherにデータを送信する
return_code=(t4_H)lan_send(lan_buf,header_len+data_len);
if (return_code < 0){
return -5;//登録失敗
}else{
//登録成功
t4_stat.t4_snd_cnt++;
t4_stat.t4_snd_byte += (header_len + data_len);
//tcp_apiから呼び出す
//TCP/IP処理関数の周期起動の制御
//パラメータcycactにしたがって、TCP/IP処理関数_process_tcpipの周期起動を制御します。
//関数_process_tcpipの周期起動間隔は、10msec以下に設定します。
//プロトコル処理部で使用します。
void tcpudp_act_cyc(unsigned char cycact)
switch(cycact){
case 0: //TCP/IP処理関数の周期起動を停止
tcpip_flag=0;
break;
case 1: //CP/IP処理関数の周期起動を開始
tcpip_flag=1;
default:
tcpip_flag = 0;
//T4処理(CPUの10mS割り込みで処理)
//T4ライブラリのTCP/IP部の処理を行います。
//本APIからドライバ層へのリードライト関数など、種々ドライバ関数が呼び出されます。
//本APIの処理時間は通信状態やドライバ層の実装方法によって変化します。
//本APIのスタックはドライバ層の実装方法によって変化します。
//本APIはtypeに”1”を指定し、任意の間隔(10msec推奨)で定期的に起動してください。
//(タイマ割り込みなどを使用)
extern BOOL ether_enable;
//WDTの10mS割り込みから
void t4_interval(void)
tcpudp_time_cnt++;
if(ether_enable && tcpip_flag)_process_tcpip(1);
//EtherCの割り込みから
void t4_interval_(void)
//T4処理(CPUの10mS割り込みで処理) end
というぐあいで、こんなことになりました、TCPのノンブロッキングサンプルから
最初にtelnetサーバーでもやってみようかと思います
シェルティです、こんにちは。
コード拝見しました。TCP/IPとEtherドライバが無駄なく結合出来ていると思います。
これから、アプリを載せていって通信速度やCPU負荷状況が気になってきた場合に、
Etherドライバに改善の余地有り、と思い返していただけると良いかなと思います。
アプリ変更せずにEtherドライバとt4_driver.c の改定のみで改善できると思います。
あと、T4用のアプリですが以下が参考になるかもしれません。
ワークスペースとしてはRXマイコン用ですがT4のAPIはSH2Aと共通なので
アプリ部分(DHCP/DNS/FTP/HTTPのコード)の移植は容易と思います。
RXファミリ 組み込み用TCP/IP M3S-T4-Tinyを使った応用例(DHCP/DNS/FTP/HTTP) Firmware Integration TechnologyR20AN0314JJ0100
RXマイコンをWebサーバにして、ブラウザからRXマイコンボード上のLEDをコントロール出来るサンプルになってました。
Webサーバのコンテンツを内蔵ROMに配置するタイプとSDカードかUSBメモリに配置するタイプが用意されています。
シェルティさん回答ありがとうございます
2014/9/11 2:21の投稿では画像を添付されてますが、どのようにしたらできますか?
ご存知であれば、教えていただけませんか?
RXファミリ 組み込み用TCP/IP M3S-T4-Tinyを使った応用例(DHCP/DNS/FTP/HTTP) Firmware Integration Technologyですがダウンロードしてftpサーバのサンプルところを取り出して
例のT4のドライバーに接続しまして、ftpからの接続とユザー名、パスワードまでは正常に行くのですが
ls-lのコマンドで固まります、もうすこしがんばってみます。
シェルティさん
ftpで転送ができるようになりました、FFFTPでの表示では400KByte秒は行くようです、
これからt4ライブラリを主に使用したいと思います、
uIPに比べて格段に速度が速いです、いろいろ教えていただきありがとうございました。