STM32F429 USB OTG Test - HS mode

LVGL v8.0.02 포팅 과정을 진행하면서 이전 펌웨어의 기능을 개선하고 있으며, 그 중 하나가 부팅 로고를 USB로 바꾸는 기능을 추가하려고 하는데, 개발보드에서 USB 인식이 되지 않아 STM32F429 Disc보드에서 USB OTG를 검증하였다. 디스커버리보드는 아래 이미지와 같이 Micro USB 포트를 제공하고 있어 따로 와이어 연결을 할 필요가 없다.

기본 USB 포트를 사용하려면 아래 회로도를 참조하여 CubeIDE 핀설정을 하도록 한다. PB13 / PB

USB OTG 모드를 HS로 설정하여도 내부 파이 사용시에는 최대 12Mbit/s 속도로 제공되며, 외부 파이를 사용할 경우에는60Mbit/s 속도를 제공하나 아래와 같이 Disc 데모보드 그렇고 개발보드 역시 내부 파이를 사용하기 때문에 HS 모드를 사용하여도 USB 속도는 최대 12Mbit로 제한된다.

USB VBUS 제어는 STM32 미들웨어인 USB HOST에서 처리해야 하며, USB_OTG_HS 모듈에서 설정하지 않고 PB13 포트를 GPIO Output로 설정하여 USB HOST에서 사용할 수 있도록 한다.

그리고 Disc 데모보드의 회로도에서 PC4 포트로 USB VBUS를 제어하고 있기 때문에 PC4 핀을 GPIO Output으로 설정하며, Low일 때 VBUS 출력이 나오도록 되어있다.

PC5는 over current로 과전류가 발생하면 전원을 차단하기 위해 GPIO Input 포트로 설정하도록 한다. 이것은 생략해도 될듯 한다. 그리고 USB를 사용하기 위해서는 시스템 클럭을 168MHz로 변경해야 한다. 180MHz로 설정할 경우 USB 클럭을 48MHz로 맞출 수가 없다.

CubeIDE로 USB OTG 설정 바탕으로 USB 마운트 및 파일 읽기를 작성하도록 한다. STM32는 USB HOST 미들웨어를 사용하여 USB 관련 이벤트를 발생시키며 usb_host.c 파일의 아래 함수에서 USB 마운트 및 언마운트를 처리할 수 있다.

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;
            usb_unmount();
            break;

        case HOST_USER_CLASS_ACTIVE:
            Appli_state = APPLICATION_READY;
            break;

        case HOST_USER_CONNECTION:
            Appli_state = APPLICATION_START;
            usb_mount();
            break;

        default:
            break;
    }
    /* USER CODE END CALL_BACK_1 */
}

usb_mount() / usb_unmount() 코드는 아래와 같으며, usb_read_background_image()에서 특정 파일을 읽을 수 있다.

extern char USBHPath[4];   /* USBH logical drive path */
extern FATFS USBHFatFS;    /* File system object for USBH logical drive */
extern ApplicationTypeDef Appli_state;

int usb_mount(void)
{
    FRESULT result = f_mount(&USBHFatFS, USBHPath, 0);
    if(result != FR_OK)
    {
        printf("ERROR :: %s() : f_mount() fail\r\n", __func__);
        return -1;
    }

    printf("INFO :: %s() : mount_path = [%s]\r\n", __func__, USBHPath);
    return 0;
}

int usb_unmount(void)
{
    FRESULT result = f_mount(NULL, "", 0);
    if(result != FR_OK)
    {
        printf("ERROR :: %s() : f_mount() fail\r\n", __func__);
        return -1;
    }

    printf("INFO :: %s()\r\n", __func__);
    return 0;
}

int usb_read_background_image(uint8_t img_type, uint8_t *buf, uint32_t *length)
{
    char file_path[256] = {0, };

    FRESULT result;
    FILINFO file_info;
    FIL     fp;

    if(Appli_state != APPLICATION_READY)
    {
        printf("ERROR :: %s() : appli_state = %d\r\n", __func__, Appli_state);
        return -1;
    }

    if(img_type == 0) sprintf(file_path, "%sbg.png", USBHPath);
    else              sprintf(file_path, "%slogo.png", USBHPath);

    printf("INFO :: %s() : file_path = [%s]\r\n", __func__, file_path);
    f_stat(file_path, &file_info);
    printf("  size = %ld\r\n", file_info.fsize);
    printf("  name = [%s]\r\n", file_info.fname);

    memset(&fp, 0x00, sizeof(FIL));
    if((result = f_open(&fp, file_path, FA_READ)) != FR_OK)
    {
        printf("ERROR :: %s() : f_open() fail : result = %d, file_path = [%s]\r\n", __func__, result, file_path);
        return -1;
    }
    printf("  flag = 0x%x\r\n", fp.flag);

    if((result = f_read(&fp, buf, file_info.fsize, (UINT *)length)) != FR_OK)
    {
        printf("ERROR :: %s() : f_read() fail : result = %d\r\n", __func__, result);
        goto rtn_code;
    }
    printf("  read = %ld, fptr = %lx\r\n", *length, fp.fptr);
    for(int i = 0 ; i < 16 ; i++) printf("0x%02X, ", buf[i]);
    printf("\b\b\r\n");

rtn_code:
    if(fp.flag != 0) f_close(&fp);
    return 0;
}

USB가 정상적으로 마운트되고 USB의 파일을 액세스 할 수 있는 상태가 되면 Appli_state는 APPLICATION_READY가 되며 이 상태에서 파일을 읽고 쓰기가 가능하다.

 

main_loop에서 아래와 같은 테스트 코드를 작성하여 bg.png 파일을 정상적으로 읽었는지 간단히 확인하였다. PNG 파일을 읽기 위해 Disc 보드의 8MB SDRAM도 활성화 시켜 테스트하였다.

int main(void)
{
    ...
    /* Infinite loop */
    /* USER CODE BEGIN WHILE */
    printf("USBTest start...\r\n");
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_4, GPIO_PIN_RESET);
    while (1)
    {
        /* USER CODE END WHILE */
        MX_USB_HOST_Process();

        /* USER CODE BEGIN 3 */
        if(Appli_state == APPLICATION_READY)
        {
            if(is_read == 0)
            {
                uint8_t *buff   = (uint8_t *)0xD0000000;
                uint32_t length = 0;

                usb_read_background_image(0, buff, &length);
                is_read = 1;
            }
        }
        HAL_Delay(10);
    }
    /* USER CODE END 3 */
}

위 소스코드는 아래의 깃허브에서 받을 수 있다. 데모보드에선 문제없이 USB OTG HS 포트로 USB 인식되는 것을 확인하였는데, 왜 개발보드에선 USB 인식이 제대로 안되는지... 다음주에나 확인이 가능할 듯 싶다.

 

GitHub - highgon2/STM32: STM32 TestCode

STM32 TestCode. Contribute to highgon2/STM32 development by creating an account on GitHub.

github.com