gpt4 book ai didi

debugging - Arduino/AVR ATmega 微 Controller ,随机复位、跳转或变量/数据损坏

转载 作者:行者123 更新时间:2023-12-02 23:01:12 24 4
gpt4 key购买 nike

我想很多 Arduino/AVRs MCU 的程序员可以分享一些知识。

我的具体问题是:
以我的 Atmel Atmega128 AVR 为例。
基于 ADC 数据,我正在运行一个循环,该循环正在对串行控制台进行一些计算,同时它还驱动了一个中断。

发生的事情是,当我确实使用了一定数量的串行输出时,程序突然变得非常不稳定。
代码内的随机跳转、随机未知中断、随机变量损坏、未设置 MCU 寄存器位的随机复位。
在特定点添加缓冲区解决了不稳定性。
更改 gcc 的优化参数也改变了行为,没有优化代码非常稳定。

检查我的答案可能的原因和真正的原因。

最佳答案

有很多陷阱,这些是一些卑鄙的:

1) 突然重置可能有多种原因。
您的 AVR 可能在太低的电压下运行,降低频率或增加电压。检查数据表,他们有一个图表,他们对此很认真:)

2) 另一个潜在问题是未处理的中断 ,您必须处理每个中断,因为未知的 IRQ 会导致立即复位。
我喜欢将此代码添加到一个特殊的“捕获所有”ISR 中,它捕获所有未处理的 IRQ。

ISR(BADISR_vect)
{

for (;;) UDR0='!';
}

此代码段将写入大量 !进入UART。或者,您可以让 LED 闪烁等。只要确保不要从那里返回,因为这只会隐藏问题,并且您可能不会在程序继续运行时发现错误。

3) 在您的 main() 或 init 代码中,您应该检查 MCU 状态寄存器 尽快并将其设置为零。
在大多数复位情况下,该寄存器将保存复位原因。
if(MCUCSR & (1<<PORF )) myprintf0P(PSTR("Power-on reset.\n"));
if(MCUCSR & (1<<EXTRF)) myprintf0P(PSTR("External reset!\n"));
if(MCUCSR & (1<<BORF )) myprintf0P(PSTR("Brownout reset!\n"));
if(MCUCSR & (1<<WDRF )) myprintf0P(PSTR("Watchdog reset!\n"));
if(MCUCSR & (1<<JTRF )) myprintf0P(PSTR("JTAG reset!\n"));
MCUCSR = 0;

4) 出现意外行为的另一个很好的原因是编译器优化。
您可以从很多选项中进行选择,优化得越多,您的代码就会被压缩得越多(至少通常如此)。无用的数据和函数被删除,代码被压缩并变成更快或更小的指令。
通常程序员在编写代码时禁用或减少优化,这有助于调试过程不会随机跳行并根据自己的代码显示相当准确的内容。
但是,如果您有一个小的内存问题(例如一个错误),则未优化的代码可能会在运行时没有明显问题,但是一旦优化程度提高,变量位置可能会发生变化,或者突然两个变量彼此相邻在堆栈或堆中,因此逐一写入可能会突然影响以前未受影响的代码。
像 valgrind 这样的调试工具不适用于 AVR,所以我最好的提示是用激活的大脑编写。
如果你玩指针,那么仔细检查你是否永远不会越界。

5) 编译器优化可以“破坏”您的轮询代码。
例如,您正在 ISR(uart、ADC、TWI 等)中写入原子(8 位)变量/寄存器。在您的主循环中,您现在查看此变量是否在您将其用作新数据的指标/标志时发生变化。
这是编写代码的正确方法,但您的编译器不知道您正在 ISR 中更改此变量。
因此,很可能优化例程就好像这个变量是静态的一样,毕竟你运行了一个无限循环并且你只在这个循环中读取它。
解决方法是设置变量volatile。
下面是一个具有两个索引的 FIFO 环形缓冲区示例,这些索引从普通代码和 ISR 代码中读取和写入:
struct fifo 
{
uint8_t size; /* size of buffer in bytes */
volatile uint8_t read; /* read pointer */
volatile uint8_t write;
unsigned char *buffer; /* fifo ring buffer */
};

6)这是我的具体问题,它导致了以上所有问题。
就我而言,整个问题都源于我在 使用 AVR 的愚蠢行为。 3.3伏和 16MHZ。在这个频率下需要大约 4.5V 才能稳定运行。
早些时候我做了很多测试,MCU 似乎运行稳定,但随着代码大小的增加,稳定性降低了。
它表现得好像我有一个非常严重的内存损坏,可能是由 ISR 触发的。
或者好像某些 libc 函数(与 progmem 相关的函数)有问题。
将设备置于 5V 解决了它。这种智慧花了我无数个小时的软件分析,我从字面上深入搜索了软件方面的每一个可能原因。
教训:如果您对微 Controller 进行编程,切勿将其视为纯软件 :)

7) 用于高级内存损坏分析 您可以将堆栈设置为特定的预定义状态。这可以极大地帮助您进行调试,因为您可以观察数据中变量的增长位置。
此外,空终止的丢失让您的指针遇到已知数据而不是未知数据。
只需使用如下代码将 C 文件添加到您的项目中:
extern void *_end, *__stack;
#define __ALD(x) ((uintptr_t)(x) - ((uintptr_t)(x) & 0x03))
#define __ALU(x) ((uintptr_t)(x) + ((uintptr_t)(x) & 0x03))
void _stackfill(void) __attribute__((naked)) __attribute__((optimize("O3"))) __attribute__((section (".init1")));
void _stackfill(void)
{
uint32_t* start = (uint32_t*)__ALU(&_end);
uint32_t* end = (uint32_t*)__ALD(&__stack);

for (uint32_t *pos = start; pos < end; pos++)
*pos = 0x41424142; // ends up as endless ascii BABA
}

此代码将自动将其自身挂接到代码的 init 部分,并在整个 sram 中写入 BABABABABABABA 模式。
这对您的程序没有坏影响,它只是使用已知模式初始化 sram。
如果您在调试期间查看它,您将看到变量被分配的位置和未分配的位置。
它工作正常,也可以写入init3。

暂时就这样了。
我希望这篇简短的综述能帮助一些程序员解决他们的 AVR 奇怪/令人沮丧的行为。

代码部分是为 ATMEGA 128 编写的,但可以在任何 8 位 AVR 上运行,只是一些寄存器名称可能需要稍作更改。

关于debugging - Arduino/AVR ATmega 微 Controller ,随机复位、跳转或变量/数据损坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23377948/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com