为什么NOP/很少额外的代码行/优化指针别名有帮助?[富士通MB90F543单片机C代码]

为什么NOP/很少额外的代码行/优化指针别名有帮助?[富士通MB90F543单片机C代码],c,debugging,optimization,embedded,softune,C,Debugging,Optimization,Embedded,Softune,我正在尝试修复富士通MB90F543的成熟程序中发现的一个错误。到目前为止,该计划已经运行了近10年,但人们发现,在某些特殊情况下,它在一开始就未能做到两件事。其中之一至关重要 在低电平和高电平初始化端口、引脚、外围设备、IRQ处理程序配置数据通过SPI从EEPROM读取后,状态指示灯打开一段时间以将其打开,数据通过SPI发送到LED驱动器。 当这些特殊情况首先发生时,只有第一个函数调用一些EEPROM读取失败,另外一些应该打开的LED灯不会打开 该程序用C语言编写,并使用Softune v30

我正在尝试修复富士通MB90F543的成熟程序中发现的一个错误。到目前为止,该计划已经运行了近10年,但人们发现,在某些特殊情况下,它在一开始就未能做到两件事。其中之一至关重要

在低电平和高电平初始化端口、引脚、外围设备、IRQ处理程序配置数据通过SPI从EEPROM读取后,状态指示灯打开一段时间以将其打开,数据通过SPI发送到LED驱动器。 当这些特殊情况首先发生时,只有第一个函数调用一些EEPROM读取失败,另外一些应该打开的LED灯不会打开

该程序用C语言编写,并使用Softune v30L32编译。 令人惊讶的是,在低级硬件init中添加单个asm NOP就足以使程序在上述情况下按预期工作。在优化设置中关闭“指针别名的控制优化”就足够了。在不同的地方添加几行代码也会有所帮助

我已经比较了编译程序的不同ASM列表,包括有和没有_ASM NOP的版本,以及前面提到的两种优化器设置,它们看起来都很好

在编译过程中,Softune编译器多年来一直打印的唯一警告如下:

***W1372L:该段位于RAM区域或I/O区域IOXTND之外

我确实意识到这是一个相当普遍的问题,但也许有人有一个更大的图景可以指出可能的原因

你知道是什么导致了这种奇怪的行为吗?如何定位错误并修复它

在初始化过程中,使用了几个长约20ms的延迟环路。虽然它们从大约2ms增加到了2ms,但是在任何一行硬件初始化函数中,甚至在函数之前或之后,单个NOP都会有所帮助

两个等待循环都有效。我已经用示波器检查过了。我已经增加了LED的开启前和关闭后

我已经通过将SPI时钟从1MHz降低到500kHz来验证了timming假设。它不会改变任何事情。降低到250kHz会使看门狗复位,因为代码的某些部分执行时间过长>25ms

还有一件事。我观察到,在任何源文件中添加局部变量有时会使问题消失或重新出现。这同样涉及初始化未初始化的局部变量。在任何文件中添加几行额外的代码都有助于或揭示问题

void main(void)
{
    watchdog_init();
    // waiting for power supply to stabilize
    wait; // about 45ms
    hardware_init();
    clear_watchdog();
    application_init();
    clear_watchdog();
    wait; // about 20ms
    test_LED();
    {...}
}

void hardware_init (void)
{
    __asm("NOP"); // how it comes it helps? - it may be in any line of the function
    io_init();      // ports initialization

    clk_init();
    timer_init();
    adc_init();

    spi_init();
    LED_init();
    spi_start();
    key_driver_init();
    can_init();
    irq_init();     // set IRQ priorities and global IRQ enable
}

这可能是许多事情中的一件,但脑海中浮现出两件事

时机

也许等待的时间不够长,电源无法稳定,而且并非所有东西都与时钟同步。NOP让一切恢复同步

对齐


也许NOP会使您的指令与硬件期望的32或64位边界对齐。我们过去经常在大型机汇编程序上这样做,因为IO操作通常希望在双字边界上进行操作。

问题解决了。它是由一个小错误引起的

EEPROM的nHOLD和nCS信号不是在MCU复位后立即初始化的,而是在首次使用EEPROM之前初始化的。因此,它们是0,非常活跃。 这意味着已选择EEPROM,但正在等待。同时,开始使用SPI进行其他传输。在8个CLK脉冲中的6个之后,EEPROM的nHOLD I/O引脚被初始化并处于高位。EEPROM不再处于保留状态,所以它为另一个外设输入最后两位数据。EEPROM上的每个后续操作都发现它没有同步CLK和MOSI

当我添加了NOP或其他任何东西时,nHOLD 0->1边的瞬间在最后一个CLK脉冲后发生了移动。现在CLK-MOSI是同步的

我所要做的就是初始化所有的EEPROM的SPI线路
在MCU复位后,特别是nHOLD和nCS。

使用硬件的一个原因是它对定时非常敏感。有时,您只需要这些NOP指令添加几毫秒的延迟,以使硬件的计时正确。您是否尝试将逻辑分析仪连接到SPI总线,以便您可以看到在初始化期间通过它发送的内容,我想你已经排除了硬件故障的可能性,例如,如果有关键的东西存在,MCU内存中的错误位会导致程序失败,但如果代码最终对齐,那么就不重要了?是的,我排除了。至于SPI,我用示波器查看了通电后发送的第一个字节。它看起来很好。当我开始阅读时,我想到的第一件事就是电源问题。当一个“不”就够了的时候,就放弃了。然后我在你的代码中看到了这个注释。嗯,至于时间。请注意,有一个长等待循环,然后是对函数的调用,它的第一条指令是NOP。它添加到等待循环中的时间延迟是没有意义的。此外,我 在呼叫之前移动NOP,所以在等待循环之后。这仍然有帮助。减少SPI时钟也无济于事。至于对齐-听起来很有趣,但是为什么添加/删除局部变量会有帮助呢?我怎样才能使代码错位呢?