我正在开发包含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确实获得锁定。
答案 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;