【问题标题】:RAM test steps through, but fails when runningRAM 测试通过,但在运行时失败
【发布时间】:2013-06-17 20:19:12
【问题描述】:

我正在进行的项目必须在程序运行之前测试 dsPIC30F 芯片的数据存储器。由于行业要求,我们不能使用 C 必须提供的任何预定义库。话虽如此,这是我测试 RAM 的方法:

Step 1 - Write the word 0xAAAA to a specific location in memory (defined by a LoopIndex added to the START_OF_RAM address)

Step 2 - increment LoopIndex

Step 3 - Repeat Steps 1-2 until LoopIndex + START_OF_RAM >= END_OF_RAM

Step 4 - Reset LoopIndex = 0

Step 5 - Read memory at LoopIndex+START_OF_RAM

Step 6 - If memory = 0xAAAA, continue, else throw RAM_FAULT_HANDLER

Step 7 - increment LoopIndex

Step 8 - Repeat Step 5 - 7 until LoopIndex + START_OF_RAM >= END_OF_RAM

现在,奇怪的是我可以单步执行代码,没问题。只要我的小指可以按 F8,它就会慢慢地循环遍历每个内存地址,但是当我尝试在第 4 步设置断点时,它会无缘无故地抛出一个随机的通用中断处理程序。我认为可能是因为我使用的for()可能超过了END_OF_RAM,但是我改变了条件的界限,它仍然不喜欢运行。

任何见解都会有所帮助。

void PerformRAMTest()
{

    // Locals
    uint32_t LoopIndex = 0;
    uint16_t *AddressUnderTest;
    uint32_t RAMvar = 0;
    uint16_t i = 0;

    // Loop through RAM and write the first pattern (0xAA) - from the beginning to the first RESERVED block
    for(LoopIndex = 0x0000; LoopIndex < C_RAM_END_ADDRESS; LoopIndex+= 2)
    {

        AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);

        *AddressUnderTest = 0xAAAA;


    }// end for

    for(LoopIndex = 0x0000; LoopIndex < C_RAM_END_ADDRESS; LoopIndex += 2)
    {
        AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);

        if(*AddressUnderTest != 0xAAAA)
            {
                // If what was read does not equal what was written, log the
                // RAM fault in NVM and call the RAMFaultHandler()
                RAMFaultHandler();
            }// end if
    }

    // Loop through RAM and write then verify the second pattern (0x55)
    // - from the beginning to the first RESERVED block
//    for(LoopIndex = C_RAM_START_ADDRESS; LoopIndex < C_RAM_END_ADDRESS; LoopIndex++)
//    {
//        AddressUnderTest = (uint32_t*)(C_RAM_START_ADDRESS + LoopIndex);
//        *AddressUnderTest = 0x5555;
//        if(*AddressUnderTest != 0x5555)
//        {
//            // If what was read does not equal what was written, log the
//            // RAM fault in NVM and call the RAMFaultHandler()
//            RAMFaultHandler();
//        }
//    }

}// end PerformRAMTest

可以看到第二遍测试写0x55。这是给我的原始实现,但它从来没有工作过(至少就调试/运行而言;用这种写入方法遇到相同的随机中断,然后在继续之前立即读取相同的地址)

更新:在几次 Clean&Builds 之后,代码现在将运行,直到它碰到堆栈指针 (WREG15),跳过,然后出错。以下是相关代码的新示例:

if(AddressUnderTest >= &SPLIMIT && AddressUnderTest <= SPLIMIT)
    {
        // if true, set the Loop Index to point to the end of the stack
        LoopIndex = (uint16_t)SPLIMIT;
    }
    else if(AddressUnderTest == &SPLIMIT) // checkint to see if AddressUnderTest points directly to the stack [This works while the previous >= &SPLIMIT does not. It will increment into the stack, update, THEN say "oops, I just hit the stack" and error out.]
    {
        LoopIndex = &SPLIMIT;
    }
    else
    {
        *AddressUnderTest = 0xAAAA;
    }

【问题讨论】:

  • 您的程序和堆栈在内存中的哪个位置?
  • 您不应该将(C_RAM_START_ADDRESS + LoopIndex) 转换为(uint16_t*)吗?
  • @LeeDanielCrocker - 数据内存理论上应该从 0x0800 开始,程序内存开始,好吧,我们不知道。我们知道 W15 寄存器是堆栈指针,并且我们有一个变量 SPLIMIT,我尝试验证并启用 LoopIndex 跳过,但是,这也不起作用。
  • @Magtheridon96 - 从理论上讲,是的,但是,总 RAM 达到 0x17FFE,而且,这也是基于给我的代码。
  • 那么,您可能在程序运行时覆盖了程序指令/数据/堆栈?这不能很好地结束。

标签: c testing embedded ram pic


【解决方案1】:

我认为您实际上希望 (C_RAM_START_ADDRESS + LoopIndex) &lt; C_RAM_END_ADDRESS 作为您的循环条件。目前,您正在从C_RAM_START_ADDRESS 循环到C_RAM_START_ADDRESS + C_RAM_END_ADDRESS,我假设它正在写入超过 RAM 的末尾。

您还应该真正将重复的代码分解到一个单独的函数中,该函数将测试模式作为参数 (DRY)。

【讨论】:

  • 我已将LoopIndex &lt; C_RAM_END_ADDRESS 更改为(C_RAM_START_ADDRESS + LoopIndex) &lt; C_RAM_END_ADDRESS,但程序仍然停止。此外,我之前将写入和读取函数拆分为两个不同的for() 循环,以测试我们遇到的问题是由于写入后读取的竞争条件造成的理论。不行,拆分后还是不行。
【解决方案2】:

好的,我们可以查看很多内容来更好地了解您的问题可能出在哪里。我想指出一些事情——希望我们能一起解决这个问题。我注意到的第一件事似乎有点不合适是这条评论:

"...总 RAM 达到 0x17FFE..."

我查阅了 dsPIC30F6012A 的数据表。您可以在图 3-8(第 33 页)中看到,SRAM 空间为 8K,从 0x0800 运行到 0x2800。另外,还有一个小花絮:

“所有有效地址均为 16 位宽,并指向数据空间内的字节”

因此,您可以为地址使用 16 位值。我也对您的更新感到有些困惑。 SPLIM 是您为其设置值的寄存器 - 并且该值限制了堆栈的大小。我不确定您的 SPLIMIT 的值是什么,但 W15 是您的实际堆栈指针寄存器,存储在那里的值是堆栈顶部的地址:

"有一个堆栈指针限制寄存器(SPLIM)关联 与堆栈指针。 SPLIM 未初始化 重启。与堆栈指针一样,SPLIM 被强制为“0”,因为所有堆栈操作都必须 字对齐。 只要有效地址 (EA) 是 使用 W15 作为源或目标生成 指针,由此产生的地址与 SPLIM 中的值。如果堆栈指针的内容 (W15) 和 SPLIM 寄存器是相等的和一个推 执行操作,堆栈错误陷阱将不会 发生。

最后,堆栈从可用的最低 SRAM 地址值增长到SPLIM。所以我建议将SPLIM 的值设置为合理的值,比如512 字节(尽管最好设置为test how much room you need for your stack)。

由于这个特定的堆栈向上增长,我将从 0x0800 加上我们为堆栈限制添加的内容开始,然后从那里进行测试(即 0x1000)。这样您就不必担心堆栈区域了。

鉴于上述情况,这就是我将如何去做。

void PerformRAMTest (void)
{
    #define SRAM_START_ADDRESS  0x0800

    /* Stack size = 512 bytes.  Assign STACK_LIMIT
       to SPLIM register during configuration. */
    #define STACK_SIZE          0x0200

    /* -2, see pg 35 of dsPIC30F6012A datasheet. */
    #define STACK_LIMIT             ((SRAM_START_ADDRESS + STACK_SIZE) - 2)
    #define SRAM_BEGIN_TEST_ADDRESS ((volatile uint16_t *)(STACK_LIMIT + 2))
    #define SRAM_END_TEST_ADDRESS   0x2800
    #define TEST_VALUE              0xAAAA

    /* No need for 32 bit address values on this platform */
    volatile uint16_t * AddressUnderTest = SRAM_BEGIN_TEST_ADDRESS

    /* Write to memory */
    while (AddressUnderTest < SRAM_END_TEST_ADDRESS)
    {
        *AddressUnderTest = TEST_VALUE;
        AddressUnderTest++;
    }

    AddressUnderTest = SRAM_BEGIN_TEST_ADDRESS;

    /* Read from memory */
    while (AddressUnderTest < SRAM_END_TEST_ADDRESS)
    {
        if (*AddressUnderTest != TEST_VALUE)
        {
            RAMFaultHandler();
            break;
        }
        else
        {
            AddressUnderTest++;
        }
    }
}

我的代码有点匆忙,所以我确信可能存在一些错误(请随时编辑),但希望这能帮助您走上正轨!

【讨论】:

  • 这很有帮助,而且在大多数情况下都有效。我目前正在调试它以查看它在哪里出错,但它肯定比我最初拥有的更简洁的编码。
  • 所以,我做了更多的挖掘工作,SPLIMIT 实际上是SPLIM 只是在另一个 IOMap 文件中手动定义的。我会考虑将其从代码中删除,然后从这里开始使用 SPLIM
  • @ThomSirveaux 出于好奇,你有没有让这个工作?
  • 我想是的。我实际上不记得了,很大程度上是因为离开了那份工作并最终成为了一名成熟的电气工程师。 :)
  • @ThomSirveaux 够公平的。我只是好奇。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-08
  • 2017-10-12
  • 2020-03-15
  • 1970-01-01
  • 2022-10-13
  • 1970-01-01
相关资源
最近更新 更多