CubeMXを用いて今回はSTM32マイコンにUSBカードリーダー的な機能(USBマスストレージクラス、MSC)を実装する方法について紹介します。今回はSDカードですが、応用すれば内蔵RAMやNOR Flash、NandFlash等への実装も可能です。今回はSTM32F746-Discoveryボードを用いました。環境はSTM32Cube FW_F7 V1.16.0+SW4STM32です。
1.CubeMX設定
1-1.ボード選択
ボード選択からSTM32F746-Discoveryを選択します。
1-2.SDMMC設定
SD4bit BUSを選択します。
SDMMCCLK clock divide factorに5を選択します。
GPIO Settingsで各IOをプルアップに選択します。
その他はデフォルトのままです。
1-3.USB_OTG_FS設定
ModeをDevice_Onlyを選択します。
その他はデフォルトのままです。
1-4.USB_DEVICE設定
「Class For FS IP」でMass Strage Classを選択します。
その他はデフォルトのままです。
1-5. クロック設定
USBのクロックを48MHzに設定します。それ以外は必要に応じて変更してください。
1-6.Heap、Stack設定
マウント時に足りなくなる可能性があるため、念のため、HeapとStackを10倍にして確保しました。使い方によってはもう少し減らしても問題ありません。
Heap 0x2000
Stack 0x4000
設定が一通り完了したら、コードを生成してプロジェクトにインポートします。
Aコード追加
コード追加が必要な部分は「usbd_strage_if.c」のみです。それ以外は既に初期化等のコードがCubeMXで自動生成されています。
72行目付近に下記のコードを追加します。
/* USER CODE BEGIN PRIVATE_DEFINES */
extern SD_HandleTypeDef hsd1;
#define CAPACITY ((uint32_t)0x80000000U)
/* USER CODE END PRIVATE_DEFINES */
extern SD_HandleTypeDef hsd1;
#define CAPACITY ((uint32_t)0x80000000U)
/* USER CODE END PRIVATE_DEFINES */
STORAGE_GetCapacity_FS関数を下記のように書き換えます。
int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
/* USER CODE BEGIN 3 */
HAL_SD_CardInfoTypeDef info;
int8_t ret = -1;
{
/* USER CODE BEGIN 3 */
HAL_SD_CardInfoTypeDef info;
int8_t ret = -1;
HAL_SD_GetCardInfo(&hsd1, &info);
*block_num = info.LogBlockNbr - 1;
*block_size = info.LogBlockSize;
if(info.LogBlockNbr<CAPACITY)
{
*block_num *= 512;
}
{
*block_num *= 512;
}
ret = 0;
return ret;
/* USER CODE END 3 */
}
return ret;
/* USER CODE END 3 */
}
ポイントは if(info.LogBlockNbr<CAPACITY)の部分です。2GB以下のSDカードの場合はif文以降がなくても動作しますが、2GBを超えるSDカードを対応させる場合には必須です。CubeMXで自動生成されるコードはSDカード2GB以下しか対応していないため、容量の条件に応じて対応させています。
STORAGE_Read_FS関数を下記のように書き換えます。
int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 6 */
int8_t ret = -1;
{
/* USER CODE BEGIN 6 */
int8_t ret = -1;
HAL_SD_ReadBlocks(&hsd1, buf, blk_addr, blk_len, HAL_MAX_DELAY);
while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER){}
ret = 0;
return ret;
/* USER CODE END 6 */
}
ret = 0;
return ret;
/* USER CODE END 6 */
}
STORAGE_Write_FS関数を下記のように書き換えます。
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
/* USER CODE BEGIN 7 */
int8_t ret = -1;
{
/* USER CODE BEGIN 7 */
int8_t ret = -1;
HAL_SD_WriteBlocks(&hsd1, buf, blk_addr, blk_len, HAL_MAX_DELAY);
while (HAL_SD_GetCardState(&hsd1) != HAL_SD_CARD_TRANSFER){}
ret = 0;
return ret;
/* USER CODE END 7 */
}
ret = 0;
return ret;
/* USER CODE END 7 */
}
上記の3つの関数を書き換えてビルドしてから、ファームを書き込みます。CN3にmicroSDカードを挿入し、CN13にmicroUSBをPCに接続するとmicroSDカードを読み書きできることが確認できました。デバイスマネージャからはSTM Product USB Deviceとして認識されます。
今回、書き換えた3つの関数をSDカードアクセス関数から別の関数に置き換えることで内蔵RAMやNOR Flash、NandFlash等をマウントすることが可能です。例えば内蔵RAMをマウントする場合は下記のように設定します。デバイス認識後、フォーマットによりファイルの読み書きができますが、RAMサイズが小さく、大きなファイルは保存できません。また、マイコンのリセットでデータが消えてしまいます。
#define STORAGE_LUN_NBR 1
#define STORAGE_BLK_NBR 100
#define STORAGE_BLK_SIZ 0x200
#define STORAGE_BLK_NBR 100
#define STORAGE_BLK_SIZ 0x200
uint8_t buffer[STORAGE_BLK_NBR*STORAGE_BLK_SIZ];
STORAGE_GetCapacity_FS関数はデフォルトのまま
STORAGE_Read_FS関数内に下記を追加
memcpy(buf, &buffer[blk_addr*STORAGE_BLK_SIZ], blk_len*STORAGE_BLK_SIZ);
STORAGE_Write_FS関数内に下記を追加
memcpy(&buffer[blk_addr*STORAGE_BLK_SIZ], buf, blk_len*STORAGE_BLK_SIZ);
今回はCubeMXを用いてSTM32マイコンにUSBカードリーダー的な機能(USBマスストレージクラス、MSC)を実装する方法を紹介しました。今後はNOR Flash、NandFlash等のマウントにも挑戦してみたいと思います。また、FatFSとも組み合わせて、MSCとマイコン側からの読み書きの機能も紹介したいと思います。