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.

[参考译文] TMS320F280039:计算错误

Guru**** 2304330 points
Other Parts Discussed in Thread: LAUNCHXL-F280039C, C2000WARE
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1505301/tms320f280039-calculation-error

器件型号:TMS320F280039
主题中讨论的其他器件:LAUNCHXL-F280039CC2000WARE

工具/软件:

我遇到了一些计算错误。

static int16_t LvBswPwm_Period_Cnt=2400;
static uint16_t test[6];

test[0]=(1.0f/6.0f*LvBswPwm_Period_Cnt);
test[1]=(2.0f/6.0f*LvBswPwm_Period_Cnt);
test[2]=(3.0f/6.0f*LvBswPwm_Period_Cnt);
test[3]=(4.0f/6.0f*LvBswPwm_Period_Cnt);
test[4]=(5.0f/6.0f*LvBswPwm_Period_Cnt);
test[5]=(6.0f/6.0f*LvBswPwm_Period_Cnt);

除5/6之外、所有计算结果都是正确的、结果为0、但不是2000。

部分配置  如下所示:

一些解决方案尝试过:

1-将优化级别更改为"关闭"、5/6结果将是正确的;

2-(5.0f*LvBsw Pwm_Period_Cnt )/ 6.0f,结果将是正确的;

我想知道这是什么原因造成的。

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

    尊敬的 Bo:

    由于测试变量的类型是 uint16_t、您能否键入 cast 乘法并查看它是否有效。 您有一些浮点计算并将结果转换为16位可能会有所不同。

    此致、

    Ozino

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

    不、它不起作用。 我有一些关于这个问题的更多信息。 它可能与__fmax 和__ max 函数存在一些关系;

    总代码如下:

        /*1 - Local Variables*/
        static int16_t LvBswPwm_Period_Cnt=0;
        static uint16_t test[6];
    
        //int16_t LvBswPwm_Period_Cnt=0;
        int16_t LvBswPwm_Duty_Cnt[2]={0,0};
        int16_t LvBswPwm_DeadTime_Cnt[2]={0,0};
    
        /*2 - Value Calculation and Limit*/
        //Period Calculation
        LvBswPwm_Period_Cnt     = (uint16_t) ( KvBswPwm_PWMCLK_kHz / Utility_floatValLimitRange(pPwmInput->Freq_kHz,KvBswPwm_FREQMIN_kHz,KvBswPwm_FREQMAX_kHz) );
    
        //Duty Calculation
        if(pPwmInput->PriDuty_U < KvBswPwm_DUTYMIN_U)
            LvBswPwm_Duty_Cnt[0]=0;
        else if(pPwmInput->PriDuty_U > KvBswPwm_DUTYMAX_U)
            LvBswPwm_Duty_Cnt[0]=(uint16_t)(KvBswPwm_DUTYMAX_U * LvBswPwm_Period_Cnt);
        else
            LvBswPwm_Duty_Cnt[0]=(uint16_t)(pPwmInput->PriDuty_U * LvBswPwm_Period_Cnt);
    
        if(pPwmInput->SecDuty_U < KvBswPwm_DUTYMIN_U)
            LvBswPwm_Duty_Cnt[1]=0;
        else if(pPwmInput->SecDuty_U > KvBswPwm_DUTYMAX_U)
            LvBswPwm_Duty_Cnt[1]=(uint16_t)(KvBswPwm_DUTYMAX_U * LvBswPwm_Period_Cnt);
        else
            LvBswPwm_Duty_Cnt[1]=(uint16_t)(pPwmInput->SecDuty_U * LvBswPwm_Period_Cnt);
    
        // DeadTime Calculation and Limit
        LvBswPwm_DeadTime_Cnt[0]= __max(LvBswPwm_Period_Cnt/2 - LvBswPwm_Duty_Cnt[0] +1,KvBswPwm_DBMIN_U);
        LvBswPwm_DeadTime_Cnt[1]= __max(LvBswPwm_Period_Cnt/2 - LvBswPwm_Duty_Cnt[1] +1,KvBswPwm_DBMIN_U);
        
        test[0]=(1.0f/6.0f*LvBswPwm_Period_Cnt);
        test[1]=(2.0f/6.0f*LvBswPwm_Period_Cnt);
        test[2]=(3.0f/6.0f*LvBswPwm_Period_Cnt);
        test[3]=(4.0f/6.0f*LvBswPwm_Period_Cnt);
        test[4]=(5.0f/6.0f*LvBswPwm_Period_Cnt);
        test[5]=(6.0f/6.0f*LvBswPwm_Period_Cnt);

    1 -如果我将变量 LubSww Pwm_Period_Cnt 定义为 volatile、则可以。

    2- 如果我在第11行之后计算 TEST[0]-TEST[5]、则可以。

    3-如果我将__max 更改为__fmax、则可以。

    4- 如果我  像上面的代码一样计算 test[0]-test[5]、则会有一个结果错误、有时会是 test[4](5/6)、有时会是 test[1](2/6)、但其他结果是正确的。  我认为编译器生成这样的代码、 __max 更改了 CPU 寄存器、但 Lubswm Pwm_Period_Cnt 值不是再次从 RAM 获得的。为什么编译器将生成这样的代码?

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

    尊敬的 Bo:

    我将问题重新路由到编译器组以获得进一步帮助。

    此致、

    Ozino

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    LvBsw Pwm_Period_Cnt 值不再从 RAM 获得。为什么编译器会生成这样的代码?

    变量  LubSww Pwm_Period_Cnt 分配一次。  当执行该分配时、寄存器被复制到  LubSww Pwm_Period_Cnt 可以视为保持相同的值。  稍后读  LubSww Pwm_Period_Cnt 可能使用该寄存器而不是再次从存储器读取。  为什么这是一个问题?  是可能的  LubSww Pwm_Period_Cnt 以外的方式进行更改?

    如果我计算   test[0]-test[5]就像上面的代码一样、会有一个结果错误、有时会是 test[4](5/6)、有时会是 test[1](2/6)、但其他结果是正确的。

    我认为这种行为变化发生在相同代码的多次运行中。  如果正确、这几乎总是意味着硬件存在一些问题、而不是编译器或软件。

    谢谢。此致、

    -乔治

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

    1 -我没有更改的值  LubSww Pwm_Period_Cnt 在代码行11之后、正如您稍后所说的  LubSww Pwm_Period_Cnt  可能使用该寄存器而不是再次从存储器读取。 但测试值 通过计算得出  LubSww Pwm_Period_Cnt 是不对的。 如果 我将变量定义为易失性类型、则变量测试计算将正确。 我认为下面的_max 函数会改变寄存器、但在计算测试时、  LubSww Pwm_Period_Cnt  不再从 ram 获得。

    LvBswPwnt[0]=__max (LvBsw/2 Pwm_Period_Cnt - Pwm_Dead Pwm_Duty_Cnt [0]+1、KvBswPwm_DBMIN_U);
    LvBswPwm_Cnt[1]=__max (LvBsw/2 Pwm_Period_Cnt - Pwm_Dead Pwm_Duty_Cnt [1]+1、KvBswPwm_DBMIN_U);

    2 - 我认为它与硬件没有关系、如果我将上面的代码更改为__fmax、它将始终获得正确的结果、即使我定义了变量也是如此  LubSww Pwm_Period_Cnt  下使用。

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

    请更改代码以便...

     使用计算出的测试值  LubSww Pwm_Period_Cnt 不正确

    对于包含 Problem 语句的源文件、 请按照 如何提交编译器测试用例一文中的说明进行操作。   

    您介绍了几种更改代码的方法、使其正常工作。  选择似乎最接近问题变体的选项。  对于第二个源文件、还 请遵循 如何提交编译器测试用例一文中的说明

    我将把两个测试用例构建到汇编代码中、并进行比较。

    关于...

    计算测试时、  LubSww Pwm_Period_Cnt  不再从 RAM 获取

    我不明白。 请解释您这样说的原因。  "你怎么知道的?"  您希望看到什么?

    谢谢。此致、

    -乔治

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

    问题 可能来自 idiv_support。

    1)我从 driverlib 空工程构建一个新工程、并在 LAUNCHXL-F280039C 上运行。 工程配置与该问题中的第一个问题相同。

    代码作为附件上传。

      演示工程位置:x:\ti\C2000Ware_5_04_00_00\driverlib\f28003x\examples\empty_projects

    2)我把代码写在 main.c 中,如下所示

    #define Utility_floatValLimitRange(x,MinVal,MaxVal)      ( __fmax(__fmin(x,MaxVal),MinVal) )
    #define Utility_intValLimitRange(x,MinVal,MaxVal)        ( __max(__min(x,MaxVal),MinVal) )
    
    int16_t Period=0;
    int16_t Duty[2]={0,0};
    int16_t Dead[2]={0,0};
    
    float32_t test[6];
    
    
    
    
    
    Period     =  (120.0e3f) / Utility_floatValLimitRange(50.0f,50.0f,70.0f);
    
    Duty[0] = 0;
    Duty[1] = 0;
    
    Dead[0] = __max(Period/2 - Duty[0] + 1 , 18);
    Dead[1] = __max(Period/2 - Duty[1] + 1 , 18);
    
    test[0] = 1.0f/6.0f*(float32_t)Period;
    test[1] = 2.0f/6.0f*(float32_t)Period;
    test[2] = 3.0f/6.0f*(float32_t)Period;
    test[3] = 4.0f/6.0f*(float32_t)Period;
    test[4] = 5.0f/6.0f*(float32_t)Period;
    test[5] = 6.0f/6.0f*(float32_t)Period;
    

    3) F280039C 的数据表指出它 支持快速整数除法(FINTDIV)、因此我更改了  idiv_support=idiv0、并获得如下结果:

    Test[1]和 Dead 无法获得正确的值;

    4)我将  idiv_support 更 改为空,这次它将得到如下正确的结果:

    5)这是测试代码

    e2e.ti.com/.../4428.empty_5F00_driverlib_5F00_project.rar

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

    某些补充、使用  idiv_support=idiv0进行项目配置。

    1)如果我改变  

    Period = (120.0e3f)/ Utility_floatValLimitRange (50.0f、50.0f、70.0f);  

    最终目的  周期= 2400; 结果将是正确的;

    2)如果我删除这两行:

    Duty[0]= 0;
    Duty[1]= 0;

    结果也是正确的。

    3)如果我更改以下两行:

    dead[0]=__max (period/2 - duty[0]+ 1、18);
    dead[1]=_max (period/2 - duty[1]+ 1、18);

    最终目的

    dead[0]=__max (period/2 + 1、18);
    dead[1]=__max (period/2 + 1、18);

    结果也是正确的。

    4)如果我更改以下两行:

    dead[0]=__max (period/2 - duty[0]+ 1、18);
    dead[1]=_max (period/2 - duty[1]+ 1、18);

    最终目的

    dead[0]=_fmax (period/2.0f - duty[0]+ 1.0f、18.0f);
    dead[1]=_fmax (period/2.0f - duty[1]+ 1.0f、18.0f);

    结果也是正确的。

    5)如果我改变计算:

    test[n]= x.0f* 6.0f/(float32_t) period;

    最终目的
    test[n]= x.0f*(float32_t) period/6.0f;

    结果将以另一种方式错误。

    6)我在芯片上使用相同的配置和代码280025,我可以得到相同的现象。

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

    您是否愿意告诉我是否有任何更新、或者是否需要我本人提供其他信息?

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

    Bo、抱歉、内部仍在讨论。 我很快就会回来。

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

    Bo、我们已经能够在内部重现此问题。 将归档编译器错误、并对此进行调查。

    谢谢、

    Sira

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

    经过进一步调查、我们还有另一个要求。  请查看最终的总体结果。  正确吗?  在问题函数的返回指令上设置一个断点、再执行几个指令、然后查看。  所有的计算都正确吗?

    谢谢。此致、

    -乔治