STM32F7xx —— 記憶體管理
目的:高效、快速的配置設定,并在适當的時候回收記憶體資源。最終就是實作malloc和free函數。(實作方法參考原子哥)
#define CONFIG_SRAM_OUT_ENABLE 0
typedef enum
{
SRAM_TYPE_IN, // 内部記憶體池
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_YPE_OUT, // 外部記憶體池(SDRAM)
#endif
SRAM_TYPE_DTCM, // DTCM記憶體池(此部分SRAM僅僅CPU可以通路!!!)
SRAM_TYPE_MAX, // 最多支援的SRAM塊數.
} sram_type_t;
// 内部SRAM
#define SRAM_IN_BLOCK_SIZE 64 // 記憶體塊大小為64位元組
#define SRAM_IN_MAX_SIZE (160 * 1024) // 最大管理記憶體160K
#define SRAM_IN_ALLOC_TABLE_SIZE (SRAM_IN_MAX_SIZE / SRAM_IN_BLOCK_SIZE)
#if(CONFIG_SRAM_OUT_ENABLE == 1)
// 外部SDRAM裡面
#define SRAM_OUT_BLOCK_SIZE 64 // 記憶體塊大小為64位元組
#define SRAM_OUT_MAX_SIZE (100 *1024) // 最大管理記憶體100K
#define SRAM_OUT_ALLOC_TABLE_SIZE (SRAM_OUT_MAX_SIZE / SRAM_OUT_BLOCK_SIZE)
#endif
// CCM,用于管理DTCM(特别注意,這部分SRAM,僅CPU可以通路!!)
#define SRAM_DTCM_BLOCK_SIZE 64 //記憶體塊大小為64位元組
#define SRAM_DTCM_MAX_SIZE (100 *1024) //最大管理記憶體60K
#define SRAM_DTCM_ALLOC_TABLE_SIZE (SRAM_DTCM_MAX_SIZE/SRAM_DTCM_BLOCK_SIZE)
//記憶體池(32位元組對齊)
__align(32) uint8_t sram_in_base[SRAM_IN_MAX_SIZE]; // 内部SRAM記憶體池
uint32_t sram_in_map_base[SRAM_IN_ALLOC_TABLE_SIZE];
#if(CONFIG_SRAM_OUT_ENABLE == 1)
__align(32) uint8_t sram_out_base[SRAM_OUT_MAX_SIZE] __attribute__((at(0xC01F4000))); // 外部SDRAM記憶體池
uint32_t sram_out_map_base[SRAM_OUT_ALLOC_TABLE_SIZE] __attribute__((at(0xC01F4000 + SRAM_OUT_MAX_SIZE))); // 外部SRAM記憶體池MAP
#endif
__align(32) uint8_t sram_dtcm_base[SRAM_DTCM_MAX_SIZE] __attribute__((at(0x20000000))); // 内部DTCM記憶體池
uint32_t sram_dtcm_map_base[SRAM_DTCM_ALLOC_TABLE_SIZE] __attribute__((at(0x20000000 + SRAM_DTCM_MAX_SIZE))); //内部DTCM記憶體池MAP
static const uint32_t memtblsize[SRAM_TYPE_MAX] = {SRAM_IN_ALLOC_TABLE_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_ALLOC_TABLE_SIZE,
#endif
SRAM_DTCM_ALLOC_TABLE_SIZE
}; //記憶體表大小
static const uint32_t memblksize[SRAM_TYPE_MAX] = {SRAM_IN_BLOCK_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_BLOCK_SIZE,
#endif
SRAM_DTCM_BLOCK_SIZE
}; //記憶體分塊大小
static const uint32_t memsize[SRAM_TYPE_MAX] = {SRAM_IN_MAX_SIZE,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
SRAM_OUT_MAX_SIZE,
#endif
SRAM_DTCM_MAX_SIZE
}; //記憶體總大小
void mymem_init(uint8_t type);
uint16_t mymem_perused(uint8_t type);
typedef struct
{
void (* init)(uint8_t );
uint16_t (* perused)(uint8_t); // 記憶體使用率
uint8_t *membase[SRAM_TYPE_MAX]; // 記憶體池 管理SRAMBANK個區域的記憶體
uint32_t *memmap[SRAM_TYPE_MAX]; // 記憶體管理狀态表
uint8_t memrdy[SRAM_TYPE_MAX]; // 記憶體管理是否就緒
} sram_dev_t;
//記憶體管理控制器
static sram_dev_t sram_dev =
{
mymem_init, // 記憶體初始化
mymem_perused, // 記憶體使用率
sram_in_base,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
sram_out_base,
#endif
sram_dtcm_base, // 記憶體池
sram_in_map_base,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
sram_out_map_base,
#endif
sram_dtcm_map_base,
0,
#if(CONFIG_SRAM_OUT_ENABLE == 1)
0,
#endif
0,
};
// 記憶體管理初始化
static void mymem_init(uint8_t memx)
{
memset(sram_dev.memmap[memx], 0, memtblsize[memx] * 4); // 記憶體狀态表資料清零
sram_dev.memrdy[memx] = 1; // 記憶體管理初始化OK
}
// 擷取記憶體使用率
// type:所屬記憶體塊
// 傳回值:使用率(擴大了10倍,0~1000,代表0.0%~100.0%)
static uint16_t mymem_perused(uint8_t type)
{
uint32_t used = 0;
uint32_t i;
for(i = 0; i < memtblsize[type]; ++i)
{
if(sram_dev.memmap[type][i])
{
used++;
}
}
return (used * 1000) / (memtblsize[type]);
}
// 記憶體配置設定(内部調用)
// type:所屬記憶體塊
// size:要配置設定的記憶體大小(位元組)
// 傳回值:0XFFFFFFFF,代表錯誤;其他,記憶體偏移位址
static uint32_t mymem_malloc(uint8_t type, uint32_t size)
{
signed long offset = 0;
uint32_t nmemb; // 需要的記憶體塊數
uint32_t cmemb = 0; // 連續空記憶體塊數
uint32_t i;
if(!sram_dev.memrdy[type])
{
sram_dev.init(type); // 未初始化,先執行初始化
}
if(size == 0)
{
return 0xFFFFFFFF; // 不需要配置設定
}
nmemb = size / memblksize[type]; // 擷取需要配置設定的連續記憶體塊數
if(size % memblksize[type])
{
nmemb++;
}
for(offset = memtblsize[type] - 1; offset >= 0; offset--) // 搜尋整個記憶體控制區
{
if(!sram_dev.memmap[type][offset])
{
cmemb++; // 連續空記憶體塊數增加
}
else
{
cmemb = 0; // 連續記憶體塊清零
}
if(cmemb == nmemb) // 找到了連續nmemb個空記憶體塊
{
for(i = 0; i < nmemb; i++) // 标注記憶體塊非空
{
sram_dev.memmap[type][offset + i] = nmemb;
}
return (offset * memblksize[type]); // 傳回偏移位址
}
}
return 0xFFFFFFFF; // 未找到符合配置設定條件的記憶體塊
}
// 釋放記憶體(内部調用)
// type:所屬記憶體塊
// offset:記憶體位址偏移
// 傳回值:0,釋放成功;1,釋放失敗;
static uint8_t mymem_free(uint8_t type, uint32_t offset)
{
int i;
if(!sram_dev.memrdy[type])// 未初始化,先執行初始化
{
sram_dev.init(type);
return 1;// 未初始化
}
if(offset < memsize[type]) // 偏移在記憶體池内.
{
int index = offset / memblksize[type]; // 偏移所在記憶體塊号碼
int nmemb = sram_dev.memmap[type][index]; // 記憶體塊數量
for(i = 0; i < nmemb; i++) // 記憶體塊清零
{
sram_dev.memmap[type][index + i] = 0;
}
return 0;
}
else
{
return 2; // 偏移超區了.
}
}
void MemInit(uint8_t type)
{
memset(sram_dev.memmap[type], 0, memtblsize[type] * 4); // 記憶體狀态表資料清零
sram_dev.memrdy[type] = 1; // 記憶體管理初始化OK
}
// 釋放記憶體(外部調用)
// type:所屬記憶體塊
// ptr:記憶體首位址
void MemFree(uint8_t type, void *ptr)
{
uint32_t offset;
if(ptr == NULL)
{
return; // 位址為0.
}
offset = (uint32_t)ptr - (uint32_t)sram_dev.membase[type];
mymem_free(type, offset); // 釋放記憶體
}
// 配置設定記憶體
void *MemAlloc(uint8_t type, uint32_t size)
{
uint32_t offset;
offset = mymem_malloc(type, size);
if(offset == 0XFFFFFFFF)
{
return NULL;
}
else
{
return (void*)((uint32_t)sram_dev.membase[type] + offset);
}
}
// 重新配置設定記憶體
void *MemRealloc(uint8_t type, void *ptr, uint32_t size)
{
uint32_t offset;
offset = mymem_malloc(type, size);
if(offset == 0xFFFFFFFF)
{
return NULL;
}
else
{
memcpy((void*)((uint32_t)sram_dev.membase[type] + offset), ptr, size); // 拷貝舊記憶體内容到新記憶體
MemFree(type, ptr); // 釋放舊記憶體
return (void*)((uint32_t)sram_dev.membase[type] + offset); // 傳回新記憶體首位址
}
}