USB CDC(Communication Device Class) 사용법
기본프로젝트를 다운로드 받는다. 어디? 여기에!
사용될 USB 핀을 찾아보자.
정리 하자면 사용되는 GPIO 핀은 다음과 같다.
기능 | 사용목적 | Netname | 포트명 |
USB | USB_FS | OTG_FS_N | PA11 |
USB | USB_FS | OTG_FS_P | PA12 |
프로젝트에서 Cube MX 를 실행한다.
실행된 Cube MX Connectivity -> USB_OTG_FS 에 Mode 를 Device_Only 를 선택한다.
|Middleware -> USB Device -> Communication Device Class (Virtual Port Com) 을 선택한다.
Clock Configuration 에 들어가면 자동으로 클럭을 해결하겠냐는 물음에 No 버튼을 누른다.
PLLSAIP 라디오 버튼을 누르고 Resolve Clock Issues 버튼을 누른다.
클럭 설정중…
변경사항을 확인 후, GENERATE CODE 버튼을 누른다.
자신의 입맛에 맞게 버튼을 누르자.
프로젝트에 정상적으로 파일이 생성되었는지 확인한다.
다음의 경로에 Add/remove include path… 버튼을 클릭한다.
- src/lib/cube/Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc
- src/lib/cube/Middlewares/ST/STM32_USB_Device_Library/Core/Inc
OK 버튼을 누른다.
src / bsp / bsp.c 파일에 초기화 함수를 작성한다.
src / lib / cube / Src / main.c 의 main 함수를 제거한다.
src / lib / cube / Src / usbd_cdc_if.c 파일에 /* USER CODE BEGIN INCLUDE */ 주석의 하단에 다음의 코드(데이터 송수신)를 작성합니다.
/* USER CODE BEGIN INCLUDE */ #include "hw_def.h" uint32_t rx_in = 0; uint32_t rx_out = 0; uint32_t rx_len = 2048; uint8_t rx_buf[2048]; USBD_CDC_LineCodingTypeDef LineCoding = { 115200, /* baud rate */ 0x00, /* stop bits-1 */ 0x00, /* parity - none */ 0x08 /* nb. of bits 8 */ }; uint32_t cdcAvailable(void){ return (rx_in - rx_out) % rx_len; } uint8_t cdcRead(void){ uint8_t ret = 0; ret = rx_buf[rx_out]; if(rx_out != rx_in){ rx_out = (rx_out + 1) % rx_len; } return ret; } void cdcDataIn(uint8_t rx_data){ uint32_t next_rx_in; rx_buf[rx_in] = rx_data; next_rx_in = (rx_in + 1) % rx_len; if(next_rx_in != rx_out){ rx_in = next_rx_in; } } uint32_t cdcWrite(uint8_t *p_data, uint32_t length){ uint32_t pre_time; pre_time = millis(); while(1){ if(CDC_Transmit_FS(p_data, length) == USBD_OK){ return length; } if (millis() - pre_time >= 100){ break; } } return 0; } /* USER CODE END INCLUDE */
src / lib / cube / Src / usbd_cdc_if.c 파일에 CDC_Control_FS 함수의 내용(라인코딩)을 추가한다.
case CDC_SET_LINE_CODING: LineCoding.bitrate = (uint32_t)(pbuf[0]); LineCoding.bitrate |= (uint32_t)(pbuf[1]<<8); LineCoding.bitrate |= (uint32_t)(pbuf[2]<<16); LineCoding.bitrate |= (uint32_t)(pbuf[3]<<24); LineCoding.format = pbuf[4]; LineCoding.paritytype = pbuf[5]; LineCoding.datatype = pbuf[6]; break; case CDC_GET_LINE_CODING: pbuf[0] = (uint8_t)(LineCoding.bitrate); pbuf[1] = (uint8_t)(LineCoding.bitrate >> 8); pbuf[2] = (uint8_t)(LineCoding.bitrate >> 16); pbuf[3] = (uint8_t)(LineCoding.bitrate >> 24); pbuf[4] = LineCoding.format; pbuf[5] = LineCoding.paritytype; pbuf[6] = LineCoding.datatype; break;
src / lib / cube / Src / usbd_cdc_if.c 파일에 CDC_Control_FS 함수의 내용(데이터 수신시 버퍼 추가)을 추가한다.
for (int i=0; i<*Len; i++){ cdcDataIn(Buf[i]); }
src / hw / driver 폴더를 생성하고 uart.c 와 uart.h 를 생성 후 생성한 폴더에 Add/remove include path… 버튼을 클릭한다.
OK 버튼을 누른다.
다음사진에 맞게 코드를 작성한다.
#include "hw_def.h" #include "uart.h" void hwInit(void);
uartInit();
#include "hw_def.h" #define UART_MAX_CH 1 void uartInit(void); bool uartOpen(uint8_t ch, uint32_t baud); uint32_t uartAvailable(uint8_t ch); uint8_t uartRead(uint8_t ch); uint32_t uartWrite(uint8_t ch, uint8_t *p_data, uint32_t length); void uartPrintf(uint8_t ch, char *fmt, ...);
#include "uart.h" extern uint32_t cdcAvailable(void); extern uint8_t cdcRead(void); extern uint32_t cdcWrite(uint8_t *p_data, uint32_t length); void uartInit(void){ } bool uartOpen(uint8_t ch, uint32_t baud){ return true; } uint32_t uartAvailable(uint8_t ch){ return cdcAvailable(); } uint8_t uartRead(uint8_t ch){ return cdcRead(); } uint32_t uartWrite(uint8_t ch, uint8_t *p_data, uint32_t length){ return cdcWrite(p_data, length); } void uartPrintf(uint8_t ch, char *fmt, ...){ char buf[256]; va_list args; int len; va_start(args, fmt); len = vsnprintf(buf, 256, fmt, args); uartWrite(ch, (uint8_t *)buf, len); va_end(args); }
#include <stdio.h> #define _DEF_UART1 0 #define _DEF_UART2 1 #define _DEF_UART3 2 #define _DEF_UART4 3
void apInit(void) { uartOpen(_DEF_UART1, 115200); } void apMain(void) { while(1) { if(uartAvailable(_DEF_UART1)>0){ uint8_t read_data; read_data = uartRead(_DEF_UART1); uartPrintf(_DEF_UART1, "rx : 0x%x rn", read_data); } } }
실행결과
장치관리자에서 포트 번호를 확인 후, 시리얼 통신(Baudrate : 115200, Stop Bit : 1, Data Bit 8, Parity : None) 을 연결을 하면
입력을 받는 즉시 다음의 화면처럼 디스플레이가 가능하다.
해당 프로젝트는 여기 버튼을 누르면 다운로드가 가능하다.