stm32 シリアル ポート IAP ルーチンの解析

定期的な取得

サンプル コードとアプリケーション ノートは、公式 Web サイト www.st.com にアクセスして入手できます。
サンプル コード: x-cube-iap-usart
アプリケーション ノート: an4657

同時に、この記事に関連するすべての資料はここからダウンロードできます:
リンク: https://pan.baidu.com/s/19nKPc_oOyRZCTfaNKTNHbw
抽出コード: q0ge

プロジェクトファイルの構造

主に 2 つのフォルダーがあります: Drivers と Projects。前者は HAL ライブラリとサンプル開発ボード BSP パッケージのドライバー ファイル、後者はサンプル プロジェクトです。シングルチップ開発ボード F1、 L0、L4 がありますが、残念ながら該当するものはありません。stm32g412dicovery 開発ボードのルーチンが手元にあるので、後で手動で移植する必要があります。ブートローダーは主に USART および CRC ペリフェラルを使用し、前者はユーザー対話とファイル転送に使用され、後者はファイル検証に使用されます。プロジェクトには、IAP_Main と IAP_Binary_Template の 2 つのフォルダーが含まれています。前者はブートローダー (主要な調査オブジェクト) の実装であり、後者はユーザー アプリ テンプレートです。
IAP_Main にはブートローダーの主要な実装ファイルと IDE に適合したプロジェクトが含まれています。プロジェクト ファイルについては何も言う必要はありません。解析が必要な主なソース コード ファイルは次のとおりです。

  • main.c main.h : メイン関数のエントリ、ペリフェラルと HAL ライブラリの初期化、ブートローダーの呼び出し、またはユーザー プログラムへのジャンプ。
  • menu.c menu.h : コマンドラインメニューの実装
  • ymodem.c ymodem.h : ymodem ファイル転送プロトコルの実装
  • flash_if.c flash_if.h : FLASH 読み取りおよび書き込み関数
  • common.c common.h : いくつかの共通関数とマクロ定義。主に menu.c と ymodem.c で呼び出されます。

ファイル間の呼び出し関係はおおよそ次のとおりです。

ここに画像の説明を挿入

stm32g412discovery 開発ボードに移植

移植にはSTM32L476G_EVALのルーチンを参考にしましたが、同じFシリーズの別のルーチンプロジェクトを移植した方が便利であることが分かりました。

  1. STM32CubeMX を直接使用して、内部クロックを使用して stm32f412zgt6 の初期化プロジェクトを生成します。上記のメインファイルをプロジェクトに追加します
    ここに画像の説明を挿入

  2. stm32f4xx_hal_conf.c ファイルで CRC および UART モジュールを有効にし、対応する .c ファイルをプロジェクトに追加し、ヘッダー ファイルを置き換えて、stm32l4xx.h を stm32f4xx.h に置き換えます。

  3. mian.c と main.h の内容をコピーし、アダプテーション開発ボードを修正します。main 関数の BSP_PB_Init と BSP_PB_GetState を再実装して、ボタン検出を初期化し、ボタンの状態を取得します。ここでは、公式の stm32412g 開発ボードを直接使用します。 BSP パッケージが変更されました。状況に応じて IAP_Init 関数を変更します。この関数は主にシリアル ポートと CRC ペリフェラルの初期化に使用されます。ここでは、開発ボードに従ってシリアル ポートを UART2 に初期化し、仮想シリアル ポートを使用します。同時に、stm32F4 シリーズの CRC のため、ペリフェラルは Ymodem プロトコルで使用される CRC16 チェック計算をサポートしていないため、ここで関連する初期化コードを削除し、チェックの後半でソフトウェア チェックを使用できます。 ;

  4. エラー情報に従って他のファイルを修正します ここで私が遭遇した状況は、common.c/.h ファイルには少量のエラーレポートがあり、flash_if.c/.h ファイルには多くのエラーが含まれているということです。 、内蔵フラッシュのパーティショニング方法は大きく異なります。下図の左側がstm32l4xxのFLASHディストリビューション、右側がstm32f412のFLASHディストリビューションです。
    ここに画像の説明を挿入
    ここで提案なのですが、flash_if.c のインターフェースを変更する際にルーチン内で STM3210C_EVAL プロジェクトを参照することを提案されており、最初はこのプロジェクトをベースに移植すべきでしたが、これは本当に誤算でした。
    flash_if.c のオプション バイトの読み取りおよび書き込み関数を変更するときに、混乱する場所があります。印刷された情報によると、オプション バイトの設定を更新した後にシステムがリセットされるはずですが、リセットされず、デモでは変更されませんオプションバイト。アップデートを再度読み込みます (おそらくデモ作成者はシステムがリセットされるのでアップデートする必要がないと考えているのでしょうか?)。その結果、表示されるメニューと実際の状況との間に矛盾が生じます。対応する機能を実行した後、下の図に示すように、menu.c に update ステートメントを追加して、この問題を解決します。
    ここに画像の説明を挿入
    もう一つ注意点がありますが、デモのオリジナルのFLASH書き込み関数FLASH_If_WriteはFLASH書き込み時にDOUBLEWORDモードを使用しているのですが、なぜF412ではHAL_ERRORを返す書き込みエラーが発生しやすいのか分かりません。書き込みモードをWORDモードに変更 この問題は解決されましたが、書き込み速度の低下にもつながります 修正・比較したコードは以下の通りです 移植完了後、FLASHの内部制御は以下のように割り当てられています: Sector0
    ここに画像の説明を挿入
    ~
    Sector1 : ブートローダー空間
    Sector2~Sector10: ユーザープログラム空間
    Sector11: 空き未使用 (ユーザープログラムが構成情報などを保存するために使用可能)

  5. 最後に、Ymodem.c ファイル内の ReceivePacket 関数を変更し、ハードウェアを使用して CRC を計算する部分をソフトウェア計算に置き換える必要があります。ルーチンには計算関数 Cal_CRC16 が用意されており、それを直接呼び出すだけです。
    ここに画像の説明を挿入

手順

ユーザプログラムをコンパイルする際の注意点は次の 2 点です。

  1. リンク時のリンクアドレスは、flash_if.hに設定したユーザプログラムの開始アドレスに合わせて調整してください IARやKeilを使用する場合は直接設定可能ですが、GCCを使用する場合はリンクファイルを直接変更する必要があります 方法は言うまでもありません、インターネット上にはたくさんあります。
  2. 割り込みベクタテーブルのオフセットを変更すると、割り込みジャンプに問題が発生しますので、HAL ライブラリを使用する場合は、system_stmf4xx.c のマクロ定義 VECT_TAB_OFFSET を変更してください。

コマンドインタラクションについて:

  1. 公式アプリケーションノート AN4657 で推奨されているターミナルツールは Tera Term ですが、実際に使ってみると難しすぎて使いづらいです。私自身のテストでは SecureCRT を使用しましたが、使用方法は似ています。アプリケーションノートを参照してください。転送されるファイルは .bin で終わるバイナリ ファイルであることに注意してください。.hex ファイルの転送は受け入れられません。通常、IDE には .bin ファイルを生成するオプションがあります。

キーコード分析

ユーザープログラムジャンプ

ここに画像の説明を挿入

上記はデモでのユーザプログラムのジャンプコードです stm32プログラムの構造上、プログラムの開始アドレスはSPスタックの開始アドレスとなります stm32のスタックはSRAM先頭に配置されているためアドレス 0x20000000 の SRAM のサイズは、128K STM32L476 の場合、SP 開始アドレスの可能な値は 0x20000000 ~ 0x2001FFFF です。if の比較ステートメントは、SP スタックの開始アドレスが開始アドレスに格納されているかどうかを比較します。プログラムのアドレス範囲がSRAMのアドレス範囲内にあるかどうかを判断します。0x2FFE0000 の値は 0x2FFFFFFF ~ 0x2001FFFF から取得されるため、この値も実際の SRAM メモリ サイズに応じて変更する必要があります。

if へのジャンプは比較的単純です。システム リセット ベクトルのアドレスは、プログラム開始アドレスの 4 バイト オフセットに格納されます。これは、最初に実行される命令のアドレスです。__set_MSP を呼び出して、MSP スタック ポインターを設定します。つまり、関数を呼び出すのと同じように最初の命令にジャンプして実行するだけで、実際にはここで PC ポインタが指されています。

ユーザープログラムのダウンロード処理

ユーザーがプログラムをダウンロードするためにメニューで 1 を選択すると、プログラム内の関数呼び出しチェーンは次のようになります。
ここに画像の説明を挿入

最終的に、関数 Ymodem_Receive は実際にプログラム データ パケットの受信作業を実行し、データ送信にエラーがなく、ファイルが受信されていない限り、継続的に ReceivePacket 関数を呼び出してデータを受信して​​分析します。 Ymodemプロトコルで送信されるパケットを受信し、処理結果に応じて応答します。

ユーザプログラムダウンロード処理におけるYmodemの通信処理全体を以下に示しますが、ベリファイエラーやFLASH書き込みエラーなどの異常な処理処理を除き、通常処理のみを記載しています。
ここに画像の説明を挿入

Ymodem をさらに理解するためにブログが提供されていますが、時間があり、包括的に理解したい場合は、公式ドキュメントのブログを読むことをお勧めします
: https://blog.csdn.net/huangdenan/article/details/ 103611081

ユーザープログラムのアップロード手順

一時的に未使用、分析なし。現時点では移植後のアップロード機能に問題があり、コードを読み込むだけで、このデモではユーザプログラムをアップロードする際に実際のプログラムサイズをアップロードするのではなく、ユーザ領域の内容をすべてアップロードします。それを使用するときは、いつかこの章を構成するために戻ってきます。

エピローグ

公式デモは何というか、あまりよく書かれているとは言えず、満足のいくものではありません。Cheng が外注されているのかどうかは非常に疑問です。このルーチンは学習、プログラム送信、FLASHプログラミング、ジャンプなどブートローダーの基本的な機能は揃っていますが、どうしても仕事で使いたい場合は自分でセットを書いた方が確実です。コード量も多くないので立ち上がるまでに時間はかかりません。とにかく時間をかけて自分で書くことにしました。
ブートローダーには他にも調査する価値のある側面がいくつかあります。

  • シリアルポート以外のインターフェース(USB、CANなど)経由でユーザープログラムを転送
  • ユーザプログラムのバージョンアップ失敗時の対応(ユーザ領域をAB領域に分割し、常に正常なユーザプログラムが利用できるようにする)
  • ブートローダー自体のアップグレード
  • 。。。。。。

おすすめ

転載: blog.csdn.net/lczdk/article/details/123341840