STM32 (Cortex-M4)

STM32 media 보드 - SD CARD

gigax 2025. 4. 23. 11:03

 SD CARD 동작
이번 글에서는 stm32f4xx 시리즈에 sd card 동작과 관련하여 정리해 보겠습니다. stm32 에서는 sdcard를 제어하기 위해서는 SDIO 라는 기능을 통해 쉽게 설정할수 있습니다.
SDIO 설정을 위해서는 회로도를 먼저 검토해봐야 합니다.


 이 회로도에서 보면 회로 구성에서 SDIO_D0 ~ SDIO_D3 까지 데이터 라인이 구성되어 있습니다. 이것은 stm32cubeide 에서 아래의 그림과 같은 설정을 의미 합니다.

※ MMC는 Multimedia Card의 약자로, SD 카드와는 핀 형식이나 타입이 다릅니다.   
회로도에서 보면 SD 카드에서 Read , Write 에서 동작은 4비트 데이터 라인으로 동작을 하고 CMD 라인은 명령 전송에 사용됩니다. CLK 라인은 통신 동기화를 위한 클럭 신호를 제공 합니다.
SD_DETECT 핀 같은 경우는 SD 카드에 슬롯을 낄 경우 SD 카드 입력을 감지 합니다. 회로 구성상 감지를 위해 pull down 으로 구성되어 있습니다.

SD DETECT 핀같은 경우는 GPIO 설정에서 pull-down 으로 설정해 줘야 합니다.

그 외에는 기본적인 SDIO 설정에서 특별히 추가로 설정할 사항은 없습니다. 물론 추후에 클록 디바이더(clock divider) 설정에 따라 데이터의 읽기 및 쓰기 속도가 달라질 수 있습니다. 안정적인 통신 방식을 위해 적절한 속도 설정이 필요하며, 초기 설정 값은 0으로 되어 있습니다.

Clock transition on which the bit capture is made
Rising transition 으로 설정되어 있습니다. 이는 클럭 신호의 상승 에지(rising edge)에서 데이터 비트를 캡처하도록 구성되어 있음을 의미합니다. SDIO 통신에서 데이터 샘플링 시점을 결정하는 중요한 설정입니다.

 

SDIO Clock divider bypass
기본적으로 Disable로 설정을 하고 이 옵션이 비활성화 되어 있어서 클럭 분주기(Clock divider) 가 정상적으로 동작 됩니다.

 

SDIO Clock output enable when the bus is idle
Disable the power save for the clock  으로 기본적으로 설정되어 있고 이는 버스 상태가 idle 상태일 때도 클록 전력을 유지 합니다. 이 설정은 빠른 응답시간이 진행 되지만 전력 소비는 증가 할수 있습니다.

SDIO hardware flow control

The hardware control flow is disabled 로 기본적으로 설정되어 있고 하드웨어 흐름제어가 비활성화 되어 있어서 데이터 전송 중 하드웨어 레벨의 흐름 제어가 적용되지 않습니다.

 

SDIOCLK clock divide factor

0으로 설정되어 있습니다. 이 값은 SDIO 클럭의 분주 비율을 결정합니다. 0으로 설정되어 있다면 기본값이나 다른 메커니즘을 통해 클럭 분주가 이루어질 수 있습니다.

Toolchain 은 stm32cubeide로 설정하고 코드 변환을 하면 아래와 같은 코드가 제작 됩니다.

SD_HandleTypeDef hsd;

/* SDIO init function */

void BSP_SDIO_SD_Init(void)
{

  /* USER CODE BEGIN SDIO_Init 0 */

  /* USER CODE END SDIO_Init 0 */

  /* USER CODE BEGIN SDIO_Init 1 */

  /* USER CODE END SDIO_Init 1 */
  hsd.Instance = SDIO;
  hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING;
  hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE;
  hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE;
  hsd.Init.BusWide = SDIO_BUS_WIDE_4B;
  hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
  hsd.Init.ClockDiv = 0x75;
  /* USER CODE BEGIN SDIO_Init 2 */
  hsd.Init.BusWide = SDIO_BUS_WIDE_1B;
  if(HAL_SD_Init(&hsd) != HAL_OK){
	  Error_Handler();
  }
  if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK) {
	  Error_Handler();
  }
  /* USER CODE END SDIO_Init 2 */

}

void BSP_SD_MspInit(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  
  __HAL_RCC_SDIO_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();
  
  /**SDIO GPIO Configuration
    PC8     ------> SDIO_D0
    PC12     ------> SDIO_CK
    PD2     ------> SDIO_CMD
  */
 
  GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
  
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.Alternate = GPIO_AF12_SDIO;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

  GPIO_InitStruct.Pin = SD_DETECT_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  HAL_GPIO_Init(SD_DETECT_GPIO_Port, &GPIO_InitStruct);
}

void BSP_SD_MspDeInit(void)
{
    __HAL_RCC_SDIO_CLK_DISABLE();
    /**SDIO GPIO Configuration
    PC8     ------> SDIO_D0
    PC12     ------> SDIO_CK
    PD2     ------> SDIO_CMD
    */
    HAL_GPIO_DeInit(GPIOC, GPIO_PIN_8|GPIO_PIN_12);
    HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2);  
}

※ 무슨 이유인지는 모르겠지만 stm32cubeide 에서는 버스 구조를 1B 로 설정한 다음 다시 4B로 버스 동작을 잡는 코드가 추가적으로 들어가야 합니다.

다음 글에서는 STM32에서 제공하는 미들웨어 기능 중 FATFS(File Allocation Table File System)를 활용하여 SD 카드에 접근하고, 데이터를 실제로 열고 읽는 동작에 대해 정리해 보겠습니다.