We have a custom board using 2MB Everspin MRAM MR4A16B (54-TSOP2 package) on EPI HB16 https://www.everspin.com/family/mr4a16b
We using Host Bus 16 with multiplexed address and data.
However, we have been having difficulty reading and writing reliably to the MRAM.
Writing issues:
In my test code, I write the same data (0xFFFF) to the whole memory. When I read it back, some of addresses have zero (0x0000) stored in them. I have verified this using the Code Composer Studio memory browser. Somehow, if I immediately read the MRAM back after each word write, the issue does not happen. Still, it would be much better to resolve root cause of this issue.
I found during testing that repeatedly writing 0xFFFF to a word at addresss 0x60XXX4XX (e.g. 0x600E0412) sometimes causes stored data at another address 0x60XXX0XX (e.g. 0x600E0012) to invert (e.g. 0xFFFF -> 0x0000; 0xA5A5 -> 0x5A5A)
Reading issues:
Repeated reads or write-then-reads of the same address sometimes result in erroneous 0x0000 reads.
Reducing the Inter-transfer Capture Width (delay between Host-Bus transfers) from the default of 2 EPI clocks to 1 EPI clock eliminates the problem with repeated reads, but does not fix the write-then-read issue.
EPIConfigHB16TimingSet(EPI0_BASE, 0, EPI_HB16_CAP_WIDTH_1);
I’m not sure why this helps.
Here is the EPI initialisation code we are using:
#define EPI_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_PORTG_PINS (GPIO_PIN_1 | GPIO_PIN_0)
#define EPI_PORTH_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
#define EPI_PORTL_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
#define EPI_PORTM_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
#define EPI_PORTP_PINS (GPIO_PIN_3 | GPIO_PIN_2)
void InitMemory(){
//Ports used for 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);
//
// The EPI0 peripheral must be enabled for use.
//
SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0);
while(!SysCtlPeripheralReady(SYSCTL_PERIPH_EPI0)) //wait for it to be ready
{
}
//
// This step configures the internal pin muxes to set the EPI pins for use
// with 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, EPI_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, EPI_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, EPI_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, EPI_PORTB_PINS, GPIO_DIR_MODE_HW);
// EPI0S29 ~ EPI0S30: P2 , 3
GPIOPinConfigure(GPIO_PP2_EPI0S29);
GPIOPinConfigure(GPIO_PP3_EPI0S30);
GPIODirModeSet(GPIO_PORTP_BASE, EPI_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, EPI_PORTB_PINS, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);
GPIOPadConfigSet(GPIO_PORTC_BASE, EPI_PORTC_PINS, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);
GPIOPadConfigSet(GPIO_PORTG_BASE, EPI_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, EPI_PORTL_PINS, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);
GPIOPadConfigSet(GPIO_PORTM_BASE, EPI_PORTM_PINS, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);
GPIOPadConfigSet(GPIO_PORTP_BASE, EPI_PORTP_PINS, GPIO_STRENGTH_8MA, GPIO_PIN_TYPE_STD);
// Configure the GPIO pins for EPI mode.
// This step also gives control of pins to the EPI module.
GPIOPinTypeEPI(GPIO_PORTA_BASE, EPI_PORTA_PINS);
GPIOPinTypeEPI(GPIO_PORTB_BASE, EPI_PORTB_PINS);
GPIOPinTypeEPI(GPIO_PORTC_BASE, EPI_PORTC_PINS);
GPIOPinTypeEPI(GPIO_PORTG_BASE, EPI_PORTG_PINS);
GPIOPinTypeEPI(GPIO_PORTH_BASE, EPI_PORTH_PINS);
GPIOPinTypeEPI(GPIO_PORTL_BASE, EPI_PORTL_PINS);
GPIOPinTypeEPI(GPIO_PORTM_BASE, EPI_PORTM_PINS);
GPIOPinTypeEPI(GPIO_PORTP_BASE, EPI_PORTP_PINS);
// Now that we have configured GPIO pins, configure the EPI module.
// 120MHz CPU, set EPI clock to 120/8 = 15MHz
// Minimum read/write cycle time = 35ns == 28MHz
EPIDividerSet(EPI0_BASE, 6); // EPI clock is 1/8th of CPU
EPIModeSet(EPI0_BASE, EPI_MODE_HB16);
EPIConfigHB16Set(EPI0_BASE,
(EPI_HB16_CSCFG_ALE_SINGLE_CS | //sets EPIS030 to operate as an address latch (ALE) and EPIS027 is used as a chip select.
EPI_HB16_MODE_ADMUX |//Address and Data are multiplexed
EPI_HB16_ALE_HIGH //Address latch enable is active high
),
0);
// EPIConfigHB16TimingSet(EPI0_BASE, 0, EPI_HB16_CAP_WIDTH_1);
// Set the address map.
// MRAM is only 2MB, choose nearest larger option.
EPIAddressMapSet(EPI0_BASE, EPI_ADDR_RAM_SIZE_16MB | EPI_ADDR_RAM_BASE_6);
}
Here is the function we use to test the memory writing:
void TestMemory(){
uint16_t pattern = 0xFFFF; // the data we write to each word
const uint32_t numBytes = 0x200000; // 2MB
const uint32_t numWords = numBytes /sizeof(uint16_t); // 16 bit words
volatile uint16_t* ramBaseAddress = (volatile uint16_t*) 0x60000000;
int index;
while(1){
for (index = 0; index < numWords; index++){
//First write the pattern to each word
ramBaseAddress[index] = pattern;
// Somehow, immediately reading the memory
// back after each write avoids the issue.
// uint16_t readBack = *ramBaseAddress;
// uint16_t readBack = ramBaseAddress[index];
}
for (index = 0; index < numWords; index++){
// Check that data in each word matches the pattern
if (ramBaseAddress[index] != pattern){
System_printf("Error @0x%x: Expected: 0x%x, Got: 0x%x\n", &ramBaseAddress[index], pattern, ramBaseAddress[index]);
System_flush();
}
}
}
}
Here's the main function for completeness
int main(void)
{
InitMemory();
TestMemory();
return (0);
}
Here is the console output of the function on one of the boards
Error @0x60180004: Expected: 0xffff, Got: 0x0
Error @0x60180404: Expected: 0xffff, Got: 0x0
Error @0x60100002: Expected: 0xffff, Got: 0x0
Error @0x60100402: Expected: 0xffff, Got: 0x0
Error @0x60040228: Expected: 0xffff, Got: 0x0
Error @0x60040628: Expected: 0xffff, Got: 0x0
Error @0x601c0108: Expected: 0xffff, Got: 0x0
Error @0x601c0508: Expected: 0xffff, Got: 0x0
Error @0x60020018: Expected: 0xffff, Got: 0x0
Error @0x60020418: Expected: 0xffff, Got: 0x0
Error @0x600a0028: Expected: 0xffff, Got: 0x0
Error @0x600a0428: Expected: 0xffff, Got: 0x0
Error @0x60000048: Expected: 0xffff, Got: 0x0
Error @0x60000448: Expected: 0xffff, Got: 0x0
Error @0x60060108: Expected: 0xffff, Got: 0x0
Error @0x60060508: Expected: 0xffff, Got: 0x0
Here is the console output of the function on another board
Error @0x60020004: Expected: 0xffff, Got: 0x0
Error @0x60020804: Expected: 0xffff, Got: 0x0
Error @0x601a1004: Expected: 0xffff, Got: 0x0
Error @0x601a1804: Expected: 0xffff, Got: 0x0
Error @0x60141004: Expected: 0xffff, Got: 0x0
Error @0x60141804: Expected: 0xffff, Got: 0x0
Error @0x601e0004: Expected: 0xffff, Got: 0x0
Error @0x601e0804: Expected: 0xffff, Got: 0x0
Error @0x601c1004: Expected: 0xffff, Got: 0x0
Error @0x601c1804: Expected: 0xffff, Got: 0x0
I have attached a zip of my project (which uses TI-RTOS for console output).
I would be grateful if a contributor can help shed some light on my memory issues.