我们在 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 进行控制台输出)。
如果一位贡献者能够帮助我了解我的记忆问题,我将不胜感激。