サンプルプログラム F405VG_SD_SDIO の説明
tri-S_CPU_F
  マイクロSDのSDIOアクセスの
 サンプルプログラムです。

  サンプルプログラムの動作を確認するために
 えがおのでんし製の評価用基板 Base-F405VG
 STMicroelectronics社のfreeの開発ツール、
 STM32CubeIDE を使用しています。

  えがおのでんし製の評価用基板 Base-F405VG には、STM32F405VGを実装した
 えがおのでんし製の評価用CPU基板 tri-S が搭載されています。



目次

えがおのでんし製の評価用基板 Base-F405VG の説明

サンプルプログラム F405VG_SD_SDIO のプロジェクト

SDIO接続の回路図

サンプルプログラム F405VG_SD_SDIO の説明
 F405VG_SD_SDIO の構成
 F405VG_SD_SDIO の動作パラメータの定義
 ユーザープログラムの実行開始位置
 F405VG_SD_SDIO の main() の説明
  1) 初期化の部分
  2) LED点滅 と SD試験 の部分

 SD試験 Test_SD の説明
  1) Test_SD のソース
  2) Test_SD の動作

 書き込みデータについて



えがおのでんし製の評価用基板 Base-F405VG の説明
  このサンプルプログラムは、
  えがおのでんし製の評価用基板 Base-F405VG を使用して動作を確認しています。

Base_F405VG_Dim

  基板については、
 Base-F405VG基板 の説明 をご覧ください。



サンプルプログラム F405VG_SD_SDIO のプロジェクト
 STM32CubeIDE 1.11.2 を使用して作成しました。
 ここからサンプルプログラムのプロジェクト W_F405VG_SD_SDIO.zip をダウンロードしてください。

  プロジェクト W_F405VG_SD_SDIO は、
 フォルダ C:\W_CubeIDE\W_F405VG\W_F405VG_SD_SDIO のように配置して作成しました。

  フォルダ C:\W_CubeIDE\W_F405VG を作成して、
 そのフォルダに W_F405VG_SD_SDIO.zip を貼り付けて解凍し、
 プロジェクト作成時と同一に C:\W_CubeIDE\W_F405VG\W_F405VG_SD_SDIO と
 配置した場合は、普通にプロジェクトを開くことができます。

  サンプルプログラムのプロジェクトを任意のフォルダに配置した場合に、
 STM32CubeIDEにより、そのプロジェクトを開く方法については
既存のプロジェクトを開く方法 をご覧ください。



SDIO接続の回路図
  マイクロSDのSDIO接続の回路図については

tri-S基板 の回路図 をご覧ください。



サンプルプログラム F405VG_SD_SDIO の説明
  マイクロSDにSDIO接続でアクセスを行うプログラムです。

  汎用FATファイルシステム・モジュール FatFs を使用して SD にアクセスします。

  メモリ容量 32GバイトのSDまでアクセスが可能です。

  KIOXIA マイクロSDカード (micro SDHC) EXCERIA 16GB 100MB/s と
  KIOXIA マイクロSDカード (micro SDHC) EXCERIA 32GB 100MB/s で
 動作を確認しています。

  このSDカードは、秋月電子通商で販売しています。

 プロジェクトを最初に開いた画面は以下のようになります。

F405VG_SD_SDIO_Scrn_First

 以下、サンプルプログラム F405VG_SD_SDIO について説明していきます。



サンプルプログラムの構成
  STM32CubeIDEの画面左側、Project Explorerの
 F405VG_SD_SDIOを展開した画面は以下のようになります。

F405VG_SD_SDIO_Tree

  サンプルプログラム F405VG_SD_SDIO の構成を以下に示します。

F405VG_SD_SDIO
  |
  |- Includes
  |
  |- C_Lib
  |    |- User_IF_Lib
  |    |    |- Blink_LED_Status : Status LED点滅処理
  |    |    |    |- Blink_LED_Status.c
  |    |    |    |- Blink_LED_Status.h
  |    |    |
  |    |    |- Detect_USW : User Switch押下検出処理
  |    |         |- Detect_USW.c
  |    |         |- Detect_USW.h
  |    |
  |    |- Wait_Interval : 時間待ち処理
  |         |- Wait_Interval.c
  |         |- Wait_Interval.h
  |
  |- Core
  |    |- Inc
  |    |    |- main.h
  |    |    |- stm32f4xx_hal_conf.h
  |    |    |- stm32f4xx_it.h
  |    |
  |    |- Src
  |    |    |- main.c
  |    |    |- stm32f4xx_hal_msp.c
  |    |    |- stm32f4xx_it.c : 割り込み処理
  |    |    |- syscalls.c
  |    |    |- system.c
  |    |    |- system_stm32f4xx.c
  |    |
  |    |- Startup
  |
  |- Drivers
  |    |- CMSIS
  |    |- STM32F4xx_HAL_Driver
  |
  |- SD_Lib
  |    |- FatFs : FatFsのモジュール
  |    |    |- diskio.c
  |    |    |- diskio.h
  |    |    |- ff_gen_drv.c
  |    |    |- ff_gen_drv.h
  |    |    |- ff.c
  |    |    |- ff.h
  |    |    |- ffconf.h
  |    |    |- integer.h
  |    |
  |    |- H_SD_SDIO : マイクロSDのSDIOのハンドラ
  |         |- bsp_driver_sd.c
  |         |- bsp_driver_sd.h
  |         |- fatfs_platform.c
  |         |- fatfs_platform.h
  |         |- sd_diskio.c
  |         |- sd_diskio.h
  |
  |- SD_Ope
  |    |- F405VG_Config : 動作パラメータの定義
  |    |    |- Dev_Conf.h
  |    |
  |    |- Test_SD : SD試験
  |    |    |- Test_SD.c
  |    |    |- Test_SD.h
  |    |
  |    |- Use_ff : FatFs利用
  |         |- Use_ff.c
  |         |- Use_ff.h
  |
  |- F405VG_SD_SDIO.launch
  |- STM32F405VGTX_FLASH.ld
  |- STM32F405VGTX_RAM.ld



 F405VG_SD_SDIO の動作パラメータの定義
  サンプルプログラム F405VG_SD_SDIO の動作パラメータの定義を
 SD_Ope/F405VG_Config/Dev_Conf.h に記述しています。

  使用する CPU の定義、ヘッダ名の定義、GPIO のポートとピンの定義、動作パラメータの定義、
 などを記述しています。



 ユーザープログラムの実行開始位置
  プログラムは、int main(void) から実行開始します。

  int main(void) は、フォルダ Core/Src/main.c にあります。

F405VG_SD_SDIO_main

  STM32CubeIDEでビルドされたプログラムは、自動的にCPUの初期化を
 行った後、int main(void) を呼び出します。

  ユーザーコード(記述したプログラム)は、
 int main(void) の先頭から実行されます。



 F405VG_SD_SDIO の main() の説明
  サンプルプログラム F405VG_SD_SDIO の main() の記述は、
 以下のとおりです。



int main(void)
{
  /* USER CODE BEGIN 1 */

  uint8_t uint8_JobNum_LED = 0;
  uint8_t uint8_JobNum_SD = 0;

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SDIO_SD_Init();
  /* USER CODE BEGIN 2 */

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //------------------------------------------------------
    // Status LED点滅
    //------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // uint16_t uint16_Time_ON  : 点灯時間
    // uint16_t uint16_Time_OFF : 消灯時間

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //------------------------------------------------------
    Blink_LED_Status(&uint8_JobNum_LED,
                     GLB_uint16_Time_LED_Status_ON,
                     GLB_uint16_Time_LED_Status_OFF);


    //--------------------------------------------------------------------
    // SD試験 : Userスイッチが押されたときファイルにデータを書き込む。
    //--------------------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //--------------------------------------------------------------------
    Test_SD(&uint8_JobNum_SD);
  }
  /* USER CODE END 3 */
}


 1) 初期化の部分

  a) CPUとPeripheral初期化
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();
   により、CPUとPeripheralなどの基本的な初期化を行います。
  PeripheralとはCPUの周辺インターフェースなどのことを言います。

   HAL_Init はプロジェクト構築時に自動的に組み込まれる、
  HAL Drivers(フォルダ Drivers/STM32F4xx_HAL_Drivers) 内に記述されています。


  b) CPU動作クロックの設定
  /* Configure the system clock */
  SystemClock_Config();

   CPUの動作クロックとPeripheralの動作クロックを設定します。

   SystemClock_Config(); の設定内容は、

int main(void)
{
     .
     .
     .
}
 の、すぐ下に記述されています。



 2) LED点滅 と SD試験 の部分
   永久ループ部分の記述を以下に示します。


  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    //------------------------------------------------------
    // Status LED点滅
    //------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // uint16_t uint16_Time_ON  : 点灯時間
    // uint16_t uint16_Time_OFF : 消灯時間

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //------------------------------------------------------
    Blink_LED_Status(&uint8_JobNum_LED,
                     GLB_uint16_Time_LED_Status_ON,
                     GLB_uint16_Time_LED_Status_OFF);


    //--------------------------------------------------------------------
    // SD試験 : Userスイッチが押されたときファイルにデータを書き込む。
    //--------------------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //--------------------------------------------------------------------
    Test_SD(&uint8_JobNum_SD);
  }
  /* USER CODE END 3 */

  Status LED点滅処理 Blink_LED_Status と
  SD試験処理 Test_SD を呼び出しています。

  Blink_LED_Status と Test_SD は並列に実行されます。



 SD試験 Test_SD の説明


  1) Test_SD のソース
  モジュール Test_SD は
 SD_Ope/Test_SD/Test_SD.c 内に記述されています。

  モジュール Test_SD のソースを以下に示します。
//--------------------------------------------------------------------
// SD試験 : Userスイッチが押されたときファイルにデータを書き込む。
//--------------------------------------------------------------------
// 引数:
// uint8_t *puint8_JobNum : 処理番号を格納する変数のポインタ

// 戻り値:
//   -1 : 処理中
//    0 : OK
//    1 : NG
//--------------------------------------------------------------------
int16_t Test_SD(uint8_t *puint8_JobNum)
{
  static uint8_t STC_uint8_JobNum_USW;  // User Switch検出処理番号

  static uint8_t STC_uint8_PathSDC[32];
  static uint8_t STC_uint8_DataSDC[16];

  unsigned int uint_WriteLength;

  DWORD dword_WriteStart;

  FRESULT enum_FRESULT;
  UINT uint_WriteByte;

  int16_t int16_Return;

  uint32_t uint32_Total;
  uint32_t uint32_Free;

  int16_t int16_I;
  uint8_t uint8_ReadData[16];
  unsigned int uint_ReadLength;



  switch(*puint8_JobNum){
  case 0:
    STC_uint8_JobNum_USW = 0;  // User Switch検出処理番号初期化


    //----------------------------------------------------------
    // FatFsの関数との関連付け
    //----------------------------------------------------------
    int16_Return = (int16_t)FATFS_LinkDriver(&SD_Driver, SDPath);
    if(int16_Return != 0){
      while(1);
    }


    //----------------------------------------------------------
    // 容量取得 : Debug
    //----------------------------------------------------------
    int16_Return = GetSpaceSDC(&uint32_Total, &uint32_Free);
    if(int16_Return == 1){
      // NG
      while(1);
    }


    //----------------------------------------------
    // User Switch入力ピン初期化
    //----------------------------------------------
    def_M_Init_USW();


    (*puint8_JobNum)++;  // 処理番号をインクリメント
                         // : 次の処理番号に移行する。 : case 1:
    int16_Return = -1;   // 処理中
    break;

  case 1:
    //-----------------------------------------------------------
    // User Switch検出
    //-----------------------------------------------------------
    // 引数:
    // uint8_t *puint8_JobNum : 処理番号が格納された変数のポインタ

    // 戻り値:
    //   -1 : 検出なし
    //    0 : 検出あり
    //-----------------------------------------------------------
    int16_Return = def_M_Detect_USW(&STC_uint8_JobNum_USW);
    if(int16_Return == -1){
      // 検出なし
      break;  // 処理番号維持 : 処理継続 : case 1: をループ
    }


    (*puint8_JobNum)++;  // 処理番号をインクリメント
                         // : 次の処理番号に移行する。 : case 2:
    int16_Return = -1;   // 処理中
    break;

  case 2:
    //--------------------------------------------------------
    // SDカード書き込み
    //--------------------------------------------------------


    //----------------------------------------------------------
    // folder および file 存在チェック
    //----------------------------------------------------------
    // 標準 : \

    //  をセット
    strcpy((char *)STC_uint8_PathSDC, "TEST_SD");

    // check folder
    int16_Return = MakeDirectorySDC(STC_uint8_PathSDC);
    if(int16_Return != 0){
      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    // \ をセット
    strcpy((char *)STC_uint8_PathSDC, "TEST_SD\\TEST_SD.TXT");


    //----------------------------------------------------------
    // Write file
    //----------------------------------------------------------
    uint_WriteLength = 13;  // 書き込みデータ数をセット


    // 論理ドライブのワークエリア登録
    f_mount(&GLB_struct_FATFS, "", 0);


    //-------------------------------------------------------
    // 書き込みデータ作成
    //-------------------------------------------------------
    int16_Return = Make_WriteData(uint_WriteLength,
                                  STC_uint8_PathSDC,
                                  &dword_WriteStart,
                                  STC_uint8_DataSDC);
    if(int16_Return != 0){
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    //----------------------------------------------------
    // ファイルにデータを書き込む。
    //----------------------------------------------------

    // Open File
    enum_FRESULT = f_open(&GLB_struct_FIL,
                          (char *)STC_uint8_PathSDC,
                          FA_OPEN_ALWAYS | FA_WRITE);
    if(enum_FRESULT != FR_OK){
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    // ファイルサイズをチェック
    if(dword_WriteStart > 0){
      // ファイルサイズが 0 でない場合。
      //----------------------------------------------------
      // データの最終位置にする。
      //----------------------------------------------------
      int16_Return = SeekFile((uint32_t)dword_WriteStart);
      if(int16_Return != 0){
        f_close(&GLB_struct_FIL);
        f_mount(defNULL, "", 0);

        return(1);  // NG
      }
    }

    // ファイルにデータを書き込む。
    enum_FRESULT = f_write(&GLB_struct_FIL,
                           (char *)STC_uint8_DataSDC,
                           uint_WriteLength, &uint_WriteByte);
    if(enum_FRESULT != FR_OK){
      f_close(&GLB_struct_FIL);
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    // 一旦、ファイルをクローズする。
    f_close(&GLB_struct_FIL);


    // 読み込みバッファクリア
    for(int16_I = 0; int16_I < (int16_t)uint_WriteLength; int16_I++){
      uint8_ReadData[int16_I] = 0;
    }


    //----------------------------------------------------
    // 書き込んだデータを読み込んで比較する。
    //----------------------------------------------------
    // Open File
    enum_FRESULT = f_open(&GLB_struct_FIL,
                          (char *)STC_uint8_PathSDC,
                          FA_READ);
    if(enum_FRESULT != FR_OK){
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }

    //----------------------------------------------------
    // 書き込む前の位置にする。
    //----------------------------------------------------
    int16_Return = SeekFile((uint32_t)dword_WriteStart);
    if(int16_Return != 0){
      f_close(&GLB_struct_FIL);
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    // データ読み込み
	enum_FRESULT = f_read(&GLB_struct_FIL,
	                      (char *)uint8_ReadData,
	                      uint_WriteLength,
	                      &uint_ReadLength);
    if(int16_Return != 0){
      f_close(&GLB_struct_FIL);
      f_mount(defNULL, "", 0);

      *puint8_JobNum = 0;
      int16_Return = 1;  // NG
      break;
    }


    // 書き込みデータと読み込みデータの比較
    for(int16_I = 0; int16_I < (int16_t)uint_WriteLength; int16_I++){
      if(STC_uint8_DataSDC[int16_I] != uint8_ReadData[int16_I]){
        f_close(&GLB_struct_FIL);
        f_mount(defNULL, "", 0);

        *puint8_JobNum = 0;
        int16_Return = 1;  // NG
        break;
      }
    }


    // ファイルをクローズする。
    f_close(&GLB_struct_FIL);

    // 論理ドライブのワークエリア解除
    f_mount(defNULL, "", 0);


    *puint8_JobNum = 1;  // User Switch検出処理に移行する。: case 1:
    int16_Return = 0;    // OK
    break;

  default:
    *puint8_JobNum = 0;
    int16_Return = -1;
    break;
  }

  return(int16_Return);
}


 2) Test_SD の動作

  a) case 0:
   i) FatFsの関数との関連付けを行います。
   ii) マイクロSDの容量を取得します。
   iii) User Switch入力ピン初期化を行います。

  b) case 1:
    User Switchの押下検出を行います。

    User Switchが押されるまで、case 1: をループします。

    User Switchが押されたら、処理番号をインクリメントして
   case 2: に移行します。

  c) case 2:
    マイクロSDにデータを書き込みます。

    マイクロSDにデータを書き込み後、読み込んで
   正常にデータが書き込まれたことをチェックします。

    マイクロSDの処理終了後、処理番号を 1 にして、case 1: の
   User Switchの押下検出に処理を移行します。



 書き込みデータについて
   tri-S基板上の User Switch を押すごとにマイクロSDにデータを書き込みます。

   最初に書き込むデータは、"TEST SD 000\r\n" です。
   次に User Switch を押したときに書き込むデータは
  "TEST SD 001\r\n" になります。

   最後に書き込まれたデータを判断して、"TEST SD " の次の "000" の部分を
  +1 して書き込むようにしています。

   "999" になったら、次は、"000" に戻ります。
   "000" から "999" を繰り返します。



A+-2C (ええ加減にC) のページに戻る




 メールアドレス: apm2c.sumi@gmail.com

 なんでも、気軽に ご相談ください。
 担当:おの

マスコット
  えがおのでんし 案内