From 27790cc05bfb084333502c3c34541347e94050f9 Mon Sep 17 00:00:00 2001 From: IOsetting Date: Sun, 6 Feb 2022 23:26:45 +0800 Subject: [PATCH] feat: usb and HID demo --- demo/usb/usb_hid.c | 437 +++++++++++++++++++++++++++++++++++++++++ include/fw_hal.h | 1 + include/fw_reg_stc8h.h | 2 + include/fw_sys.h | 18 ++ include/fw_usb.h | 175 +++++++++++++++++ src/fw_usb.c | 39 ++++ 6 files changed, 672 insertions(+) create mode 100644 demo/usb/usb_hid.c create mode 100644 include/fw_usb.h create mode 100644 src/fw_usb.c diff --git a/demo/usb/usb_hid.c b/demo/usb/usb_hid.c new file mode 100644 index 0000000..d1e241b --- /dev/null +++ b/demo/usb/usb_hid.c @@ -0,0 +1,437 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "fw_hal.h" + +__CODE uint8_t DEVICEDESC[18]; +__CODE uint8_t CONFIGDESC[41]; +__CODE uint8_t HIDREPORTDESC[27]; +__CODE uint8_t LANGIDDESC[4]; +__CODE uint8_t MANUFACTDESC[8]; +__CODE uint8_t PRODUCTDESC[30]; +__XDATA uint8_t HidFreature[64]; +__XDATA uint8_t HidInput[64]; +__XDATA uint8_t HidOutput[64]; +SETUP Setup; +EP0STAGE Ep0Stage; + +void USB_Init(); +uint8_t CalCheckSum(uint8_t *buf, uint8_t len); + +void main() +{ + uint8_t i; + GPIO_P3_SetMode(GPIO_Pin_0|GPIO_Pin_1, GPIO_Mode_Input_HIP); + + USB_Init(); + EA = 1; + HidOutput[0]=0xaa; + HidOutput[1]=0x55; + HidOutput[2]=0x02; + for(i=3;i<64;i++) HidOutput[i] = 0; + HidOutput[3] = (uint8_t)(0x01); + HidOutput[4] = (uint8_t)(0x02); + HidOutput[5] = (uint8_t)(0x01); + HidOutput[6] = (uint8_t)(0x02); + HidOutput[7] = CalCheckSum(HidOutput,7); + + while (1); +} + +void USB_Init() +{ + SYS_EnableOscillator48M(); + USBCLK = 0x00; + USBCON = 0x90; + IP2H |= 0x80; // highest priority + IP2 |= 0x80; + USB_WriteReg(FADDR, 0x00); + USB_WriteReg(POWER, 0x08); + USB_WriteReg(INTRIN1E, 0x3f); + USB_WriteReg(INTROUT1E, 0x3f); + USB_WriteReg(INTRUSBE, 0x00); + USB_WriteReg(POWER, 0x01); + Ep0Stage.bStage = EPIDLE; + IE2 |= 0x80; +} + +INTERRUPT(USB_Routine, EXTI_VectUSB) +{ + uint8_t intrusb; + uint8_t intrin; + uint8_t introut; + uint8_t csr; + uint8_t cnt; + uint16_t len; + intrusb = USB_ReadReg(INTRUSB); + intrin = USB_ReadReg(INTRIN1); + introut = USB_ReadReg(INTROUT1); + if (intrusb & RSTIF) + { + USB_WriteReg(INDEX, 1); + USB_WriteReg(INCSR1, INCLRDT); + USB_WriteReg(INDEX, 1); + USB_WriteReg(OUTCSR1, OUTCLRDT); + Ep0Stage.bStage = EPIDLE; + } + if (intrin & EP0IF) + { + USB_WriteReg(INDEX, 0); + csr = USB_ReadReg(CSR0); + if (csr & STSTL) + { + USB_WriteReg(CSR0, csr & ~STSTL); + Ep0Stage.bStage = EPIDLE; + } + if (csr & SUEND) + { + USB_WriteReg(CSR0, csr | SSUEND); + } + switch (Ep0Stage.bStage) + { + case EPIDLE: + if (csr & OPRDY) + { + Ep0Stage.bStage = EPSTATUS; + USB_ReadFIFO(FIFO0, (uint8_t *)&Setup); + ((uint8_t *)&Ep0Stage.wResidue)[0] = Setup.wLengthH; + ((uint8_t *)&Ep0Stage.wResidue)[1]= Setup.wLengthL; + switch (Setup.bmRequestType & REQUEST_MASK) + { + case STANDARD_REQUEST: + switch (Setup.bRequest) + { + case SET_ADDRESS: + USB_WriteReg(FADDR, Setup.wValueL); + break; + + case SET_CONFIG: + USB_WriteReg(INDEX, 1); + USB_WriteReg(INCSR2, INMODEIN); + USB_WriteReg(INMAXP, 8); + USB_WriteReg(INDEX, 1); + USB_WriteReg(INCSR2, INMODEOUT); + USB_WriteReg(OUTMAXP, 8); + USB_WriteReg(INDEX, 0); + break; + + case GET_DESCRIPTOR: + Ep0Stage.bStage = EPDATAIN; + switch (Setup.wValueH) + { + case DESC_DEVICE: + Ep0Stage.pData = DEVICEDESC; + len = sizeof(DEVICEDESC); + break; + + case DESC_CONFIG: + Ep0Stage.pData = CONFIGDESC; + len = sizeof(CONFIGDESC); + break; + + case DESC_STRING: + switch (Setup.wValueL) + { + case 0: + Ep0Stage.pData = LANGIDDESC; + len = sizeof(LANGIDDESC); + break; + + case 1: + Ep0Stage.pData = MANUFACTDESC; + len = sizeof(MANUFACTDESC); + break; + + case 2: + Ep0Stage.pData = PRODUCTDESC; + len = sizeof(PRODUCTDESC); + break; + + default: + Ep0Stage.bStage = EPSTALL; + break; + } + break; + + case DESC_HIDREPORT: + Ep0Stage.pData = HIDREPORTDESC; + len = sizeof(HIDREPORTDESC); + break; + + default: + Ep0Stage.bStage = EPSTALL; + break; + } + if (len < Ep0Stage.wResidue) + { + Ep0Stage.wResidue = len; + } + break; + + default: + Ep0Stage.bStage = EPSTALL; + break; + } + break; + + case CLASS_REQUEST: + switch (Setup.bRequest) + { + case GET_REPORT: + Ep0Stage.pData = HidFreature; + Ep0Stage.bStage = EPDATAIN; + break; + + case SET_REPORT: + Ep0Stage.pData = HidFreature; + Ep0Stage.bStage = EPDATAOUT; + break; + + case SET_IDLE: + break; + + case GET_IDLE: + case GET_PROTOCOL: + case SET_PROTOCOL: + default: + Ep0Stage.bStage = EPSTALL; + break; + } + break; + + default: + Ep0Stage.bStage = EPSTALL; + break; + } + + switch (Ep0Stage.bStage) + { + case EPDATAIN: + USB_WriteReg(CSR0, SOPRDY); + goto L_Ep0SendData; + break; + + case EPDATAOUT: + USB_WriteReg(CSR0, SOPRDY); + break; + + case EPSTATUS: + USB_WriteReg(CSR0, SOPRDY | DATEND); + Ep0Stage.bStage = EPIDLE; + break; + + case EPSTALL: + USB_WriteReg(CSR0, SOPRDY | SDSTL); + Ep0Stage.bStage = EPIDLE; + break; + } + } + break; + + case EPDATAIN: + if (!(csr & IPRDY)) + { + L_Ep0SendData: + cnt = Ep0Stage.wResidue > 64 ? 64 : Ep0Stage.wResidue; + USB_WriteFIFO(FIFO0, Ep0Stage.pData, cnt); + Ep0Stage.wResidue -= cnt; + Ep0Stage.pData += cnt; + if (Ep0Stage.wResidue == 0) + { + USB_WriteReg(CSR0, IPRDY | DATEND); + Ep0Stage.bStage = EPIDLE; + } + else + { + USB_WriteReg(CSR0, IPRDY); + } + } + break; + + case EPDATAOUT: + if (csr & OPRDY) + { + cnt = USB_ReadFIFO(FIFO0, Ep0Stage.pData); + Ep0Stage.wResidue -= cnt; + Ep0Stage.pData += cnt; + if (Ep0Stage.wResidue == 0) + { + USB_WriteReg(CSR0, SOPRDY | DATEND); + Ep0Stage.bStage = EPIDLE; + } + else + { + USB_WriteReg(CSR0, SOPRDY); + } + } + break; + } + } + + if (intrin & EP1INIF) + { + USB_WriteReg(INDEX, 1); + csr = USB_ReadReg(INCSR1); + if (csr & INSTSTL) + { + USB_WriteReg(INCSR1, INCLRDT); + } + if (csr & INUNDRUN) + { + USB_WriteReg(INCSR1, 0); + } + } + + if (introut & EP1OUTIF) + { + USB_WriteReg(INDEX, 1); + csr = USB_ReadReg(OUTCSR1); + if (csr & OUTSTSTL) + { + USB_WriteReg(OUTCSR1, OUTCLRDT); + } + if (csr & OUTOPRDY) + { + USB_ReadFIFO(FIFO1, HidInput); + USB_WriteReg(OUTCSR1, 0); + + if((HidInput[0]==0xaa) && (HidInput[1]==0x55) && (HidInput[2]==0x01)) + { + USB_WriteReg(INDEX, 1); + USB_WriteFIFO(FIFO1, HidOutput, 64); + USB_WriteReg(INCSR1, INIPRDY); + } + } + } +} + +__CODE uint8_t DEVICEDESC[18] = +{ + 0x12, //bLength(18); + 0x01, //bDescriptorType(Device); + 0x00,0x02, //bcdUSB(2.00); + 0x00, //bDeviceClass(0); + 0x00, //bDeviceSubClass0); + 0x00, //bDeviceProtocol(0); + 0x40, //bMaxPacketSize0(64); + 0x54,0x53, //idVendor(5354); + 0x80,0x43, //idProduct(4380); + 0x00,0x01, //bcdDevice(1.00); + 0x01, //iManufacturer(1); + 0x02, //iProduct(2); + 0x00, //iSerialNumber(0); + 0x01, //bNumConfigurations(1); +}; + +__CODE uint8_t CONFIGDESC[41] = +{ + 0x09, //bLength(9); + 0x02, //bDescriptorType(Configuration); + 0x29,0x00, //wTotalLength(41); + 0x01, //bNumInterfaces(1); + 0x01, //bConfigurationValue(1); + 0x00, //iConfiguration(0); + 0x80, //bmAttributes(BUSPower); + 0x32, //MaxPower(100mA); + 0x09, //bLength(9); + 0x04, //bDescriptorType(Interface); + 0x00, //bInterfaceNumber(0); + 0x00, //bAlternateSetting(0); + 0x02, //bNumEndpoints(2); + 0x03, //bInterfaceClass(HID); + 0x00, //bInterfaceSubClass(0); + 0x00, //bInterfaceProtocol(0); + 0x00, //iInterface(0); + 0x09, //bLength(9); + 0x21, //bDescriptorType(HID); + 0x01,0x01, //bcdHID(1.01); + 0x00, //bCountryCode(0); + 0x01, //bNumDescriptors(1); + 0x22, //bDescriptorType(HID Report); + 0x1b,0x00, //wDescriptorLength(27); + 0x07, //bLength(7); + 0x05, //bDescriptorType(Endpoint); + 0x81, //bEndpointAddress(EndPoint1 as IN); + 0x03, //bmAttributes(Interrupt); + 0x40,0x00, //wMaxPacketSize(64); + 0x01, //bInterval(10ms); + 0x07, //bLength(7); + 0x05, //bDescriptorType(Endpoint); + 0x01, //bEndpointAddress(EndPoint1 as OUT); + 0x03, //bmAttributes(Interrupt); + 0x40,0x00, //wMaxPacketSize(64); + 0x01, //bInterval(10ms); +}; + +__CODE uint8_t HIDREPORTDESC[27] = +{ + 0x05,0x0c, //USAGE_PAGE(Consumer); + 0x09,0x01, //USAGE(Consumer Control); + 0xa1,0x01, //COLLECTION(Application); + 0x15,0x00, // LOGICAL_MINIMUM(0); + 0x25,0xff, // LOGICAL_MAXIMUM(255); + 0x75,0x08, // REPORT_SIZE(8); + 0x95,0x40, // REPORT_COUNT(64); + 0x09,0x01, // USAGE(Consumer Control); + 0xb1,0x02, // FEATURE(Data,Variable); + 0x09,0x01, // USAGE(Consumer Control); + 0x81,0x02, // INPUT(Data,Variable); + 0x09,0x01, // USAGE(Consumer Control); + 0x91,0x02, // OUTPUT(Data,Variable); + 0xc0, //END_COLLECTION; +}; + +__CODE uint8_t LANGIDDESC[4] = +{ + 0x04,0x03, + 0x09,0x04, +}; + +__CODE uint8_t MANUFACTDESC[8] = +{ + 0x08,0x03, + 'S',0, + 'T',0, + 'C',0, +}; + +__CODE uint8_t PRODUCTDESC[30] = +{ + 0x1e,0x03, + 'S',0, + 'T',0, + 'C',0, + '8',0, + ' ',0, + 'F',0, + 'w',0, + 'L',0, + 'i',0, + 'b',0, + ' ',0, + 'H',0, + 'I',0, + 'D',0, +}; + +uint8_t CalCheckSum(uint8_t *buf, uint8_t len) +{ + uint8_t i; + uint8_t cs=0; + for (i = 0; i < len; i++) + { + cs += buf[i]; + } + return cs; +} diff --git a/include/fw_hal.h b/include/fw_hal.h index 3eb53f2..6de4676 100644 --- a/include/fw_hal.h +++ b/include/fw_hal.h @@ -37,6 +37,7 @@ #include "fw_pwm.h" #include "fw_rtc.h" #include "fw_dma.h" +#include "fw_usb.h" #endif #endif diff --git a/include/fw_reg_stc8h.h b/include/fw_reg_stc8h.h index 82d2c89..5404e84 100644 --- a/include/fw_reg_stc8h.h +++ b/include/fw_reg_stc8h.h @@ -52,7 +52,9 @@ SFR(RSTCFG, 0xFF); #define IRC32KCR (*(unsigned char volatile __XDATA *)0xfe04) #define MCLKOCR (*(unsigned char volatile __XDATA *)0xfe05) #define IRCDB (*(unsigned char volatile __XDATA *)0xfe06) +#define IRC48MCR (*(unsigned char volatile __XDATA *)0xfe07) #define X32KCR (*(unsigned char volatile __XDATA *)0xfe08) +#define RSTFLAG (*(unsigned char volatile __XDATA *)0xfe09) #define PxPU 0xfe10 #define P0PU SFRX(PxPU + 0) #define P1PU SFRX(PxPU + 1) diff --git a/include/fw_sys.h b/include/fw_sys.h index 0aa40fa..064472a 100644 --- a/include/fw_sys.h +++ b/include/fw_sys.h @@ -142,6 +142,24 @@ typedef enum */ #define SYS_SetClockOutputPin(__PORT__) SFRX_ASSIGN(MCLKOCR, 7, (__STATE__)) +/** + * Enable 48MHz USB OSC +*/ +#define SYS_EnableOscillator48M() do { \ + SFRX_ON(); \ + RSTFLAG = 0x07; \ + (IRC48MCR) = (IRC48MCR) | (0x01 << 7); \ + while (!(IRC48MCR & 0x01)); \ + SFRX_OFF(); \ + } while(0) +/** + * Disable 48MHz USB OSC +*/ +#define SYS_DisableOscillator48M() do { \ + SFRX_ON(); \ + (IRC48MCR) = (IRC48MCR) & ~(0x01 << 7); \ + SFRX_OFF(); \ + } while(0) void SYS_SetClock(void); void SYS_Delay(uint16_t t); diff --git a/include/fw_usb.h b/include/fw_usb.h new file mode 100644 index 0000000..2bc7dc4 --- /dev/null +++ b/include/fw_usb.h @@ -0,0 +1,175 @@ +// Copyright 2021 IOsetting +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef ___FW_USB_H___ +#define ___FW_USB_H___ + +#include "fw_conf.h" +#include "fw_types.h" + +/** + * STC8H8K64U(LQFP48) (LQFP64) +*/ + +#define FADDR 0x00 +#define POWER 0x01 +#define INTRIN1 0x02 +#define EP5INIF 0x20 +#define EP4INIF 0x10 +#define EP3INIF 0x08 +#define EP2INIF 0x04 +#define EP1INIF 0x02 +#define EP0IF 0x01 +#define INTROUT1 0x04 +#define EP5OUTIF 0x20 +#define EP4OUTIF 0x10 +#define EP3OUTIF 0x08 +#define EP2OUTIF 0x04 +#define EP1OUTIF 0x02 +#define INTRUSB 0x06 +#define SOFIF 0x08 +#define RSTIF 0x04 +#define RSUIF 0x02 +#define SUSIF 0x01 +#define INTRIN1E 0x07 +#define EP5INIE 0x20 +#define EP4INIE 0x10 +#define EP3INIE 0x08 +#define EP2INIE 0x04 +#define EP1INIE 0x02 +#define EP0IE 0x01 +#define INTROUT1E 0x09 +#define EP5OUTIE 0x20 +#define EP4OUTIE 0x10 +#define EP3OUTIE 0x08 +#define EP2OUTIE 0x04 +#define EP1OUTIE 0x02 +#define INTRUSBE 0x0B +#define SOFIE 0x08 +#define RSTIE 0x04 +#define RSUIE 0x02 +#define SUSIE 0x01 +#define FRAME1 0x0C +#define FRAME2 0x0D +#define INDEX 0x0E +#define INMAXP 0x10 +#define CSR0 0x11 +#define SSUEND 0x80 +#define SOPRDY 0x40 +#define SDSTL 0x20 +#define SUEND 0x10 +#define DATEND 0x08 +#define STSTL 0x04 +#define IPRDY 0x02 +#define OPRDY 0x01 +#define INCSR1 0x11 +#define INCLRDT 0x40 +#define INSTSTL 0x20 +#define INSDSTL 0x10 +#define INFLUSH 0x08 +#define INUNDRUN 0x04 +#define INFIFONE 0x02 +#define INIPRDY 0x01 +#define INCSR2 0x12 +#define INAUTOSET 0x80 +#define INISO 0x40 +#define INMODEIN 0x20 +#define INMODEOUT 0x00 +#define INENDMA 0x10 +#define INFCDT 0x08 +#define OUTMAXP 0x13 +#define OUTCSR1 0x14 +#define OUTCLRDT 0x80 +#define OUTSTSTL 0x40 +#define OUTSDSTL 0x20 +#define OUTFLUSH 0x10 +#define OUTDATERR 0x08 +#define OUTOVRRUN 0x04 +#define OUTFIFOFUL 0x02 +#define OUTOPRDY 0x01 +#define OUTCSR2 0x15 +#define OUTAUTOCLR 0x80 +#define OUTISO 0x40 +#define OUTENDMA 0x20 +#define OUTDMAMD 0x10 +#define COUNT0 0x16 +#define OUTCOUNT1 0x16 +#define OUTCOUNT2 0x17 +#define FIFO0 0x20 +#define FIFO1 0x21 +#define FIFO2 0x22 +#define FIFO3 0x23 +#define FIFO4 0x24 +#define FIFO5 0x25 +#define UTRKCTL 0x30 +#define UTRKSTS 0x31 + +#define EPIDLE 0 +#define EPSTATUS 1 +#define EPDATAIN 2 +#define EPDATAOUT 3 +#define EPSTALL -1 + +#define GET_STATUS 0x00 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 +#define SET_ADDRESS 0x05 +#define GET_DESCRIPTOR 0x06 +#define SET_DESCRIPTOR 0x07 +#define GET_CONFIG 0x08 +#define SET_CONFIG 0x09 +#define GET_INTERFACE 0x0A +#define SET_INTERFACE 0x0B +#define SYNCH_FRAME 0x0C +#define GET_REPORT 0x01 +#define GET_IDLE 0x02 +#define GET_PROTOCOL 0x03 +#define SET_REPORT 0x09 +#define SET_IDLE 0x0A +#define SET_PROTOCOL 0x0B +#define DESC_DEVICE 0x01 +#define DESC_CONFIG 0x02 +#define DESC_STRING 0x03 +#define DESC_HIDREPORT 0x22 +#define STANDARD_REQUEST 0x00 +#define CLASS_REQUEST 0x20 +#define VENDOR_REQUEST 0x40 +#define REQUEST_MASK 0x60 + +typedef struct +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint8_t wValueL; + uint8_t wValueH; + uint8_t wIndexL; + uint8_t wIndexH; + uint8_t wLengthL; + uint8_t wLengthH; +} SETUP; + +typedef struct +{ + uint8_t bStage; + uint16_t wResidue; + uint8_t *pData; +} EP0STAGE; + + +uint8_t USB_ReadReg(uint8_t addr); +void USB_WriteReg(uint8_t addr, uint8_t dat); +uint8_t USB_ReadFIFO(uint8_t fifo, uint8_t *pdat); +void USB_WriteFIFO(uint8_t fifo, uint8_t *pdat, uint8_t cnt); + +#endif diff --git a/src/fw_usb.c b/src/fw_usb.c new file mode 100644 index 0000000..46bf0f3 --- /dev/null +++ b/src/fw_usb.c @@ -0,0 +1,39 @@ +#include "fw_usb.h" +#include "fw_sys.h" + +uint8_t USB_ReadReg(uint8_t addr) +{ + uint8_t dat; + while (USBADR & 0x80); + USBADR = addr | 0x80; + while (USBADR & 0x80); + dat = USBDAT; + return dat; +} + +void USB_WriteReg(uint8_t addr, uint8_t dat) +{ + while (USBADR & 0x80); + USBADR = addr & 0x7f; + USBDAT = dat; +} + +uint8_t USB_ReadFIFO(uint8_t fifo, uint8_t *pdat) +{ + uint8_t cnt; + uint8_t ret; + ret = cnt = USB_ReadReg(COUNT0); + while (cnt--) + { + *pdat++ = USB_ReadReg(fifo); + } + return ret; +} + +void USB_WriteFIFO(uint8_t fifo, uint8_t *pdat, uint8_t cnt) +{ + while (cnt--) + { + USB_WriteReg(fifo, *pdat++); + } +} \ No newline at end of file