microSDへのwrite処理をバックグラウンドにできませんか


Arduinoで開発しています。  
100Hz(10ms)でセンサデータ取得しRAMにため込み、10秒ごとに100KB程度のデータをmicroSDにwriteしています。  
microSDの処理時間がクロック周波数156
MHzの時、20ms～40msでセンサの周期10msより長いため、microSDにwriteすると、センサ取得時間を逃してしまいます。

質問1.microSDへのwriteを高速化する方法はありませんか。  
質問2.microSDへのWriteをノンブロッキング処理に変更する方法はありませんか。  
質問3.内蔵FLASHの容量は8MBで間違いありませんか。




> 質問1.microSDへのwriteを高速化する方法はありませんか。  
>  質問2.microSDへのWriteをノンブロッキング処理に変更する方法はありませんか。

microSDへの書き込みを高速化する方法については知らないのですが、  
Arduinoのloop処理だけでは実現できないと思うので、  
どうすれば良いかちょっと方法を考えてみました。

  1. マルチタスクで処理する
  2. マルチコアを使う

(1) マルチタスク化

SPRESENSEのArduino環境は中にOSが搭載されているのでマルチタスクで動かすことができます。  
task_create()関数でSD書き込み専用のタスクを作成します。  
作成するタスクはsetup/loopよりも優先度を低くしておきます。  
setup/loopが優先度100で動作しているので、優先度はそれよりも低い90で作成しておきます。

センサデータ用のRAMはA面/B面のダブルバッファを用意しておいて、  
A面->B面->A面->... と順番にバッファリングするようにします。  
A面のバッファが溜まった状態で、SD書き込み専用タスクへA面データの書き込み処理を依頼します。  
A面をSDカードへ書き込みしている間は、センサーデータをB面に溜め続けます。

以下のようなイメージで並行動作させます。

[code]

    センサデータ A面→B面→A面->...
    SDへ書き込み     A面→B面->...
    
[/code]

ざっくりとした実装イメージは以下の通りです。

[code]

    SDClass SD;
    File file;
    sem_t sem; // タスク間通信用セマフォ
    
    static int save_task(int argc, FAR char *argv[])
    {
      while (1) {
        sem_wait(&sem);
        file.write(buf, size); // 溜まったバッファをファイルに書き込み
        file.flush();
      }
    }
    
    void setup()
    {
      while (!SD.begin());
      file = SD.open("sensor.log", FILE_WRITE);
      sem_init(&sem, 0, 0);
      task_create("save_task", 90, 2048, save_task, NULL);
    }
    
    void loop()
    {
      センサデータ取得A面/B面へ保存
      
      if (バッファが溜まったら) {
        sem_post(&sem); // 書き込みタスクを起こす
      }
      usleep(1);
    }
    
[/code]

(2) マルチコアを使う

SPRESENSEのマルチコア環境を使用して、  
<https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_multicore>  
センサデータの取得をSubCoreで実行し、SDカードへの書き込みをMainCoreで実行します。

こちらもダブルバッファにしておいて、  
SubCoreはセンサデータをA面/B面に順番に溜めておいてバッファが一杯になったら  
MainCoreにバッファのポインタを渡すだけ、  
MainCoreはポインタを受け取ったらそれをSDカードへ書き込むだけ、  
こちらの方が簡単に実現できそうな気がします。

> 質問3.内蔵FLASHの容量は8MBで間違いありませんか。

内蔵FLASHはトータル8MBで、半分の4MBがファームウェア(プログラム)保存領域、  
もう半分の4MBがアプリケーションから自由に触れるストレージ領域になっているようです。




> 質問1.microSDへのwriteを高速化する方法はありませんか。  
>  質問2.microSDへのWriteをノンブロッキング処理に変更する方法はありませんか。

microSDへの書き込みを高速化する方法については知らないのですが、  
Arduinoのloop処理だけでは実現できないと思うので、  
どうすれば良いかちょっと方法を考えてみました。

  1. マルチタスクで処理する
  2. マルチコアを使う

(1) マルチタスク化

SPRESENSEのArduino環境は中にOSが搭載されているのでマルチタスクで動かすことができます。  
task_create()関数でSD書き込み専用のタスクを作成します。  
作成するタスクはsetup/loopよりも優先度を低くしておきます。  
setup/loopが優先度100で動作しているので、優先度はそれよりも低い90で作成しておきます。

センサデータ用のRAMはA面/B面のダブルバッファを用意しておいて、  
A面->B面->A面->... と順番にバッファリングするようにします。  
A面のバッファが溜まった状態で、SD書き込み専用タスクへA面データの書き込み処理を依頼します。  
A面をSDカードへ書き込みしている間は、センサーデータをB面に溜め続けます。

以下のようなイメージで並行動作させます。

[code]

    センサデータ A面→B面→A面->...
    SDへ書き込み     A面→B面->...
    
[/code]

ざっくりとした実装イメージは以下の通りです。

[code]

    SDClass SD;
    File file;
    sem_t sem; // タスク間通信用セマフォ
    
    static int save_task(int argc, FAR char *argv[])
    {
      while (1) {
        sem_wait(&sem);
        file.write(buf, size); // 溜まったバッファをファイルに書き込み
        file.flush();
      }
    }
    
    void setup()
    {
      while (!SD.begin());
      file = SD.open("sensor.log", FILE_WRITE);
      sem_init(&sem, 0, 0);
      task_create("save_task", 90, 2048, save_task, NULL);
    }
    
    void loop()
    {
      センサデータ取得A面/B面へ保存
      
      if (バッファが溜まったら) {
        sem_post(&sem); // 書き込みタスクを起こす
      }
      usleep(1);
    }
    
[/code]

(2) マルチコアを使う

SPRESENSEのマルチコア環境を使用して、  
<https://developer.sony.com/develop/spresense/docs/arduino_tutorials_ja.html#_tutorial_multicore>  
センサデータの取得をSubCoreで実行し、SDカードへの書き込みをMainCoreで実行します。

こちらもダブルバッファにしておいて、  
SubCoreはセンサデータをA面/B面に順番に溜めておいてバッファが一杯になったら  
MainCoreにバッファのポインタを渡すだけ、  
MainCoreはポインタを受け取ったらそれをSDカードへ書き込むだけ、  
こちらの方が簡単に実現できそうな気がします。

> 質問3.内蔵FLASHの容量は8MBで間違いありませんか。

内蔵FLASHはトータル8MBで、半分の4MBがファームウェア(プログラム)保存領域、  
もう半分の4MBがアプリケーションから自由に触れるストレージ領域になっているようです。

