This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C129ENCPDT:EPI 主机总线16的 MRAM 读/写问题

Guru**** 2455560 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/640574/tm4c129encpdt-mram-read-write-issue-with-epi-host-bus-16

器件型号:TM4C129ENCPDT

我们在 EPI HB16https://www.everspin.com/family/mr4a16b 上提供了使用2MB Everspin MRAM MR4A16B (54-TSOP2封装)的定制电路板

我们使用具有多路复用地址和数据的主机总线16。

但是、我们一直难以可靠地读取和写入 MRAM。

 

书写问题:

在我的测试代码中、我将相同的数据(0xFFFF)写入整个存储器。 当我读回它时、一些地址中存储了零(0x0000)。 我已经使用 Code Composer Studio 存储器浏览器验证了这一点。 在某种程度上、如果我在每个字写入后立即读回 MRAM、则不会发生该问题。 不过,解决这一问题的根本原因要好得多。

在测试过程中、我发现反复向地址0x60XXX4XX 的字写入0xFFFF (例如0x600E0412)有时会导致另一地址0x60XXX0XX (例如0x600E0012)的存储数据反相(例如0xFFFF -> 0x0000;0xA5A5 -> 0x5A5A)

 

阅读问题:

对同一地址的重复读取或先写后读有时会导致错误的0x0000读取。

将传输间捕捉宽度(主机总线传输之间的延迟)从默认的2个 EPI 时钟减少到1个 EPI 时钟、可以消除重复读取时的问题、但不能解决先写后读问题。

EPIConfigHB16TimingSet (EPI0_BASE、0、EPI_HB16_CAP_WIDTH_1); 

我不知道为什么这会有所帮助。

 

下面是我们使用的 EPI 初始化代码:

#define EP_PORta_Pins (GPIO_PIN_7 | GPIO_PIN_6)
#define EPI_PORTB_Pins (GPIO_PIN_2 | GPIO_PIN_3)
#define EPI_PORTC_Pins (GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4)#define EPI_PORT_PIN_0_PIN_PIN_0

| GPIO_PIN_PIN_0_GPIO_PIN_PIN_0 (GPIO_0
)|GPIO_PIN_PIN_PIN_PIN_0)|GPIO_PIN_PIN_PIN_PIN_0_GPIO_PIN_PIN_PIN_0_PIN_GPIO_0 |
#define | GPIO_PIN_PIN_PIN_PIN_0_PIN_GPIO_PIN_PIN_PIN_PIN_PIN_0_PIN_PIN_PIN_PIN_0_PIN_PIN_PIN (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
#define EPI_PORTP_PINS (GPIO_PIN_3 | GPIO_PIN_2)


void InitMemory (){
用于 EPI0的//端口
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOC);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOG);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOH);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOL);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOM);
SysCtlPeripheralEnable (SYSCTL_Periph_GPIOP);

//
//必须启用 EPI0外设才能使用。
//
SysCtlPeripheralEnable (SYSCTL_Periph_EPI0);
while (!SysCtlPeripheralReady (SYSCTL_Periph_EPI0))//等待它准备就绪
{
}

//
//此步骤配置内部管脚多路复用器以设置要使用的 EPI 管脚
//使用 EPI。

// EPI0S4 ~ EPI0S7:C4 ~ 7
GPIOPinConfigure (GPIO_PC4_EPI0S7);
GPIOPinConfigure (GPIO_PC5_EPI0S6);
GPIOPinConfigure (GPIO_PC6_EPI0S5);
GPIOPinConfigure (GPIO_PC7_EPI0S4);
GPIODirModeSet (GPIO_PORTC_BASE、EP_PORTC_Pins、GPIO_DIR_MODE_HW);

// EPI0S8 ~ EPI0S9:A6 ~ 7
GPIOPinConfigure (GPIO_PA6_EPI0S8);
GPIOPinConfigure (GPIO_PA7_EPI0S9);
GPIODirModeSet (GPIO_Porta_base、EPI_Porta_Pins、GPIO_DIR_MODE_HW);

// EPI0S10 ~ EPI0S11:G0 ~ 1
GPIOPinConfigure (GPIO_PG0_EPI0S11);
GPIOPinConfigure (GPIO_PG1_EPI0S10);
GPIODirModeSet (GPIO_PORTG_base、EP_PORTG_Pins、GPIO_DIR_MODE_HW);

// EPI0S12 ~ EPI0S15:M0 ~ 3
GPIOPinConfigure (GPIO_PM0_EPI0S15);
GPIOPinConfigure (GPIO_PM1_EPI0S14);
GPIOPinConfigure (GPIO_PM2_EPI0S13);
GPIOPinConfigure (GPIO_PM3_EPI0S12);
GPIODirModeSet (GPIO_PORTM_BASE、EP_PORTM_Pins、GPIO_DIR_MODE_HW);

// EPI0S16 ~ EPI0S19:l0 ~ 3
GPIOPinConfigure (GPIO_PL0_EPI0S16);
GPIOPinConfigure (GPIO_PL1_EPI0S17);
GPIOPinConfigure (GPIO_PL2_EPI0S18);
GPIOPinConfigure (GPIO_PL3_EPI0S19);
GPIODirModeSet (GPIO_PORTL_base、EPI_PORTL_Pins、GPIO_DIR_MODE_HW);

// EPI0S28:B2 ~ B3
GPIOPinConfigure (GPIO_PB2_EPI0S27);
GPIOPinConfigure (GPIO_PB3_EPI0S28);
GPIODirModeSet (GPIO_PORTB_BASE、EP_PORTB_Pins、GPIO_DIR_MODE_HW);


// EPI0S29 ~ EPI0S30:P2,3.
GPIOPinConfigure (GPIO_PP2_EPI0S29);
GPIOPinConfigure (GPIO_PP3_EPI0S30);
GPIODirModeSet (GPIO_PORTP_BASE、EP_PORTP_Pins、GPIO_DIR_MODE_HW);

// EPI0S00 ~ EPI0S03:H0 ~ H3
GPIOPinConfigure (GPIO_PH0_EPI0S0);
GPIOPinConfigure (GPIO_PH1_EPI0S1);
GPIOPinConfigure (GPIO_PH2_EPI0S2);
GPIOPinConfigure (GPIO_PH3_EPI0S3);
GPIODirModeSet (GPIO_Porth_BASE、EPI_Porth_Pins、GPIO_DIR_MODE_HW);

GPIOPadConfigSet (GPIO_Porta_base、EPI_Porta_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTB_BASE、EP_PORTB_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTC_BASE、EP_PORTC_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTG_base、EP_PORTG_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_Porth_BASE、EPI_Porth_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTL_base、EP_PORTL_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTM_BASE、EP_PORTM_Pins、GPIO_Strength _8mA、GPIO_PIN_TYPE_STD);
GPIOPadConfigSet (GPIO_PORTP_BASE、EP_PORTP_PINS、GPIO_FORMENT_8mA、GPIO_PIN_TYPE_STD);

//为 EPI 模式配置 GPIO 引脚。
//此步骤还为 EPI 模块提供引脚控制。
GPIOPinTypeEPI (GPIO_Porta_base、EPI_Porta_Pins);
GPIOPinTypeEPI (GPIO_PORTB_BASE、EP_PORTB_Pins);
GPIOPinTypeEPI (GPIO_PORTC_BASE、EP_PORTC_Pins);
GPIOPinTypeEPI (GPIO_PORTG_base、EP_PORTG_Pins);
GPIOPinTypeEPI (GPIO_Porth_BASE、EPI_Porth_Pins);
GPIOPinTypeEPI (GPIO_PORTL_base、EPI_PORTL_Pins);
GPIOPinTypeEPI (GPIO_PORTM_BASE、EP_PORTM_Pins);
GPIOPinTypeEPI (GPIO_PORTP_BASE、EP_PORTP_Pins);

//现在我们已经配置了 GPIO 引脚,配置 EPI 模块。
// 120MHz CPU,将 EPI 时钟设置为120/8 = 15MHz
//最小读取/写入周期时间= 35ns = 28MHz
EPIDividerSet (EPI0_BASE、6);// EPI 时钟为 CPU 的1/8

EPImodeSet (EPI0_BASE、EPI_MODE_HB16);
EPIConfigHB16Set (EPI0_BASE、
(EPI_HB16_CSCFG_ALE_SINGLE_CS |//将 EPIS030设置为作为地址锁存器(ALE)运行、而 EPIS027用作芯片选择。
EPI_HB16_MODE_ADMUX |//Address 和 Data 复用
EPI_HB16_ALE_HIGH //地址锁存使能为高电平有效
)、
0);

// EPIConfigHB16TimingSet (EPI0_BASE、0、EPI_HB16_CAP_WIDTH_1);

//设置地址映射。
// MRAM 仅为2MB,请选择最接近的更大选项。
EPIAddressMapSet (EPI0_BASE、EPI_ADDR_RAM_SIZE = 16MB | EPI_ADDR_RAM_BASE_6);
} 

 

下面是我们用于测试存储器写入的函数:

void TestMemory(){

uint16_t pattern = 0xFFFF;//我们写入每个字的数据
const uint32_t numBytes = 0x200000;// 2MB
const uint32_t NumWords = numBytes /sizeof (uint16_t);// 16位字
volatile uint16_t* ramBaseAddress =(volatile uint16_t*) 0x60000000;
int 索引;
while (1){
对于(index = 0;index < NumWords;index++){
//首先将模式写入每个字
ramBaseAddress[index]=模式;


//石榴,立即读取内存
//在每次写入后返回可以避免该问题。

// uint16_t readback =* ramBaseAddress;
// uint16_t readback = ramBaseAddress[index];
}

对于(index = 0;index < NumWords;index++){
//检查每个字中的数据是否与模式匹配
if (ramBaseAddress[index]!= pattern){
System_printf ("Error @0x%x:Expected:0x%x、GOT:0x%x\n"、&ramBaseAddress[index]、pattern、ramBaseAddress[index]);
system_flush();
}
}

} 

以下是完整性的主要功能

int main (void)
{
InitMemory();

TestMemory();

返回(0);
} 

这是其中一个板上的功能控制台输出

错误@0x60180004:预期:0xFFFF、得到:0x0

错误@0x60180404:预期:0xFFFF、GOT:0x0

 

错误@0x60100002:预期:0xFFFF、得到:0x0

Error @0x60100402:Expected:0xFFFF、GOT:0x0

 

错误@0x60040228:预期值:0xFFFF、得到:0x0

错误@0x60040628:预期值:0xFFFF、得到:0x0

 

错误@0x601c0108:预期:0xFFFF、获取:0x0

错误@0x601c0508:预期:0xFFFF、获取:0x0

 

错误@0x60020018:预期值:0xFFFF、得到:0x0

错误@0x60020418:预期:0xFFFF、得到:0x0

 

错误@0x600a0028:预期值:0xFFFF、得到:0x0

错误@0x600a0428:预期值:0xFFFF、得到:0x0

 

错误@0x60000048:预期值:0xFFFF、得到:0x0

错误@0x60000448:预期:0xFFFF、GOT:0x0

 

错误@0x60060108:预期值:0xFFFF、得到:0x0

错误@0x60060508:预期值:0xFFFF、得到:0x0

这是另一个电路板上的功能控制台输出

错误@0x60020004:预期值:0xFFFF、得到:0x0

Error @0x60020804:Expected:0xFFFF、GOT:0x0

 

错误@0x601a1004:预期:0xFFFF、得到:0x0

错误@0x601a1804:预期:0xFFFF、得到:0x0

 

ERROR @0x60141004:Expected:0xFFFF、GOT:0x0

错误@0x60141804:预期:0xFFFF、得到:0x0

 

错误@0x601e0004:预期:0xFFFF、得到:0x0

错误@0x601e0804:预期:0xFFFF、GOT:0x0

 

ERROR @0x601c1004:Expected:0xFFFF、GOT:0x0

错误@0x601c1804:预期:0xFFFF、得到:0x0

 

我已附上项目的 zip 文件(该文件使用 TI-RTOS 进行控制台输出)。

e2e.ti.com/.../MemTestEPI.zip

如果一位贡献者能够帮助我了解我的记忆问题,我将不胜感激。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Aaron、

    可能存在一些计时问题。 您需要检查 EPI 是否正确配置为与 MRAM 对接。 请确保 EPI 接口满足所有时序要求。 例如、您是否满足 E14参数的设置时间要求? 您可以在数据表的电气特性部分中找到 EPI HB16接口特性。 以下摘录。

    还请使用示波器捕获接口波形、并查看信号是否存在任何异常。 时序问题可能是由于 PCB 板上的布线过长所致。 检查传输线路端接是否正确、否则可能会出现一些不必要的振铃/反射。