GR-SAKURA
GR-KURUMI
GR-COTTON
GR-CITRUS
GR-PEACH
GR-KAEDE
GR-ADZUKI
GR-LYCHEE
GR-ROSE
GR-MANGO(*)
SNShield
Web Compiler
IDE for GR
TOPPERS関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
はじめまして。まぐと申します。
現在、ポーリングでデータの受信を待ち、処理をしているのですが
送られてくるデータが高速のため、取りこぼしが発生しています。
そこで割り込みを用いて、1フレーム受信するたびに
データを確認し、選定を行いたいと考えています。
r_ether.c の中にある
void INT_Excep_ETHER_EINT(void) のプログラムを改良すれば
実装できるのではないかと考えているのですが
どのように手をつければよいか、分からなかったため
こちらに投稿させていただきました。
ライブラリのバージョン 2.11 webコンパイラを用いています。
よろしくお願いします。
まぐさん
シェルティと申します、こんにちは。
RXマイコンのフォーラムに住んでいましたが、今回GR-SAKURAのフォーラムも参照させていただきました。投稿から間があいてしまっていて申し訳ないのですが少しウェブコンパイラについても勉強してみましたので、もしよろしければご確認ください。
取りこぼしとのことなのでUDP通信を使われていると思います。UDP受信が発生するとご推察の通り、INT_Excep_ETHER_EINT()が割り込みで呼び出され、TCP/IPライブラリを経由してEthernet.cppのt4_udp_callback()に飛んできます。そのあと、受信データをudp_rcv_dat()で取り出し、R_BYTEQ_Put()でリングバッファに書き込んでいます。
ユーザサイドからは、任意のタイミングでEthernetUDP::read()を使用してリングバッファから受信データを取り出す構造になっています。
従いまして、リングバッファが溢れない限り取りこぼすことはありません。(ハードの受信性能限界を超えて物理的にパケットが大量に受信された場合を除きます)
このリングバッファの容量を増やしてみる案はいかがでしょうか?リングバッファの容量はEthernet.cppの上のほうにあるRING_SIZで1024バイトに設定されています。
以上です
シェルティさん
書き込みありがとうございます。
そのように構築され動作しているのは知りませんでした。
ありがとうございます。
となりますとEthernetUDP.write()を使えば
良きタイミングで送信してくれるということでしょうか?
timer.c のCMT1.CMCORの数値を変更すると
短時間で送信されるようになったので
そのような理解でいいのでしょうか?
現状としましては
INT_Excep_ETHER_EINT()の中を無理やり変更しました。
今のところ問題なく受信できています。
ただ、シェルティさんのおっしゃるとおり
複数のライブラリを経由していますので
他の関数に支障が出ているかもしれません。
下記に変更したソースコードを載せています。
#if 0 /*If ET_LINKSTA is not connected, LINK status is decected by using software polling. */
/* When the link signal change interrupt is generated */
if (status_ecsr & EMAC_LCHNG_INT)
{
/* The state of the link signal is confirmed and Link Up/Down is judged. */
/* When becoming Link up */
if (ETHERC.PSR.BIT.LMON == LINK_PRESENT)
g_ether_LchngFlag = ETHER_FLAG_ON_LINK_ON;
}
/* When Link becomes down */
else
g_ether_LchngFlag = ETHER_FLAG_ON_LINK_OFF;
#endif
//When the Magic Packet detection interrupt is generated
if (status_ecsr & EMAC_MPD_INT)
g_ether_MpdFlag = ETHER_FLAG_ON;
/* Because each bit of the ECSR register is cleared when one is written,*/
/* the value read from the register is written and the bit is cleared.*/
//Clear all ETHERC status BFR, PSRTO, LCHNG, MPD, ICD
ETHERC.ECSR.LONG = status_ecsr;
↓これ以下を変更↓
//EDMAC.EESR.LONG = status_eesr; /* Clear EDMAC status bits */ ←コメントアウト
//lan_inthdr(); ←コメントアウト
/* This is sample code */
#if 1 ←0から1に変更
if (status_eesr & EMAC_RFCOF_INT)
if (status_eesr & EMAC_TC_INT)
if (status_eesr & EMAC_FR_INT)
1フレーム受信ごとに必要なデータかどうか判別し
バッファーに書き込み
if (status_eesr & EMAC_RDE_INT)
if (status_eesr & EMAC_RFOF_INT)
EDMAC.EESR.LONG = status_eesr;
以下省略
もうご存知でしょうが、速さは早いことにこしたことはないのですいが、規格上、UDPは、TCPと異なり、パケット損失許容のプロトコルなので、パケットロスありを前提に、プログラムでは、再送手順も含めて、組まれるのが良いと思います。
シェルティです、こんにちは。
> となりますとEthernetUDP.write()を使えば> 良きタイミングで送信してくれるということでしょうか?
はい、この理解でOKです。
> timer.c のCMT1.CMCORの数値を変更すると> 短時間で送信されるようになったので> そのような理解でいいのでしょうか?
こちらはNGです。タイマーを早くするとTCP/IP全体の挙動が早くなりますので、たとえばTCP再送(1回目2秒、2回目4秒、3回目8秒・・・)の時間間隔がおかしくなります。UDPだけを使う分にはOKです。
このTCP/IPは送信API発行を10ms周期のタイマ割り込みで検出している関係上、送信API発行後実際にパケットが送出されるまでに最大10msの時間がかかります。TCP/IPのAPIを直接操作すれば対処方法はあるのですが、ArduinoのラッパーであるEthernetUDP.write()の階層から操作する場合は対処方法が無さそうです。
本格的に性能面も突き詰めたものづくりをされたい場合は、E1エミュレータを購入してGR-SAKURAでCS+なりe2 studioなり、ルネサス製のツールでデバッグしたほうが良いと思われます。
また、改造いただいたコードの提示ありがとうございます。改造自体には問題はありませんが、この改造ですと、EthernetUDP.read()は無関係ですね。この改造はTCP/IPやUDPは使用せず、Ethernet層だけで通信を行うものです。途中コメントアウトされているlan_inthdr()がTCP/IP層の起動のための関数です。
以下目的が無い場合は、Ethernetに対しTCP/IP(またはUDP/IP)を載せる必要はありません。・ルータを超えてインターネット側の端末と通信したい場合・既存のTCP/IPアプリ(Webブラウザなど)と通信したい場合
UDPに関しての注意事項としては、digipontaさんがおっしゃる通りです。TCP/IPを使わない場合は、通信データが届かないかもしれないことを想定したアプリの組み方が必要です。
digipontaさん、シェルティさん
コメントありがとうございます。
非常に参考になります。
コメントいただいた点を踏まえてプログラムを組みたいと思います。
不明な点が見つかりましたら、またこちらに書き込みたいと思います。
ありがとうございました。