今回はHALを使ってuSDカードにアクセスしてみます。
投稿時の開発環境を記しておきます。
PC:Windows10 OS
IDE: STM32CubeIDE Version1.3.0
Configurator: STM32CubeMX Version5.6.0
Board: STM32Nucleo-F401RE
Mbedを使ったアクセス
以前、 STM32CubeIDEでMbedする SDカード編 の記事では Mbedによる方法を紹介しました。
Mbedでは SPI を使ったアクセス方法になるのですが、今回は SDIO を使ってみました。
つなぐ本数は増えますが、その分アクセスタイム(通信速度)は上がります。
そして前回は大きなSDカードを使いましたが、今回は今風にマイクロSDカードで試してみました。
でもちっちゃい・・・
いえいえ、目の訓練のためです 笑
SDカードコネクタ等を準備する
今回は こちら のマイクロSDカードコネクタを使ってみました。
取り扱いについては こちら をご覧ください。
電源電圧は 3.3V です。
今回はカード検出スイッチ(9番と10番ピン)を使いません。
SDカードと、それからパソコンで読めるようにカードリーダーも準備しておいてください。
SDカードは こちら を使いました。
配線する
以下のように接続しました。
CLKを除く〇のついた信号は3.3Vにプルアップしてください。
STの回路例を見たところ10kΩがついていたので、それに合わせました。
ファイルシステム
ファイルシステムは FatFS を使います。
UM1721 に目を通しておいてください。
5.3項のサンプルおよび FW のサンプル を参考にして動かしてみようと思います。
プロジェクトを作成する
IDEを起動し、File- New – STM32 Project を選択し、Target Selection ウィンドウが出たら Board Selector タブを選択し Boards List から NUCLEO-F401RE を選択し Next ボタンを押します。
Project 名に F401SdioHAL と入力し、Finishボタンを押します。
Initialize all peripherals with their default Mode ? と聞いてくるので Yesを押します。
This kind of project is associated with the STM32CubeMx perspective. Do you want to open this perspective now ? と聞いてくるので Yesを押します。
コードジェネレーターでSDIOを設定する
Pinout & Configuration – Categories – Connectivity – SDIO を選択し、
SDIO Mode and Configuration の Modeから MMC 4bits Wide Bus を選択します。
Parameter Settings の SDIOCLK clock divide factor の値を 0 から 10 に変更します。
( 0で動かず、 5で動かず、 10を試したら動きました )
この値は SDIOClock = AHBClock / (SDIOCLK clock divide + 2) に使われるようです。
0では速すぎて動かないようなので適切な値に調整する必要があるようです。
次に GPIO Settings で、赤枠の部分が上の配線の表と一致していることを確認します。
(もし違っていたら合わせないといけません)
ここで一度ビルドし、main.c の以下の関数をコピーして保存しておきます。
static void MX_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_1B;
hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_DISABLE;
hsd.Init.ClockDiv = 10;
if (HAL_SD_Init(&hsd) != HAL_OK)
{
Error_Handler();
}
if (HAL_SD_ConfigWideBusOperation(&hsd, SDIO_BUS_WIDE_4B) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SDIO_Init 2 */
/* USER CODE END SDIO_Init 2 */
}
コードジェネレーターでFATFSを追加する
続いて Pinout & Configuration – Categories – MiddleWare から FATFS を選択します。
FATFS Mode and Configuration Mode のところで SD Card にチェックを入れます。
そしてもう一度、ビルドします。
以下の警告ウィンドウが出ても構わずに Yes を押します。
これはカード検出の設定を行っていないという警告です。
今回は使わないので無視します。
コードジェネレータのバグなのか?
なぜかFATFSを追加すると、MX_SDIO_SD_Init()の中身が壊れます。
if文、2つがなくなっていることを確認してください。
そこで、先ほど保存しておいたコードで上書きします。
コードジェネレーターを走らせるたびに、ここの部分が壊れるので注意してください。
コーディングする
main.c の whileループの前に以下のコードを貼りつけます。
コードが MX_FATFS_Init()と重複するので、MX_FATFS_Init()はコメントにします。
MX_SDIO_SD_Init();
// MX_FATFS_Init();
/* USER CODE BEGIN 2 */
FATFS SDFatFs; /* File system object for SD disk logical drive */
FIL MyFile; /* File object */
char SDPath[4]; /* SD disk logical drive path */
static uint8_t buffer[_MAX_SS]; /* a work buffer for the f_mkfs() */
FRESULT res; /* FatFs function common result code */
uint32_t byteswritten, bytesread; /* File write/read counts */
uint8_t wtext[] = "Hi, this is STM32 working with FatFs"; /* File write buffer */
uint8_t rtext[100]; /* File read buffer */
/*##-1- Link the SD disk I/O driver ########################################*/
if(FATFS_LinkDriver(&SD_Driver, SDPath) == 0)
{
/*##-2- Register the file system object to the FatFs module ##############*/
if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) != FR_OK)
{
/* FatFs Initialization Error */
Error_Handler();
}
else
{
/*##-3- Create a FAT file system (format) on the logical drive #########*/
FRESULT fr;
fr = f_mkfs((TCHAR const*)SDPath, FM_ANY, 0, buffer, sizeof(buffer));
if (fr != FR_OK)
{
Error_Handler();
}
else
{
/*##-4- Create and Open a new text file object with write access #####*/
if(f_open(&MyFile, "STM32.TXT", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
{
/* 'STM32.TXT' file Open for write Error */
Error_Handler();
}
else
{
/*##-5- Write data to the text file ################################*/
res = f_write(&MyFile, wtext, sizeof(wtext), (void *)&byteswritten);
if((byteswritten == 0) || (res != FR_OK))
{
/* 'STM32.TXT' file Write or EOF Error */
Error_Handler();
}
else
{
/*##-6- Close the open text file #################################*/
f_close(&MyFile);
/*##-7- Open the text file object with read access ###############*/
if(f_open(&MyFile, "STM32.TXT", FA_READ) != FR_OK)
{
/* 'STM32.TXT' file Open for read Error */
Error_Handler();
}
else
{
/*##-8- Read data from the text file ###########################*/
res = f_read(&MyFile, rtext, sizeof(rtext), (UINT*)&bytesread);
if((bytesread == 0) || (res != FR_OK)) /* EOF or Error */
{
/* 'STM32.TXT' file Read or EOF Error */
Error_Handler();
}
else
{
/*##-9- Close the open text file #############################*/
f_close(&MyFile);
/*##-10- Compare read data with the expected data ############*/
if ((bytesread != byteswritten))
{
/* Read data is different from the expected data */
Error_Handler();
}
else
{
/* Success of the demo: no error occurrence */
}
}
}
}
}
}
}
}
/*##-11- Unlink the SD disk I/O driver ####################################*/
FATFS_UnLinkDriver(SDPath);
/* USER CODE END 2 */
ビルドして実行する
ビルドして1行ずつステップ実行しエラーがないことを確認していきます。
Error_Handler() にかからずに最後まで実行できたら成功。だと思います。。
カードリーダーでuSDカードの内容を見てみます。
STM32.TXT というファイルがあり、ファイルの内容が以下の通りなら成功です。
Hi, this is STM32 working with FatFs
いかがでしたか?
うまく書き込みができたでしょうか。
ありがとうございます。
大変参考になりました。
ようやくSDカードが読めました。
なお記事中のFatFsをリンクすると・・・については
f_mount を呼び出したときに内部で
BSP_SD_Initが呼ばれます。
このBSP_SD_Init のなかでHAL_SD_Initが呼ばれるのですが、
BSP_SD_Initがweak なので、これをUser Codeでオーバーライドすると良いようです。
コメントありがとうございました。
お役に立てたようで良かったです。
お返事が遅くなり、すみませんでした。
moon