ST/STM32F746DIS

STM32F746G DISCOVERY - SDRAM

engineer4ever 2025. 4. 19. 11:53

 

MCU
STM32F746G DISCOVERY(ST)
IDE
Atollic(TrueSTUDIO), STM32CubeMX
목표
외부 SDRAM 추가

 

1. SDRAM External memory interface

1) STM32F746 DISCOVERY SDRAM Pin map(자세히는 MB1191 참고)

 

2) SDRAM signals

SDRAM signal
Port
I/O
type
Description
Alternate function
SDCLK
PG8
O
SDRAM clock
-
SDCKE[1:0]
PC3
O
SDCKE0 : SDRAM Bank 1 Clock Enable
SDCKE1 : SDRAM Bank 2 Clock Enable
-
SDNE[1:0]
PH3
O
SDNE0: SDRAM Bank 1 Chip Enable
SDNE1: SDRAM Bank 2 Chip Enable
-
A[12:0]
A0~A11
O
Address
FMC_A[12:0]
D[31:0]
D0~D15
I/O
Bidirectional data bus
FMC_D[31:0]
BA[1:0]
PG5,PG4
O
Bank Address
FMC_A[15:14]
NRAS
PF11
O
Row Address Strobe
-
NCAS
PG15
O
Column Address Strobe
-
SDNWE
PH5
O
Write Enable
-
NBL[3:0]
PE1,PE0
O
Output Byte Mask for write accesses
(memory signal name: DQM[3:0])
FMC_NBL[3:0]

 

2. STM32CubeMX : SDRAM 추가

- 'Clock Configuration' Tab으로 이동

1) HCKL = 216MHz

 

- 'Pinout & Configuration' Tab으로 이동

1) Connectivity - FMC 선택

 

2) SDRAM1 선택

3) Clock and chip enable : SDCKE0 + SDNE0(PC3, PH3)

SDCKE0 기본 할당 PH2 → PC3으로 변경

4) Internal bank number : 4 banks(BA0, BA1)

5) Address : 12 bits(A0 ~ A11 ; 최대 13 bits)

6) Data : 16 bits

7) Byte enable : 16-bit byte enable

 

2. SDNRAS,SDNCAS,SDCLK는 회로도와 동일하게 자동 할당

1) column addr : 8bit(A0 ~A7)

2) row addr : 12bit(A0 ~A11)

3) CAS latency : 3 memory cycles(100MHz 이상 동작시)

4) write protection : disabled

5) SDRAM CLK = HCLK/2=108MHz(max 143MHz)

6) burst read : Disabled

7) read pipe delay : 1 HCLK clock cycle

 

8) Load mode register to active daly : 2

9) Exit self-refresh delay : 7

10) Self-refresh time : 4

11) SDRAM common row cycle delay : 7

12) write recovery time : 3

13) SDRAM common row precharge delay : 2

14) Row to column delay : 2

- GENERATE CODE 클릭


- FMC만 설정한다고 SDRAM을 바로 쓸수 있는게 아니고 SDRAM을 초기화 해줘야 하는데 여기서는 bsp sdram library를 사용함

- BSP library를 프로젝트 폴더에 넣고 시작할것

 

 

3. ATOLLIC 실행

1) C/C++ General > Paths and Symbols > Includes > GNU C에 BSP 폴더 추가

 

2) C/C++ General > Paths and Symbols > Source Location에 BSP 폴더 추가

 

3) BSP_SDRAM_Initialization() 수정

: Command.CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1으로 되어있는지 확인

void BSP_SDRAM_Initialization(uint32_t RefreshCount)
{
  __IO uint32_t tmpmrd =0;

  /* Step 1:  Configure a clock configuration enable command */
  Command.CommandMode             = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK1;
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = 0;

  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);

  /* Step 2: Insert 100 us minimum delay */ 
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);

  /* Step 3: Configure a PALL (precharge all) command */ 
  Command.CommandMode             = FMC_SDRAM_CMD_PALL;
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK1;
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = 0;

  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);  
  
  /* Step 4: Configure an Auto Refresh command */ 
  Command.CommandMode             = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK1;
  Command.AutoRefreshNumber       = 4;
  Command.ModeRegisterDefinition  = 0;

  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
  
  /* Step 5: Program the external memory mode register */
  tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |
                     SDRAM_MODEREG_CAS_LATENCY_3           |
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD |
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
  
  Command.CommandMode             = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget           = FMC_SDRAM_CMD_TARGET_BANK1;
  Command.AutoRefreshNumber       = 1;
  Command.ModeRegisterDefinition  = tmpmrd;

  /* Send the command */
  HAL_SDRAM_SendCommand(&hsdram1, &Command, SDRAM_TIMEOUT);
  
  /* Step 6: Set the refresh rate counter */
  /* Set the device refresh rate */
  HAL_SDRAM_ProgramRefreshRate(&hsdram1, RefreshCount); 
}
 

 

4) main.c 수정

: BSP_SDRAM_Initialization(REFRESH_COUNT); 호출

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
#define SDRAM_ADDRESS 0xC0000000

/* USER CODE BEGIN 2 */
BSP_SDRAM_Initialization(REFRESH_COUNT);
 

 

5) Linker Script 수정

: SDRAM 추가

- SDRAM 사용 예제를 찾아보면 SDRAM 주소에 직접 데이터를 쓰는 경우를 봤는데, 변수 한두개도 아니고 64Mbit 용량을 주소에다가 직접 사용하는건 비효율적이라고 본다.

MEMORY
{
RAM (xrw)      : ORIGIN = 0x20000000, LENGTH = 320K
FLASH (rx)      : ORIGIN = 0x8000000, LENGTH = 1024K
SDRAM (xrw)      : ORIGIN = 0xC0000000, LENGTH = 8M
}
 

 

Compile시에 아래와 같이 SDRAM이 할당된 것을 확인 할 수 있다.

 

6) 실제로 SDRAM에 변수를 사용하기 위해서 .bss를 SDRAM에 할당하자.

  /* Uninitialized data section */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss secion */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >SDRAM
 

이게 잘 될까? 결론부터 얘기하면 동작하지 않는다.

SDRAM 초기화에 사용하는 변수중에 .bss로 할당 되는 변수가 있는데, SDRAM에 변수를 할당해야 하는데 SDRAM은 초기화가 되지 않았다? 아직 집을 짓지도 않았는데, 그 집주소에 택배를 보내는 꼴이다.

 

그러면 어떻게 해야 하나?

1. Bootloader로 SDRAM을 살리고 본 프로그램에서 변수를 SDRAM에 할당

2. 내가 쓰고자 하는 소스가 있는 폴더만 SDRAM에 할당 하도록 함

 

여기서는 2번 방법에 대해 설명한다. 아래와 같이 링커 스트립트를 수정하면, USER 폴더 안에 있는 소스의 모든 변수는 SDRAM에 할당 된다.

  .bss_sdram :
  {
  . = ALIGN(8);
  
  	_sbss_sdram = .; 
  	*USER* (.bss .bss* COMMON)
  	
  	. = ALIGN(8);
  } >SDRAM
  
  /* Uninitialized data section into "RAM" Ram type memory */
  . = ALIGN(4);
  .bss :
  {
    /* This is used by the startup in order to initialize the .bss section */
    _sbss = .;         /* define a global symbol at bss start */
    __bss_start__ = _sbss;
    *(.bss)
    *(.bss*)
    *(COMMON)

    . = ALIGN(4);
    _ebss = .;         /* define a global symbol at bss end */
    __bss_end__ = _ebss;
  } >RAM
 

 

Debug 폴더 안의 map 파일을 열어보면 USER 폴더안의 소스의 변수 'flag_filter'가 SDRAM에 할당 된것을 확인 할 수 있다.

 

.bss_sdram      0x0c010000        0x4
                0x0c010000                _sbss_sdram = .
 *USER*(.bss .bss* COMMON)
 .bss.flag_filter
                0x0c010000        0x4 USER\temp.o
                0x0c010000                flag_filter
                0x0c010004                _ebss_sdram = .
                0x0c010004                . = ALIGN (0x4)

.bss            0x20000074      0x1fc
                0x20000074                _sbss = .
                0x20000074                __bss_start__ = _sbss
 *(.bss)
 

'ST > STM32F746DIS' 카테고리의 다른 글

STM32F746G DISCOVERY - LCD + TOUCH  (0) 2025.04.19
STM32F746G DISCOVERY - LCD I/F  (0) 2025.04.19
STM32F746G DISCOVERY - TIM(IC, OC, PWM)  (0) 2025.04.19
STM32F746G DISCOVERY - TIMER  (0) 2025.04.19
STM32F746G DISCOVERY - UART(DMA)  (0) 2025.04.19