2021年4月3日土曜日

Raspberry Pi PicoをUSBメモリーにしてみた

 MSCのサンプルアプリは8KByteのRAMドライブを使用していますがこのRAMドライブをフラッシュに置き換えていわゆるUSBメモリー的な動作をするようにしてみました。

まずはRAMドライブが512Byte/セクターになっているのでこれをフラッシュの消去単位である4KByte/セクターに変更します。ブロック数も256ブロックにして合計1MByteのドライブになるようにします。

enum
{
  DISK_BLOCK_NUM  = 256,
  DISK_BLOCK_SIZE = 4096
};


合わせてBPBの内容をこのサイズに合わせます。

uint8_t msc_disk[ 4 /*DISK_BLOCK_NUM*/][DISK_BLOCK_SIZE] =
{
  {
      0xEB, 0x3C, 0x90,   /* BS_jmpBoot */
      0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30,   /* BS_OEMName "MSDOS5.0" */
      0x00, 0x10,   /* ☆BPB_BytePerSec */
      0x01,         /* BPB_SecPerClus */
      0x01, 0x00,   /* BPB_RsvdSecCnt */
      0x01,         /* BPB_NumFATs */
      0x80, 0x00,   /* ☆BPB_RootEntCnt */
      0x00, 0x01,   /* ☆BPB_TotSec16 */
      0xF8,         /* BPB_Media  */
      0x01, 0x00,   /* BPB_FATSz16 */
      0x01, 0x00,   /* BPB_SecPerTrk */
      0x01, 0x00,   /* BPB_NumHeads */
      0x00, 0x00, 0x00, 0x00, /* BPB_HiddSec */
      0x00, 0x00, 0x00, 0x00, /* BPB_TotSec32 */

BPBの表記はリトルエンディアンなのでセクターサイズ(BPB_BytePerSec)4096=0x1000が0x00,0x10となり、セクターサイズが8倍になったのでルートエントリー(BPB_RootEntCnt)が0x10から0x80(128個)、トータルセクターサイズ(BPB_TotSec16)は256=0x100なので0x00,0x01となります。

管理情報を予め書いておかないとアクセスできないので未フォーマットの場合(BPBのシグネイチャーが書かれていないことで判断)管理情報をフラッシュに書き込みます。

void msc_init(void)
{
#if 1 /* 0にすると強制フォーマット */
  flash_read( 0, 0, temp_buff, 512);
  if (( temp_buff[510] != 0x55) || (temp_buff[511] != 0xaa))
#endif
  {
    flash_range_erase( FLASH_TARGET_OFFSET, SECTOR_SIZE *4);
    flash_range_program( FLASH_TARGET_OFFSET, msc_disk[0], SECTOR_SIZE *4);
  }
}


後は肝心の読み書きAPIのwrite10,read10をフラッシュの読み書きに置き換えます。

void flash_read( int32_t sec, int32_t offset, uint8_t *p_buff, int32_t size )
{
  memcpy( p_buff, &flash_target_contents[sec*4096+offset], size);
}


void flash_write( int32_t sec, int32_t offset, uint8_t *p_buff, int32_t size )
{
  if (offset == 0)
  {
    flash_range_erase( FLASH_TARGET_OFFSET+ sec*4096, SECTOR_SIZE);
  }
  flash_range_program( FLASH_TARGET_OFFSET+ sec*4096 +offset, p_buff, size);
}

ReadはRP2040のeXecute In Place(XIP)の仕組みのおかげでダイレクトにメモリにマッピングされているように見えますので単純にメモリーコピーで読めます。問題なのは書き込みの方でフラッシュに書き込みを行うとキャッシュのコヒーレンシーの問題が出てしまいキャッシュをクリアする必要があるのですが、このキャッシュの管理がコードを実行しているXIPと共通なのでコードの実行に支障が出て書き込み時にストールしてしまうことがあります。データシートを見ると何か回避策がありそうな感じですが。一般的なセオリーであるフラッシュ書き込み時には別のメモリー(RAM)でコードを実行するという方法で回避します。調べてみると実に簡単にRAM上で実行できました。

CMakeLists.txtに以下の1行を足すだけです。

pico_set_binary_type(TestMSC copy_to_ram)

これで1MByteのUSBメモリーになりました。


Pico側でもこのファイルを読み書きできるように実装すればPCとのデータ共有が楽になるのでアプリケーションの幅が広がるかなと思います。


2 件のコメント:

  1. はじめまして。
    こちらの記事を見て、↓のサンプルアプリ
    https://github.com/hathach/tinyusb/tree/master/examples/device/cdc_msc
    をフラッシュドライブがマウントされるように改造してみているのですが、マウントされません。
    もし可能でしたら、お作りになったコードの全体を見せていただけないでしょうか。

    返信削除
    返信
    1. その後いろいろ試したらできるようになりました。失礼しました

      削除