메뉴 닫기

OPEN CR USB CDC 사용하기(UART 편)

USB CDC Run

USB CDC(Communication Device Class) 사용법

기본프로젝트를 다운로드 받는다. 어디? 여기에!

사용될 USB 핀을 찾아보자.

OpenCR USB Port
OpenCR USB Port

Open CR USB Circuit

정리 하자면 사용되는 GPIO 핀은 다음과 같다.

기능 사용목적 Netname 포트명
USB USB_FS OTG_FS_N PA11
USB USB_FS OTG_FS_P PA12

프로젝트에서 Cube MX 를 실행한다.

Run Cube.ioc

실행된 Cube MX Connectivity -> USB_OTG_FS 에 Mode 를 Device_Only 를 선택한다.
Selection USB_FS Device Only

|Middleware -> USB Device -> Communication Device Class (Virtual Port Com) 을 선택한다.

Selection Communication Device Class

Clock Configuration 에 들어가면 자동으로 클럭을 해결하겠냐는 물음에 No 버튼을 누른다.
Do you want to run automatic clock issues solver
PLLSAIP 라디오 버튼을 누르고 Resolve Clock Issues 버튼을 누른다.
PLLSAIP Click클럭 설정중…
Searching Solution, Please Wait...

변경사항을 확인 후, GENERATE CODE 버튼을 누른다.
Generating user source code...

자신의 입맛에 맞게 버튼을 누르자.
The Code is successfully generated under Default_HAL

프로젝트에 정상적으로 파일이 생성되었는지 확인한다.
Check STM32 USB Device Library

다음의 경로에 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

Add/remove include path... "Cube Middlewares ST STM32_USB_Device_Library Core Inc"Add/remove include path... "Cube Middlewares ST STM32_USB_Device_Library Class CDC Inc"

OK 버튼을 누른다.
Select configurations to modify

 

src / bsp / bsp.c 파일에 초기화 함수를 작성한다.
USB Device init function Write

src / lib / cube / Src / main.c 의 main 함수를 제거한다.
Removing main function for usb cdc

src / lib / cube / Src / usbd_cdc_if.c 파일에 /* USER CODE BEGIN INCLUDE */ 주석의 하단에 다음의 코드(데이터 송수신)를 작성합니다.

Insert the source code into usbd_cdc_if.c

/* 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 함수의 내용(라인코딩)을 추가한다.
Add line coding attribute to usbd_cdc_if.c

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 함수의 내용(데이터 수신시 버퍼 추가)을 추가한다.
Added to usbd_cdc_if.c to save to buffer when receiving data

for (int i=0; i<*Len; i++){
  cdcDataIn(Buf[i]);
}

src / hw / driver 폴더를 생성하고 uart.c 와 uart.h 를 생성 후 생성한 폴더에 Add/remove include path… 버튼을 클릭한다.
Add folder and uart.c and uart.hAdd/remove include path...

OK 버튼을 누른다.
Select configurations to modify

다음사진에 맞게 코드를 작성한다.

Insert the source code into hw.h

#include "hw_def.h"

#include "uart.h"

void hwInit(void);

Insert the source code into hw.c

uartInit();

Insert the source code into uart.h

#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, ...);

Insert the source code into uart.c

#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);
}

Insert the source code into def.h

#include <stdio.h>

#define _DEF_UART1 0
#define _DEF_UART2 1
#define _DEF_UART3 2
#define _DEF_UART4 3

Insert the source code into ap.c

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);
    }

  }
}

 

실행결과
USB CDC Run

장치관리자에서 포트 번호를 확인 후, 시리얼 통신(Baudrate : 115200, Stop Bit : 1, Data Bit 8, Parity : None) 을 연결을 하면
입력을 받는 즉시 다음의 화면처럼 디스플레이가 가능하다.

해당 프로젝트는 여기 버튼을 누르면 다운로드가 가능하다.

 

 

 

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다