1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RaspberryPi Pico と trykernelで dualcoreマイコン開発 その3 内蔵SPIフラッシュにデータ書き込み

Last updated at Posted at 2025-04-08

設定データを内部FLASHに記憶させたい

・システムを作る中、設定データ(例えばIPアドレスなど)を内部に記憶させたいですよね。
・picoには1Mもフラッシュ領域があり、その一部を設定データ記憶に使えれば便利です。
・フラッシュ操作はSDKのAPIを使って簡単に実装できました。

picoの内蔵フラッシュ

・picoの内蔵SPIフラッシュは「W25Q16JVUXIQ」という型式。
・容量は2MByte、アドレス:は0x000000 ~ 0x1FFFFFです。
・ただし2MBすべて使えるわけでなく、使えるのは1MByteのみです。
・ROMエリア(0x000000~0x0FFFFF)とXIP(0x100000~0x1FFFFF)エリアで分かれており、
 ROMエリアには工場出荷時に書き込まれるブートローダ(消せない)が実装されています。
・ユーザープログラムなど、自由に書き込める領域はXIPエリアになります。
・Pico起動時、CPUはROMに格納されたブートローダを実行します。ブートローダは、
 フラッシュメモリの初期化やXIPモードの設定などを行い、その後にXIP領域に格納された
 ユーザープログラムを実行します。
・ROMはPicoの起動処理を行い、XIPはユーザープログラムの実行領域として機能します。


image.png

フラッシュ操作APIの説明

・[hardware/flash.h]をインクルードして使います。

image.png

★削除
■flash_range_erase
・機能:指定されたアドレス範囲のフラッシュメモリを消去します。
・注意:フラッシュメモリは、書き込み前に消去する必要があります。
・引数:offset: 消去を開始するフラッシュメモリのアドレス count: 消去するバイト数
・備考:フラッシュメモリは、セクタ単位で消去されます。セクタサイズは通常4KBです。
    countは、セクタサイズの倍数である必要があります。

★書き込み
■flash_range_program
・機能:指定されたアドレス範囲のフラッシュメモリにデータを書き込みます。
・引数:offset: 書き込みを開始するフラッシュメモリのアドレス 
    src: 書き込むデータのポインタ count: 書き込むバイト数
・備考:フラッシュメモリは、ページ単位で書き込まれます。
    ページサイズは通常256バイトです。

★読み込み
・特別なAPIは必要なく、アドレスを直接読むことで値をreadできます。
image.png

消去、書き込み時の注意点

・フラッシュメモリへの削除、書き込み中に、別のコアがプログラムコードを含む
 フラッシュ領域にアクセスするとエラーが発生し、例外ハンドラへ飛びます。
・この期間は別のコアも命令をフェッチしたり、データを読み出したりできません。
・フラッシュ内の同じページではなく、フラッシュ自体へのアクセスが禁止されます。
・Picoのマルチコア環境では、core0とcore1が独立して動作するため、片方のコア
 がフラッシュ書き込みを行っている間も、もう片方のコアは動作していますので、
 普通にフラッシュAPIを使うとエラーとなります。

消去、書き込み時の対策(割り込みの禁止)

・対策としてはそのままですが、別のコアを停止させるAPIが用意されています。
・その前に割り込みを禁止しておきます。
・save_and_disable_interrupts()は、割り込みの状態を保存し、すべての
 プロセッサコアの割り込みを無効化するために使用されます。
・これは割り込みによって中断されてはならないコード領域を保護するために
 使用します。(クリティカルセクション)
・使用した場合、必ず対応する restore_interrupts() を呼び出して、保存し
 ておいた割り込みの復元が必要です。そうしないと、システム全体の割り込みが
 無効化されたままになり異常動作となります。(デッドロック)

    // 割り込み無効にする
    uint32_t ints = save_and_disable_interrupts();

    // コア0を停止
    multicore_lockout_start_blocking();

    // Flash消去
    //  消去単位 FLASH_SECTOR_SIZE(4096Byte) の倍数
    flash_range_erase(FLASH_TARGET_OFFSET, FLASH_SECTOR_SIZE);
    // Flash書き込み
    //  書込単位 FLASH_PAGE_SIZE(256Byte) の倍数
    flash_range_program(FLASH_TARGET_OFFSET, wd, FLASH_PAGE_SIZE);

    // コア0を再開
    multicore_lockout_end_blocking();
    
    // 割り込みフラグを戻す
    restore_interrupts(ints);

消去、書き込み時の対策(victimコアの宣言とロック)

・multicore_lockout_start_blockingは、「victim core」に定義したコアを一時的に停止して
 割り込み無効にするAPIです。 (実際はRAM 内のコードでタイトなループを実行)
・タイムアウト付きのmulticore_lockout_start_timeout_us()を使うこともできます。
・使用方法として事前に「victim」コア(他のコアにロックされる可能性のあるコア)
 として定義する必要があります。multicore_lockout_victim_init()APIを呼び出して、
 宣言しておきます。

void main_c0(void)
{
    /*c0は停止可能なサブコアとして定義*/
    multicore_lockout_victim_init();
    
    gpio_init(LED_PIN);                 // GPIO初期化
    gpio_set_dir(LED_PIN, GPIO_OUT);    // GPIOを出力に設定

    i2cLcdPerfInit();    

    while (1) {
        disp_adc_val();
        sleep_ms(100);
    }
}

・ロックアウトが不要になると、multicore_lockout_end_blocking()APIを呼び出します。
・タイムアウト付きのmulticore_lockout_end_timeout_us()を使うこともできます。

image.png

今日はここまで。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?