From 5e6f6ca4f78fecd553cb91287a4e379b115909da Mon Sep 17 00:00:00 2001 From: IOsetting Date: Wed, 9 Feb 2022 12:39:39 +0800 Subject: [PATCH] feat: usb keyboard demo --- demo/usb/usb_hid.c | 30 +- demo/usb/usb_keyboard.c | 684 ++++++++++++++++++++++++++++++++++++++++ include/fw_usb.h | 16 +- 3 files changed, 715 insertions(+), 15 deletions(-) create mode 100644 demo/usb/usb_keyboard.c diff --git a/demo/usb/usb_hid.c b/demo/usb/usb_hid.c index 63e00b8..80aaa91 100644 --- a/demo/usb/usb_hid.c +++ b/demo/usb/usb_hid.c @@ -79,6 +79,10 @@ INTERRUPT(USB_Routine, EXTI_VectUSB) intrusb = USB_ReadReg(INTRUSB); intrin = USB_ReadReg(INTRIN1); introut = USB_ReadReg(INTROUT1); + + /** + * Reset Interrupt + */ if (intrusb & RSTIF) { USB_SelectEndPoint(1); @@ -87,23 +91,29 @@ INTERRUPT(USB_Routine, EXTI_VectUSB) USB_WriteReg(OUTCSR1, OUTCLRDT); Ep0Stage.bStage = USB_CtrlState_Idle; } + + /** + * Endpoint-0 Interrupt + */ if (intrin & EP0IF) { USB_SelectEndPoint(0); csr = USB_ReadReg(CSR0); - if (csr & STSTL) + if (csr & STSTL) // Sent Stall { USB_WriteReg(CSR0, csr & ~STSTL); Ep0Stage.bStage = USB_CtrlState_Idle; } - if (csr & SUEND) + + if (csr & SUEND) // Setup End { USB_WriteReg(CSR0, csr | SSUEND); } + switch (Ep0Stage.bStage) { case USB_CtrlState_Idle: - if (csr & OPRDY) + if (csr & OPRDY) // Out Packet Ready { Ep0Stage.bStage = USB_CtrlState_SettingUp; USB_ReadFIFO(FIFO0, (uint8_t *)&usb_request); @@ -280,7 +290,10 @@ INTERRUPT(USB_Routine, EXTI_VectUSB) break; } } - + + /** + * Endpoint-1 In Interrupt + */ if (intrin & EP1INIF) { USB_SelectEndPoint(1); @@ -294,7 +307,10 @@ INTERRUPT(USB_Routine, EXTI_VectUSB) USB_WriteReg(INCSR1, 0); } } - + + /** + * Endpoint-1 Out Interrupt + */ if (introut & EP1OUTIF) { USB_SelectEndPoint(1); @@ -307,8 +323,8 @@ INTERRUPT(USB_Routine, EXTI_VectUSB) { USB_ReadFIFO(FIFO1, HidInput); USB_WriteReg(OUTCSR1, 0); - - if((HidInput[0]==0xaa) && (HidInput[1]==0x55) && (HidInput[2]==0x01)) + /** Write response */ + if((HidInput[0] == 0xaa) && (HidInput[1] == 0x55) && (HidInput[2] == 0x01)) { USB_SelectEndPoint(1); USB_WriteFIFO(FIFO1, HidOutput, 64); diff --git a/demo/usb/usb_keyboard.c b/demo/usb/usb_keyboard.c new file mode 100644 index 0000000..9bd95ca --- /dev/null +++ b/demo/usb/usb_keyboard.c @@ -0,0 +1,684 @@ +// 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. + +/** + * USB Keyboard Demo + * + * P0: 8 bits for 4x4 Key matrix + * P6.0: NumLock + * P6.1: CapsLock +*/ + +#include "fw_hal.h" +#include + +#define MAIN_Fosc 24000000L +#define Timer0_Reload (65536UL -(MAIN_Fosc / 1000)) //Timer 0 frequency 1000Hz +#define KeyIO P0 + +__BIT B_1ms; // 1ms flag +__BIT KeyChangeTemp; +__BIT KeyChangeFlag; +uint16_t cnt50ms; +uint16_t KeyCode; // code of key pressed +uint16_t OldKeyCode; // for key status changing check +uint16_t NewKeyCode; // new key status +uint16_t KeyHoldTime; + +__CODE uint8_t DEVICEDESC[18]; +__CODE uint8_t CONFIGDESC[41]; +__CODE uint8_t HIDREPORTDESC[63]; +__CODE uint8_t LANGIDDESC[4]; +__CODE uint8_t MANUFACTDESC[8]; +__CODE uint8_t PRODUCTDESC[30]; +__CODE uint8_t KeyMap[16]; +__XDATA uint8_t HidFreature[64]; +__XDATA uint8_t HidInput[64]; +__XDATA uint8_t HidOutput[64]; +usb_request_t usb_request; +EP0STAGE Ep0Stage; + +void USB_Init(void); +void KeyScan(void); +void SendKeyStatus(void); + + +void main() +{ + uint8_t i; + + GPIO_P1_SetMode(GPIO_Pin_All, GPIO_Mode_InOut_QBD); + GPIO_P3_SetMode(GPIO_Pin_0|GPIO_Pin_1, GPIO_Mode_Input_HIP); + GPIO_P6_SetMode(GPIO_Pin_All, GPIO_Mode_Output_PP); + + USB_Init(); + + TIM_Timer0_Config(HAL_State_ON, TIM_TimerMode_16BitAuto, 1000); + EXTI_Timer0_SetIntState(HAL_State_ON); + EXTI_Timer0_SetIntPriority(EXTI_IntPriority_High); + TIM_Timer0_SetRunState(HAL_State_ON); + EXTI_Global_SetIntState(HAL_State_ON); + + for(i = 0; i < 8; i++) + { + HidInput[i]=0; + } + + while (1) + { + if(B_1ms) // every 1 ms + { + B_1ms = 0; + if(++cnt50ms >= 30) // scan every 30 ms + { + cnt50ms = 0; + KeyScan(); + } + if(KeyChangeFlag) // if key status changed + { + KeyChangeFlag = 0; + SendKeyStatus(); + } + } + } +} + +void USB_Init() +{ + SYS_EnableOscillator48M(); + USB_SetClockSource(USB_ClockSource_6M); + USB_SetEnabled(HAL_State_ON); + USB_SetDpDmPullUp(HAL_State_ON); + EXTI_USB_SetIntPriority(EXTI_IntPriority_Highest); + + 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 = USB_CtrlState_Idle; + + EXTI_USB_SetIntState(HAL_State_ON); +} + +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 = USB_CtrlState_Idle; + } + if (intrin & EP0IF) + { + USB_WriteReg(INDEX, 0); + csr = USB_ReadReg(CSR0); + if (csr & STSTL) + { + USB_WriteReg(CSR0, csr & ~STSTL); + Ep0Stage.bStage = USB_CtrlState_Idle; + } + if (csr & SUEND) + { + USB_WriteReg(CSR0, csr | SSUEND); + } + switch (Ep0Stage.bStage) + { + case USB_CtrlState_Idle: + if (csr & OPRDY) + { + Ep0Stage.bStage = USB_CtrlState_SettingUp; + USB_ReadFIFO(FIFO0, (uint8_t *)&usb_request); + ((uint8_t *)&Ep0Stage.wResidue)[0] = usb_request.wLength.bb.bh; + ((uint8_t *)&Ep0Stage.wResidue)[1] = usb_request.wLength.bb.bl; + switch (usb_request.bmRequestType & REQUEST_TYPE_MASK) + { + case USB_RequestType_Standard: + switch (usb_request.bRequest) + { + case USB_StdReq_SetAddress: + USB_WriteReg(FADDR, usb_request.wValue.bb.bl); + break; + + case USB_StdReq_SetConfiguration: + USB_SelectEndPoint(1); + USB_WriteReg(INCSR2, INMODEIN); + USB_WriteReg(INMAXP, 8); + USB_SelectEndPoint(1); + USB_WriteReg(INCSR2, INMODEOUT); + USB_WriteReg(OUTMAXP, 8); + USB_SelectEndPoint(0); + break; + + case USB_StdReq_GetDescriptor: + Ep0Stage.bStage = USB_CtrlState_DataIn; + switch (usb_request.wValue.bb.bh) + { + case USB_DescriptorType_Device: + Ep0Stage.pData = DEVICEDESC; + len = sizeof(DEVICEDESC); + break; + + case USB_DescriptorType_Configuration: + Ep0Stage.pData = CONFIGDESC; + len = sizeof(CONFIGDESC); + break; + + case USB_DescriptorType_String: + switch (usb_request.wValue.bb.bl) + { + 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 = USB_CtrlState_Stalled; + break; + } + break; + + case USB_DescriptorType_Report: + Ep0Stage.pData = HIDREPORTDESC; + len = sizeof(HIDREPORTDESC); + break; + + default: + Ep0Stage.bStage = USB_CtrlState_Stalled; + break; + } + if (len < Ep0Stage.wResidue) + { + Ep0Stage.wResidue = len; + } + break; + + default: + Ep0Stage.bStage = USB_CtrlState_Stalled; + break; + } + break; + + case USB_RequestType_Class: + switch (usb_request.bRequest) + { + case USB_HidReq_GetReport: + Ep0Stage.pData = HidFreature; + Ep0Stage.bStage = USB_CtrlState_DataIn; + break; + + case USB_HidReq_SetReport: + Ep0Stage.pData = HidFreature; + Ep0Stage.bStage = USB_CtrlState_DataOut; + break; + + case USB_HidReq_SetIdle: + break; + + case USB_HidReq_GetIdle: + case USB_HidReq_GetProtocol: + case USB_HidReq_SetProtocol: + default: + Ep0Stage.bStage = USB_CtrlState_Stalled; + break; + } + break; + + default: + Ep0Stage.bStage = USB_CtrlState_Stalled; + break; + } + + switch (Ep0Stage.bStage) + { + case USB_CtrlState_DataIn: + USB_WriteReg(CSR0, SOPRDY); + goto L_Ep0SendData; + break; + + case USB_CtrlState_DataOut: + USB_WriteReg(CSR0, SOPRDY); + break; + + case USB_CtrlState_SettingUp: + USB_WriteReg(CSR0, SOPRDY | DATEND); + Ep0Stage.bStage = USB_CtrlState_Idle; + break; + + case USB_CtrlState_Stalled: + USB_WriteReg(CSR0, SOPRDY | SDSTL); + Ep0Stage.bStage = USB_CtrlState_Idle; + break; + } + } + break; + + case USB_CtrlState_DataIn: + 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 = USB_CtrlState_Idle; + } + else + { + USB_WriteReg(CSR0, IPRDY); + } + } + break; + + case USB_CtrlState_DataOut: + 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 = USB_CtrlState_Idle; + } + 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, HidOutput); + USB_WriteReg(OUTCSR1, 0); + + P6 = ~HidOutput[0]; // update LED status + } + } +} + +uint8_t KeyCount(uint16_t dat) +{ + uint8_t i; + + i = 0; + while(dat) + { + if(dat & 0x8000) i++; + dat <<= 1; + } + return i; +} + +//HidInput first byte for special keys,second byte is reserved,the reset 6 bytes for normal keys +void SendKeyStatus(void) +{ + uint8_t i,n; + + if(KeyCode) // if key pressed + { + // 4*4 key matrix,max 3 keys pressed simultaneously + if(KeyCount(KeyCode) > 3) + { + return; // too many keys + } + else + { + n = 2; + for(i=0;i<16;i++) + { + if(i == 1) + { + if(KeyCode & (1<= 1) + { + KeyHoldTime = 1; + KeyCode = OldKeyCode; + if(KeyChangeTemp) + { + KeyChangeTemp = 0; + KeyChangeFlag = 1; // Set send flag + } + } + } +} + +__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,0x44, //idProduct(4480); + 0x00,0x01, //bcdDevice(1.00); + 0x01, //iManufacturer(1); + 0x02, //iProduct(2); + 0x03, //iSerialNumber(3); + 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); + 0xa0, //bmAttributes(BUSPower); + 0xc8, //MaxPower(400mA); + + 0x09, //bLength(9); + 0x04, //bDescriptorType(Interface); + 0x00, //bInterfaceNumber(0); + 0x00, //bAlternateSetting(0); + 0x02, //bNumEndpoints(2); + 0x03, //bInterfaceClass(HID); + 0x01, //bInterfaceSubClass(1); + 0x01, //bInterfaceProtocol(1); + 0x00, //iInterface(0); + + 0x09, //bLength(9); + 0x21, //bDescriptorType(HID); + 0x01,0x10, //bcdHID(1.01); + 0x00, //bCountryCode(0); + 0x01, //bNumDescriptors(1); + 0x22, //bDescriptorType(HID Report); + 0x3f,0x00, //wDescriptorLength(63); + 0x07, //bLength(7); + 0x05, //bDescriptorType(Endpoint); + 0x81, //bEndpointAddress(EndPoint1 as IN); + 0x03, //bmAttributes(Interrupt); + 0x40,0x00, //wMaxPacketSize(64); + 0x0a, //bInterval(10ms); + 0x07, //bLength(7); + 0x05, //bDescriptorType(Endpoint); + 0x01, //bEndpointAddress(EndPoint1 as OUT); + 0x03, //bmAttributes(Interrupt); + 0x40,0x00, //wMaxPacketSize(64); + 0x0a, //bInterval(10ms); +}; + +__CODE uint8_t HIDREPORTDESC[63] = +{ + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x06, // USAGE (Keyboard) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl) + 0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x08, // REPORT_COUNT (8) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x08, // REPORT_SIZE (8) + 0x81, 0x03, // INPUT (Cnst,Var,Abs) + 0x95, 0x05, // REPORT_COUNT (5) + 0x75, 0x01, // REPORT_SIZE (1) + 0x05, 0x08, // USAGE_PAGE (LEDs) + 0x19, 0x01, // USAGE_MINIMUM (Num Lock) + 0x29, 0x05, // USAGE_MAXIMUM (Kana) + 0x91, 0x02, // OUTPUT (Data,Var,Abs) + 0x95, 0x01, // REPORT_COUNT (1) + 0x75, 0x03, // REPORT_SIZE (3) + 0x91, 0x03, // OUTPUT (Cnst,Var,Abs) + 0x95, 0x06, // REPORT_COUNT (6) + 0x75, 0x08, // REPORT_SIZE (8) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0xFF, // LOGICAL_MAXIMUM (255) + 0x05, 0x07, // USAGE_PAGE (Keyboard) + 0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated)) + 0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application) + 0x81, 0x00, // INPUT (Data,Ary,Abs) + 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, + ' ',0, + 'U',0, + 'S',0, + 'B',0, + ' ',0, + 'D',0, + 'e',0, + 'v',0, + 'i',0, + 'c',0, + 'e',0, +}; + +__CODE uint8_t KeyMap[16] = { + 0x53, //0: Num Lock + 0xFF, //1: NULL - Left Ctrl + 0xFF, //2: NULL - Left ALT + 0x2A, //3: BackSpace + + 0x5F, //4: 7 + 0x60, //5: 8 + 0x61, //6: 9 + 0x62, //7: 0 + + 0x5C, //8: 4 + 0x5D, //9: 5 + 0x5E, //A: 6 + 0x63, //B: DEL + + 0x59, //C: 1 + 0x5A, //D: 2 + 0x5B, //E: 3 + 0x58, //F: Return +}; \ No newline at end of file diff --git a/include/fw_usb.h b/include/fw_usb.h index 4a204b1..2dfdf62 100644 --- a/include/fw_usb.h +++ b/include/fw_usb.h @@ -65,14 +65,14 @@ #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 SSUEND 0x80 // Serviced Setup End +#define SOPRDY 0x40 // Serviced OPRDY(Out Packet Ready) +#define SDSTL 0x20 // Send Stall +#define SUEND 0x10 // Setup End +#define DATEND 0x08 // Data End +#define STSTL 0x04 // Sent Stall +#define IPRDY 0x02 // In Packet Ready +#define OPRDY 0x01 // Out Packet Ready #define INCSR1 0x11 #define INCLRDT 0x40 #define INSTSTL 0x20