Files
player/Project/Src/Drive/Source/mymem.c
andy eab38c8eff 添加tftp协议
1.usb连接上之后,可以使用tftp协议传输文件
2.解决写入sd卡时如果buff地址不是4字节对齐时数据错位的问题
2025-10-18 23:55:18 +08:00

564 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mymem.h"
#include "sdram.h"
#include "stm32f4xx.h"
// 定义是否使用ccm内存1使用0不使用
#define USE_CCM 0
#ifndef BOOTLOADER
#define OS_RTT
#ifdef OS_RTT
#include "rthw.h"
#define IRQ_DISABLE() rt_enter_critical()
#define IRQ_ENABLE() rt_exit_critical()
#else
#include "os.h"
#define IRQ_DISABLE() \
{ \
CPU_SR_ALLOC(); \
CPU_CRITICAL_ENTER(); \
}
#define IRQ_ENABLE() CPU_CRITICAL_EXIT()
#endif
#else
#define IRQ_DISABLE() \
{}
#define IRQ_ENABLE() \
{}
#endif
static void exmem_init(void); // 内存管理初始化函数
static uint32_t exmem_malloc(uint32_t size); // 内存分配
static uint8_t exmem_free(uint32_t offset); // 内存释放
static void mem_init(void); // 内存管理初始化函数
static uint32_t mem_malloc(uint32_t size); // 内存分配
static uint8_t mem_free(uint32_t offset); // 内存释放
static void ccm_init(void);
void mymem_init(void) {
mem_init();
exmem_init();
// ccm_init();
}
#define EXMEM_BLOCK_SIZE (256) // 内存块大小为64字节
#define EXMEM_MAX_SIZE \
((uint64_t)((SDRAM_USER_SIZE)) * EXMEM_BLOCK_SIZE / (EXMEM_BLOCK_SIZE + 2))
#define EXMEM_ALLOC_TABLE_SIZE \
((uint32_t)(EXMEM_MAX_SIZE / EXMEM_BLOCK_SIZE) & \
(~3)) // 内存表大小,必须为偶数,双字对齐
// 分配的内存都是双字对齐的
#define EXMEM_BASE ((uint8_t *)(SDRAM_USER_ADDR + EXMEM_ALLOC_TABLE_SIZE * 2))
#define EXMEMMAP_BASE ((uint16_t *)(SDRAM_USER_ADDR))
// 内存管理参数
uint32_t exmemtblsize; // 内存表大小
uint32_t exmemblksize; // 内存分块大小
uint64_t exmemsize; // 内存总大小
// 内存管理控制器
struct _m_mallco_dev exmallco_dev;
// 复制内存
//*des:目的地址
//*src:源地址
// n:需要复制的内存长度(字节为单位)
void mymemcpy(void *des, void *src, uint32_t n) {
uint8_t *xdes = des;
uint8_t *xsrc = src;
while (n--)
*xdes++ = *xsrc++;
}
// 设置内存
//*s:内存首地址
// c :要设置的值
// count:需要设置的内存大小(字节为单位)
void mymemset(void *s, uint8_t c, uint32_t count) {
uint8_t *xs = s;
while (count--)
*xs++ = c;
}
// 内存管理初始化
// memx:所属内存块
static void exmem_init(void) {
exmemtblsize = EXMEM_ALLOC_TABLE_SIZE; // 内存表大小
exmemblksize = EXMEM_BLOCK_SIZE; // 内存分块大小
exmemsize = EXMEM_MAX_SIZE; // 内存总大小
exmallco_dev.membase = EXMEM_BASE; // 内存池
exmallco_dev.memmap = EXMEMMAP_BASE; // 内存管理状态表
exmallco_dev.memrdy = 0; // 内存管理未就绪
mymemset(exmallco_dev.memmap, 0, exmemtblsize * 2); // 内存状态表数据清零
mymemset(exmallco_dev.membase, 0, exmemsize); // 内存池所有数据清零
exmallco_dev.memrdy = 1; // 内存管理初始化OK
}
// 获取内存使用率
// memx:所属内存块
// 返回值:使用率(0~100)
int exmem_perused(void) {
uint32_t used = 0;
uint32_t i;
for (i = 0; i < exmemtblsize; i++) {
if (exmallco_dev.memmap[i])
used++;
}
return (used * 10000) / (exmemtblsize);
}
// 内存分配(内部调用)
// memx:所属内存块
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
static uint32_t exmem_malloc(uint32_t size) {
signed long offset = 0;
uint32_t nmemb; // 需要的内存块数
uint32_t cmemb = 0; // 连续空内存块数
uint32_t i;
if (size == 0)
return 0XFFFFFFFF; // 不需要分配
// 获取需要分配的连续内存块数
nmemb = (size+exmemblksize-1) / exmemblksize;
for (offset = exmemtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区
{
if (!exmallco_dev.memmap[offset])
cmemb++; // 连续空内存块数增加
else
cmemb = 0; // 连续内存块清零
if (cmemb == nmemb) // 找到了连续nmemb个空内存块
{
for (i = 0; i < nmemb; i++) // 标注内存块非空
{
exmallco_dev.memmap[offset + i] = nmemb;
}
return (offset * exmemblksize); // 返回偏移地址
}
}
return 0XFFFFFFFF; // 未找到符合分配条件的内存块
}
// 释放内存(内部调用)
// memx:所属内存块
// offset:内存地址偏移
// 返回值:0,释放成功;1,释放失败;
static uint8_t exmem_free(uint32_t offset) {
// 偏移在内存池内.
if (offset < exmemsize) {
// 偏移所在内存块号码
uint32_t index = offset / exmemblksize;
// 内存块数量
uint32_t nmemb = exmallco_dev.memmap[index];
// 内存块清零
for (int i = 0; i < nmemb; i++) {
exmallco_dev.memmap[index + i] = 0;
}
return 0;
} else
return 2;
}
//------------------------------------内部SRAM---------------------------------------
#define SRAM_USER_SIZE (110 * 1024)
uint8_t g_sram_mem[SRAM_USER_SIZE];
#define MEM_BLOCK_SIZE (32) // 内存块大小为64字节
#define MEM_MAX_SIZE \
(((SRAM_USER_SIZE)) * MEM_BLOCK_SIZE / (MEM_BLOCK_SIZE + 2))
#define MEM_ALLOC_TABLE_SIZE \
((MEM_MAX_SIZE / MEM_BLOCK_SIZE) & (~3)) // 内存表大小,必须为偶数,双字对齐
#define SRAM_USER_ADDR ((uint32_t)g_sram_mem)
// 分配的内存都是双字对齐的
#define MEM_BASE ((uint8_t *)(SRAM_USER_ADDR + MEM_ALLOC_TABLE_SIZE * 2))
#define MEMMAP_BASE ((uint16_t *)(SRAM_USER_ADDR))
// 内存管理参数
uint32_t memtblsize; // 内存表大小
uint32_t memblksize; // 内存分块大小
uint32_t memsize; // 内存总大小
// 内存管理控制器
struct _m_mallco_dev mallco_dev;
// 内存管理初始化
// memx:所属内存块
static void mem_init(void) {
memtblsize = MEM_ALLOC_TABLE_SIZE; // 内存表大小
memblksize = MEM_BLOCK_SIZE; // 内存分块大小
memsize = MEM_MAX_SIZE; // 内存总大小
// mallco_dev.init=mem_init; //内存初始化
// mallco_dev.perused=mem_perused; //内存使用率
mallco_dev.membase = MEM_BASE; // 内存池
mallco_dev.memmap = MEMMAP_BASE; // 内存管理状态表
mallco_dev.memrdy = 0; // 内存管理未就绪
mymemset(mallco_dev.memmap, 0, memtblsize * 2); // 内存状态表数据清零
mymemset(mallco_dev.membase, 0, memsize); // 内存池所有数据清零
mallco_dev.memrdy = 1; // 内存管理初始化OK
}
// 获取内存使用率
// memx:所属内存块
// 返回值:使用率(0~100)
int mem_perused(void) {
uint32_t used = 0;
uint32_t i;
for (i = 0; i < memtblsize; i++) {
if (mallco_dev.memmap[i])
used++;
}
return (used * 10000) / (memtblsize);
}
// 内存分配(内部调用)
// memx:所属内存块
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
static uint32_t mem_malloc(uint32_t size) {
signed long offset = 0;
uint16_t nmemb; // 需要的内存块数
uint16_t cmemb = 0; // 连续空内存块数
uint32_t i;
// if(!mallco_dev.memrdy)mallco_dev.init();//未初始化,先执行初始化
if (size == 0)
return 0XFFFFFFFF; // 不需要分配
nmemb = size / memblksize; // 获取需要分配的连续内存块数
if (size % memblksize)
nmemb++;
for (offset = memtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区
{
if (!mallco_dev.memmap[offset])
cmemb++; // 连续空内存块数增加
else
cmemb = 0; // 连续内存块清零
if (cmemb == nmemb) // 找到了连续nmemb个空内存块
{
for (i = 0; i < nmemb; i++) // 标注内存块非空
{
mallco_dev.memmap[offset + i] = nmemb;
}
return (offset * memblksize); // 返回偏移地址
}
}
return 0XFFFFFFFF; // 未找到符合分配条件的内存块
}
// 释放内存(内部调用)
// memx:所属内存块
// offset:内存地址偏移
// 返回值:0,释放成功;1,释放失败;
static uint8_t mem_free(uint32_t offset) {
int i;
if (!mallco_dev.memrdy) // 未初始化,先执行初始化
{
// mallco_dev.init();
return 1; // 未初始化
}
if (offset < exmemsize) // 偏移在内存池内.
{
int index = offset / memblksize; // 偏移所在内存块号码
int nmemb = mallco_dev.memmap[index]; // 内存块数量
for (i = 0; i < nmemb; i++) // 内存块清零
{
mallco_dev.memmap[index + i] = 0;
}
return 0;
} else
return 2; // 偏移超区了.
}
//------------------------------------内部CCM---------------------------------------
#if USE_CCM == 1
#define CCM_USER_SIZE 64 * 1024
uint8_t g_ccm_mem[CCM_USER_SIZE] __attribute__((at(0x10000000)));
#define CCM_BLOCK_SIZE (32) // 内存块大小为64字节
#define CCM_MAX_SIZE (((CCM_USER_SIZE)) * CCM_BLOCK_SIZE / (CCM_BLOCK_SIZE + 2))
#define CCM_ALLOC_TABLE_SIZE \
((CCM_MAX_SIZE / CCM_BLOCK_SIZE) & (~3)) // 内存表大小,必须为偶数,双字对齐
#define CCM_USER_ADDR ((uint32_t)g_ccm_mem)
// 分配的内存都是双字对齐的
#define CCM_BASE ((uint8_t *)(CCM_USER_ADDR + CCM_ALLOC_TABLE_SIZE * 2))
#define CCMMAP_BASE ((uint16_t *)(CCM_USER_ADDR))
// 内存管理参数
uint32_t ccm_memtblsize; // 内存表大小
uint32_t ccm_memblksize; // 内存分块大小
uint32_t ccm_memsize; // 内存总大小
// 内存管理控制器
struct _m_mallco_dev ccm_mallco_dev;
// 内存管理初始化
// memx:所属内存块
static void ccm_init(void) {
ccm_memtblsize = CCM_ALLOC_TABLE_SIZE; // 内存表大小
ccm_memblksize = CCM_BLOCK_SIZE; // 内存分块大小
ccm_memsize = CCM_MAX_SIZE; // 内存总大小
ccm_mallco_dev.membase = CCM_BASE; // 内存池
ccm_mallco_dev.memmap = CCMMAP_BASE; // 内存管理状态表
ccm_mallco_dev.memrdy = 0; // 内存管理未就绪
mymemset(ccm_mallco_dev.memmap, 0, ccm_memtblsize * 2); // 内存状态表数据清零
mymemset(ccm_mallco_dev.membase, 0, ccm_memsize); // 内存池所有数据清零
ccm_mallco_dev.memrdy = 1; // 内存管理初始化OK
}
// 获取内存使用率
// memx:所属内存块
// 返回值:使用率(0~100)
int ccm_perused(void) {
uint32_t used = 0;
uint32_t i;
for (i = 0; i < ccm_memtblsize; i++) {
if (ccm_mallco_dev.memmap[i])
used++;
}
return (used * 10000) / (ccm_memtblsize);
}
// 内存分配(内部调用)
// memx:所属内存块
// size:要分配的内存大小(字节)
// 返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
static uint32_t ccm_malloc(uint32_t size) {
signed long offset = 0;
uint16_t nmemb; // 需要的内存块数
uint16_t cmemb = 0; // 连续空内存块数
uint32_t i;
// if(!mallco_dev.memrdy)mallco_dev.init();//未初始化,先执行初始化
if (size == 0)
return 0XFFFFFFFF; // 不需要分配
nmemb = size / ccm_memblksize; // 获取需要分配的连续内存块数
if (size % ccm_memblksize)
nmemb++;
for (offset = ccm_memtblsize - 1; offset >= 0; offset--) // 搜索整个内存控制区
{
if (!ccm_mallco_dev.memmap[offset])
cmemb++; // 连续空内存块数增加
else
cmemb = 0; // 连续内存块清零
if (cmemb == nmemb) // 找到了连续nmemb个空内存块
{
for (i = 0; i < nmemb; i++) // 标注内存块非空
{
ccm_mallco_dev.memmap[offset + i] = nmemb;
}
return (offset * ccm_memblksize); // 返回偏移地址
}
}
return 0XFFFFFFFF; // 未找到符合分配条件的内存块
}
// 释放内存(内部调用)
// memx:所属内存块
// offset:内存地址偏移
// 返回值:0,释放成功;1,释放失败;
static uint8_t ccm_free(uint32_t offset) {
int i;
if (!ccm_mallco_dev.memrdy) // 未初始化,先执行初始化
{
// mallco_dev.init();
return 1; // 未初始化
}
if (offset < exmemsize) // 偏移在内存池内.
{
int index = offset / ccm_memblksize; // 偏移所在内存块号码
int nmemb = ccm_mallco_dev.memmap[index]; // 内存块数量
for (i = 0; i < nmemb; i++) // 内存块清零
{
ccm_mallco_dev.memmap[index + i] = 0;
}
return 0;
} else
return 2; // 偏移超区了.
}
#endif
// 释放内存(外部调用)
// memx:所属内存块
// ptr:内存首地址
void myfree(void *ptr) {
IRQ_DISABLE();
uint32_t free_addr = (uint32_t)ptr;
uint32_t offset;
if (ptr == NULL) {
IRQ_ENABLE();
return; // 地址为0.
} else if ((free_addr & 0xf0000000) == 0x20000000) // sram
{
offset = (uint32_t)ptr - (uint32_t)mallco_dev.membase;
mem_free(offset); // 释放内存
} else {
offset = (uint32_t)ptr - (uint32_t)exmallco_dev.membase;
exmem_free(offset); // 释放内存
}
// printf ("free:%#X\r\n",free_addr);
IRQ_ENABLE();
}
// 分配内存(外部调用)
// 首先尝试在内部分配,失败后再外部分配
// size:内存大小(字节)
// 返回值:分配到的内存首地址.
void *mymalloc(size_t size) {
IRQ_DISABLE();
uint32_t offset;
void *ret_addr = NULL;
if (size > 5 * 1024)
offset = 0XFFFFFFFF;
else
offset = mem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)mallco_dev.membase + offset);
} else {
offset = exmem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)exmallco_dev.membase + offset);
}
}
// printf ("malloc:%#X,%d\r\n",(uint32_t)ret_addr,size);
IRQ_ENABLE();
return ret_addr;
}
// 分配内存(外部调用)
// 首先尝试在内部分配,失败后再外部分配
// size:内存大小(字节)
// 返回值:分配到的内存首地址.
void *mymalloc_fast(uint32_t size) {
IRQ_DISABLE();
uint32_t offset;
void *ret_addr = NULL;
offset = mem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)mallco_dev.membase + offset);
} else {
offset = exmem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)exmallco_dev.membase + offset);
}
}
// printf ("malloc:%#X,%d\r\n",(uint32_t)ret_addr,size);
IRQ_ENABLE();
return ret_addr;
}
// 分配外部内存(外部调用)
// 首先尝试在内部分配,失败后再外部分配
// size:内存大小(字节)
// 返回值:分配到的内存首地址.
void *mymalloc_exm(uint32_t size) {
IRQ_DISABLE();
uint32_t offset;
void *ret_addr = NULL;
offset = exmem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)exmallco_dev.membase + offset);
}
IRQ_ENABLE();
return ret_addr;
}
#if USE_CCM == 1
// 释放CCM内存
void myfree_ccm(void *ptr) {
IRQ_DISABLE();
uint32_t free_addr = (uint32_t)ptr;
uint32_t offset;
if (ptr == NULL) {
IRQ_ENABLE();
return; // 地址为0.
} else if ((free_addr & 0xf0000000) == 0x10000000) // sram
{
offset = (uint32_t)ptr - (uint32_t)ccm_mallco_dev.membase;
ccm_free(offset); // 释放内存
} else {
offset = (uint32_t)ptr - (uint32_t)exmallco_dev.membase;
exmem_free(offset); // 释放内存
}
// printf ("free:%#X\r\n",free_addr);
IRQ_ENABLE();
}
// 分配CCM内存
void *mymalloc_ccm(uint32_t size) {
IRQ_DISABLE();
uint32_t offset;
void *ret_addr = NULL;
offset = ccm_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)ccm_mallco_dev.membase + offset);
} else {
offset = exmem_malloc(size);
if (offset != 0XFFFFFFFF) {
ret_addr = (void *)((uint32_t)exmallco_dev.membase + offset);
}
}
IRQ_ENABLE();
return ret_addr;
}
#endif
// 重新分配内存(外部调用)
// memx:所属内存块
//*ptr:旧内存首地址
// size:要分配的内存大小(字节)
// 返回值:新分配到的内存首地址.
void *myrealloc(void *ptr, uint32_t size) {
IRQ_DISABLE();
void *ret_addr;
ret_addr = mymalloc_exm(size);
if (ret_addr != NULL) {
if (ptr != NULL) {
mymemcpy(ret_addr, ptr, size);
myfree(ptr);
}
}
IRQ_ENABLE();
return ret_addr;
}
// 分配内存并清零
void *mycalloc(uint32_t size) {
void *ptr = mymalloc(size);
if (ptr)
mymemset(ptr, 0, size);
return ptr;
}
////////////////////////////////////////////////////////////////////////////////
// 基本调用接口
void *malloc(size_t size) { return mymalloc(size); }
void free(void *ptr) { myfree(ptr); }
void *realloc(void *ptr, size_t size) { return myrealloc(ptr, size); }
void *calloc(size_t nmemb, size_t size) { return mycalloc(nmemb * size); }