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関連
女子美コラボ
その他
※プロデューサミーティング中
作り方使い方資料
イベント関連
作品記事
体験記事
ライブラリ
ツール
その他・過去ファイル
がじぇるね岡宮です。
画像処理をするImageライブラリを評価バージョンE1.10として公開させていただきました。
大変すみませんが、プロデューサーの皆様から多く意見を反映したいため、スケッチリファレンスはまだ作成していません。(若干言い訳がましいですね・・・)。デフォルトのサンプルコードから、ある程度読み取っていただければありがたいです。サンプルでは動体検知しかしていませんが、人物検知用のライブラリは実装しています。
ちなみに、動体検知は写真3枚、人物検知は1枚で行います。
パラメータ(感度とか)の調整はまだ入れてません。ドライバとしては入ってますので、既存ライブラリの実装を参考にお試しいただければと思います。既に純正CCRXでのWebカメラサンプルでは感度調整など簡単にお試しできますが、普通の生活空間では結局デフォルトがちょうどいいと感じがしたので、日程を優先してE1.10を公開しました。
まだ動くことだけしか確認できていませんが、ファイルのタイムスタンプが2063年なのは何故だろうと思ってました。
FATのタイムスタンプの年が7bitで1980年スタートなので、
15 - 1980 = 0xf8530x53(83) + 1980 = 2063
となっている模様です。
なので、スケッチのdateTime()は以下とする必要がありますね。
*date = FAT_DATE((t.year+2000), t.mon, t.day);
※RTCの年カウンタは16bitなのに8bitしか使えないなんて。
RTCライブラリですが、GR-SAKURA スケッチV2.02も同様の仕様となっておりだいぶ混乱しました。
年データのコンバートには、HEX2BCD()と BCD2HEX() は16ビットへの拡張をされたらいかがでしょう。
Akagawaさん、ご確認ありがとうございます!まずは一個つぶせてよかったです。
SAKURAの方と現象が似てますね。
んんん。何故か、上記に掲載しているサンプルソースは、SD関係をコメントアウトして、Ether/utility/driver/r_ether.c を修正しても、DHCP失敗で、動かないみたいです、これは、私のNW環境のせいかどうか、未確認。ただし、IPアドレス指定すると、接続ができました。
一応、HTTPプロトコルが不完全だったので、そこも修正して、サンプルソースコードを、下に再掲載します。とりあえず、IEから、ピントが合っているかどうかぐらいは、分るようになったのですが、Server.write( adr, size )が途中で戻ってきて、下画像のように、データ転送が途中で切れてしまうようです。なお、同じバイト数で戻ってくる訳ではないようです。一難去ってまた一難ですが、この症状の解消は、何かヒントはありますか?
あと、SDのコメントアウトを外すと、前の投稿と同じ、SD.begin(SS)で、SDメモリが挿さってるけど、入ってないとかエラー出ました。
【サンプルプログラム】 IEからは、http://192.168.1.250/ でアクセス
#define __ETHER__ // #define __SD__ #include <Arduino.h> #include "Image.h" #ifdef __SD__ #include "SD.h" #endif // __SD__ #include "RTC.h" #ifdef __ETHER__ #include <Ethernet.h> byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 }; byte myIp[] = { // IPアドレスを固定で指定しました 192,168,1,250 }; EthernetServer Server(80); #endif // __ETHER__ Image image[3]; RTC_TIMETYPE t; void dateTime(uint16_t* date, uint16_t* time); void setup(){ pinMode( PIN_LED0, OUTPUT ); digitalWrite( PIN_LED0, 1 ); // ON Serial.begin(9600); while(!Serial.available()); // wait to press key Serial.read(); //dummy Serial.println("start"); #ifdef __ETHER__ #if 0 if (Ethernet.begin(mac) == 0) { Serial.println("DHCP fail"); while(1); } #else Ethernet.begin(mac, myIp ); #endif Server.begin(); Serial.print("server is at "); Serial.println(Ethernet.localIP()); #endif // __ETHER__ #ifdef __SD__ pinMode(SS, OUTPUT); if(!SD.begin(SS)){ Serial.println("Card failed, or not present."); } else { Serial.println("Success to access SD."); } #endif // __SD__ rtc_init(); t.year = 15; t.mon = 9; t.day = 2; t.weekday = RTC_WEEK_WEDNESDAY; t.hour = 17; t.min = 0; t.second = 0; rtc_set_time(&t); for(int i = 0; i < 2; i++){ image[i].begin(); } #ifdef __SD__ SdFile::dateTimeCallback( &dateTime ); #endif // __SD__ } void loop(){ static int cnt = 0; #ifdef __ETHER__ EthernetClient client = Server.available(); if (!client.connected()) { return; } while (client.available()) { char c = client.read(); } #endif // __ETHER__ digitalWrite( PIN_LED0, 0 ); // OFF for(int i = 0; i < 3; i++){ Serial.print("Capturing image"); Serial.println(); image[i].captureStart(); while(!image[i].isCaptureFinished()); image[i].createGrayImage(); } digitalWrite( PIN_LED0, 1 ); // ON if( 0 == image[2].movingDetection(image[0].getCreatedGrayImage(), image[1].getCreatedGrayImage())){ Serial.println("finish detection"); Serial.print("Moving Number is:"); Serial.println(image[2].getMovingNumber()); Serial.print("The biggest moving is in area:"); Serial.println(image[2].getMovingArea(0)); } image[2].createJpg(); Serial.println("Write jpg to SD:"); char fn[50]; cnt++; sprintf (fn, "test%d.jpg", cnt); #ifdef __SD__ File file = SD.open(fn, FILE_WRITE); #endif // __SD__ uint8_t* adr = image[2].getCreatedJpg(); int32_t size = image[2].getCreatedJpgSize(); #ifdef __ETHER__ Server.print( "HTTP/1.1 200 OK\r\n" ); Server.print( "Content-Type: image/jpeg\r\n" ); Server.print( "\r\n" ); #endif // __ETHER__ #ifdef __ETHER__ Serial.println( size ); Serial.println( Server.write( adr, size ) ); // 途中で戻ってきてしまう(^_^;) #endif // __ETHER__ #ifdef __SD__ for (int i = 0; i < size; i++){ file.write(*adr); adr++; } file.close(); #endif // __SD__ delay(1); #ifdef __ETHER__ client.stop(); #endif // __ETHER__ Serial.println("Done."); } void dateTime(uint16_t* date, uint16_t* time) { rtc_get_time(&t); #ifdef __SD__ *date = FAT_DATE(t.year, t.mon, t.day); *time = FAT_TIME(t.hour, t.min, t.second); #endif // __SD__ }
さらに、下記の修正かけて、残りを送ろとすると、戻ってこないようです。
#if 0 Serial.println( Server.write( adr, size ) ); #else for( i=0; i<size;) { len = Server.write( &(adr[i]), (size - i) ); Serial.println( len ); if (len <= 0) { Serial.println("zero len"); break; } i += len; } #endif
-------
【補足】
httpでJPEGバイナリデータを応答する場合、簡易的には、下記の3行を送った後に続けて、JPEGバイナリデータを送れば済みます。この3行の最後は、空行です。行端コードは、LF+CR ("\r\n")。こうしとくと、htmlファイル側で、<img src= でも表示ができます。
Server.print( "HTTP/1.1 200 OK\r\n" ); Server.print( "Content-Type: image/jpeg\r\n" ); Server.print( "\r\n" );
あれ。確かにDHCP動かない。昨日は動いたと思ったんですが、なんだったんだろう...。中途半端な情報でスミマセン。
解析が遅れており申し訳ありません。今日は開発者もきちんと時間を割けませんでした。私ももう少し調べます。
時間がかかり申し訳ありません。
GR-SAKURA側でのSDのmalloc干渉に加えて、スタックの配置に問題がありました。
まだ、Ether動作は確認できていませんが、SDに関してはlinker_arduino.gsiのスタック以降の記載を以下にすると快適に動作しました。
実はGR-SAKURAはistackが0x20000でも評価上問題なかったのですが、なにやらここにはメモリが存在するようでたまたま動作していたようです。気持ち悪いのでGR-SAKURA側のスタック設定も変えようと思っています。
.istack 0x7FFFC : AT (0x7FFFC)
{
_istack = .;
} > RAM
.ustack 0x7FEFC : AT (0x7FEFC)
_ustack = .;
.data 0x21000 : AT (_mdata)
_data = .;
*(.data)
*(.data.*)
*(D)
*(D_1)
*(D_2)
_edata = .;
._RX_DESC :
. = ALIGN(32);
._TX_DESC :
._ETHERNET_BUFFERS :
*(._ETHERNET_BUFFERS)
.gcc_exc :
*(.gcc_exc)
.bss :
_bss = .;
*(.bss)
*(.bss.**)
*(COMMON)
*(B)
*(B_1)
*(B_2)
_ebss = .;
_end = .;
あ、記載忘れましたがEtherのデスクリプタやバッファのattribute指定はaligned(0x20)指定ではなくセクション指定に戻すようにします。
> 実はGR-SAKURAはistackが0x20000でも評価上問題なかったのですが、なにやらここにはメモリが存在するようでたまたま動作していたようです。
スタック領域にデータを積む PUSH 命令の動作が
tmp = src; SP = SP - 4; *SP = tmp;
となっており(サブルーチン呼び出しの JSR や割り込みでのスタック操作も同様)、スタックポインタの初期値は RAM 領域の最後(0001FFFF) +1 で問題ないのでは?
KAEDE についても、
.istack 0x7FFFC : AT (0x7FFFC) .ustack 0x7FEFC : AT (0x7FEFC)
-4 する必要はないと思います。
なるほど。
SDライブラリに関しては、istackを0x80000を0x7FFFCにすると回避できるんですよね。。
現在の KAEDE のリンカスクリプトでは
.istack 0x20000 : AT (0x20000)
となってるので不具合が出て当たり前なのですが、これを 0x80000 にしても不具合、0x7FFFC にすると回避ということであれば、スタック以外の何者かが 0x7fffc~0x7ffff を使ってる可能性が考えられるので、デバッガのアクセスブレークかなんかを使って突き止めた方が良い気がしますね。
現時点、GR-KAEDEで動作確認するのは、attributeを元に戻して、istackとusatackの値を変えて、動かしてみれば良いのでしょうか?
Fujitaさん、アドバイスありがとうございます。アクセスブレークで遊んでいる内に0x80000のスタック問題が発生しなくなってしまいました。どうやらスタック自身の問題ではなく、他にあるようです。早とちりですみません。
プロデューサミーティングまで時間がないため、まずは私の方で動作確認が取れたものをE1.11として本日Webコンパイラにアップしたいと思います。
> アクセスブレークで遊んでいる内に0x80000のスタック問題が発生しなくなってしまいました。
「なんか直った」ということであれば、「なんかまたおかしくなった」ということもあり得るので、原因が特定できるまではとりあえず 0x7fffc にしといた方が無難ですね。
Fujitaさん、情けない限りですみません。セクション順やistack/ustackの変更と、ビルド・デバッグ・ブレーク設定の繰り返しで元に戻したつもりが再現せずになってしまいました。ただ、その一方でEtherサーバーは動かず紛糾していたのですが、Etherデスクリプタの容量を2倍にしたらサーバーも動くようになり、SDも、カメラも問題なく動くようになったので、E1.11では0x80000にさせていただきました。同じような問題が起きたとき、ここを起点に調べるようにいたします。ご協力ありがとうございました。
なおデスクリプタ2倍化で動くようになった要因については開発陣に聞くようにしました。
> 現時点、GR-KAEDEで動作確認するのは、attributeを元に戻して、
> istackとusatackの値を変えて、動かしてみれば良いのでしょうか?
上記が、正い修正か不明ですが、これやったら、ブラウザから接続できなくなりました。
Ether内部処理自身で、メモリが汚されているような気もします。
digipontaさん、先ほどE1.11をアップしましたので、お手数ですがお試しいただけますでしょうか?
試しましたが、イーサネット周りは、状況は変わらないようです。GR-KAEDE側で送信が途中で戻ってきます。残りを送ろうとすると、戻ってこないです。ブラウザーを止めると、GR-KAEDE側は、エラーで返ってきて終わります。TCPセッションは、正常ですが、データ送信が途中でハングという状況です。
すみません、KAEDEを持ち帰り忘れまして確認できないのですが、SDのコメント外した場合、SD周りは動きますか?
今、動作確認したところ、Card failed, or not present.とでて、同じ症状のままでした。メモリ\利用の競合でしょうか?
ぱらぱら、ソース眺めていて、今回の問題とは関係ないかもしれないけど、Arduino系のヘッダファイルには「typedef unsigned int word;」とか、気持ち悪さがありますね(;^ω^) wordといえば16bitと思うんですけど。wordは使わないのが吉らしい。
そうですね。私の場合V850で育ったのでwordは32bitのイメージでした。今回のJPEGエンコードエンジンのアセンブルでも.wordはGNURXでは32bit、CCRXでは16bit扱いで若干嵌ったりしました。
私は、8bit世代なので、byte(8bit),word(16bit)ですね。マイクロソトも、歴史が古いんで、これと同じですね。
もう、大まかに実行トレースしてると思いますが、イーサとSDの両方を有効にすると、
gr_sketch.cpp → SD.begin(SS) → ... → Sd2Card.cpp → uint8_t Sd2Card::readData(uint32_t block, uint16_t offset, uint16_t count, uint8_t* dst) → uint8_t Sd2Card::waitStartBlock(void) → status_ = spiRec() → SD_CARD_ERROR_READ
上までみると、spiRec()の呼び出しでエラーになっているようで、深いところで、何か競合しているようです。
------- spiRecの呼び出しからのトレース -------Sd2Card.cpp→ status_ = spiRec()→ static uint8_t spiRec(void) {→ return SPI.transfer(0xFF); // here used→ SPI.h→ inline static uint8_t transfer(uint8_t data) ← この定義がありました(ミスリード訂正)
inline static uint8_t transfer(uint8_t data)が、ゼロを返しているようです。ここからは、MPUのレジスタをアクセスするステップが増えます。イーサと、何かハードリソースが、競合してるんでしょうか?
-------ただ、上記の問題が、SDを無効にして、イーサネットだけ有効にした時の不具合の原因と同じかどうかはわからなくなってきたので、念のための確認ですが、イーサネットのサーバの応答ですが、一度に送信できるデータサイズに、インプリ上の制限があったりしますか?ご参考
時間切れで検証まで出来てないんですが、リンカスクリプトで
._RX_DESC :{ . = ALIGN(32);} > RAM._TX_DESC :{ . = ALIGN(32);} > RAM
とありますが、これは32バイト分の領域を確保したいという意図でしょうか?であれば、これだと開始アドレスによってまちまちのサイズとなってしまうので(map参照)、
._RX_DESC :{ . += 32;} > RAM._TX_DESC :{ . += 32;} > RAM
とすべきなのではないでしょうか?(32bitアラインメントが必要かどうかがわかりませんが...)
セクションのアライメントが 32 の倍数というだけで、領域は
gr_common/lib/Ethernet/utility/driver/r_ether.c:
static descriptor_s rx_descriptors[EMAC_NUM_RX_DESCRIPTORS*2] __attribute__ ((section("._RX_DESC"))); //TODO static descriptor_s tx_descriptors[EMAC_NUM_TX_DESCRIPTORS*2] __attribute__ ((section("._TX_DESC"))); //TODO
で確保してるので、そこは大丈夫なんじゃないかと思います。
# コメントの //TODO は気になるな…
イーサーの方は、初回の送信は、途中で帰ってくるけどエラーではないので、トレースしても拾い難いと思うのですが、多分、残データを送りなおそうとすると、関数が戻ってこないので、この止まってるところがどこか分かると、原因が分かりそうな気がしてます。あと、TCPセッションは生き続けているので、デバッカでいきなり止めても、どっか別のとこで、正常に動いているようにしか見えない可能性が大きい。どちらかというと、厄介なバグ。printfデバックが、無難な領域になってるような(^_^;) あと、私は、GR-Sakuraとは別のライブラリを持ってきてるのかと思ってました。同じということは、特電さんのコードでしょうか?
現時点の推理は、送信にウェイトが入る要因は、なんだろうか?割り込み待ちになるんだろうか? でも、ブラウザを落とすと戻ってくることを考えると、ポーリングで待っているとも推定。送信が中断する条件は、どこかの変数を見ていると仮定するると、その変数が中断要因を維持している状態で、再送信すると、この変数が解除するまで、ポーリング待ち。セッションが切れると、それが解除されるか、別の変数の状態の変化で、再送信は戻ってくる。
tcp_api.cとか要所ようしょ、下記の分岐コンパイルがあるのですが、__GNUC__も、GRSAKURAも、未定義みたいです。GR-KAEDE用のマクロ定義は、これでOKでしょうか? あと、tcp_api.cで、Serial.printが使えないみたいです。何を、includeすれば使えるようになりますか?
#if defined(__GNUC__) || defined(GRSAKURA)
#include "t4define.h"
#endif
おっしゃる通りです。寝ぼけていたようで...。
どちらかというと、
#define EMAC_BUFSIZE (1536) /* Must be 32-byte aligned */
とあるので、._ETHERNET_BUFFERSにALIGN(32)をつけた方が良さそうですね。
Inomataさん、私の方でも再現しまして、原因が分かりました。Server.writeのサイズ指定がlong unsigned intであるにも関わらず、tcpのドライバの中でsint16になっっているようです。
具体的にはtcp_api.cの中の572行目にある下記で、本来は80000バイトぐらいの値が入るはずが65535を超えた分が代入され、およそ4分の1しかデータが書かれません。ただ、このサイズの型宣言がされているtcp.hだけ変更しても、状況は改善しませんでしたので、これについてはライブラリ開発者に聞いてみようと思います。
head_tcb[cepid-1].req.d.dr.dtsiz = len;
digipontaさんのソースを以下のようにとりあえず行うことで、すべての写真データがアップされることが確認できました。
Serial.println( Server.write( adr, 60000 ) ); // 途中で戻ってきてしまう(^_^;) int32_t rest_size = size - 60000; Serial.println( Server.write( adr+60000, rest_size ) ); // 途中で戻ってきてしまう(^_^;)
Okamiyaさん、Good Jobです。有難うございます。あとは、SDメモリとの競合ですね。
私も、修正して試してみました。データが最後までは、行けてないないようで、最後の方きれてますね。でも、何とか、ピント合わせに、使える状況になりました。ライブラリの対策版を待ちましょう。