Nick
The bank allocation itself is controlled in IOMUXC_GPR_GPR17 and I set IOMUXC_GPR_GPR14 to a fixed 512k on the 1062 so that the full possible area is covered. Non-modulo sizes are valid since, for example, 448k DTC is a size that can be configured by eFUSE setting. According to the FlexRAM documentation, if you set a modulo value in IOMUXC_GPR_GPR14 that is "smaller" than the DTC any accesses above the size set with hard fault, so allocating 480k DTC and 256k in IOMUX_GPR_GPR14 would mean that only the first 256k of it could physically be accessed without a hard fault but setting it to the next largest (512k) allow all 480k to be accessed - therefore the decision to simply set to the largest possible modulo size.
I use a routine which configures the ITC/DTC according to the size of ITC requested (since I usually run all code in ITC) - that is, it allocates enough for the code that is to be run and any left over to DTC.
static unsigned char *fnConfigureFlexRAM(unsigned long ulCodeSize)
{
unsigned char *ptrTopOfRAM;
int i = 0;
unsigned long ulBankConfig = 0;
register unsigned long ulFlexRamConfig = (IOMUXC_GPR_GPR16_FLEXRAM_BANK_CFG_SEL_CFG | IOMUXC_GPR_GPR16_RESERVED);
volatile unsigned long ulRemapAddress = (unsigned long)IOMUXC_GPR_GPR16_ADD;
volatile register signed long slOffset;
int iOCRAM_banks = 0;
int iDTC_banks;
int iITC_banks;
#if !defined ENABLE_DATA_CACHE
int iOCRAM_banks_needed;
#endif
iITC_banks = ((ulCodeSize + (FLEX_RAM_GRANULARITY - 1))/FLEX_RAM_GRANULARITY);
iDTC_banks = (FLEX_RAM_BANKS - iITC_banks);
ptrTopOfRAM = (unsigned char *)(RAM_START_ADDRESS_DTC + (iDTC_banks * FLEX_RAM_GRANULARITY));
#if SIZE_OF_FLEX_RAM >= (512*1024)
IOMUXC_GPR_GPR14 = (IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_512K | IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_512K);
#elif SIZE_OF_FLEX_RAM >= (256*1024)
IOMUXC_GPR_GPR14 = (IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_256K | IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_256K);
#else
IOMUXC_GPR_GPR14 = (IOMUXC_GPR_GPR14_CM7_CFGITCMSZ_128K | IOMUXC_GPR_GPR14_CM7_CFGDTCMSZ_128K);
#endif
if ((iOCRAM_banks + iITC_banks + iDTC_banks) > FLEX_RAM_BANKS) {
_EXCEPTION("Too many RAM banks defined!");
}
#if defined iMX_RT1011
slOffset = -((1 - iDTC_banks) * FLEX_RAM_GRANULARITY);
#else
slOffset = -((FLEX_RAM_BANKS/2 - iDTC_banks) * FLEX_RAM_GRANULARITY);
#endif
#if !defined ENABLE_DATA_CACHE
iOCRAM_banks_needed = iOCRAM_banks;
#endif
if (iDTC_banks != 0) {
ulFlexRamConfig |= IOMUXC_GPR_GPR16_INIT_DTCM_EN;
}
if (iITC_banks != 0) {
ulFlexRamConfig |= IOMUXC_GPR_GPR16_INIT_ITCM_EN;
}
while (iITC_banks-- != 0) {
ulBankConfig |= (IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG_BANK0_ITCM << i);
i += 2;
}
while (iOCRAM_banks-- != 0) {
ulBankConfig |= (IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG_BANK0_OCRAM << i);
i += 2;
}
while (iDTC_banks-- != 0) {
ulBankConfig |= (IOMUXC_GPR_GPR17_FLEXRAM_BANK_CFG_BANK0_DTCM << i);
i += 2;
}
POWER_UP_ATOMIC(3, FLEXRAM1_CLOCK);
IOMUXC_GPR_GPR17 = ulBankConfig;
_SYNCHRONISATION_DATA_BARRIER();
slOffset -= ((RAM_START_ADDRESS - RAM_START_ADDRESS_DTC));
fnAdjustStackPointer((volatile unsigned long *)ulRemapAddress, ulFlexRamConfig, slOffset);
#if !defined ENABLE_DATA_CACHE
if (iOCRAM_banks_needed == 0) {
POWER_DOWN_ATOMIC(3, OCRAM_CLOCK);
}
#endif
return ptrTopOfRAM;
}
fnAdjustStackPointer() is a routine (partly assembler) that does the actual swap at run time and preserves the stack so that the change can be performed at any time during an operating program. Since the split is defined at run time rather than being fixed (eg. by eFUSEs or hard defines) it is very suitable for boot loader use to adapt to the actual application that is to operate. It runs compatibly on i.MX RT 1011...1064.
Attached is an "extract" from the uTasker i.MX RT 1060 user's manual explaining the FlexRAM layout strategy.
Regards
Mark
[uTasker project developer for Kinetis and i.MX RT]