RAMの割当
RAMの割当
RAMの割当について記述しています。
MCUXpresso の C/C++ Build>MCU Settings の諸機能とは互換性がありません。RAMの割り当てについて変更などを行う場合は、リンカスクリプトのユーザ定義を記述する、または、
TWENETmcs/linker/linkscripts
以下のリンカスクリプトを変更します。RAMの割当
TWWLIET GOLD の SRAM 領域は以下のようになっています。
BASE | TOP(末尾+1) | SIZE | |
---|---|---|---|
SRAM11 | 0x0402_C000 | 0x0403_0000 | 16KB |
SRAM10 | 0x0402_8000 | 0x0402_C000 | 16KB |
SRAM9 | 0x0402_4000 | 0x0402_8000 | 16KB |
SRAM8 | 0x0402_0000 | 0x0402_4000 | 16KB |
SRAM7 | 0x0401_5000 | 0x0401_6000 | 4KB |
SRAM6 | 0x0401_4000 | 0x0401_5000 | 4KB |
SRAM5 | 0x0401_2000 | 0x0401_4000 | 8KB |
SRAM4 | 0x0401_0000 | 0x0401_2000 | 8KB |
SRAM3 | 0x0400_C000 | 0x0401_0000 | 16KB |
SRAM2 | 0x0400_8000 | 0x0400_C000 | 16KB |
SRAM1 | 0x0400_4000 | 0x0400_8000 | 16KB |
SRAM0 | 0x0400_0000 | 0x0400_4000 | 16KB |
TWENET ではメモリマップを以下のように定義しています。
BASE | TOP | サイズ | 用途 | RET | バンク名 | |
---|---|---|---|---|---|---|
アプリケーション利用 | 0x0400_0000 | コンパイル時に決定 | ~64KB | MMACのリンク時に必要 | 〇 | SRAM0..3 |
ヒープ | 0x0401_5000 (変更可) | 0x0401_5C00 | 3KB | ヒープ領域 (malloc, new) | 〇 | SRAM7 |
未使用 | 0x0402_0000 | 0x0402_C000 | 48KB | 未使用領域 | SRAM8,9,10 SRAM11 | |
未使用 | 0x0402_C000 | 0x0402_F000 | 12KB | 未使用領域 | SRAM11 | |
スタック | 0x0402_F000 | 0x0403_0000 | 4KB | スタック領域 | SRAM11 | |
(BASE: 開始アドレス, TOP: 終了アドレス+1, RET: スリープ時のRAM保持)
- アプリケーション利用領域は、コンパイル時に決まる静的なメモリ範囲です。末尾アドレスは
(uint32)&_end_fw_retention
にて参照できます。スリープ時には末尾アドレスをもとに不要なバンクを保持しないように設定してます。 - ヒープ領域は、
malloc()
やnew
演算子で確保される領域です。一般論として領域補確保・解放を繰り返すと断片化が問題になり、これを意識してアプリケーションの実装を行います。規定ではメモリの割り当てをSRAMのバンク7としています。ただし、バンク7の末尾512バイトはマイコン半導体の仕様で、続く512バイトはTWENETにて予約しています。- この領域は
App_User_Defs.ld
(build ディレクトリ直下に配置する) にHEAP_START=0x04014000;
HEAP_SIZE = 8192 - BANK7_RESERVE;
のように記述することで調整できます。HEAP_START
はヒープの開始アドレス、HEAP_SIZE
は確保サイズです。代表的な組み合わせを挙げます。- 0x04014000, 8192-BANK7_RESERVE(7KB, BANK6-7)
- 0x04012000,16384-BANK7_RESERVE(15KB, BANK5-7)
- 0x04010000,24576-BANK7_RESERVE(23KB, BANK4-7)
- 0x0,0 (最大限、つまり
_end_fw_rentention
から 0x04016000-BANK7_RESERVE までの領域をHEAPに設定する)
- この領域は
- 未使用領域は、SRAM8,9,10 の各16KBです。
- スタック領域は、SRAM11 の一番最後 (
0x0403_0000
)から 4096 バイトを規定として確保しています。- この領域は
App_User_Defs.ld
(build ディレクトリ直下に配置する) にSTACK_SIZE = 8192;
のように記述すると、サイズを変更することができます。またSTACK_TOP = 0x04024000;
のように、末尾アドレスを指定できます。 - build ディレクトリに作成される mapファイルの
_vStackTop
__StackLimit
を確認してください。 - この領域はスリープ時に保持されません。
- この領域は
スリープ時の保持領域の設定
アプリケーション利用領域やヒープ領域は、TWENETライブラリ内でスリープ時に保持すべきSRAMバンクを適切に設定しています。アプリケーションの設計や実装によっては、保持されないバンクを保持状態にしたい場合もあります。TWENETcmptライブラリ中に定義されるグローバル変数 G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD()
に、追加的に必要なバンクに対応するビットをセットしておきます。
例えばバンク8,9の32KBを保持したい場合は、TWENET CライブラリのToCoNet_vSleep()
や mwx ライブラリのthe_twelite.sleep()
呼び出し前に以下を指定します。
G_TWENET_POWER_DOWN_RETENTION_CONFIG_ADD() = PM_CFG_SRAM_BANK8_RET | PM_CFG_SRAM_BANK9_RET;
※ 保持するSRAM領域が増えると、その分スリープ電流が増加します。
App_User_Defs.ld 設定例
未指定時は HEAP は 0x0401_5000
から0x0401_5FE0
、STACKは 0x0402_F000
から0x0403_0000
となります。以下に .../build/App_User_Defs.ld
の設定例を記載します。
- HEAPを
_end_fw_retention
から0x0401_5FE0
まで最大限確保する。
HEAP_START = 0;
HEAP_SIZE = 0;
- RAM6,7にHEAPを確保する (約8KB)。
HEAP_START = 0x04014000;
HEAP_SIZE = 8192 - BANK7_RESERVE;
- HEAPを
_end_fw_retention
から0x0401_5000
まで、STACKを0x0401_5000
から0x0401_5FE0
とする。(0x0402_0000
から0x0403_0000
のBANK8..11を未使用領域にする)
HEAP_TOP = 0x04015000;
HEAP_START = 0;
HEAP_SIZE = 0;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
注:HEAP_START
とHEAP_SIZE
がともに0の場合 HEAP_TOP
を設定できます。この場合 HEAP_TOP
は0x0402_0000
以上の領域には設定できません。
- HEAP領域に
0x0402_0000
から64KB確保しSTACK領域は0x04015fe0
以下の領域に移動する。
HEAP_START = 0x04020000;
HEAP_SIZE = 0x10000;
STACK_TOP = 0x04015fe0;
STACK_SIZE = 4096-BANK7_RESERVE;
OneTime_Heap.c,h
TWENETutils には、メモリ破棄を行わず順番にメモリを確保するための One Time Heap を用意しています。未使用領域の利用を容易にするものです。
#include <OneTimeHeap.h>
OTHEAP_tsContext scOTHeap;
void setup() {
uint32 u32bytes;
void *p;
// 0x0402_0000 から 0x0402_4000 の 16KB 領域を利用する。
OTHEAP_Init(&scOTHeap, 0x04020000, 0x04024000, NULL);
Serial << crlf << "--- One Time HEAP ---";
Serial << crlf << format("start %08x", (uint32)OTHEAP_pvGetRegionStart(&scOTHeap));
Serial << crlf << format("top %08x", (uint32)OTHEAP_pvGetRegionTop(&scOTHeap));
// 100バイト確保する
u32bytes = 100;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_0004 (4バイトのヘッダの後が利用可能)
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// ヘッダは次のブロックのアドレス (0x0402_0068)
// 10バイト確保する (4バイト境界に配置されるため実際は12バイト)
u32bytes = 10;
Serial << crlf;
Serial << crlf << format("head %08x", (uint32)OTHEAP_pvGetHead(&scOTHeap));
p = OTHEAP_pvAlloc(&scOTHeap, u32bytes, TRUE);
// p=0x0402_006c
Serial << crlf << format("alloc %dbytes [%08x->%08x)", u32bytes, (uint32)p, (uint32)p+u32bytes);
if(p) Serial << crlf << format("next %08x", *(uint32*)((uint32)p - 4));
// ヘッダは次のブロックのアドレス (0x0402_0078)
// 最後に確保されたブロックを開放する。解放されたブロックのアドレス(p=0x0402_006c)
p = OTHEAP_pvFreeLastBlock(&scOTHeap);
}