サンプルプログラム F446RE_eMMC_8bit の説明
IF_Nuc64_eMMC_F
  eMMCのSDIOアクセスの
 サンプルプログラムです。

  8bits (SDIO_D0 - SDIO_D7) の
 BUS幅でアクセスします。

  STMicroelectronics社製の評価用基板、NUCLEO-F446RE と
 freeの開発ツール、STM32CubeIDE を使用しています。


目次

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

SDIO接続の回路図

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

 eMMC試験 Test_eMMC の説明
  1) Test_eMMC のソース
  2) Test_eMMC の動作

動作試験用基板 の説明
 動作試験用基板 Base-Nucleo-64 の説明
 動作試験用基板 IF-Nuc64-eMMC の説明



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

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

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

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



SDIO接続の回路図
  eMMCのSDIO接続の回路図については

IF_Nuc64_eMMC の回路図 をご覧ください。



サンプルプログラム F446RE_eMMC_8bit の説明
  eMMCにSDIO接続でアクセスを行うプログラムです。
  BUS幅は SDIO_D0 - SDIO_D7 の8bits です。

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

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


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

F446RE_eMMC_8bit_Scrn_First

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



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

F446RE_eMMC_8bit_Tree

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

F446RE_eMMC_8bit
  |
  |- Includes
  |
  |- Blink_LED_Status : Status LED点滅処理
  |     |- Blink_LED_Status.c
  |     |- Blink_LED_Status.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
  |
  |- Detect_USW : User Switch押下検出処理
  |     |- Detect_USW.c
  |     |- Detect_USW.h
  |
  |- Drivers
  |     |- CMSIS
  |     |- STM32F4xx_HAL_Driver
  |
  |- F446RE_eMMC_8bit_Config : 動作パラメータの定義
  |     |- Dev_Conf.h
  |
  |- FatFs : FatFsのモジュール
  |     |- diskio.c
  |     |- diskio.h
  |     |- ff_gen_drv.c
  |     |- ff_gen_drv.h
  |     |- ff.c
  |     |- ff.h
  |     |- ffconf.h
  |     |- integer.h
  |
  |- H_eMMC_SDIO : eMMCのSDIOのハンドラ
  |     |- bsp_driver_eMMC.c
  |     |- bsp_driver_eMMC.h
  |     |- eMMC_diskio.c
  |     |- eMMC_diskio.h
  |
  |- Test_eMMC : eMMC試験
  |     |- Test_eMMC.c
  |     |- Test_eMMC.h
  |
  |- Use_ff : FatFs利用
  |     |- Use_ff.c
  |     |- Use_ff.h
  |
  |- Wait_Interval : 時間待ち処理
  |     |- Wait_Interval.c
  |     |- Wait_Interval.h
  |
  |- F446RE_eMMC_8bit.launch
  |- STM32F446RETX_FLASH.ld
  |- STM32F446RETX_RAM.ld



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

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



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

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

F446RE_eMMC_8bit_main

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

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



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



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

  uint8_t uint8_JobNum_LED = 0;
  uint8_t uint8_JobNum_eMMC = 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_MMC_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);


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

    // 戻り値:
    //   -1 : 処理中
    //    0 : OK終了
    //    1 : NG
    //--------------------------------------------------------------------
    Test_eMMC(&uint8_JobNum_eMMC);
  }
  /* 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点滅 と eMMC試験 の部分
   永久ループ部分の記述を以下に示します。


  /* 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);


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

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

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

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



 eMMC試験 Test_eMMC の説明


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

  モジュール Test_eMMC のソースを以下に示します。

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

// 戻り値:
//   -1 : 処理中
//    0 : OK
//    1 : NG
//--------------------------------------------------------------------
int16_t Test_eMMC(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(&eMMC_Driver, DrivePath);
    if(int16_Return != 0){
      while(1);
    }


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


    (*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
    //----------------------------------------------------------
    // 論理ドライブのワークエリア登録
    f_mount(&GLB_struct_FATFS, "", 0);

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


    // ファイルのサイズを取得する。
    dword_WriteStart = f_size(&GLB_struct_FIL);

    // ファイルの最後尾に移動する。
    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;
    }


    //------------------------------------------
    // 書き込みデータセット
    //------------------------------------------
    strcpy((char *)STC_uint8_DataSDC, "TEST_SD");
    STC_uint8_DataSDC[7] = 0x0D;
    STC_uint8_DataSDC[8] = 0x0A;
    STC_uint8_DataSDC[9] = '\0';


    uint_WriteLength = 9;  // 書き込みデータ数をセット

    //----------------------------------------------------
    // ファイルにデータを書き込む。
    //----------------------------------------------------
    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 < 16; 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_eMMC の動作

  a) case 0:
   1) FatFsの関数との関連付けを行います。
   2) eMMCの容量を取得します。
   3) User Switch入力ピン初期化を行います。

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

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

  c) case 2:
    eMMCにデータを書き込みます。

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

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



動作試験用基板 の説明
  このサンプルプログラムは、
 えがおのでんし製の試験用基板 Base-Nucleo-64 と IF-Nuc64-eMMC を
 使用して動作を確認しています。



 動作試験用基板 Base-Nucleo-64 の説明
  さまざまな、インターフェース基板を接続して動作試験を行うことができます。

Base_Nucleo_64_Dim

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



 動作試験用基板 IF-Nuc64-eMMC の説明
  SDIO接続でeMMCにアクセスするためのインターフェース基板です。

IF_Nuc64_eMMC_Dim

  基板については、
 IF-Nuc64-eMMC基板 の説明 をご覧ください。



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




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

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

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