CH32x035 의 USB Custom HID 테스트 해 보자.
참고 소스코드는 https://github.com/openwch/ch32x035/tree/main/EVT/EXAM/USB/USBFS/DEVICE/CompatibilityHID 를 수정하여 작성하였다.
WCH에서 제공하는 USB HID코드는 UART에서 받은 데이터를 HID로 전송하도록 되어 있는데 스위치 누르면 HID 데이터 전송하고 PC에서 받은 HID레포트 데이터를 출력 하도록 코드를 수정 하였다.
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(115200);
GPIO_INIT();
Led1Off();
printf("SystemClk:%d\r\n", SystemCoreClock);
printf("ChipID:%08x\r\n", DBGMCU_GetCHIPID() );
/* Variables init */
Var_Init( );
/* UART2 init */
//UART2_Init();
//UART2_DMA_Init();
TIM3_Init();
/* Usb Init */
USBFS_RCC_Init( );
USBFS_Device_Init( ENABLE , PWR_VDD_SupplyVoltage());
while(1)
{
if(!GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
{
printf("Press SW\r\n");
SendReport();
Delay_Ms(200);
}
//USB 인식 되어 있으면
if(USBFS_DevEnumStatus)
{
//UART2_Rx_Service();
//UART2_Tx_Service();
HID_Rx_Service();
}
}
}
펌웨어 다운로드 하고 USB장치를 인식 시키면 HID장치가 인식되는 것을 확인 할 수 있다.
데이터 수신시 USBFS_IRQHandler() 함수에서 처리되고 HID_SET_REPORT에서 HID_Set_Report_Flag를 확인하면 된다.
void USBFS_IRQHandler( void )
{
:
/* data-out stage processing */
case USBFS_UIS_TOKEN_OUT:
switch( intst & ( USBFS_UIS_TOKEN_MASK | USBFS_UIS_ENDP_MASK ) )
{
/* end-point 0 data out interrupt */
case USBFS_UIS_TOKEN_OUT | DEF_UEP0:
if( intst & USBFS_UIS_TOG_OK )
{
if ( ( USBFS_SetupReqType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
{
if (( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS)
{
switch( USBFS_SetupReqCode )
{
case HID_SET_REPORT:
memcpy(&HID_Report_Buffer[0],USBFS_EP0_Buf,DEF_USBD_UEP0_SIZE);
HID_Set_Report_Flag = SET_REPORT_WAIT_DEAL;
USBFSD->UEP0_CTRL_H = USBFS_UEP_T_TOG | USBFS_UEP_T_RES_NAK;
break;
default:
break;
}
}
}
else
{
/* Standard request end-point 0 Data download */
/* Add your code here */
}
}
break;
:
HID 수신 데이터 처리 함수
void HID_Rx_Service()
{
uint16_t i;
if (HID_Set_Report_Flag == SET_REPORT_WAIT_DEAL)
{
printf("Set Report:\r\n");
for (i = 0; i < 64; ++i)
{
printf("%02x ",HID_Report_Buffer[i]);
}
printf("\r\n");
if(pbuf[0])
{
Led1On();
}
else Led1Off();
HID_Set_Report_Flag = SET_REPORT_DEAL_OVER;
USBFSD->UEP0_TX_LEN = 0;
USBFSD->UEP0_CTRL_H = USBFS_UEP_T_RES_ACK | USBFS_UEP_T_TOG;
}
}
기존에 테스트 했던 HID 프로그램으로 테스트 해보 았다. 정상적으로 잘 구동이된다.
요즘에는 PC프로그램으로 파이썬을 많이 이용하는데 파이썬에서 USB HID를 지원하는 라이브러리가 있어 테스트 해 보았다.
먼저 pywinusb 를 설치 해야 한다.
PS D:\WORK\ARM\CH32V\ch32x035_ssm\chx035_test> pip install pywinusb
Collecting pywinusb
Downloading pywinusb-0.4.2.zip (61 kB)
---------------------------------------- 61.7/61.7 KB 3.4 MB/s eta 0:00:00
Preparing metadata (setup.py) ... done
Using legacy 'setup.py install' for pywinusb, since package 'wheel' is not installed.
Installing collected packages: pywinusb
Running setup.py install for pywinusb ... done
Successfully installed pywinusb-0.4.2
WARNING: You are using pip version 22.0.4; however, version 23.3.2 is available.
You should consider upgrading via the 'C:\Users\jhpark\AppData\Local\Programs\Python\Python39\python.exe -m pip install --upgrade pip' command.
PS D:\WORK\ARM\CH32V\ch32x035_ssm\chx035_test>
간단히 CH32X035 의 LED를 On/Off 할수 있는 USB HID 제어 파이썬 코드를 작성해 보았다.
import sys
from PySide2.QtCore import QSize
from PySide2.QtWidgets import QApplication, QPushButton, QVBoxLayout, QWidget
import pywinusb.hid as hid
class HIDController:
USB_CFG_VENDOR_ID = 0x1a86 #0x16c0 # 5824 = voti.nl
USB_CFG_DEVICE_ID = 0xfe07 #0x05DF # obdev's shared PID for HIDs
filter = None
hid_device = None
device = None
report = None
last_row_status = None
def __init__(self):
self.get_Hid_USBDevice()
def get_Hid_USBDevice(self):
self.filter = hid.HidDeviceFilter(vendor_id=self.USB_CFG_VENDOR_ID, product_id=self.USB_CFG_DEVICE_ID)
self.hid_device = self.filter.get_devices()
self.device = self.hid_device[0]
def open_device(self):
if self.device.is_active():
if not self.device.is_opened():
self.device.open()
self.get_report()
return True
else:
print("Device already opened")
return True
else:
print("Device is not active")
return False
def close_device(self):
if self.device.is_active():
if self.device.is_opened():
self.device.close()
return True
else:
print("Device already closed")
else:
print("Device is not active")
return True
def get_report(self):
if not self.device.is_active():
self.report = None
for rep in self.device.find_output_reports() + self.device.find_feature_reports():
self.report = rep
def write_row_data(self, buffer: list):
if self.report is not None:
self.report.send(raw_data=buffer)
return True
else:
print("Cannot write in the report. check if your device is still plugged")
return False
g_tx_data = []
class Window(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.button1 = QPushButton(
text="Led1On", parent=self
)
self.button2 = QPushButton(
text="Led1Off", parent=self
)
self.button1.setFixedSize(300, 200)
self.button1.clicked.connect(self.onClick1)
self.button2.setFixedSize(300, 200)
self.button2.clicked.connect(self.onClick2)
layout = QVBoxLayout()
layout.addWidget(self.button1)
layout.addWidget(self.button2)
self.setLayout(layout)
global hid_device
global g_led_status
global g_tx_data
hid_device = HIDController()
hid_device.open_device()
g_led_status = 0
for x in range(65):
g_tx_data.append(x)
#rc.write_row_data(tx_data)
def onClick1(self):
global hid_device
global g_tx_data
print("Press bt1")
g_tx_data[2] = 0
hid_device.write_row_data(g_tx_data)
def onClick2(self):
global hid_device
global g_tx_data
g_tx_data[2] = 1
hid_device.write_row_data(g_tx_data)
print("2 Press")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
#sys.exit(app.exec())
sys.exit(app.exec_())
실행결과 윈도우에서 HID로 제어 되는것을 확인 할 수 있다.
반응형