Skip to main content
Visitor II
February 12, 2024
Question

SDRAM with just one Bank Address pin

  • February 12, 2024
  • 1 reply
  • 1332 views

I've tried to see if I can get away with using just one bank address pin for a 4-bank SDRAM (IS42/45S16160J). My understanding is that this would half the addressable memory, as I could only access two banks instead of four.

In the STM32H7 user manual I find the following table that matches my SDRAM:

ChS_0-1707748426163.png

This indicates to me that the banks are laid out as contiguous memory blocks.

However, when I try this by configuring BA1 as GPIO output and set it to either low or high, I find that I can access the whole memory but only using 1- or 2-byte access, while 4-byte access are not working anymore (atleast not on 0xd0000000). It also doesn't seem to matter how I init the InternalBankNumber field for the FMC HAL API, both FMC_SDRAM_INTERN_BANKS_NUM_2 and FMC_SDRAM_INTERN_BANKS_NUM_4 seem to lead to the same result.

Can anyone explain what's going on here? Am I missing something?

Bonus question: How are 4-byte accesses handled in general over a 16-bit bus? Does the FMC send two READ/WRITE commands? In the code below a burst length of 1 is used.

Below is my init and test code.

 

/* FMC initialization function */
static void MX_FMC_Init(void)
{
 FMC_SDRAM_TimingTypeDef SdramTiming = {0};

 /** Perform the SDRAM1 memory initialization sequence
 */
 hsdram1.Instance = FMC_SDRAM_DEVICE;
 /* hsdram1.Init */
 hsdram1.Init.SDBank = FMC_SDRAM_BANK2;
 hsdram1.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_9;
 hsdram1.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_13;
 hsdram1.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_16;
 hsdram1.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
 hsdram1.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_2;
 hsdram1.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
 hsdram1.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_2;
 hsdram1.Init.ReadBurst = FMC_SDRAM_RBURST_ENABLE;
 hsdram1.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_2;
 /* SdramTiming */
 SdramTiming.LoadToActiveDelay = 2;
 SdramTiming.ExitSelfRefreshDelay = 8;
 SdramTiming.SelfRefreshTime = 5;
 SdramTiming.RowCycleDelay = 6;
 SdramTiming.WriteRecoveryTime = 3;
 SdramTiming.RPDelay = 2;
 SdramTiming.RCDDelay = 2;

 if (HAL_SDRAM_Init(&hsdram1, &SdramTiming) != HAL_OK)
 {
 Error_Handler( );
 }

 FMC_SDRAM_CommandTypeDef Command;
 /* Step 1 and Step 2 already done in HAL_SDRAM_Init() */
 /* Step 3: Configure a clock configuration enable command */
 Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE; /* Set MODE bits to "001" */
 Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2; /* configure the Target Bank bits */
 Command.AutoRefreshNumber = 1;
 Command.ModeRegisterDefinition = 0;
 HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
 HAL_Delay(1); /* Step 4: Insert 100 us minimum delay - Min HAL Delay is 1ms */
 /* Step 5: Configure a PALL (precharge all) command */
 Command.CommandMode = FMC_SDRAM_CMD_PALL; /* Set MODE bits to "010" */
 HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
 /* Step 6: Configure an Auto Refresh command */
 Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE; /* Set MODE bits to "011" */
 Command.AutoRefreshNumber = 2;
 HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
 /* Step 7: Program the external memory mode register */
 Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;/*set the MODE bits to "100" */
 Command.ModeRegisterDefinition = (uint32_t)0 | 0<<3 | 2<<4 | 0<<7 | 1<<9;
 HAL_SDRAM_SendCommand(&hsdram1, &Command, 0xfff);
 /* Step 8: Set the refresh rate counter - refer to section SDRAM refresh timer register in RM0455 */
 /* Set the device refresh rate
 * COUNT = [(SDRAM self refresh time / number of row) x SDRAM CLK] – 20
 = [(64ms/4096) * 100MHz] - 20 = 1562.5 - 20 ~ 1542 */
 HAL_SDRAM_ProgramRefreshRate(&hsdram1, 1542);
}

//Test code
volatile uint8_t* sdram_start = (uint8_t*)0xD0000000;
volatile uint32_t sdram_size = 32*1024*1024;

static bool check_1byte(volatile uint32_t index)
{
	return ((volatile uint8_t*)sdram_start)[index] != (volatile uint8_t)index;
}
static bool check_2byte(volatile uint32_t index)
{
	return ((volatile uint16_t*)sdram_start)[index] != (volatile uint16_t)index;
}
static bool check_4byte(volatile uint32_t index)
{
	return ((volatile uint32_t*)sdram_start)[index] != (volatile uint32_t)index;
}
static void set_1byte(volatile uint32_t index)
{
	((volatile uint8_t*)sdram_start)[index] = (volatile uint8_t)index;
}
static void set_2byte(volatile uint32_t index)
{
	((volatile uint16_t*)sdram_start)[index] = (volatile uint16_t)index;
}
static void set_4byte(volatile uint32_t index)
{
	((volatile uint32_t*)sdram_start)[index] = (volatile uint32_t)index;
}

static bool sdram_test_with_byte_size(bool (*check_fn)(volatile uint32_t), void (*set_fn)(volatile uint32_t), size_t byte_size, bool breakpoint)
{
	volatile uint32_t max_index = sdram_size / byte_size;
	//Write memory
	for(volatile uint32_t i = 0; i < max_index; i++)
	{
		set_fn(i);
	}
	//Invalidate cache
 SCB_CleanDCache();
 SCB_InvalidateDCache();
 
 //Wait some time to test retention
	for(volatile uint64_t i = 0; i < 1ull * 100 * 1000 * 1000; i++)
	{
	}
	
	//Check memory
	for(volatile uint32_t i = 0; i < max_index; i++)
	{
		if(check_fn(i))
		{
			if(breakpoint)
				__BKPT(0);
			else
				return false;
		}
	}
	return true;
}

//Called as sdram_test((uint8_t*)0xd0000000, 32*1024*1024, 1, true);
bool sdram_test(uint8_t* start, uint32_t size, uint32_t n, bool breakpoint)
{
	sdram_start = start;
	sdram_size = size;
	for(uint32_t i = 0; i < n; i++)
	{
		bool result = sdram_test_with_byte_size(check_1byte, set_1byte, 1, breakpoint);
		if(!breakpoint && !result)
			return false;

		result = sdram_test_with_byte_size(check_2byte, set_2byte, 2, breakpoint);
		if(!breakpoint && !result)
			return false;

		result = sdram_test_with_byte_size(check_4byte, set_4byte, 4, breakpoint);
		if(!breakpoint && !result)
			return false;
	}
	return true;
}

 

 

    This topic has been closed for replies.

    1 reply

    ST Employee
    February 14, 2024

    Hi All,

     

    This case has been routed to our online support center for direct support from our team.

     

    Regards,
    Jake

    ST Support