This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28375D:不返回 FREE()

Guru**** 2568585 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/977322/tms320f28375d-free-does-not-return

器件型号:TMS320F28375D

我有一个大型、复杂的项目、该项目中的一段代码使用动态内存分配。  有时,当我更改代码的不相关部分时,这会导致具有动态内存分配的部分中的 FREE()函数永远不会返回。  我要修改的不相关代码是.ebss 存储器块中的一个大型静态结构。  在项目设置中堆大小定义为0x2000、.esysmem 块映射到 RAMGS0-1、我已将其配置为从地址0xC000开始的0x2000大小块。  .ebss 位于 RAMGS3-10中(长度0x8000、从0xF000开始)。

是否有什么可能导致 free()崩溃的想法? 或有关如何调试它的建议?

以下是我的 cmd 文件。

//########################################################################################################################
//
////文件:dual_axis_f2837x_flash_lnk_cpu1.cmd.cmd
//
////##########################################################################
//$TI 发布:MotorControl SDK v3.00.01.00美元
//$发布 日期:星期二5月26日19:13:59 CDT 2020 $
//版权所有:
//版权所有(C) 2017-2020德州仪器(TI)公司- http://www.ti.com/
//

只要
满足以下条件,就允许以源代码和二进制形式重新分发和使用//修改或不修改//:
//
//重新分发源代码必须保留上述版权
//声明、此条件列表和以下免责声明。
//
//二进制形式的再发行必须复制上述版权
//声明、此条件列表和//

分发随附的//文档和/或其他材料中的以下免责声明。
////
未经

事先书面许可,不能使用德州仪器公司的名称或//其贡献者的名称来认可或推广源自此软件的产品//。
////
本软件由版权所有者和贡献者提供
//“按原样”,不

承认任何明示或暗示的保证,包括但不限于//适销性和对//特定用途适用性的暗示保证。 在任何情况下、版权
//所有者或贡献者都不对任何直接、间接、偶然、
//特殊、模范、 或相应的损害(包括但不
限于采购替代产品或服务;丧失使用、
//数据或利润; 或业务中断)、无论

出于何种原因使用
本软件(即使被告知可能会造成此类损坏)、还是出于任何原因而产生的任何//责任理论(无论是合同、严格责任还是侵权行为)//(包括疏忽或其他)。
//$
//########################################################################################################################
//除了这个内存连接器命令文件之外,
//将头连接器命令文件直接添加到项目中。
//将
//外设结构链接到
//内存映射中的适当位置需要使用头链接器命令文件。
//
//对于 BIOS 应用程序,添加: F28004x_Headers_BIOS.cmd
//对于非 BIOS 应用添加:F28004x_Headers_nonBIOS.cmd
//
如果使用
// CLA C 编译器
//项目属性-> C2000链接器->高级选项->命令文件
//预处理->--,用户必须在项目链接器设置中定义 CLA_C define
#ifdef CLA_C
//定义
将由 CLA 编译器用于局部符号和 temps 的 CLA 暂存区的大小
//还强制引用标记
了//暂存区的特殊符号。
CLA_ScratchPad_size = 0x100;
--undef_sym=__cla_scratchpad_end
--undef_sym=_cla_scratchpad_start
#endif //cla_C


MEMORY
{
PAGE 0://程序存储器*/
/*内存(RAM/FLASH)块可移动到 Page1进行数据分配*/
/* begin 用于"引导至闪存"引导加载程序模式*/

begin:origin = 0x080000、length = 0x000002
RAMM0:origin = 0x000123,length = 0x0002DD
RAMD0:origin = 0x00B000、length = 0x000800
RAMLS0:origin = 0x008000、length = 0x001800
// RAMLS1:origin = 0x008800,length = 0x000800
// RAMLS2:origin = 0x009000、length = 0x000800
RAMLS3:origin = 0x009800,length = 0x000800
RAMLS4:origin = 0x00A000、length = 0x000800
RAMGS14 :origin = 0x01A000、length = 0x001000 /*仅在 F28379D、F28377D、F28375D 器件上可用。 移除其他设备上的线路。 */
RAMGS15 :origin = 0x01B000、length = 0x000FF8 /*仅在 F28379D、F28377D、F28375D 器件上可用。 移除其他设备上的线路。 //

RAMGS15_RSVD :origin = 0x01BFF8,length = 0x000008 //保留并不用于代码,根据勘误咨询“内存:有效内存之外的预取”*/

重置:origin = 0x3FFFC0、length = 0x000002

//闪存扇区*/
FLASHA :origin = 0x080002、length = 0x001FFE//片上闪存*/
FLASHB :origin = 0x082000、length = 0x002000//片上闪存*/
FLASHC :origin = 0x084000、length = 0x002000//片上闪存*/
FLASHD :origin = 0x086000、length = 0x002000//片上闪存*/
FLASHE :origin = 0x088000、length = 0x008000//片上闪存*/
FLASHF :origin = 0x090000、length = 0x008000//片上闪存*/
FLASHG :origin = 0x098000、length = 0x008000//片上闪存*/
FLASHH :origin = 0x0A0000、length = 0x008000//片上闪存*/
FLASHI :origin = 0x0A8000、length = 0x008000//片上闪存*/
FLASHJ :origin = 0x0B0000、length = 0x008000//片上闪存*/
FLASHK :origin = 0x0B8000、length = 0x002000//片上闪存*/
FLASHL :origin = 0x0BA000、length = 0x002000//片上闪存*/
FLASHM :origin = 0x0BC000、length = 0x002000//片上闪存*/
FLASHN :origin = 0x0BE000、length = 0x001FF0/*片上闪存*/

// FLASHN_RSVD :origin = 0x0BFFF0,length = 0x000010 //根据勘误咨询“Memory:Prepetching Beyond valid Memory”(内存:有效内存之外的预取)来保留并不用于代码*/

页1:/* Data Memory */
/*内存(RAM/FLASH)块可移动到 PAGE0进行程序分配*/

BOOT_RSVD :origin = 0x000002、length = 0x000121 // M0的一部分,引导 ROM 将此用于栈*/
RAMM1 :origin = 0x000400、length = 0x0003F8 /*片上 RAM 块 M1 *//
RAMM1_RSVD :origin = 0x0007F8,length = 0x000008 /*根据勘误咨询"Memory:Prepetching Beyond Valid Memory"(内存:有效内存之外的预取)来保留和不用于代码*/
RAMD1 :origin = 0x00B800,length = 0x000800

RAMLS5 :origin = 0x00A800,length = 0x000800

RAMGS0 :origin = 0x00C000、length = 0x002000
// RAMGS1 :origin = 0x00D000、length = 0x001000
RAMGS2 :origin = 0x00E000、length = 0x001000
RAMGS3 :origin = 0x00F000、length = 0x008000
// RAMGS4 :origin = 0x010000,length = 0x001000
// RAMGS5 :origin = 0x011000,length = 0x001000
// RAMGS6 :origin = 0x012000,length = 0x001000
// RAMGS7 :origin = 0x013000、length = 0x001000
// RAMGS8 :origin = 0x014000、length = 0x001000
// RAMGS9 :origin = 0x015000,length = 0x001000
// RAMGS10 :origin = 0x016000,length = 0x001000

// RAMGS11 :origin = 0x017000、length = 0x000FF8 //取消对 F28374D、F28376D 器件的注释*//

RAMGS11_RSVD:origin = 0x017FF8,length = 0x000008 //根据勘误表中的“Memory:Prepetching Beyond valid Memory”*/

RAMGS11保留并不用于代码 :origin = 0x017000,length = 0x003000 /*仅在 F28379D、F28377D、F28375D 器件上可用。 移除其他设备上的线路。 */
/ RAMGS12 :origin = 0x018000、length = 0x001000 /*仅在 F28379D、F28377D、F28375D 器件上可用。 移除其他设备上的线路。 */
/ RAMGS13 :origin = 0x019000、length = 0x001000 /*仅在 F28379D、F28377D、F28375D 器件上可用。 移除其他设备上的线路。 //

CPU2TOCPU1RAM:origin = 0x03F800,length = 0x000400
CPU1TOCPU2RAM:origin = 0x03FC00,length = 0x000400

CLA1_MSGRAMLOW:origin = 0x001480,length = 0x000080
CLA1_MSGRAMHIGH:origin = 0x001500,length = 0x000080




*/*分配程序区域
:> FLASHG PAGE = 0,align (8)
.text :>> FLASHB | FLASHH | FLASHI | FLASHJ | FLASHK | FLASHL | FLASHM | FLASHN PAGE = 0,ALIGN (8)
codestart :>开始页= 0,align (8)
/*分配未初始化的数据段:*/
.stack :> RAMM1 PAGE = 1.
switch :> FLASHG PAGE = 0,align (8)
.reset :>重置,PAGE = 0,TYPE = DSECT //未使用,*/
DMARAML4:>RAMGS2 PAGE = 1


#if defined (__TI_EABI __)

.init_array :> FLASHG,PAGE = 0, align (8)
.bss :> RAMLS5,page = 1.bss
:output :> RAMLS3,页= 0
.bss:CIO :> RAMLS5,page = 1.data
:> RAMLS5,page = 1
.sysmem :> RAMLS5,page = 1/*
初始化段进入 Flash */
.const :> FLASHG,PAGE = 0, align (8)
#else
.pinit :> FLASHG,PAGE = 0, align (8)
.ebss :> RAMGS3,page = 1

.esysmem :> RAMGS0,PAGE = 1.CIO

:> RAMLS5,page = 1/*
初始化段进入 Flash */
.econst :> FLASHG PAGE = 0,align (8)
#endif

// Filter_RegsFile :> RAMGS0,PAGE = 1

// SHARERAMGS0:> RAMGS0,PAGE = 1
// SHARERAMGS1:> RAMGS1,PAGE = 1
// ramgs0 :> RAMGS0, PAGE = 1
// ramgs1 :> RAMGS1、 PAGE = 1/*

闪存编程缓冲器*/
BufferDataSection:>RAMD1,PAGE = 1,ALIG(8)


MSGRAM_CPU1_TO_CPU2:>CPU1TOCPU2RAM,type=NOINIT
MSGRAM_CPU2_TO_CPU1:>CPU2TOCPU1RAM,type=NOINIT

/* CLA 特定部分*/
#if defined (__TI_EABI __)
Cla1Prog :LOAD = FLASHF、
运行= RAMLS4、
Load_start (Cla1funcsLoadStart)、
LOAD_END (Cla1funcsLoadEnd)、
run_start (Cla1funcsRunStart)、
load_size (Cla1funcsLoadSize)、
align (8)
#else
Cla1Prog :LOAD = FLASHF、
运行= RAMLS4、
load_start (_Cla1funcsLoadStart)、
load_end (_Cla1funcsLoadEnd)、
run_start (_Cla1funcsRunStart)、
load_size (_Cla1funcsLoadSize)、
align (8)
#endif
ClaData:> RAMLS3


#ifdef __TI_Compiler_version__
#if __TI_Compiler_version__>=15009000

#if defined (_TI_EABI)

组{.TI.ramfunc{-l F021_API_F2837xD_FPU32.lib}
load = FLASHB、
run = RAMLS0、
load_start (RamfuncsLoadStart)、
load_size (RamfuncsLoadSize)、
load_end (RamfuncsLoadEnd)、
run_start (RamfuncsRunStart)、
run_size (RamfuncsRunSize)、
run_end (RamfuncsRunEnd)、
page = 0、align (8)
其他


组{.TI.ramfunc{-l F021_API_F2837xD_FPU32.lib}
load = FLASHB、
run = RAMLS0、
load_start (_RamfuncsLoadStart)、
load_size (_RamfuncsLoadSize)、
load_end (_RamfuncsLoadEnd)、
run_start (_RamfuncsRunStart)、
run_size (_RamfuncsRunSize)、
run_end (_RamfuncsRunEnd)、
page = 0、align (8)

#endif

其他
组{ramfuncs{-l F021_API_F2837xD_FPU32.lib}}
负载= FLASHB、
run = RAMLS0、
load_start (_RamfuncsLoadStart)、
load_size (_RamfuncsLoadSize)、
load_end (_RamfuncsLoadEnd)、
run_start (_RamfuncsRunStart)、
run_size (_RamfuncsRunSize)、
run_end (_RamfuncsRunEnd)、
page = 0、align (8)
#endif
#endif



Cla1ToCpuMsgRAM:>CLA1_MSGRAMLOW,type=NOINIT
CpuToCla1MsgRAM:>CLA1_MSGRAMIGH,type=NOINIT

/* SFRA 特定段*//
SFRA_F32_Data:>RAMGS9,=CLA/ CLA





/ CLA 已分配内存/#64个字

段/ CLA / CLA 必须对齐 :
{*。obj (CLAscratch)
。 += CLA_ScratchPad_size;
*。obj (CLAscratch_end)}> RAMLS3


.scratchpad :> RAMLS3
.bss_cla :> RAMLS3


#if defined (__TI_EABI __)
.const_cla :LOAD = FLASHF、
运行= RAMLS3、

RUN_START (Cla1ConstRunStart)、
Load_start (Cla1ConstLoadStart)、
load_size (Cla1ConstLoadSize)、
align (8)
#else
.const_cla :LOAD = FLASHF、
运行= RAMLS3、
run_start (_Cla1ConstRunStart)、
Load_start (_Cla1ConstLoadStart)、
load_size (_Cla1ConstLoadSize)、
PAGE = 0
#endif
#endif //cla_C

//使用 IPC API 驱动程序时需要以下段定义*/
组:> CPU1TOCPU2RAM,PAGE = 1
{
PUTBUFFER
PUTWRITEIDX
GETREADIDX
}

组:> CPU2TOCPU1RAM,PAGE = 1
{
GETBUFFER:TYPE = DSECT
GETWRITEIDX:TYPE = DSECT
PUTREADIDX:TYPE = DSECT
}

}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    编译器 RTS 库的源代码是编译器安装的一部分。  如果将编译器作为 CCS 的一部分安装,则该位置类似于...

    C:\ti\ccs1011\ccs\tools\compiler\ti-cgt-C2000_20.2.4.LTS lib\src

    所有动态内存分配函数、包括 free、都位于文件 memory.c 中将该文件复制到您的项目中。  现在、动态存储器分配函数的实现将使该文件在您的项目中局部显示、而不是 RTS 库。  测试并确保没有任何变化。  现在,添加以下编译器选项:-DMALLOC_debug -DMALLOC_guard。  这些选项定义了预处理器符号 malloc_debug malloc_guard,它们在 memory.c 中启用调试代码。  再次测试并查看打印出来的内容。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    George、感谢您的建议。  我尝试执行此操作后,一旦我将 memory.c 文件复制到项目中,所有内容都开始工作,这意味着 free()返回正确。  如果我在没有进行任何其他更改的情况下从工程中删除 memory.c,则 FREE()将不再返回。  我在 TI v20.2.1.LTS、v20.2.3.LTS 和 v20.2.4.LTS 编译器版本(每次使用20.2.3中的 memory.c)上尝试过此操作。  CCS 版本为10.1.1.00004。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    问题的原因可能始终存在。  但是、随着函数和数据更改存储器位置、问题的影响也会不断增加。  这样的问题很难调试。  您为查找原因所做的更改可能会使其消失。

    以下是一项需要考虑的建议...

    将项目置于失败的状态。  在映射文件中、记下 RTS 库中文件 memory.c.obj 的.text 段的存储器位置。  假设它看起来像这样...

    0008207c 0000028c rts2800_fpu32.lib:memory.c.obj (.text) 

    第一个数字是存储器地址。  现在、将 memory.c 作为项目中的文件。  强制其位于同一地址。  在链接器命令文件中,SECTIONS 指令中的第一行应类似于...

    for_memory
    {
    memory.obj (.text)
    }> 0x0008207c 

    测试并确保仍然出现问题。  然后使用我在上一篇文章中提到的预处理器符号进行编译。  这可能会导致问题消失。  但是、如果没有、这将为您提供调试方法。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我找到了程序在 free()中被挂起的位置。  它是 memory.c 行741上的 while 循环:

    while (当前<数据包)
    {
    上一个=当前;
    当前= NEW_PACKET (当前);
    } 

    在启用 malloc_debug 和 malloc_guard 标志的情况下、不会向控制台打印任何内容。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    确保在您的系统中、像放置这样的 C I/O 函数通常起作用。  创建一个类似于...的小程序

    #include 
    int main()
    {
    PUs ("Hello、world!");
    } 

    确保在 CCS Console 视图中显示输出。  如果没有、请尝试使用 printf 的一些提示

    尝试在 每个动态存储器分配前后添加对_TI_heap_check 的调用。  也许您可以使用宏来实现这一点。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的,所以我尝试在 main()函数的开头放置以下行。

    PUs ("Hello、world!"); 

    这导致控制台打印出一组:

    无法识别地址(0xA800)处 CIO 缓冲器中的无效 CIO 命令(11)。 请检查器件和程序存储器映射。 

    我意识到我没有在调用 main()的文件中包含 stdio.h。  完成此操作后、我成功打印了"Hello、world!" 控制台。

    之后,我添加 了__TI_heap_check();每次调用 malloc()和 free()之前和之后。  再次编译并运行代码会导致代码再次卡住、但不会将任何内容打印到控制台。  在单步执行代码后,它现在似乎在 发生 FREE()被调用后锁定在__TI_heap_check()调用内部。  看起来 _TI_heap_check()卡在这个 while 循环中(从 memory.c 的第1057行开始):

    while ((unsigned char *) packet < heap_end())
    {
    //fputs ("ti_heap_check"、stderr);
    #ifdef malloc_guard
    if (packet->guard!= GUARDWORD)
    {
    #ifdef malloc_debug
    fputs ("heap_check:损坏的防护字\n"、stderr);
    #endif
    _TI_resource_unlock (_TI_lock_heap_alLOC);
    返回(void *)&packet->guard;
    }
    #endif
    
    数据包= NEW_PACKET (packet);
    } 

    请注意、它从不向控制台打印任何内容。  我希望确保 fputs 函数正常工作、因此我在 while 循环中添加了 fputs 调用(请参阅上面注释的代码)。  编译并运行后、我会按预期输出一组"ti_heap_check"。

    请注意,如果我将附加的 fputs()调用注释掉,则不会看到任何控制台输出,因此 __TI_heap_check()函 数似乎不会达到(packet->guard != GUARDWORD)的情况。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我正在与其他专家讨论这一主题。  我希望下周早些时候能回来。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    谢谢你。 如果有办法秘密发送项目代码、以便您可以在本地重现问题、我也愿意这样做、如果有用的话。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请收集更多信息。  对您的代码进行2次更改。

    第一个更改配置 C I/O 函数、以便它们不会对 malloc free 进行任何调用。  在函数 main 中,在调用任何 C I/O 函数之前,添加以下行...

    静态 char buffer[128];//任何大小都将执行*/
    setvbuf (stdout、buffer、_IOLBF、sizeof (buffer)); 

    该代码将 C I/O 函数配置为使用该静态缓冲区、而不是使用调用 malloc 的缓冲区。

    第二个变化... 改为将对_TI_heap_check 的所有调用更改为 _TI_heap_stats 。

    将该信息收集到文本文件中。  使用文件扩展名.txt。  将该文本文件附加到下一个帖子。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    请忽略 TI 认为已解决的设置。  我必须是错误地这样做的。  此问题未解决。

    谢谢、此致、

    乔治

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    乔治,我相信我找到了这个问题的根本原因。  如果我回答正确、问题是代码逻辑1。  基本上、具有动态存储器分配的代码应该在禁用中断的情况下运行、这是因为计时器 ISR 中有一段代码假定动态存储器分配代码已经完全执行。

    我注意到、当程序锁定时、ISR 计数器继续递增、这使我陷入了这种状况。

    我将继续使用此逻辑修复程序运行测试、但我认为现在可以安全地假设问题已解决。  感谢你的帮助。