AnsweredAssumed Answered

External SDRAM EMC Configuration Help W9816G6JH-6

Question asked by Matt Lang on Mar 21, 2019
Latest reply on Mar 27, 2019 by Matt Lang

Hello,

 

I am developing firmware on the LPC54605J256ET180. I have custom hardware with an external SDRAM chip connected to the EMC. I was hoping I could get some help configuring all the different timing registers for my RAM chip.

 

I am using the NXP emc driver and following the demo app used for the OM13092 LPCXpresso54608 Dev board.

 

RAM chip:

Winbond W9816G6JH-6

 

MCU Setup:

1) Using 12MHz external crystal and running core clock at 180MHz

 

Initialization Code:

// The SDRAM timing.
#define HW_SDRAM_REFRESHPERIOD_NS (32 * 1000000 / 2048) // 4096 rows/ 64ms) // 4096 rows/ 64ms
#define HW_SDRAM_TRP_NS (18u) ///< Precharge command period
#define HW_SDRAM_TRAS_NS (42u) ///< Active to precharge command period
#define HW_SDRAM_TSREX_NS (72u) ///< Self-refresh exit time
#define HW_SDRAM_TAPR_NS (18u) ///< Last-data-out to active command time
#define HW_SDRAM_TWRDELT_NS (22u) ///< Write recovery time
#define HW_SDRAM_TRC_NS (60u) ///< Selects the active to active command period
#define HW_SDRAM_RFC_NS (60u) ///< Selects the auto-refresh period
#define HW_SDRAM_XSR_NS (72u) ///< Time for exit self-refresh to active command
#define HW_SDRAM_RRD_NS (12u) ///< Latency for active bank A to active bank B
#define HW_SDRAM_MRD_NCLK (2u)
#define HW_SDRAM_RAS_NCLK (2u)
#define HW_SDRAM_MODEREG_VALUE (0x23u)
#define HW_SDRAM_DEV_MEMORYMAP (0x21u) // 16Mbits (1M*16, 2banks, 11 rows, 8 columns)
static void HW_InitSDRAM(void) {
emc_basic_config_t basicConfig;
emc_dynamic_timing_config_t dynTiming;
emc_dynamic_chip_config_t dynChipConfig;

// Initialize the I/O pins
HW_InitSDRAMPins();
// BOARD_InitPins();

/* Basic configuration. */
basicConfig.endian = kEMC_LittleEndian;
basicConfig.fbClkSrc = kEMC_IntloopbackEmcclk;
/*
* EMC Clock = CPU FREQ/2 here can fit CPU freq from 12M ~ 180M.
* If you change the divide to 0 and EMC clock is larger than 100M
* please take refer to emc.dox to adjust EMC clock delay.
*/
basicConfig.emcClkDiv = 1;
/* Dynamic memory timing configuration. */
dynTiming.readConfig = kEMC_Cmddelay;
dynTiming.refreshPeriod_Nanosec = HW_SDRAM_REFRESHPERIOD_NS;
dynTiming.tRp_Ns = HW_SDRAM_TRP_NS;
dynTiming.tRas_Ns = HW_SDRAM_TRAS_NS;
dynTiming.tSrex_Ns = HW_SDRAM_TSREX_NS;
dynTiming.tApr_Ns = HW_SDRAM_TAPR_NS;
dynTiming.tWr_Ns =
(((1000000000 / CLOCK_GetFreq(kCLOCK_EMC)) * 1) + HW_SDRAM_TWRDELT_NS); /* one clk + HW_SDRAM_TWRDELT_NS */
dynTiming.tDal_Ns = dynTiming.tWr_Ns + dynTiming.tRp_Ns;
dynTiming.tRc_Ns = HW_SDRAM_TRC_NS;
dynTiming.tRfc_Ns = HW_SDRAM_RFC_NS;
dynTiming.tXsr_Ns = HW_SDRAM_XSR_NS;
dynTiming.tRrd_Ns = HW_SDRAM_RRD_NS;
dynTiming.tMrd_Nclk = HW_SDRAM_MRD_NCLK;
/* Dynamic memory chip specific configuration: Chip 0 - MTL48LC8M16A2B4-6A */
dynChipConfig.chipIndex = 0;
dynChipConfig.dynamicDevice = kEMC_Sdram;
dynChipConfig.rAS_Nclk = HW_SDRAM_RAS_NCLK;
dynChipConfig.sdramModeReg = HW_SDRAM_MODEREG_VALUE;
dynChipConfig.sdramExtModeReg = 0; /* it has no use for normal sdram */
dynChipConfig.devAddrMap = HW_SDRAM_DEV_MEMORYMAP;
/* EMC Basic configuration. */
EMC_Init(EMC, &basicConfig);
/* EMC Dynamc memory configuration. */
EMC_DynamicMemInit(EMC, &dynTiming, &dynChipConfig, 1);
}

 

 

With the code above, it passes the test routines, BUT only when I run the MCU core clock at 96MHz with BOARD_BootClockFROHF96M.

 

But when I run the core clock at 180MHz with BOARD_BootClockPLL180M, it fails the _______.

 

I increased the clock divider, but that does not seem to get it to work. I'm guessing the timing parameters are wrong. I kinda had to guess on some of them because i'm not sure how to get them from the datasheet. 

 

Specifically the HW_SDRAM_REFRESHPERIOD_NS parameter. I'm not sure how to choose this value with the datasheet.

 

The test routines are the same ones used in the lpcxpresso54608_driver_examples_emc_sdram. But here there are anyway:

 

 

#define SDRAM_BASE_ADDR 0xa0000000
#define SDRAM_SIZE_BYTES 2000000 //(8 * 1024 * 1024)
#define SDRAM_EXAMPLE_DATALEN (SDRAM_SIZE_BYTES / 4)
#define SDRAM_TEST_PATTERN (2)
pti_return_t SDRAM_DataBusCheck(volatile uint32_t* address) {
uint32_t data = 0;

/* Write the walking 1's data test. */
for(data = 1; data != 0; data <<= 1) {
*address = data;

/* Read the data out of the address and check. */
if(*address != data) {
return pti_error;
}
}
return pti_success;
}

pti_return_t SDRAM_AddressBusCheck(volatile uint32_t* address, uint32_t bytes) {
uint32_t pattern = 0x55555555;
uint32_t size = bytes / 4;
uint32_t offset;
uint32_t checkOffset;

/* write the pattern to the power-of-two address. */
for(offset = 1; offset < size; offset <<= 1) {
   address[offset] = pattern;
}
address[0] = ~pattern;

/* Read and check. */
uint32_t *ptr = NULL;
for(offset = 1; offset < size; offset <<= 1) {
   ptr = &address[offset];
   if(*ptr != pattern) {
      return pti_error;
   }
}

if(address[0] != ~pattern) {
   return pti_error;
}

/* Change the data to the revert one address each time
* and check there is no effect to other address. */
for(offset = 1; offset < size; offset <<= 1) {
   address[offset] = ~pattern;
   for(checkOffset = 1; checkOffset < size; checkOffset <<= 1) {
      if((checkOffset != offset) && (address[checkOffset] != pattern)) {
         return pti_error;
      }
   }
   address[offset] = pattern;
}
return pti_success;
}

static void test(void) {
volatile uint32_t index;
uint32_t* sdram = (uint32_t*)SDRAM_BASE_ADDR; /* SDRAM start address. */

/* Data/address bus check. */
if(SDRAM_DataBusCheck(sdram) != pti_success) {
LOG_DEBUG(MOD_ALL_BASE, "\r\n SDRAM data bus check is failure.\r\n");
}

if(SDRAM_AddressBusCheck(sdram, SDRAM_SIZE_BYTES) != pti_success) {
LOG_DEBUG(MOD_ALL_BASE, "\r\n SDRAM address bus check is failure.\r\n");
}

LOG_DEBUG(MOD_ALL_BASE, "\r\n Start EMC SDRAM access example.\r\n");
LOG_DEBUG_PF(MOD_ALL_BASE, "\r\n SDRAM Write Start, Start Address 0x%x, Data Length %d !\r\n", sdram,
SDRAM_EXAMPLE_DATALEN);
/* Prepare data and write to SDRAM. */
for(index = 0; index < SDRAM_EXAMPLE_DATALEN; index++) {
*(uint32_t*)(sdram + index) = index;
}
LOG_DEBUG(MOD_ALL_BASE, "\r\n SDRAM Write finished!\r\n");

LOG_DEBUG_PF(MOD_ALL_BASE, "\r\n SDRAM Read/Check Start, Start Address 0x%x, Data Length %d !\r\n", sdram,
SDRAM_EXAMPLE_DATALEN);
/* Read data from the SDRAM. */
uint32_t* ptr = NULL;
uint32_t value = 0;
for(index = 0; index < SDRAM_EXAMPLE_DATALEN; index++) {
ptr = sdram + index;
value = *ptr;
if(value != index) {
LOG_DEBUG(MOD_ALL_BASE, "\r\n SDRAM Write Data and Read Data Check Error!\r\n");
break;
}
}

LOG_DEBUG(MOD_ALL_BASE, "\r\n SDRAM Write Data and Read Data Succeed.\r\n");
}

 

If someone could help me tune the EMC to work with my RAM chip I would greatly appreciate it.

 

Link to datasheet for SDRAM chip:
http://www.winbond.com/resource-files/w9816g6jh_a02.pdf 

Outcomes