Board : STM32F429ZI (Nucleo 144)
STM32CubeIDE : version 1.10.1
Firmware Package : FW_F4 V1.27.1
Clock Configuration
USB 48MHz 클락을 설정하기 위해 HSE를 사용했다.
USB_OTG_FS 설정
보드가 Host 모드로 동작하게 설정해준다.
USB Flash Drive는 자체전원이 없으니 VBUS를 통해 전원을 공급해주어야 한다.
그래서 USB_ID핀과, USB_SOF핀은 비활성화 됐는데, USB에서 ID핀은 On-The-Go (OTG) 기능을 지원하기 위해 사용되므로 호스트 또는 디바이스 기능만 가진 USB장치를 사용하는 경우 ID핀은 필요하지 않다.
그리고 SOF 타이밍 동기화에 물리적인 SOF핀을 사용하는 경우도 있으나 내부적으로 SOF 타이머를 사용하여 SOF 신호를 생성하는 방법이 비용과 복잡도가 낮아서 여기선 SOF 타이머를 사용해 USB버스에서 SOF 신호를 생성하게 된다.
📝 SOF 란?
USB의 Start of Frame (SOF) 신호는 USB 버스에서 전송되는 신호 중 하나이며, USB 장치의 시간 동기화를 위해 사용된다. USB 버스는 일반적으로 1ms 주기로 SOF 패킷을 전송하며, 이 패킷에는 현재 프레임 번호가 포함된다.
SOF 신호는 USB 호스트가 생성하고 모든 USB 디바이스는 이 신호를 수신하여 동기화하여, 이를 통해 USB 호스트와 디바이스는 동일한 시간 기준으로 데이터 전송을 수행할 수 있다.
USB_HOST 설정
Middleware - USB_HOST 에서 Class for FS IP에 MSC를 선택해준다.
Platform Settings에선 VBUS drive핀으로 PG6핀을 선택한다.
회로도를 보면 PG6핀이 VBUS에 +5V를 공급하는 Enable핀 역할을 하는 것을 볼 수 있다. 신호특성은 Active High이다.
FATFS 설정
USB Disk를 선택한다.
그 다음 LFN을 Enable하는데 아래 3가지 옵션이 있다.
BSS는 초기화되지 않은 전역변수와 정적변수를 저장하는 영역이고, STACK은 지역변수와 함수 호출 스택 등을 저장하는 영역으로 다른 목적으로 사용되고 있으니, LFN을 위한 추가적인 버퍼를 할당하는데는 동적으로 메모리를 할당하여 사용하는 공간인 HEAP을 선택했다. 그러니 FatFs라이브러리에서 INIT_NAMBUF()와 FREE_NAMBUF() 매크로 함수를 통해 할당과 해제를 하더라.
/ 0: Disable support of LFN. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
그리고 인터넷에 있는 튜토리얼에선 MAX_SS를 4096으로 바꾸라고 가이드한다. USB 스토리지 장치에서 사용되는 섹터 사이즈는 512바이트 또는 4096바이트인데 아직까진 512바이트가 더 일반적이다. 어차피 USB도 FAT 또는 FAT32 파일시스템으로 포맷해야하니 하는김에 사용할 USB의 섹터사이즈를 확인해서 필요한 경우 수정해주면 된다.
섹터 사이즈는 크면 대용량 파일을 다룰 때 장점을 가지지만 용량이 작은 파일을 다룰 때는 오히려 성능 저하가 발생할 수 있다.
파일구조
FATFS - Target - usbh_diskio.h, usbh_diskio.c 에는 물리적인 외부 저장 장치(USB)의 읽기/쓰기를 제어하는 드라이버가 있다.
Middlewares - Third_Party - FatFs - src - diskio.h, diskio.c 는 FatFs 라이브러리의 low level disk I/O 모듈로 외부 저장장치의 물리적 읽기/쓰기 동작을 제어하는데 사용되는 함수를 정의하고 있다. 개발자는 이 파일에서 정의된 인터페이스를 참고하여 구현하면 되는데 그건 STM사에서 이미 구현해 두었고 그게 usbh_diskio.h, usbh_diskio.c 파일에 있다.
그리고 ff_gen_drv.h, ff_gen_drv.c 파일의 FATFS_LinkDriver() 함수가 구현된 USBH_Driver를 FATFS 파일 시스템과 연결하는 역할을 하고, 이게 main.c에서 MX_FATFS_Init() 함수를 통해 호출된다.
그리고 USB_HOST - App - usb_host.c 파일에 USBH_UserProcess() 함수는 USB상태가 바뀌면 호출되는 콜백함수로 USB가 connect 됐을 때, disconnect 됐을 때 수행할 작업을 여기다 추가할 수도 있다.
테스트 코드
이제 #include "fatfs.h" 하고 FatFs API사용하여 USB 저장장치를 읽고 쓸 수 있다. fatfs.h 에서 "ff.h"를 include 하고 있다. 아니면 바로 ff.h를 포함한다.
static void USBH_UserProcess (USBH_HandleTypeDef *phost, uint8_t id)
{
/* USER CODE BEGIN CALL_BACK_1 */
switch(id)
{
case HOST_USER_SELECT_CONFIGURATION:
break;
case HOST_USER_DISCONNECTION:
Appli_state = APPLICATION_DISCONNECT;
f_mount(NULL, "", 1);
break;
case HOST_USER_CLASS_ACTIVE:
Appli_state = APPLICATION_READY;
FRESULT res;
res = f_mount(&filesystem, "", 0);
res = f_open(&file, "/test_long_file_name.txt", FA_CREATE_ALWAYS|FA_WRITE);
char buff[30] = "Hello, World!\r\n";
int byteWritten;
res = f_write(&file, buff, strlen(buff), (UINT *)&byteWritten);
res = f_close(&file);
if(res == FR_OK)
{
printMsg("Test Success!\r\n");
}
else
{
printMsg("Test Failed!\r\n");
}
break;
case HOST_USER_CONNECTION:
Appli_state = APPLICATION_START;
break;
default:
break;
}
/* USER CODE END CALL_BACK_1 */
}
f_mount() 함수는 파일 시스템 객체(FATFS)를 논리 드라이브에 mount 또는 unmount하는 역할을 한다.
논리 드라이브는 "0:/", "1:/", "2:/" 이렇게 나가는데 빈 문자열을 인자로 넣으면 함수안을 보면 알겠지만 자동으로 0번째 볼륨에 마운트하게 된다.
세번째 파라미터인 opt의 경우 값이 0이면 파일시스템이 실제로 마운트되지 않고, f_opendir(), f_open()과 같은 함수가 호출될 때까지 마운트를 지연시키고, 값이 1인 경우엔 즉시 마운트된다.
그리고 만약 첫번째 매개변수가 NULL인 경우 f_mount() 함수는 FATFS 객체에 NULL을 대입해 unmount하는 용도로 쓰인다.
만약 FatFs 라이브러리를 사용하는데 익숙하지 않다면 아래 파일(from Controller's tech)을 확인하는게 도움될 수 있다.
'임베디드 개발 > STM32 (ARM Cortex-M)' 카테고리의 다른 글
STM32 ] TFTP Server 파일 송수신 + USB Host MSC (9) | 2023.04.15 |
---|---|
STM32 ] TFTP Server (0) | 2023.04.14 |
STM32 ] 유저 버튼 고장 수리하기 (0) | 2023.04.09 |
STM32 ] 커스텀 부트로더 (IAP) (4) | 2023.02.15 |
STM32 ] 내장 부트로더와 Flash Loader 사용하기 (0) | 2023.02.07 |