当遇到奇怪的问题时,用32位MCU向下移动16位宽的DRAM

时间:2016-05-10 07:02:50

标签: arm embedded cortex-a

我正在开发包含32位MCU(Cortex A5)和16位宽DRAM芯片(LPDDR2)的定制板。 MCU有一个支持DDR3和LPDDR2的板载DRAM控制器,我使用LPDDR2进行工作设置。

现在,由于功率限制,我试图在启动时在MCU和DRAM(它们都使用相同的PLL)上降低一半的时钟频率,这就是我的麻烦开始的地方。

如上所述,我确实使用全频率工作设置(DRAM:400MHz,MCU:396MHz),因此人们可以预期根据DRAM数据表将频率减半并更新时序应该是另一个工作设置,但是号

DRAM init在启动时从MCU内部运行,所有测试也是如此。整个过程由特定于板的U-Boot 2015.04版本处理。

我有一组在MCU启动时运行的测试,以验证DRAM的完整性。其中一个测试是所谓的“步行位”测试,我使用32位uint,按顺序切换每个位,然后读回来验证。

我发现,当回读时,低16位没有被触摸,而高16位似乎被改变了。经过一些调查,我发现了以下模式(假设水印“0xaa”):

   write    ->  readback
0x8000_0000 -> 0x0000_aaaa
0x4000_0000 -> 0x0000_aaaa
0x2000_0000 -> 0x0000_aaaa
0x1000_0000 -> 0x0000_aaaa
[...]
0x0008_0000 -> 0x0000_aaaa
0x0004_0000 -> 0x0000_aaaa
0x0002_0000 -> 0x0000_aaaa
0x0001_0000 -> 0x0000_aaaa

0x0000_8000 -> 0x8000_aaaa
0x0000_4000 -> 0x4000_aaaa
0x0000_2000 -> 0x2000_aaaa
0x0000_1000 -> 0x1000_aaaa
[...]
0x0000_0008 -> 0x0008_aaaa
0x0000_0004 -> 0x0004_aaaa
0x0000_0002 -> 0x0002_aaaa
0x0000_0001 -> 0x0001_aaaa

水印存在,虽然我怀疑它是从之前的调试会话到达的。我将在稍后讨论,因此我现在主要关注的是“走路位” - 测试通过。

这是内存转储:

(gdb) x/16b addr  
0x80000000:     0x00    0x00    0x55    0x55    0x55    0x55    0x00    0x80
0x80000008:     0xaa    0xaa    0xaa    0xaa    0xaa    0xaa    0x00    0x55
(gdb) p/x *addr
$59 = 0x55550000
(gdb) set *addr = 0xaabbccdd
(gdb) p/x *addr 
$60 = 0xccdd0000
(gdb) x/16b addr
0x80000000:     0x00    0x00    0xdd    0xcc    0xbb    0xaa    0x00    0x80
0x80000008:     0xaa    0xaa    0xaa    0xaa    0xaa    0xaa    0x00    0x55

任何人都可以告诉我可能导致此类行为的原因吗?

干杯

注意:我故意遗漏了MCU和DRAM规范,因为我认为只有JEDEC / DFI才能解决这个问题。

编辑:添加了内存转储。

编辑:以下是“步行位”测试的来源。从位于DRAM上的存储区域的MCU内部运行。假设没有错误:

static u32 __memtest_databus(volatile u32 * const addr)
{
  /* Walking bit */

  u32 pattern = (1u << 31);
  u32 failmask = 0;

  for(; pattern; pattern >>= 1)
  {
    *addr = pattern;

    if(*addr != pattern)
      failmask |= pattern;
  }

  return failmask;
}

编辑:已检查PLL和VCO,并且设置正确。 PLL稳定,DRAM PHY确实获得锁定。

Link to DRAM Data Sheet

2 个答案:

答案 0 :(得分:0)

字节看起来像是已经移位,而不是改变。

<强>引用

(gdb) x/16b addr
0x80000000:     0x00    0x00    *0xdd    0xcc    0xbb    0xaa*    0x00    0x80
0x80000008:     0xaa    0xaa    0xaa    0xaa    0xaa    0xaa    0x00    0x55

<强>引文结束

答案 1 :(得分:0)

这里有一个严重错误:u32 pattern = (1 << 31);

整型常量1的类型为int,在ARM系统上为32位。

你将这个带符号的数字移出界限并调用未定义的行为;什么事情都可能发生。变量pattern可以获得任何值。

正确的代码是u32 pattern = (u32)1 << 31;u32 pattern = 1u << 31;