DynamicLoad - プログラムの動的読み込み

DynamicLoad - プログラムの動的読み込み

バイナリファイルを読み込んで、Flashへ自己書き込みし、そのコードを実行するテストです。

Load the binary file, and then programming the Flash, then run the code.

Import programDynamicLoad

dynamic load and run users binary file. self write the flash memory.

how to make binary

読み込むバイナリファイルは mbed 環境では作ることができないので、 Sourcery G++ Lite でコンパイルします。

コンパイルしてできた.binファイルを、ファイル名 "test.dat" として mbedのUSBストレージ(USBメモリ)へ保存しておきます。

compiled.bin rename to "test.dat", and save to mbed USB strage (USB memory).

リンカースクリプトを編集しFlashの 0x00040000 番地からコードが始まるようにします。 (このサンプルではファイルを読み込むアドレスを 0x00040000 としているため)

Linker script:

lpc17xx.ld

  IROM (rx) : ORIGIN = 0x00040000, LENGTH = 256k

  IRAM0 (rwx) : ORIGIN = 0x10002000, LENGTH = 24k

or

ldscript_gnu.ld

  rom (rx)  : ORIGIN = 0x00040000, LENGTH = 256K
  ram (rwx) : ORIGIN = 0x10002000, LENGTH =  24K

Information

メモリーマップに注意! mbedの Heap はRAMの先頭アドレスから、Stack は最後尾アドレスから。 読み込むプログラムがRAMの内容を破壊しないよう .heap や .stack の定義を確認してください。

スタートアップのコードを編集し、リセットハンドラを割り込みではなく単なる関数にします。 そしてシステムの初期化ルーチンを再実行しないようにします。

Startup file:

startup_LPC17xx.c

//void Reset_Handler(void) __attribute__((__interrupt__));
void Reset_Handler(void);

//    SystemInit();

or

startup_LPC17xx.s

/*    LDR     R0, =SystemInit */
/*    BLX     R0 */

Sample:

LED1 を点滅するサンプル。

sample.c

#include "LPC17xx.h"

volatile uint32_t TimeTick = 0;

void SysTick_Handler(void) {
	if (TimeTick) TimeTick --;
}

int main (void) {
	int i;

	LPC_PINCON->PINSEL3 &= (~(3 << 4)); // P1_18 GPIO
	LPC_GPIO1->FIODIR |= (1 << 18); // P1_18 Output

	SysTick_Config(SystemCoreClock / 1000); // SysTick Timer 1ms

	for (;;) {
		for (i = 0; i < 5; i ++) {
			LPC_GPIO1->FIOSET = (1 << 18); // LED ON
			TimeTick = 500;
			while (TimeTick);

			LPC_GPIO1->FIOCLR = (1 << 18); // LED OFF
			TimeTick = 500;
			while (TimeTick);
		}
	}

	return 0;
}

make して、mbedのUSBストレージへ "test.dat" というファイル名で保存します。

DynamicLoad もmbed環境でコンパイルし、mbedへ書き込みます。

mbedをリセットし、DynamicLoad が実行されると、test.dat を読み込み、プログラムの実行が test.dat に移ります。

参考


3 comments on DynamicLoad - プログラムの動的読み込み:

09 May 2015

とても有用なプログラムを公開していただき、ありがとうございます。 2つ質問をさせてください。 ロードされる側のプログラムのリンカスクリプトで、RAM領域を0x10002000から24KB、と定義していて、 これによってHeap領域が0x10002000から後が使われますが、ロードする側のプログラムのHeap領域は0x10000000からで、それとは重ならないように後にずらしている、という理解でよろしいでしょうか。

またStack領域は、そもそもRAM領域の最後尾アドレスから使われるので、両プログラムとも共通にしてもよい(StackへのPush/Popは(両プログラムで共通の)スタックポインタを使って行われるため、両プログラムでスタックされるデータが重なることはない)、という理解でよろしいでしょうか。

11 Aug 2015

これを作ったときから時間がたっていて、なぜこうしたか記憶があいまいなのですが・・・

Heapは、ご指摘の通り、重ならないようにです。  Heapはスタートアップルーチンでメモリの確保が行われますので、アドレスをちゃんと指定しておくようにします。

Stackもご指摘の通り、Push/Popするだけなのでデータが重なることはないので、特に何もしていません。

ロードして呼び出すプログラムが、呼び出し元のプログラムへ戻らないとするならば、同じメモリアドレスを使ってもいいかもしれません。

11 Aug 2015

ところで、このプログラムには少々不具合があります。 IAPライブラリのページで Tedd OKANO さんも追記されていますが、IAPを呼び出しているところに

  __disable_irq()
     :
  __enable_irq()

を入れてください。

Please log in to post comments.