./../
  I D :    암호 :    ID저장      회원가입    네게(쥔장) 쪽지보내기    메모장    각종계산기    컬러빠렛    이모티콘(프레임, 새창)    보유장비
목록으로 가기..
STM32 개발 때 다양한 USB CDCs 사용CDC, CP210x, FTDI, CH34x, PL2303) 김종호 | 삭제하기

# USB Serial Unified Driver (CDC, CP210x, FTDI, CH34x, PL2303) 이 문서는 STM32 USB Host Library에서 다중 USB 시리얼 칩셋(CDC, CP2102, FT232, CH340, PL2303)을 플러그 앤 플레이로 지원하기 위해 작성된 **통합 드라이버(Unified Driver)**에 대한 가이드 및 전체 소스 코드 백업입니다. --- ## 1. 필수 라이브러리 패치 (Core Patches) ### 1.1. usbh_core.c 패치 Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_core.c의 HOST_CHECK_CLASS 부분을 다음과 같이 변경해야 합니다. ```c case HOST_CHECK_CLASS: if (phost->ClassNumber == 0U) { USBH_UsrLog("No Class has been registered."); } else { phost->pActiveClass = NULL; for (idx = 0U; idx < USBH_MAX_NUM_SUPPORTED_CLASS; idx++) { if (phost->pClass[idx] != NULL && phost->pClass[idx]->ClassCode == phost->device.CfgDesc.Itf_Desc[0].bInterfaceClass) { phost->pActiveClass = phost->pClass[idx]; if (phost->pActiveClass->Init(phost) == USBH_OK) { phost->gState = HOST_CLASS_REQUEST; USBH_UsrLog("%s class started.", phost->pActiveClass->Name); phost->pUser(phost, HOST_USER_CLASS_SELECTED); break; } phost->pActiveClass = NULL; } } if (phost->pActiveClass == NULL) { phost->gState = HOST_ABORT_STATE; USBH_UsrLog("No registered class for this device."); } } ``` ### 1.2. usbh_conf.h 패치 CM7/USB_HOST/Target/usbh_conf.h에서 다음 설정들을 반드시 적용해야 합니다. (스택 오버플로우로 인한 Hard Fault 방지) ```c // 등록할 클래스 수를 5개로 늘림 #define USBH_MAX_NUM_SUPPORTED_CLASS 5U // USB 처리 스레드의 스택 사이즈를 1024(word = 4096 bytes)로 증가 #define USBH_PROCESS_STACK_SIZE ((uint16_t)1024) ``` --- ## 2. 통합 드라이버 파일 전체 소스 코드 아래는 EEPROM 등에서 읽은 설정값으로 통신 속도 및 포맷을 동적으로 적용할 수 있는 기능이 포함된 통합 드라이버의 전체 코드입니다. ### 2.1. usbh_serial.h ```c #ifndef USBH_SERIAL_H #define USBH_SERIAL_H #ifdef __cplusplus extern "C" { #endif #include "usbh_core.h" #include "usbh_cdc.h" extern USBH_ClassTypeDef CP210x_Class; extern USBH_ClassTypeDef FTDI_Class; extern USBH_ClassTypeDef CH34x_Class; extern USBH_ClassTypeDef PL2303_Class; USBH_StatusTypeDef USBH_Serial_RegisterClasses(USBH_HandleTypeDef *phost); USBH_StatusTypeDef USBH_Serial_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length); // Call this before USB device connection (e.g., at boot after reading EEPROM) // baudrate: e.g. 115200, 9600 // databits: 5, 6, 7, 8 // parity: 0:None, 1:Odd, 2:Even, 3:Mark, 4:Space // stopbits: 0:1 bit, 1:1.5 bits, 2:2 bits void USBH_Serial_InitSettings(uint32_t baudrate, uint8_t databits, uint8_t parity, uint8_t stopbits); #ifdef __cplusplus } #endif #endif ``` ### 2.2. usbh_serial.c ```c #include "usbh_serial.h" static uint32_t Serial_BaudRate = 115200; static uint8_t Serial_DataBits = 8; static uint8_t Serial_Parity = 0; static uint8_t Serial_StopBits = 0; void USBH_Serial_InitSettings(uint32_t baudrate, uint8_t databits, uint8_t parity, uint8_t stopbits) { Serial_BaudRate = baudrate; Serial_DataBits = databits; Serial_Parity = parity; Serial_StopBits = stopbits; } // ========================================== // CP210X DRIVER // ========================================== typedef enum { CP210X_INIT_IFC_ENABLE, CP210X_INIT_SET_BAUDDIV, CP210X_INIT_SET_LINE_CTL, CP210X_INIT_DONE } CP210x_State; typedef struct { uint8_t InEp, OutEp, InPipe, OutPipe; uint16_t InEpSize, OutEpSize; CP210x_State state; } CP210x_HandleTypeDef; static CP210x_HandleTypeDef CP210x_Handle; static USBH_StatusTypeDef CP210x_Init(USBH_HandleTypeDef *phost) { if (phost->device.DevDesc.idVendor != 0x10C4) return USBH_FAIL; printf("[CP210x] Vendor ID Matched!\r\n"); uint8_t interface = USBH_FindInterface(phost, 0xFF, 0x00, 0x00); if (interface == 0xFF) { printf("[CP210x] Interface failed!\r\n"); return USBH_FAIL; } printf("[CP210x] Interface found: %d\r\n", interface); USBH_SelectInterface(phost, interface); phost->pActiveClass->pData = &CP210x_Handle; CP210x_HandleTypeDef *CP210x = (CP210x_HandleTypeDef *)phost->pActiveClass->pData; for (uint8_t i = 0; i < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; i++) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress & 0x80) { CP210x->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; CP210x->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } else { CP210x->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; CP210x->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } } CP210x->OutPipe = USBH_AllocPipe(phost, CP210x->OutEp); CP210x->InPipe = USBH_AllocPipe(phost, CP210x->InEp); USBH_OpenPipe(phost, CP210x->OutPipe, CP210x->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, CP210x->OutEpSize); USBH_OpenPipe(phost, CP210x->InPipe, CP210x->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, CP210x->InEpSize); USBH_LL_SetToggle(phost, CP210x->OutPipe, 0); USBH_LL_SetToggle(phost, CP210x->InPipe, 0); CP210x->state = CP210X_INIT_IFC_ENABLE; printf("[CP210x] Init OK!\r\n"); return USBH_OK; } static USBH_StatusTypeDef CP210x_DeInit(USBH_HandleTypeDef *phost) { CP210x_HandleTypeDef *CP210x = (CP210x_HandleTypeDef *)phost->pActiveClass->pData; if (CP210x->OutPipe) { USBH_ClosePipe(phost, CP210x->OutPipe); USBH_FreePipe(phost, CP210x->OutPipe); } if (CP210x->InPipe) { USBH_ClosePipe(phost, CP210x->InPipe); USBH_FreePipe(phost, CP210x->InPipe); } return USBH_OK; } static USBH_StatusTypeDef CP210x_CtlReq(USBH_HandleTypeDef *phost, uint8_t req, uint16_t value) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_INTERFACE; phost->Control.setup.b.bRequest = req; phost->Control.setup.b.wValue.w = value; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, NULL, 0); } static USBH_StatusTypeDef CP210x_Requests(USBH_HandleTypeDef *phost) { CP210x_HandleTypeDef *CP210x = (CP210x_HandleTypeDef *)phost->pActiveClass->pData; USBH_StatusTypeDef status; switch (CP210x->state) { case CP210X_INIT_IFC_ENABLE: status = CP210x_CtlReq(phost, 0x00, 0x0001); if (status == USBH_OK) { printf("[CP210x] IFC_ENABLE OK\r\n"); CP210x->state = CP210X_INIT_SET_BAUDDIV; } break; case CP210X_INIT_SET_BAUDDIV: { uint32_t bauddiv = 3686400 / Serial_BaudRate; status = CP210x_CtlReq(phost, 0x01, bauddiv); if (status == USBH_OK) { printf("[CP210x] SET_BAUDDIV (%lu) OK\r\n", Serial_BaudRate); CP210x->state = CP210X_INIT_SET_LINE_CTL; } break; } case CP210X_INIT_SET_LINE_CTL: { uint16_t line_ctl = (Serial_DataBits << 8); if (Serial_Parity == 1) line_ctl |= 0x0010; else if (Serial_Parity == 2) line_ctl |= 0x0020; else if (Serial_Parity == 3) line_ctl |= 0x0030; else if (Serial_Parity == 4) line_ctl |= 0x0040; if (Serial_StopBits == 2) line_ctl |= 0x0002; status = CP210x_CtlReq(phost, 0x03, line_ctl); if (status == USBH_OK) { printf("[CP210x] SET_LINE_CTL OK\r\n"); CP210x->state = CP210X_INIT_DONE; } break; } case CP210X_INIT_DONE: return USBH_OK; } return USBH_BUSY; } static USBH_StatusTypeDef CP210x_BgndProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } static USBH_StatusTypeDef CP210x_SOFProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } USBH_ClassTypeDef CP210x_Class = { "CP210x_Class", 0xFF, CP210x_Init, CP210x_DeInit, CP210x_Requests, CP210x_BgndProcess, CP210x_SOFProcess, NULL }; USBH_StatusTypeDef USBH_CP210x_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length) { CP210x_HandleTypeDef *CP210x = (CP210x_HandleTypeDef *)phost->pActiveClass->pData; if (phost->gState != HOST_CLASS || phost->device.is_disconnected) return USBH_FAIL; USBH_URBStateTypeDef urb = USBH_LL_GetURBState(phost, CP210x->OutPipe); if (urb == USBH_URB_IDLE || urb == USBH_URB_DONE || urb == USBH_URB_NOTREADY || urb == USBH_URB_ERROR || urb == USBH_URB_STALL) { USBH_BulkSendData(phost, pbuff, length, CP210x->OutPipe, 1); return USBH_OK; } return USBH_BUSY; } // ========================================== // FTDI DRIVER // ========================================== typedef enum { FTDI_INIT_RESET, FTDI_INIT_SET_BAUD, FTDI_INIT_SET_DATA, FTDI_INIT_SET_FLOW, FTDI_INIT_SET_MODEM, FTDI_INIT_DONE } FTDI_State; typedef struct { uint8_t InEp, OutEp, InPipe, OutPipe; uint16_t InEpSize, OutEpSize; FTDI_State state; } FTDI_HandleTypeDef; static FTDI_HandleTypeDef FTDI_Handle; static USBH_StatusTypeDef FTDI_Init(USBH_HandleTypeDef *phost) { if (phost->device.DevDesc.idVendor != 0x0403) return USBH_FAIL; printf("[FTDI] Vendor ID Matched!\r\n"); uint8_t interface = USBH_FindInterface(phost, 0xFF, 0xFF, 0xFF); if (interface == 0xFF) { printf("[FTDI] FindInterface Failed!\r\n"); return USBH_FAIL; } printf("[FTDI] Interface found: %d\r\n", interface); USBH_SelectInterface(phost, interface); phost->pActiveClass->pData = &FTDI_Handle; FTDI_HandleTypeDef *FTDI = (FTDI_HandleTypeDef *)phost->pActiveClass->pData; for (uint8_t i = 0; i < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; i++) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress & 0x80) { FTDI->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; FTDI->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } else { FTDI->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; FTDI->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } } FTDI->OutPipe = USBH_AllocPipe(phost, FTDI->OutEp); FTDI->InPipe = USBH_AllocPipe(phost, FTDI->InEp); USBH_OpenPipe(phost, FTDI->OutPipe, FTDI->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, FTDI->OutEpSize); USBH_OpenPipe(phost, FTDI->InPipe, FTDI->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, FTDI->InEpSize); USBH_LL_SetToggle(phost, FTDI->OutPipe, 0); USBH_LL_SetToggle(phost, FTDI->InPipe, 0); FTDI->state = FTDI_INIT_RESET; return USBH_OK; } static USBH_StatusTypeDef FTDI_DeInit(USBH_HandleTypeDef *phost) { FTDI_HandleTypeDef *FTDI = (FTDI_HandleTypeDef *)phost->pActiveClass->pData; if (FTDI->OutPipe) { USBH_ClosePipe(phost, FTDI->OutPipe); USBH_FreePipe(phost, FTDI->OutPipe); } if (FTDI->InPipe) { USBH_ClosePipe(phost, FTDI->InPipe); USBH_FreePipe(phost, FTDI->InPipe); } return USBH_OK; } static USBH_StatusTypeDef FTDI_CtlReq(USBH_HandleTypeDef *phost, uint8_t req, uint16_t value, uint16_t index) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_DEVICE; phost->Control.setup.b.bRequest = req; phost->Control.setup.b.wValue.w = value; phost->Control.setup.b.wIndex.w = index; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, NULL, 0); } static USBH_StatusTypeDef FTDI_Requests(USBH_HandleTypeDef *phost) { FTDI_HandleTypeDef *FTDI = (FTDI_HandleTypeDef *)phost->pActiveClass->pData; USBH_StatusTypeDef status; switch (FTDI->state) { case FTDI_INIT_RESET: status = FTDI_CtlReq(phost, 0x00, 0x0000, 0); if (status == USBH_OK || status == USBH_NOT_SUPPORTED || status == USBH_FAIL) { printf("[FTDI] RESET status: %d\r\n", status); FTDI->state = FTDI_INIT_SET_BAUD; } break; case FTDI_INIT_SET_BAUD: { uint32_t divisor = 3000000 / Serial_BaudRate; status = FTDI_CtlReq(phost, 0x03, divisor, 0); if (status == USBH_OK || status == USBH_NOT_SUPPORTED || status == USBH_FAIL) { printf("[FTDI] BAUD (%lu) status: %d\r\n", Serial_BaudRate, status); FTDI->state = FTDI_INIT_SET_DATA; } break; } case FTDI_INIT_SET_DATA: { uint16_t data = (Serial_DataBits & 0x0F); if (Serial_Parity == 1) data |= (1 << 8); else if (Serial_Parity == 2) data |= (2 << 8); else if (Serial_Parity == 3) data |= (3 << 8); else if (Serial_Parity == 4) data |= (4 << 8); if (Serial_StopBits == 2) data |= (2 << 11); status = FTDI_CtlReq(phost, 0x04, data, 0); if (status == USBH_OK || status == USBH_NOT_SUPPORTED || status == USBH_FAIL) { printf("[FTDI] DATA status: %d\r\n", status); FTDI->state = FTDI_INIT_SET_FLOW; } break; } case FTDI_INIT_SET_FLOW: status = FTDI_CtlReq(phost, 0x02, 0x0000, 0); if (status == USBH_OK || status == USBH_NOT_SUPPORTED || status == USBH_FAIL) { printf("[FTDI] FLOW status: %d\r\n", status); FTDI->state = FTDI_INIT_SET_MODEM; } break; case FTDI_INIT_SET_MODEM: status = FTDI_CtlReq(phost, 0x01, 0x0303, 0); if (status == USBH_OK || status == USBH_NOT_SUPPORTED || status == USBH_FAIL) { printf("[FTDI] MODEM status: %d\r\n", status); FTDI->state = FTDI_INIT_DONE; } break; case FTDI_INIT_DONE: return USBH_OK; } return USBH_BUSY; } static uint8_t FTDI_RxBuffer[64]; static USBH_StatusTypeDef FTDI_BgndProcess(USBH_HandleTypeDef *phost) { FTDI_HandleTypeDef *FTDI = (FTDI_HandleTypeDef *)phost->pActiveClass->pData; static uint8_t rx_state = 0; if (phost->gState == HOST_CLASS && !phost->device.is_disconnected) { if (rx_state == 0) { USBH_BulkReceiveData(phost, FTDI_RxBuffer, FTDI->InEpSize, FTDI->InPipe); rx_state = 1; } else { USBH_URBStateTypeDef urb = USBH_LL_GetURBState(phost, FTDI->InPipe); if (urb == USBH_URB_DONE || urb == USBH_URB_NOTREADY || urb == USBH_URB_ERROR || urb == USBH_URB_STALL) { rx_state = 0; } } } else { rx_state = 0; } return USBH_OK; } static USBH_StatusTypeDef FTDI_SOFProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } USBH_ClassTypeDef FTDI_Class = { "FTDI_Class", 0xFF, FTDI_Init, FTDI_DeInit, FTDI_Requests, FTDI_BgndProcess, FTDI_SOFProcess, NULL }; USBH_StatusTypeDef USBH_FTDI_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length) { FTDI_HandleTypeDef *FTDI = (FTDI_HandleTypeDef *)phost->pActiveClass->pData; if (phost->gState != HOST_CLASS || phost->device.is_disconnected) return USBH_FAIL; USBH_URBStateTypeDef urb = USBH_LL_GetURBState(phost, FTDI->OutPipe); if (urb == USBH_URB_IDLE || urb == USBH_URB_DONE || urb == USBH_URB_NOTREADY || urb == USBH_URB_ERROR || urb == USBH_URB_STALL) { USBH_BulkSendData(phost, pbuff, length, FTDI->OutPipe, 1); return USBH_OK; } return USBH_BUSY; } // ========================================== // CH34X DRIVER // ========================================== typedef enum { CH34X_INIT_SETUP, CH34X_INIT_BAUD, CH34X_INIT_DONE } CH34x_State; typedef struct { uint8_t InEp, OutEp, InPipe, OutPipe; uint16_t InEpSize, OutEpSize; CH34x_State state; } CH34x_HandleTypeDef; static CH34x_HandleTypeDef CH34x_Handle; static USBH_StatusTypeDef CH34x_Init(USBH_HandleTypeDef *phost) { if (phost->device.DevDesc.idVendor != 0x1A86) return USBH_FAIL; uint8_t interface = USBH_FindInterface(phost, 0xFF, 0x01, 0x02); if (interface == 0xFF) interface = 0; USBH_SelectInterface(phost, interface); phost->pActiveClass->pData = &CH34x_Handle; CH34x_HandleTypeDef *CH34x = (CH34x_HandleTypeDef *)phost->pActiveClass->pData; for (uint8_t i = 0; i < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; i++) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress & 0x80) { CH34x->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; CH34x->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } else { CH34x->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; CH34x->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } } CH34x->OutPipe = USBH_AllocPipe(phost, CH34x->OutEp); CH34x->InPipe = USBH_AllocPipe(phost, CH34x->InEp); USBH_OpenPipe(phost, CH34x->OutPipe, CH34x->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, CH34x->OutEpSize); USBH_OpenPipe(phost, CH34x->InPipe, CH34x->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, CH34x->InEpSize); USBH_LL_SetToggle(phost, CH34x->OutPipe, 0); USBH_LL_SetToggle(phost, CH34x->InPipe, 0); CH34x->state = CH34X_INIT_SETUP; return USBH_OK; } static USBH_StatusTypeDef CH34x_DeInit(USBH_HandleTypeDef *phost) { CH34x_HandleTypeDef *CH34x = (CH34x_HandleTypeDef *)phost->pActiveClass->pData; if (CH34x->OutPipe) { USBH_ClosePipe(phost, CH34x->OutPipe); USBH_FreePipe(phost, CH34x->OutPipe); } if (CH34x->InPipe) { USBH_ClosePipe(phost, CH34x->InPipe); USBH_FreePipe(phost, CH34x->InPipe); } return USBH_OK; } static USBH_StatusTypeDef CH34x_CtlReq(USBH_HandleTypeDef *phost, uint8_t req, uint16_t value, uint16_t index) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_TYPE_VENDOR | USB_REQ_RECIPIENT_DEVICE; phost->Control.setup.b.bRequest = req; phost->Control.setup.b.wValue.w = value; phost->Control.setup.b.wIndex.w = index; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(phost, NULL, 0); } static USBH_StatusTypeDef CH34x_Requests(USBH_HandleTypeDef *phost) { CH34x_HandleTypeDef *CH34x = (CH34x_HandleTypeDef *)phost->pActiveClass->pData; switch (CH34x->state) { case CH34X_INIT_SETUP: if (CH34x_CtlReq(phost, 0xA1, 0, 0) == USBH_OK) CH34x->state = CH34X_INIT_BAUD; break; case CH34X_INIT_BAUD: if (CH34x_CtlReq(phost, 0x9A, 0x1312, 0xCC1A) == USBH_OK) CH34x->state = CH34X_INIT_DONE; break; case CH34X_INIT_DONE: return USBH_OK; } return USBH_BUSY; } static USBH_StatusTypeDef CH34x_BgndProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } static USBH_StatusTypeDef CH34x_SOFProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } USBH_ClassTypeDef CH34x_Class = { "CH34x_Class", 0xFF, CH34x_Init, CH34x_DeInit, CH34x_Requests, CH34x_BgndProcess, CH34x_SOFProcess, NULL }; USBH_StatusTypeDef USBH_CH34x_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length) { CH34x_HandleTypeDef *CH34x = (CH34x_HandleTypeDef *)phost->pActiveClass->pData; if (phost->gState != HOST_CLASS || phost->device.is_disconnected) return USBH_FAIL; USBH_URBStateTypeDef urb = USBH_LL_GetURBState(phost, CH34x->OutPipe); if (urb == USBH_URB_IDLE || urb == USBH_URB_DONE || urb == USBH_URB_NOTREADY || urb == USBH_URB_ERROR || urb == USBH_URB_STALL) { USBH_BulkSendData(phost, pbuff, length, CH34x->OutPipe, 1); return USBH_OK; } return USBH_BUSY; } // ========================================== // PL2303 DRIVER // ========================================== typedef enum { PL2303_INIT_SETUP, PL2303_INIT_DONE } PL2303_State; typedef struct { uint8_t InEp, OutEp, InPipe, OutPipe; uint16_t InEpSize, OutEpSize; PL2303_State state; } PL2303_HandleTypeDef; static PL2303_HandleTypeDef PL2303_Handle; static USBH_StatusTypeDef PL2303_Init(USBH_HandleTypeDef *phost) { if (phost->device.DevDesc.idVendor != 0x067B) return USBH_FAIL; uint8_t interface = USBH_FindInterface(phost, 0xFF, 0x00, 0x00); if (interface == 0xFF) interface = 0; USBH_SelectInterface(phost, interface); phost->pActiveClass->pData = &PL2303_Handle; PL2303_HandleTypeDef *PL2303 = (PL2303_HandleTypeDef *)phost->pActiveClass->pData; for (uint8_t i = 0; i < phost->device.CfgDesc.Itf_Desc[interface].bNumEndpoints; i++) { if (phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress & 0x80) { PL2303->InEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; PL2303->InEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } else { PL2303->OutEp = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].bEndpointAddress; PL2303->OutEpSize = phost->device.CfgDesc.Itf_Desc[interface].Ep_Desc[i].wMaxPacketSize; } } PL2303->OutPipe = USBH_AllocPipe(phost, PL2303->OutEp); PL2303->InPipe = USBH_AllocPipe(phost, PL2303->InEp); USBH_OpenPipe(phost, PL2303->OutPipe, PL2303->OutEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, PL2303->OutEpSize); USBH_OpenPipe(phost, PL2303->InPipe, PL2303->InEp, phost->device.address, phost->device.speed, USB_EP_TYPE_BULK, PL2303->InEpSize); USBH_LL_SetToggle(phost, PL2303->OutPipe, 0); USBH_LL_SetToggle(phost, PL2303->InPipe, 0); PL2303->state = PL2303_INIT_SETUP; return USBH_OK; } static USBH_StatusTypeDef PL2303_DeInit(USBH_HandleTypeDef *phost) { PL2303_HandleTypeDef *PL2303 = (PL2303_HandleTypeDef *)phost->pActiveClass->pData; if (PL2303->OutPipe) { USBH_ClosePipe(phost, PL2303->OutPipe); USBH_FreePipe(phost, PL2303->OutPipe); } if (PL2303->InPipe) { USBH_ClosePipe(phost, PL2303->InPipe); USBH_FreePipe(phost, PL2303->InPipe); } return USBH_OK; } static USBH_StatusTypeDef PL2303_Requests(USBH_HandleTypeDef *phost) { PL2303_HandleTypeDef *PL2303 = (PL2303_HandleTypeDef *)phost->pActiveClass->pData; switch (PL2303->state) { case PL2303_INIT_SETUP: { static uint8_t line_coding[7] = {0x00, 0xC2, 0x01, 0x00, 0x00, 0x00, 0x08}; // 115200 8N1 phost->Control.setup.b.bmRequestType = 0x21; phost->Control.setup.b.bRequest = 0x20; phost->Control.setup.b.wValue.w = 0; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 7; if (USBH_CtlReq(phost, line_coding, 7) == USBH_OK) PL2303->state = PL2303_INIT_DONE; } break; case PL2303_INIT_DONE: return USBH_OK; } return USBH_BUSY; } static USBH_StatusTypeDef PL2303_BgndProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } static USBH_StatusTypeDef PL2303_SOFProcess(USBH_HandleTypeDef *phost) { return USBH_OK; } USBH_ClassTypeDef PL2303_Class = { "PL2303_Class", 0xFF, PL2303_Init, PL2303_DeInit, PL2303_Requests, PL2303_BgndProcess, PL2303_SOFProcess, NULL }; USBH_StatusTypeDef USBH_PL2303_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length) { PL2303_HandleTypeDef *PL2303 = (PL2303_HandleTypeDef *)phost->pActiveClass->pData; if (phost->gState != HOST_CLASS || phost->device.is_disconnected) return USBH_FAIL; USBH_URBStateTypeDef urb = USBH_LL_GetURBState(phost, PL2303->OutPipe); if (urb == USBH_URB_IDLE || urb == USBH_URB_DONE || urb == USBH_URB_NOTREADY || urb == USBH_URB_ERROR || urb == USBH_URB_STALL) { USBH_BulkSendData(phost, pbuff, length, PL2303->OutPipe, 1); return USBH_OK; } return USBH_BUSY; } // ========================================== // UNIFIED WRAPPER // ========================================== USBH_StatusTypeDef USBH_Serial_RegisterClasses(USBH_HandleTypeDef *phost) { if (USBH_RegisterClass(phost, USBH_CDC_CLASS) != USBH_OK) return USBH_FAIL; if (USBH_RegisterClass(phost, &CP210x_Class) != USBH_OK) return USBH_FAIL; if (USBH_RegisterClass(phost, &FTDI_Class) != USBH_OK) return USBH_FAIL; if (USBH_RegisterClass(phost, &CH34x_Class) != USBH_OK) return USBH_FAIL; if (USBH_RegisterClass(phost, &PL2303_Class) != USBH_OK) return USBH_FAIL; return USBH_OK; } USBH_StatusTypeDef USBH_Serial_Transmit(USBH_HandleTypeDef *phost, uint8_t *pbuff, uint16_t length) { if (phost->gState != HOST_CLASS) return USBH_FAIL; if (phost->pActiveClass == USBH_CDC_CLASS) return USBH_CDC_Transmit(phost, pbuff, length); else if (phost->pActiveClass == &CP210x_Class) return USBH_CP210x_Transmit(phost, pbuff, length); else if (phost->pActiveClass == &FTDI_Class) return USBH_FTDI_Transmit(phost, pbuff, length); else if (phost->pActiveClass == &CH34x_Class) return USBH_CH34x_Transmit(phost, pbuff, length); else if (phost->pActiveClass == &PL2303_Class) return USBH_PL2303_Transmit(phost, pbuff, length); return USBH_FAIL; } ``` --- ## 3. 예제 코드 (main.c 적용 방법) ```c #include "usbh_serial.h" extern USBH_HandleTypeDef hUsbHostHS; // MX_USB_HOST_Init()에서 생성된 전역 변수 void myTaskFunc01(void *argument) { // 1. EEPROM 또는 사용자 설정에서 불러온 값을 적용 (USB 통신 시작 전) uint32_t saved_baud = 9600; USBH_Serial_InitSettings(saved_baud, 8, 0, 0); // 2. USB 호스트 모듈 초기화 (내부적으로 스레드 구동) MX_USB_HOST_Init(); uint32_t cnt = 0; char txBuffer[64]; for(;;) { // 3. 디바이스가 인식되고 통신 준비가 끝난 상태(HOST_CLASS)일 때 데이터 전송 if (hUsbHostHS.gState == HOST_CLASS) { int len = snprintf(txBuffer, sizeof(txBuffer), "Tick: %lu\r\n", cnt++); USBH_Serial_Transmit(&hUsbHostHS, (uint8_t *)txBuffer, len); } osDelay(1000); } } // 4. 드라이버 등록 (usb_host.c 내부) void MX_USB_HOST_Init(void) { if (USBH_Init(&hUsbHostHS, USBH_UserProcess, HOST_HS) != USBH_OK) { Error_Handler(); } // 기존 USBH_RegisterClass 대신 Unified 함수 호출 if (USBH_Serial_RegisterClasses(&hUsbHostHS) != USBH_OK) { Error_Handler(); } if (USBH_Start(&hUsbHostHS) != USBH_OK) { Error_Handler(); } } ```

첨언 달기
이름 : 암호 :
번호    제목...(첨언) 작성일 접속
xxx [공지]자유겔러리 등록 오류 수정 완료 2017-12-22 685432
xxx [공지]자료실 다운로드 오류 처리 2017-12-01 31350
xxx [공지]비난, 광고 게시물을 신고, 차단, 삭제됩니다. 2005-06-26 27037
261 [M D]  Windows 10 Home을 Windows 10 Pro로 업그레이드하는 방법 2026-10-22(목) 21
260 [C#]  시뮬레이터용 동역학 패킷 C# 2026-10-21(수) 22
259 [CPP]  시뮬레이터용 동역학 패킷 C/C++ 2026-10-21(수) 22
258 [M D]  VS Code 4대 AI 바이브코딩 명령어(`/`) & 맥락 호출(`@`) 완벽 통합 가이드 2026-10-20(화) 20
257 [일반]  VS Code에서 Google AI 사용할때 자동 agree 2026-10-02(금) 87
256 [C#]  asp.net .net core connectionString Encryption 표준 암호화 방법 2026-09-24(목) 82
255 [CPP]  MS Windows 64bit Time Converter 2026-09-23(수) 109
254 [M D]  STM32H747I-DISCO 이더넷(RMII) 및 LwIP 완벽 구현 및 트러블슈팅 가이드 2026-09-17(목) 131
253 [일반]  .net core Web 생성하면 나오는 구조 2026-09-12(토) 101
252 [M D] > STM32 개발 때 다양한 USB CDCs 사용CDC, CP210x, FTDI, CH34x, PL2303) < 2026-09-11(금) 115
251 [M D]  STM32H747I-DISCO CP2102 USB Host 트러블슈팅 종합 보고서 2026-09-11(금) 89
250 [일반]  STM32H747I-DISCO에서 STM32CubeMX 템플릿때문에 USB OTG 문제 발생할때 2026-09-10(목) 135
249 [M D]  TouchGFX에서 버튼같은거 삭제 했을때 make: *** No rule to make target.. 오류 2026-08-20(목) 159
248 [M D]  STM TouchGFX설계할때 main에서 View에 접근하는 순서 2026-08-16(일) 133
247 [M D]  STM TouchGFX설계할때 View가 main에 접근하는 순서 2026-08-16(일) 181
246 [M D]  MCU Task관리할때 필요한 세마포어(Semaphore)와 뮤텍스(Mutex) 2026-08-09(일) 174
245 [M D]  STM32F 마이컴 공부할때 RAM에 올려서 시험하기.(속도 빠름) 2026-08-08(토) 181
244 [일반]  STM32F767과 FreeRTOS를 이용해 설계할때 Time base Source는? 2026-08-08(토) 170
243 [일반]  VSCode로 STM32 개발할때 printf에서 실수 출력 안되면 2026-07-16(목) 1030
242 [일반]  VisualStudio으로 만든 프로그램 .net 버전 올리기 위해 2026-07-02(목) 1261
검색 :
Page : 이전 1  2  3  4  5  6  7  8  9  10  11  12  13  다음




Copyright 2003-2026 ⓒ 김종호. All rights reserved. kimjongho.co.kr kimjongho.kr kimjongho.net kimjongho.com