ファームウェアのアップグレードが必要です。 USB DFUクラスを使用する予定です。しかし、ファームウェアアップグレードのコマンドは、私の場合、PCアプリケーションから送信されます。したがって、システムメモリにあるブートローダーに切り替える必要があります。最初はアプリケーションを実行しているので、ユーザーフラッシュから起動されます。つまり、ユーザーフラッシュ用に構成されたBoot0およびBoot 1ピンがあります。 DFUブートローダーがシステムフラッシュにあるので、Boot0およびBoot1ピンの設定を変更する必要があります。 Boot 0やBoot 1の設定がユーザーフラッシュメモリと同じままで、アプリケーションでシステムメモリにジャンプするような方法はありますか?
Boot0/1ピンは、メモリからユーザーコードをロードする必要があるかどうか、またはブートローダーをロードする必要があるかどうかを確認するために、プロセッサの起動時にのみサンプリングされます。これらのピンの状態は、後でブートローダーに影響を与えません。
私も同じような要求に直面し、ブートローダーをオンデマンドでロードする2つの方法を見つけました。
まず、ユーザーコードからブートローダーに「ジャンプ」できます。たとえば、ボタンが押されたときにブートローダーにジャンプできます。
しかし...これは、単純なJUMP命令よりもはるかに複雑です。ブートローダーを使用するには、一部のレジスタとデバイスを正しく再構成する必要があります。JUMP中にIRQがトリガーされないようにする必要があります...実際、リセット後に開始されたかのようにプロセッサを再構成する必要があります。このテクニックに関するいくつかの情報を見つけることができます: STからのこのビデオ 。
私はSTM32F1xxプロジェクトでこの種のことをなんとかしてやりました。ただし、STM32F4に基づくより複雑なプロジェクトでは、これは本当に困難になります...すべてのデバイス(タイマー、通信インターフェイス、ADC、DACなど)を停止し、IRQがトリガーされないようにして、再構成する必要がありますすべての時計、...
代わりに、この2番目のソリューションを実装することにしました。ブートローダーにジャンプする場合、バックアップレジスタの1つにバイトを書き込んでから、ソフトリセットを発行します。次に、プロセッサが再起動すると、プログラムの最初で、このレジスタを読み取ります。このレジスタには、ブートローダーモードで再起動する必要があることを示す値が含まれています。次に、ブートローダーへのジャンプは youtubeビデオ で示されているようにはるかに簡単です。
MicroPythonには、DFUモードに入るのに使用されるpyb.bootloader()関数があります。
実装可能なCコード ソースリポジトリ内 が見つかります。
私はSTM32F4バージョン( the #else
ブロック )とF7バリアントを(何度か)何度も使用しました。
上記のリンクは、ファイルが変更されると古くなる可能性があるため、ここに関数の本文を配置します。
// Activate the bootloader without BOOT* pins.
STATIC NORETURN mp_obj_t machine_bootloader(void) {
pyb_usb_dev_deinit();
storage_flush();
HAL_RCC_DeInit();
HAL_DeInit();
#if defined(MCU_SERIES_F7)
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
//__set_MSP(*((uint32_t*) 0x1FF00000));
__ASM volatile ("movw r3, #0x0000\nmovt r3, #0x1FF0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
((void (*)(void)) *((uint32_t*) 0x1FF00004))();
#else
__HAL_REMAPMEMORY_SYSTEMFLASH();
// arm-none-eabi-gcc 4.9.0 does not correctly inline this
// MSP function, so we write it out explicitly here.
//__set_MSP(*((uint32_t*) 0x00000000));
__ASM volatile ("movs r3, #0\nldr r3, [r3, #0]\nMSR msp, r3\n" : : : "r3", "sp");
((void (*)(void)) *((uint32_t*) 0x00000004))();
#endif
while (1);
}
Pyb_usb_dev_deinit()関数はUSBをシャットダウンし、storage_flushはキャッシュされたファイルシステムデータをすべて書き出します。 HAL関数は、STM32Cube HALファイルから取得されます。
Dfu-utilの新しいバージョン(IIRC 0.8以降)を使用している場合は、-s :leave
コマンドラインオプションを指定して、フラッシュの最後に新しくフラッシュされたプログラムを実行できます。上記と組み合わせて、ボードに触れずにフラッシュ/テストサイクルを実行し、ファームウェアがハードクラッシュした場合にのみBOOT0/RESETを使用します。
python pydfu.pyと呼ばれるDFUフラッシャー: https://github.com/micropython/micropython/blob/master/tools/pydfu.py もありますdfu-utilより少し高速です。
ブートローダーの状態をシミュレートできます。コンデンサと並列抵抗をBOOTピンからグランドに接続します。別の空きピンをBOOTピンに接続します。コンデンサは外部ピンで充電でき、抵抗で放電できます。計算/実験できる正確な値を覚えていません(RC回路の時定数が重要です)。
外部ピンを1に設定してこのコンデンサを充電し、NVIC_SystemReset
。リセット後、ブートローダーが実行されます。コンデンサに接続された抵抗器が放電を行います。ファームウェアの更新後、デバイスをリセットすると、アプリケーションで実行されます。
一部のアプリケーションでこれを使用しており、正常に動作します。このソリューションの欠点は、外部回路が必要なことですが、実装が非常に簡単で、すべてのSTM32デバイスに共通です。
新しい画像にジャンプすることはthat難しいことではありません。パワーオンセルフテストの一環として、これを成功させました。
void (* const jumpFunction)(void) = (void (*)(void))(APPLICATION_ADDRESS + 4ul + 1ul);
4のオフセットはスタックポインターを通過することで、1のオフセットはThumbmodeの場合です。__set_MSP((uint32_t)*APPLICATION_ADDRESS)
、2番目のイメージの最初の4バイトには、新しいスタックポインターが含まれます。jumpFunction();
SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
が設定されます。これをSCB->VTOR = APPLICATION_ADDRESS | VECT_TAB_OFFSET;
に変更する必要があります私はPOSTでプログラムをFLASH_BASE
に配置し、そのスタックにコア結合SRAMを使用して、メインSRAMでメモリチェックを実行し、メインプログラムの信頼性をチェックしてジャンプしますメインプログラムへ。
何も変わっていないかのように、メインプログラムをデバッグできます。
NB!私は最近これを自分でやったばかりです。確認する必要があることがいくつかあります。 1つの懸念は、ソフトウェアのリセットで何が起こるかです。 2番目のプログラムから呼び出された場合、最初のプログラムではなく、2番目のプログラムのリセットルーチンに移動すると思います。