ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

arduinoコミュの大容量のデータを扱うには?

  • mixiチェック
  • このエントリーをはてなブックマークに追加
まず
Flashメモリ(PROGMEMで使う部分)
I2C
RS232C(115200bps)
どこからのデータ転送が早いのでしょう?

Flashメモリは近く(?)にあるから、一番早い気がします。
I2Cはアナログ7ビットなので、それなりに早い気がします。
RS232Cは古い規格だし、1ビット転送なのでボーレートを最高にしても遅い気がします。

しかしFlashメモリにはプログラム上でPROGMEMを使いデータを置き、IDEからの転送しか出来ませんよね?
#実行中のプログラム中からは読み込みしか出来ませんよね?

今回は
-----------------------------------------
大量のデータを高速に読み込みたいです。
データはある程度の容量ごとに分かれています。
-----------------------------------------
を悩んでいます。

自分の考えとしては.....
「外部メモリ(SDカードとか)を用意して、I2Cうを使い必要なデータをFlashメモリに転送し、高速に読み込もう!」
と考えていたのですが......Flashメモリにはプログラムからの書き込みが出来ません。

さて、どうしようかな?
実はプログラムでFlashメモリに書き込む方法が方法があったりしませんか?
#ライブラリとかあったら最高なんですが....

コメント(17)

大容量のデータを外部メモリで読み書きしたいという事であれば、SPIはいかがでしょうか。速度はAVRとしてはクロックの1/4までだそうで、I2Cよりは高速にアクセスできると思います。
http://www.arduino.cc/en/Tutorial/SPIEEPROM

I2Cは「低速でもいいからハードをシンプルにしたい」という場合に向いている方式でしょうかね。

内蔵のFlashメモリ(PROGMEMで使う部分)に書き込むには、Arduinoとして使う限りは(スケッチから書き換えるには)不可能じゃないかと思います。ATmegaのFlashメモリはブートローダーセクションとアプリケーションセクションのふたつの領域に分けられていますが、アプリケーションセクションに書き込むための命令(SPM命令)はブートローダーセクション上でしか実行できません。
ってことで、ブートローダーを書き換えれば可能だとは思いますが…。
すばらしい!

と思ったら、大きな条件を書いていませんでした....。

アナログピンは全部空いてるけど、デジタルピンは0と1しか空いていません。

データは1度書き込んだら通常は読み込みしかしません。
なので書き込み時だけDATAOUTを繋ぐとかでも使えるのでしょうか?
#通常はDATAINのみ繋いで使う感じですね。

SLAVESELECTってピンは、つながないとダメなのでしょうか?(笑)
意味が分からないのですが、PCにのHDDにはマスターとスレーブがあり、ケーブルセレクトで接続した場合....
と同じ感じでスレーブを考えると、1個しか使わない場合はGNDか5Vに接続しておくだけでも良くね?とか。
なんとかデジタルピン2つだけで使えませんかね?
#先に書いた通り書き込み時は4ピンとも使えるのですが、通常の読み込み時は2ピンしか空いていません
#もしくはアナログピンで、どーにかならないでしょうか?

あと紹介されたページではArduinoのデジタル10,11,12,13ピンを使うように書かれていますが、現状デジタルピンは0と1しか空いていません。
こちらライブラリ内をいじれば大丈夫なのですかね?
#PWM使用とかしていたら他には移せないのですよね?

-------------

と思いきや、スレーブはバリバリ使ってますね。
#これは接続しないとダメそうですね。

ソフトのことは解ってもハードのことが分からない若山ですが
結局SLAVESELECTはLOWかHIGHなので0Vか5Vって事でアナログでも出来ないかなぁ?とか。
SPICLOCKってタイミングを取るだけのハートビートみたいなものならアナログでも出来ないかなぁ?とか。
もしくはDATAINも0か1か1ビット読むだけなら0Vか5Vだと思うのでアナログでも読めないかなぁ?とか。
勝手な想像を膨らませてみました。

これからライブラリの中を見てみますが、それ以前に「ダメでしょう」とか「こうすれば大丈夫!」みたいな事がありましたら教えて下さい。
ところで....SPI_Serial_EEPROMってのが、なかなか見付かりません。

もしかして秋月で売っている「3線式シリアルEEPROM」ってのがSPIの事なのか?
例えばコレ
http://akidukidenshi.com/catalog/g/gI-00594/
コレが一番大容量っぽいので、コレでOKなら明日にでも買いに行くつもりです。

あとはマルツでブレッドボードに刺さらないタイプを発見!
http://www.marutsu.co.jp/user/shohin.php?p=60166
半田付けが苦手なのでスルー予定(笑)

とりあえず秋月に行ってSPIとI2Cを今スグ買ってきます!
SPIを使う場合、SS, MOSI, MISO, SCKは必ずArduinoのデジタル 10,11,12,13番(PB2, PB3, PB4, PB5)を使う事になります。これはATmegaのハードがそのようになっているので、変更できません。

秋月は、こちらですね。
http://akizukidenshi.com/catalog/g/gI-00594/

これの「3線式シリアル」はSPIとは違うようですね。でも互換性はあるらしい(すみません、詳細はわかりません)。メモリとATMegaのデータシートを見ながらプログラムを作る事になるかと思いますが、詳細はわかりません(すみません)。

あと、ひょっとして誤解されているかもしれませんが、Arduinoのアナログ端子はデジタル端子として使用できます。アナログ0〜5が、デジタル14〜19として使えます。
なので、もしPWMとかを使わず、digitalRead(), digitalWrite()で読み書きしているだけであれば、それらをアナログ端子に移動してデジタル10〜13を空ける…という事も可能かもしれません。
(I2Cの通信もArduinoの名称でのアナログ4,5ピンを使っているだけであって、通信はアナログではなくデジタルです。)

部品の入手のしやすさや空き端子数を考えると、I2Cも選択肢にいれたほうがいいかもしれませんね。
1.ちゃんと  http://akizukidenshi.com/catalog/g/gI-00594/ を買いました。
2.3線式とSPIは違うのですか....まぁピンの名前が似ているので、ピンハイだけ間違えないように作ってみます。
3.むむむ...デジタル10,11,12,13は固定なのですね....チト困った。
4.アナログはデジタルとして使えたのか.....ちょっと恥ずかしい質問でしたね。
5.I2Cもコレ http://akizukidenshi.com/catalog/g/gI-02525/ を買いました!
 #ココ http://arms22.blog91.fc2.com/blog-entry-262.html に書かれていた容量の一番大きいのを買ったつもりです

今日はヤボ用で秋葉原に24:45迄いたので作業は明日!

jtakaoさん、有難う御座いました!
こんばんは
Spartfunでこんなのありますよ これもSPI インターフェースです。
私はこれを使っていますよ。
MicroSD shield
http://www.sparkfun.com/commerce/product_info.php?products_id=9802

これの場合EEPROMとちがってRAWアクセスだけではなくFAT16のライブラリーがリンク先からDLできますのでちょっとソースコード改造して使えば色々できます。
ただパフォーマンスの点で言うと(?)ですがメリットとしてはEEPROMとちがくて入手性いいSDカードと本当に大容量の点ですかね。 2Gまでたっぷり使えます。

ただ8ビットマイコンで2g の容量読み書きするってあんまりケース的にないかもしれませんが長期で何かのログ取ったりできるとおもいます。

ちなみにCS(SS)信号は8pinを使っているので複数のスレーブデバイスを接続する場合は注意する必要があります
はじめちゃん様
SDカードは超大容量で魅力的なのですが、なんとなく遅いイメージが有ります。
#勝手な想像ですがI2Cより遅く思えて却下していました
SDかーどは以前接続してみた事があるのですが、やはりデジタルピンを多く使用するので.......と思っていたのですが
アナログピンもデジタル化出来る事がわかり「それも試す価値アリかな?」って気もしますね!

因みに以前SDカードを試した時のトピです。
http://mixi.jp/view_bbs.pl?id=51521607&comm_id=447391
以前のSDカードのページを見て気になりました。
SDカードでもデジタルの10,11,12,13ピンを使っています。
これも「この場所固定」なんでしょうか?
http://zampoh.cocolog-nifty.com/photos/uncategorized/2008/12/31/sdcard_sch.png
わかにゃん様

ここにATMELのSpecificationがありますが(英語ですが。。。)
http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf
それによるとSS以外の端子は内部で固定ロジックに入っているわけではなく
SPI制御レジスタの方向ビットの制御で入力される(スレーブモード)か出力(マスターモード)かを
決めているようです。SS端子はほかのポート使ってタイミング合わせて制御すればどんどん増やせそうです。

ほかの端子についてはそれぞれ シフトレジスタ、クロックジェネレーターに接続されていますので
変更は難しいかもしれないですね。

TWIで複数デバイス接続する場合は負荷要領の計算(プルアップ)がすぐ変わってしまうため。
ブレッドボードで試したりする場合はちょっと大変なんですが(っていうか面倒だから負荷要領なんていちいちデータシートで確認したくない すぐ組みたいものぐさなので・・・w)
SPIの場合少々乱暴に直結しても大概通信とってくれる印象がありますね。
あとはTWIと比較するとコマンド数が多いのも利点でしょうか。


あと速度についてですがSPCRレジスターのクロックモードの変更ってしましたか?
SPCRレジスターを以下のように変更すればできます。
確か、クロックの4逓倍までしかチップが対応していなかったような記憶がありますが・・・
(普段速度追求することをしていないので未検証)
転送する前にSetup内で定義すればOKです

SPCR = (1<<SPE)|(1<<MSTR)|(0<<SPR1)|(0<<SPR0) (最高速度の場合 4MHz)
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0) (最低速度の場合 250KHz)

特にこの記述EEPROMを読み書きしたい場合は重要ですよ

あとはインクメンタルアクセスを駆使するとパフォーマンスはI2Cの比じゃなく早くなるんじゃないでしょうか。
SDでできたか忘れましたがSPI EEPROMはできるものがおおいですよ
(SS落としたまま連続でRかWするアクセスです)

写真は手持ちの部品で複数スレーブは作れそうなので組み立てまでやってみました・・・
どういう用途に使おうかな・・・w
はじめちゃん様

上記文章が難しすぎて理解できません....

とりあえず買ってきた部品に手がつけられていない状態なので
まずはSPIとI2Cを繋いで既存ライブラリで動かしてみます。

しかし「何だか早く読み書き出来るらしい」事はわかったので
次の課題として研究したいと思います!
#理解できたら...ですけどね
おぉ、ブレッドボード付きのシールド(あってる?)ですか。
自分もやってみよ〜。
わかにゃん様

別トピ立てられている件はなにかSPIで折り返し通信されたいようですね。
スレーブを二つ使う場合はSPIアクセスのプログラム的な問題があるかもしれませんね。

こういう物はだんだん触って覚えるものですよね。
ただあんまりライブラリーに頼るのは推奨できませんよ。
簡単なリード ライトは自分で作成を挑戦することをおすすめします。
(その方が覚えると思うので)

わかにゃんさんのやりたい事はDMAアクセスですね。
ARMとかV850 SHなどの32ビットマイコンを使われる場合はこういう機能が
実装されています。

ATmega328のような8ビットマイコンの場合 自動車エンジンをチューニングするような
面白さはあるように思えます。I2CとSPIでデータ交換する場合尚更オーバーヘッドが気になるかもw

マイコンの動作最速化の究極言語はアセンブラですね。
アセンブラ主流の時代からマイコンいじりしている私としてはやっぱりコンパイラって非効率に処理している気がして心配になるときがありますよ


ぜひ頑張ってください。

#スケッチ見せたいですが…ここに貼りつけるのは無粋ですよね
#みなさんどうしているんでしょうか?
じろ〜様

これはduemilanove の上にMicroSD shiedを載せて配線面倒なのでミニブレッドを載せて配線しています。
ミニブレッドボードは裏面が両面テープになっているのでめんどくさいときはそのまま固定して完成として
終わらせてしまう手もありますよw
>8 わかにゃんさん

この場合もSPIを使っているようなので、基本的には10,11,12,13固定です。
ただしこの例に限らず、ATmegaをマスター側として使う限りにおいては、厳密に言えばSS(この図ではCS)はDigital10番固定である必要はありません。
データシートにも記載されていますが、ATmegaをSPIのマスター側として使用し、かつPB2(Arduinoで言うDigital10番)を出力モードで使用する場合、その出力はSPIの動作に影響しません。つまり自由に使えます。
逆に言えばDigital10番は汎用の入力ピンとしては使えません(もしLが入力されると、ATmegaのSPIがスレーブとして動作してしまう)。

ということで、どうせSPI使用時には他のデバイスにSSとして1本接続する必要があるのだから、普通は10番を使う事でしょう。

SSに関しては、#2で御指摘されているとおり、
>1個しか使わない場合はGNDか5Vに接続しておくだけでも良くね?とか。
というのもアリのようですね(実際にはアクティブLなのでGNDに接続)。実際にそのように解説されているページもあります。しかしその場合、連続して送信されるデータの1ビット目をどのように判断するのか、ちょっとわかりません。リセットされてからずっと、クロックの数で0,1,2…7,0,1,2…とカウントし続けるって事なのでしょうかね。ノイズとかで狂ったらどうなるのだろ。
SSが接続されていれば、普通はSSがLになった次のクロックが1ビット目になるので、きちんとSSを接続し、送信前にLに、送信後にHに…と、きちんと制御するべきかな…と思ってます。


あと、3線式のAT93C86ですが、少なくともCS端子の論理がSPIとは逆なので、SPI用のプログラムそのままでは動作しないと思いますので念のため。
(SPIは、SSがLで動作。AT93C86はCSがHで動作。)
皆様色々と有難う御座います。

とりあえず現状の報告です。

http://akizukidenshi.com/catalog/g/gI-02525/
上記のI2Cの1メガビットメモリを買い、5VとGNDとA5とA4を繋ぎ、書き込み>読み込み>コンペア迄進みました。
報告するほどの進行状況ではないのですが、Wire.begin()をしてなくて2時間くらい悩みました...。

http://www.arduino.cc/playground/Code/I2CEEPROM
上記ページのi2c_eeprom_write_byteとi2c_eeprom_read_byteを何も考えずにパクったバチが当たった感じです。

とりあえず、これで「遅いのか?」を確認してみます。

で.....なんでこんな事を始めたかと言うと、先日のMTM05でYM2151Shieldを買ったのですが
Arduinoのメモリ容量の関係で1曲づつしか曲が鳴らせないのを何とかしたいと思った次第。

つまりI2Cからのデータ読み込みで問題なく曲が鳴れば、今回はミッションコンプリートとしたいと思います。
と言いつつも、SPIのメモリも買ったので、別途検証はしようと思います!

さて、I2Cからの読み込みでも曲が鳴れば嬉しいのですが....
一旦まとめ

YM2151ShealdではFlash(PROGMEM)内の曲データを再生していました。
しかしFlash容量の関係で1曲づつ転送して聞くしかありませんでした。
そこで外部メモリを付けてたくさんの曲を入れて再生させるように改造したかったのですが...

I2C接続のEEPROMで実験してみました。
PROGMEMよりもWire関数でI2SのEEPROM読み込みの方が遅いらしく
若干曲が遅くなる部分が出てしまいました。

------

次にトライしようと思うのはSPI接続のEEPROMです。
こちらはI2C接続のEEPROMよりも早く読める可能性があるようです。

YM2151Shieldはデジタルピンの2〜13を使っているので
ゲタをかましてデジタル2〜9とアナログ0〜3に変更します。
プログラム側はデファイン定義されていたので簡単にずらせるようです。

......とりあえずデジタル2〜9とアナログ0〜3で動くことの確認まで出来ました!

いよいよSPI接続のEEPROMに挑戦です!

残念ながら、どのくらい早い(遅い)かを数値的に見る予定はありません。
今回は「とにかく曲がちゃんと鳴れば結果オーライ!」で終了する予定です(笑)

------


P.S.
 I2CのEEPROMからの読み込みプログラムを以下に添付します。
 連続データの読み込みも、毎回コレを呼び出しているのですが無駄でしょうか?
 #どっかにあったサンプルをそのまま使っているだけです

uint8_t ReadData8(uint16_t addr) {
uint8_t rdata = 0xFF;
Wire.beginTransmission((uint8_t)0x50);
Wire.send((uint8_t)((uint16_t)addr >> 8));
Wire.send((uint8_t)((uint16_t)addr & 0xff));
Wire.endTransmission();
Wire.requestFrom((uint8_t)0x50,(uint8_t)1);
if(Wire.available()) rdata = Wire.receive();
return (uint8_t)rdata;
}

もし連続で読む場合の改良法とかありましたら教えていただけると助かったりします。

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

arduino 更新情報

arduinoのメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。

人気コミュニティランキング