cancel
Showing results for 
Search instead for 
Did you mean: 

SDRAM with just one Bank Address pin

ChS
Associate

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;
}

 

 

1 REPLY 1
Jacob WOODRUFF
ST Employee

Hi All,

 

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

 

Regards,
Jake

ST Support