├── projects ├── usb_blink_pc_host │ ├── compile.sh │ └── usb_blink_pc.c ├── Makefile ├── usb_blink │ ├── Makefile │ └── src │ │ └── main.c ├── Makefile.include └── include │ ├── usb_desc.h │ └── usb_intr.h ├── .gitignore └── README.md /projects/usb_blink_pc_host/compile.sh: -------------------------------------------------------------------------------- 1 | gcc -trigraphs -o usb_blink_pc usb_blink_pc.c -lusb-1.0 -lpthread -lrt 2 | 3 | -------------------------------------------------------------------------------- /projects/Makefile: -------------------------------------------------------------------------------- 1 | SUBDIRS = $(shell ls -d */) 2 | 3 | .PHONY: $(SUBDIRS) 4 | 5 | 6 | $(SUBDIRS): 7 | $(MAKE) -C $@ 8 | 9 | .DEFAULT_GOAL := all 10 | all: $(SUBDIRS) 11 | 12 | 13 | print-% : ; @echo $* = $($*) 14 | -------------------------------------------------------------------------------- /projects/usb_blink/Makefile: -------------------------------------------------------------------------------- 1 | TARGET = blink 2 | 3 | C_FILES = \ 4 | ../src/main.c \ 5 | ../../../include/debug.c 6 | 7 | pre-flash: 8 | 9 | 10 | MK_ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 11 | 12 | include $(MK_ROOT_DIR)/../Makefile.include 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # General temp files 2 | *.DS_Store 3 | *.swp 4 | *.lck 5 | *.autosave 6 | *~ 7 | 8 | # GNU/Make 9 | */*.s 10 | 11 | # SDCC 12 | *.adb 13 | *.hex 14 | *.lst 15 | *.map 16 | *.asm 17 | *.ihx 18 | *.lk 19 | *.mem 20 | *.rel 21 | *.rst 22 | *.sym 23 | *.bin 24 | 25 | # project output 26 | */out 27 | **/usb_blink_pc -------------------------------------------------------------------------------- /projects/Makefile.include: -------------------------------------------------------------------------------- 1 | ####################################################### 2 | 3 | # toolchain 4 | CC = sdcc 5 | OBJCOPY = objcopy 6 | PACK_HEX = packihx 7 | WCHISP = sudo ../../tools/wchisptool 8 | 9 | ####################################################### 10 | 11 | ifndef FREQ_SYS 12 | FREQ_SYS = 24000000 13 | endif 14 | 15 | ifndef XRAM_SIZE 16 | XRAM_SIZE = 0x0400 17 | endif 18 | 19 | ifndef XRAM_LOC 20 | XRAM_LOC = 0x0000 21 | endif 22 | 23 | ifndef CODE_SIZE 24 | CODE_SIZE = 0x2800 25 | endif 26 | 27 | ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 28 | 29 | 30 | CFLAGS := -V -mmcs51 --model-small \ 31 | --xram-size $(XRAM_SIZE) --xram-loc $(XRAM_LOC) \ 32 | --code-size $(CODE_SIZE) \ 33 | -I$(ROOT_DIR)../include -I$(ROOT_DIR)include -DFREQ_SYS=$(FREQ_SYS) \ 34 | $(EXTRA_FLAGS) 35 | 36 | LFLAGS := $(CFLAGS) 37 | 38 | RELS := $(C_FILES:.c=.rel) 39 | 40 | print-% : ; @echo $* = $($*) 41 | 42 | %.rel : %.c 43 | $(CC) -c $(CFLAGS) $< 44 | 45 | # Note: SDCC will dump all of the temporary files into this one, so strip the paths from RELS 46 | # For now, get around this by stripping the paths off of the RELS list. 47 | 48 | $(TARGET).ihx: $(RELS) 49 | $(CC) $(notdir $(RELS)) $(LFLAGS) -o $(TARGET).ihx 50 | 51 | $(TARGET).hex: $(TARGET).ihx 52 | $(PACK_HEX) $(TARGET).ihx > $(TARGET).hex 53 | 54 | $(TARGET).bin: $(TARGET).ihx 55 | $(OBJCOPY) -I ihex -O binary $(TARGET).ihx $(TARGET).bin 56 | 57 | out/$(TARGET).bin: all_tidy 58 | 59 | 60 | flash: out/$(TARGET).bin pre-flash 61 | $(WCHISP) -f out/$(TARGET).bin -g 62 | 63 | print-rels: 64 | @echo $(RELS) 65 | 66 | .DEFAULT_GOAL := all_tidy 67 | 68 | all_tidy: 69 | mkdir -p out 70 | $(MAKE) -C out -f ../Makefile all 71 | cp -f out/$(TARGET).bin ./ 72 | 73 | 74 | all: print-rels $(TARGET).bin $(TARGET).hex 75 | 76 | clean: 77 | rm -f \ 78 | $(notdir $(RELS:.rel=.asm)) \ 79 | $(notdir $(RELS:.rel=.lst)) \ 80 | $(notdir $(RELS:.rel=.mem)) \ 81 | $(notdir $(RELS:.rel=.rel)) \ 82 | $(notdir $(RELS:.rel=.rst)) \ 83 | $(notdir $(RELS:.rel=.sym)) \ 84 | $(notdir $(RELS:.rel=.adb)) \ 85 | $(TARGET).lk \ 86 | $(TARGET).map \ 87 | $(TARGET).mem \ 88 | $(TARGET).ihx \ 89 | $(TARGET).hex \ 90 | $(TARGET).bin 91 | rm -rf out 92 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ch554_sdcc_usb_blinky 2 | This is a demo Blinky project for CH55x MCU. It's based on ch554_sdcc sdk (https://github.com/Blinkinlabs/ch554_sdcc.git) , but improves the code clarity of the USB handling part. 3 | 4 | 5 | Features: 6 | 7 | - setups GPIO and controls LED 8 | - setups custom USB device on CH55x MCU 9 | - handles custom USB data transfers, in both directions (from and to the MCU) 10 | - enters the bootloader triggered via USB control transfer 11 | - contains PC Host program for communicating with the MCU over USB 12 | 13 | 14 | The goal of this demo project was to improve the USB handling code, which - at the point 15 | of writing - was hard to maintain and not very practical for beginners to reuse in other 16 | projects. This code separates the common USB code into its own source file, which - in 17 | theory - does not need to be changed and should work straight away. The customistaion 18 | of the USB code is done via preprocessor variables which can be defined in the main.c 19 | program, or if they are undefined, a default placeholder is used. 20 | 21 | The customisable options are: 22 | 23 | - endpoint0 buffer size 24 | - vendor and product ids 25 | - vendor and product names 26 | - device power consumption 27 | - USB speed (Low speed / Full speed) 28 | - number of endpoints (optional) 29 | - endpoint definitions (optional) 30 | - control transfer data hanndler for endpoint0 (optional) 31 | - endpoint data handlers (optional) 32 | 33 | PC Host controller program: 34 | --------------------------- 35 | 36 | The program interacts with the CH55x USB Blinky program and controlls the following properties 37 | in order to demonstrate how to do custom data transfers between the Host (PC) and the 38 | USB device (MCU): 39 | - toggles the LED blinking speed (fast /slow) - a 1 byte control transfer; from Host to MCU 40 | - sets a custom blinking speed - a 3 byte control transfer; from Host to MCU 41 | - reads current value of blinking speed - a 1 byte control transfer that sends back 2 bytes 42 | via buffer (up to 32 bytes); from MCU to Host 43 | - transfers a bliking data sequence into MCU and starts it - a 1 byte control transfer + up 44 | to 32 bytes of data buffer; fom Host to MCU 45 | 46 | Building and running: 47 | --------------------- 48 | 1) setup the ch554_sdcc sdk (https://github.com/Blinkinlabs/ch554_sdcc.git) and make sure you 49 | can compile and run the examples in the example directory 50 | 2) copy the 'projects' directory from this repo into the root of the ch554_sdcc sdk (examples 51 | and projects directories will be on the same level) 52 | 3) enter projects/usb_blink directory and run 'make' to build, then 'make flash' to upload 53 | the binary to your CH55x device 54 | 4) disconnect and connect CH55x device from your PC 55 | 5) enter projects/usb_blink_pc_host directory and run 'compile.sh' to produce usb_blink_pc 56 | executable 57 | 6) run './usb_blink_pc -h' for options how to interact with the blinky demo 58 | -------------------------------------------------------------------------------- /projects/include/usb_desc.h: -------------------------------------------------------------------------------- 1 | 2 | /****************************************************************************** 3 | * USB Standard descriptors 4 | *****************************************************************************/ 5 | #ifndef USB_DESC_H 6 | #define USB_DESC_H 7 | 8 | /* Descriptor types */ 9 | #define USB_DESC_DEV 0x01 10 | #define USB_DESC_CFG 0x02 11 | #define USB_DESC_STR 0x03 12 | #define USB_DESC_INTF 0x04 13 | #define USB_DESC_EP 0x05 14 | 15 | /* Endpoints */ 16 | #define USB_EP01_OUT 0x01 17 | #define USB_EP01_IN 0x81 18 | #define USB_EP02_OUT 0x02 19 | #define USB_EP02_IN 0x82 20 | #define USB_EP03_OUT 0x03 21 | #define USB_EP03_IN 0x83 22 | #define USB_EP04_OUT 0x04 23 | #define USB_EP04_IN 0x84 24 | 25 | /* Configuration attributes */ 26 | #define USB_CONF_DEFAULT (0x01 << 7) //default value 27 | #define USB_CONF_SELF (0x01 << 6) //self-powered 28 | #define USB_CONF_RWKU (0x01 << 5) //remote wake-up 29 | 30 | /* Endpoint transfer type */ 31 | #define USB_TRNT_CTRL 0x00 //control transfer 32 | #define USB_TRNT_ISO 0x01 //isochronous transfer 33 | #define USB_TRNT_BULK 0x02 //bulk transfer 34 | #define USB_TRNT_INT 0x03 //interrupt transfer 35 | 36 | /* Isochronous endpoint synchronization type */ 37 | #define USB_ISOS_NS (0x00 << 2) //no synchronization 38 | #define USB_ISOS_AS (0x01 << 2) //asynchronous 39 | #define USB_ISOS_AD (0x02 << 2) //adaptive 40 | #define USB_ISOS_SY (0x03 << 2) //synchronous 41 | 42 | /* Isochronous endpoint Usage Type */ 43 | #define USB_ISOU_DE (0x00 << 4) //data endpoint 44 | #define USB_ISOU_FE (0x01 << 4) //feedback endpoint 45 | #define USB_ISOU_IE (0x02 << 4) //implicit feedback data endpoint 46 | 47 | 48 | 49 | /* Device descriptor */ 50 | typedef struct _USB_DEV_DSC 51 | { 52 | uint8_t bLength; 53 | uint8_t bDscType; 54 | uint16_t bcdUSB; 55 | uint8_t bDevCls; 56 | uint8_t bDevSubCls; 57 | uint8_t bDevProtocol; 58 | uint8_t bMaxPktSize0; 59 | uint16_t idVendor; 60 | uint16_t idProduct; 61 | uint16_t bcdDevice; 62 | uint8_t iMFR; 63 | uint8_t iProduct; 64 | uint8_t iSerialNum; 65 | uint8_t bNumCfg; 66 | } USB_DEV_DSC; 67 | 68 | /* Configuration descriptor */ 69 | typedef struct _USB_CFG_DSC 70 | { 71 | uint8_t bLength; 72 | uint8_t bDscType; 73 | uint16_t wTotalLength; 74 | uint8_t bNumIntf; 75 | uint8_t bCfgValue; 76 | uint8_t iCfg; 77 | uint8_t bmAttributes; 78 | uint8_t bMaxPower; 79 | } USB_CFG_DSC; 80 | 81 | /* Interface descriptor */ 82 | typedef struct _USB_INTF_DSC 83 | { 84 | uint8_t bLength; 85 | uint8_t bDscType; 86 | uint8_t bIntfNum; 87 | uint8_t bAltSetting; 88 | uint8_t bNumEPs; 89 | uint8_t bIntfCls; 90 | uint8_t bIntfSubCls; 91 | uint8_t bIntfProtocol; 92 | uint8_t iIntf; 93 | } USB_INTF_DSC; 94 | 95 | /* Endpoint descriptor */ 96 | typedef struct _USB_EP_DSC 97 | { 98 | uint8_t bLength; 99 | uint8_t bDscType; 100 | uint8_t bEPAdr; 101 | uint8_t bmAttributes; 102 | uint16_t wMaxPktSize; 103 | uint8_t bInterval; 104 | } USB_EP_DSC; 105 | 106 | #endif /* USB_DESC_H */ 107 | -------------------------------------------------------------------------------- /projects/usb_blink/src/main.c: -------------------------------------------------------------------------------- 1 | // Blink a LED connected to pin 1.4 2 | // an control the blink speed via USB 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define DEFAULT_ENDP0_SIZE 32 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | // standard USB descriptor definitions 16 | #include "usb_desc.h" 17 | 18 | // custom USB definitions, must be set before the "usb_intr.h" is included 19 | 20 | 21 | 22 | #define USB_CUST_PRODUCT_ID 0x001e 23 | #define USB_CUST_CONF_POWER 120 24 | #define USB_CUST_PRODUCT_NAME_LEN 7 25 | #define USB_CUST_PRODUCT_NAME { 'B', 'l', 'i', 'n', 'k', 'y', 0 } 26 | #define USB_CUST_CONTROL_TRANSFER_HANDLER handleVendorControlTransfer() 27 | #define USB_CUST_CONTROL_DATA_HANDLER handleVendorDataTransfer() 28 | 29 | // function declaration for custom USB transfer handlers 30 | static uint16_t handleVendorControlTransfer(); 31 | static void handleVendorDataTransfer(); 32 | 33 | // USB interrupt handlers - does the most of the USB grunt work 34 | #include "usb_intr.h" 35 | 36 | // GPIO setup 37 | #define PORT1 0x90 38 | #define PORT3 0xb0 39 | 40 | #define LED_PIN 4 41 | SBIT(LED, PORT1, LED_PIN); 42 | 43 | #define COMMAND_TOGGLE_BLINK 0xD1 44 | #define COMMAND_READ_BLINK_TIME 0xD0 45 | #define COMMAND_SET_BLINK_TIME 0xD3 46 | #define COMMAND_SET_BLINK_SEQUENCE 0xD4 47 | #define COMMAND_JUMP_TO_BOOTLOADER 0xB0 48 | 49 | __xdata __at (0x0020) uint8_t seqBuf[DEFAULT_ENDP0_SIZE]; 50 | 51 | volatile __idata uint16_t blinkTime = 250; 52 | volatile __idata uint8_t command; 53 | 54 | 55 | 56 | /******************************************************************************* 57 | * Jump to bootloader 58 | *******************************************************************************/ 59 | static void jumpToBootloader() 60 | { 61 | USB_INT_EN = 0; 62 | USB_CTRL = 0x6; 63 | EA = 0; 64 | mDelaymS(100); 65 | bootloader(); 66 | while(1); 67 | } 68 | 69 | /******************************************************************************* 70 | * Handler of the vendor Control transfer requests sent from the Host to 71 | * Endpoint 0 72 | * 73 | * Returns : the length of the response that is stored in Ep0Buffer 74 | *******************************************************************************/ 75 | 76 | static uint16_t handleVendorControlTransfer() 77 | { 78 | switch (UsbIntrSetupReq) { 79 | // read blink time and send it back to the Host 80 | case COMMAND_READ_BLINK_TIME : { 81 | uint16_t* dst = (uint16_t*) Ep0Buffer; 82 | *dst = blinkTime; // write the blikTime to the Ep0buffer 83 | return 2; // request to transfer 2 bytes back to the host 84 | }; break; 85 | 86 | // toggle blink time 87 | case COMMAND_TOGGLE_BLINK : { 88 | blinkTime = (blinkTime == 250) ? 100 : 250; 89 | } break; 90 | 91 | //set blink time 92 | case COMMAND_SET_BLINK_TIME : { 93 | // read the value from the wValue of the control transfer 94 | blinkTime = ((uint16_t)UsbSetupBuf->wValueH<<8) | (UsbSetupBuf->wValueL);; 95 | } break; 96 | case COMMAND_SET_BLINK_SEQUENCE : { 97 | //nothing to do, just wait for the data and confirm this transfer by returning 0 98 | } break; 99 | //jump to bootloader - remotely triggered from the Host! 100 | case COMMAND_JUMP_TO_BOOTLOADER : { 101 | jumpToBootloader(); 102 | } break; 103 | default: 104 | return 0xFF; // Command not supported 105 | } // end of the switch 106 | command = 0; 107 | return 0; // no data to transfer back to the host 108 | } 109 | 110 | static void handleVendorDataTransfer() 111 | { 112 | switch (UsbIntrSetupReq) { 113 | // Ah! The data for blink sequence arrived. 114 | case COMMAND_SET_BLINK_SEQUENCE : { 115 | // copy the contents of the EP0 buffer into the sequence buffer 116 | memcpy(seqBuf, Ep0Buffer, USB_RX_LEN); 117 | command = COMMAND_SET_BLINK_SEQUENCE; 118 | blinkTime = 0; //interrupt the default blinking 119 | } break; 120 | } 121 | } 122 | 123 | static void setupGPIO() 124 | { 125 | // Configure pin 1.4 as GPIO output 126 | P1_DIR_PU = 0; 127 | P1_MOD_OC &= ~(1 << LED_PIN); 128 | P1_DIR_PU |= (1 << LED_PIN); 129 | 130 | } 131 | 132 | // this delay can be interrupted, so we can exit earlier if needed 133 | static void delayNonBlocking(uint16_t d) 134 | { 135 | uint16_t bt = blinkTime; 136 | 137 | while (d > 100) { 138 | mDelaymS(100); 139 | // delay interrupted when a new value is set into the blinkTime 140 | if (bt != blinkTime) { 141 | return; 142 | } 143 | d -= 100; 144 | } 145 | if (d) { 146 | mDelaymS(d); 147 | } 148 | } 149 | 150 | static void playBlinkySequence() 151 | { 152 | uint8_t seqPos = 0; 153 | 154 | // re-initialise blinkTime so we can detect an interrupt within the non-blocking delay 155 | blinkTime = 100; 156 | 157 | // play the whole sequence buffer 158 | while (seqPos < DEFAULT_ENDP0_SIZE) { 159 | uint16_t opcode = seqBuf[seqPos++]; 160 | //early exit on 0 sequence 'opcode' or when the playback was cancelled 161 | if (0 == opcode || COMMAND_SET_BLINK_SEQUENCE != command) { 162 | break; 163 | } 164 | // handle the 'jump' opcode 165 | if (opcode & (1<<7)) { 166 | seqPos = opcode & 0x1F; // jump only to a sequence offset between 0-32 167 | } else { 168 | //turn the LED on or off and then wait 169 | LED = (opcode & 0x10) ? 1 : 0; 170 | delayNonBlocking((opcode & 0xF) << 6); // delay in units of 64 milliseconds 171 | } 172 | } 173 | 174 | //turn off the led 175 | LED = 0; 176 | 177 | command = 0; 178 | } 179 | 180 | void main() { 181 | 182 | CfgFsys(); // CH55x main frequency setup 183 | mDelaymS(5); // wait for the internal crystal to stabilize. 184 | 185 | // configure GPIO ports 186 | setupGPIO(); 187 | 188 | // configure USB 189 | USBDeviceCfg(); 190 | 191 | while (1) { 192 | if (command == COMMAND_SET_BLINK_SEQUENCE) { 193 | //this will block until the sequence is finished 194 | playBlinkySequence(); 195 | } 196 | delayNonBlocking(blinkTime); 197 | LED = !LED; 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /projects/usb_blink_pc_host/usb_blink_pc.c: -------------------------------------------------------------------------------- 1 | /* usb_blink_pc - control app CH55x blink demo 2 | * 3 | * Copyright (C) 2019 Ole 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | * 25 | * Build with: 26 | * 27 | * gcc -o usb_blink_pc usb_blink_pc.c -lusb-1.0 -lpthread -lrt 28 | * 29 | * USB lib API reference: 30 | * http://libusb.sourceforge.net/api-1.0 31 | * 32 | */ 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #ifdef MINGW 41 | #include 42 | #else 43 | #include 44 | #endif 45 | 46 | 47 | #define VENDOR_ID 0xFFFF 48 | #define PRODUCT_ID 0x001e 49 | 50 | //see usb1.1 page 183: value bitmap: Host->Device, Vendor request, Recipient is interface 51 | #define TYPE_OUT_ITF 0x41 52 | 53 | //see usb1.1 page 183: value bitmap: Device->Host, Vendor request, Sender is interface 54 | #define TYPE_IN_ITF (0x41 | (1 << 7)) 55 | 56 | #define COMMAND_TOGGLE_BLINK 0xD1 57 | #define COMMAND_READ_BLINK_TIME 0xD0 58 | #define COMMAND_SET_BLINK_TIME 0xD3 59 | #define COMMAND_SET_BLINK_SEQUENCE 0xD4 60 | #define COMMAND_JUMP_TO_BOOTLOADER 0xB0 61 | 62 | #define ACTION_PRINT_HELP 1 63 | #define ACTION_SET_VERBOSE 2 64 | 65 | static uint8_t descriptor[256]; 66 | 67 | static uint8_t outBuf[32]; //output (command) buffer 68 | static uint8_t resBuf[32]; //input (response) buffer 69 | 70 | static const char *const strings[2] = { "info", "fatal" }; 71 | 72 | // some fancy blinking sequence 73 | static const char sequence[] = { 74 | 0x04, // off for 4 units 75 | 76 | 0x16, // on for 6 units 77 | 0x06, // off for 6 units 78 | 0x15, // on for 5 units 79 | 0x05, // off for 5 units 80 | 0x14, // on for 4 units 81 | 0x04, // off for 4 units 82 | 0x13, // on for 3 units 83 | 0x03, // off for 3 units 84 | 0x12, // on for 2 units 85 | 0x02, // off for 2 units 86 | 87 | 0x11, // on for 1 units 88 | 0x01, // off for 1 units 89 | 0x11, // on for 1 units 90 | 0x01, // off for 1 units 91 | 0x11, // on for 1 units 92 | 0x01, // off for 1 units 93 | 0x11, // on for 1 units 94 | 0x01, // off for 1 units 95 | 96 | 0x12, // on for 2 units 97 | 0x02, // off for 2 units 98 | 0x13, // on for 3 units 99 | 0x03, // off for 3 units 100 | 0x14, // on for 4 units 101 | 0x04, // off for 4 units 102 | 0x15, // on for 5 units 103 | 0x05, // off for 5 units 104 | 105 | (1<<7) | 1, //jump to address 1 106 | 0 //safety terminator 107 | }; 108 | 109 | char debug = 0; 110 | char verbose = 0; 111 | int action = 0; 112 | int blinkTime = 0; 113 | 114 | 115 | static void infoAndFatal(const int s, char *f, ...) { 116 | va_list ap; 117 | va_start(ap,f); 118 | fprintf(stderr, "usb_blink_pc: %s: ", strings[s]); 119 | vfprintf(stderr, f, ap); 120 | va_end(ap); 121 | if (s) exit(s); 122 | } 123 | 124 | #define info(...) infoAndFatal(0, __VA_ARGS__) 125 | #define fatal(...) infoAndFatal(1, __VA_ARGS__) 126 | 127 | static void usage(void) { 128 | info("\n" 129 | "*** [usb-blink] **************************************************\n" 130 | "command line tool for testing CH55x blink demo\n" 131 | "ver. 0.1.1 \n" 132 | "***************************************************************\n" 133 | "usage: [sudo] usb-blink command [parameter]\n" 134 | "commands:\n" 135 | " -h : prints this help \n" 136 | " -v : set verbose mode \n" 137 | " -debug : print USB library debugging info \n" 138 | " -boot : reset the CH55x into bootloader mode \n" 139 | " -w ms : send the blink time in milliseconds to the device\n" 140 | " -r : read the current blink time from the device\n" 141 | " -t : toggle between 100 / 250 ms blink time\n" 142 | " -seq : send a blink sequnce to the device\n" 143 | ); 144 | exit(1); 145 | } 146 | 147 | static int dumpBuffer(uint8_t* buf, int size) { 148 | int i; 149 | for (i = 0; i < size; i++) { 150 | printf("%02X ", buf[i]); 151 | if (i % 16 == 15) { 152 | printf("\n"); 153 | } 154 | } 155 | printf("\n"); 156 | return 0; 157 | } 158 | 159 | static int sendControlTransfer(libusb_device_handle *h, uint8_t command, uint16_t param1, uint16_t param2, uint8_t len) { 160 | int ret; 161 | 162 | ret = libusb_control_transfer(h, TYPE_OUT_ITF, command, param1, param2, outBuf, len, 50); 163 | if (verbose) { 164 | info("control transfer out: result=%i \n", ret); 165 | } 166 | return ret; 167 | } 168 | 169 | static int recvControlTransfer(libusb_device_handle *h, uint8_t command) { 170 | int ret; 171 | memset(resBuf, 0, sizeof(resBuf)); 172 | 173 | ret = libusb_control_transfer(h, TYPE_IN_ITF, command, 0, 0, resBuf, sizeof(resBuf), 50); 174 | if (verbose) { 175 | info("control transfer (0x%02x) incoming: result=%i\n", command, ret); 176 | dumpBuffer(resBuf, sizeof(resBuf)); 177 | } 178 | return ret; 179 | } 180 | 181 | //try to find the blinky usb device 182 | static libusb_device_handle* getDeviceHandle(libusb_context* c) { 183 | int max; 184 | int ret; 185 | int device_index = -1; 186 | int i; 187 | libusb_device** dev_list = NULL; 188 | struct libusb_device_descriptor des; 189 | struct libusb_device_handle* handle; 190 | 191 | ret = libusb_get_device_list(c, &dev_list); 192 | if (verbose) { 193 | info("total USB devices found: %i \n", ret); 194 | } 195 | max = ret; 196 | //print all devices 197 | for (i = 0; i < max; i++) { 198 | ret = libusb_get_device_descriptor(dev_list[i], & des); 199 | if (des.idVendor == VENDOR_ID && des.idProduct == PRODUCT_ID) { 200 | if (verbose) { 201 | info("device %i vendor=%04x, product=%04x bus:device=%i:%i\n", 202 | i, des.idVendor, des.idProduct, 203 | libusb_get_bus_number(dev_list[i]), 204 | libusb_get_device_address(dev_list[i]) 205 | ); 206 | } 207 | if (device_index == -1) { 208 | device_index = i; 209 | } 210 | } 211 | } 212 | 213 | if (device_index < 0) { 214 | libusb_free_device_list(dev_list, 1); 215 | fatal("no device found\n"); 216 | } 217 | 218 | if (verbose) { 219 | info("using device: %i \n", device_index); 220 | } 221 | 222 | ret = libusb_open(dev_list[device_index], &handle); 223 | if (verbose) { 224 | info("open device result=%i\n", ret); 225 | } 226 | if (ret) { 227 | libusb_free_device_list(dev_list, 1); 228 | fatal("device open failed\n"); 229 | } 230 | 231 | libusb_free_device_list(dev_list, 1); 232 | 233 | //get config 234 | ret = libusb_get_descriptor(handle, LIBUSB_DT_DEVICE, 0, descriptor, 18); 235 | if (verbose) { 236 | info("get device descriptor 0 result=%i\n", ret); 237 | } 238 | ret = libusb_get_descriptor(handle, LIBUSB_DT_CONFIG, 0, descriptor, 255); 239 | if (verbose) { 240 | info("get device configuration 0 result=%i\n", ret); 241 | } 242 | usleep(20*1000); 243 | 244 | return handle; 245 | } 246 | 247 | 248 | static void checkArgumentValue(int i, int argc, char** argv, char* fatalText) { 249 | if (i >= argc || argv[i][0] == '-') { 250 | fatal(fatalText); 251 | } 252 | } 253 | 254 | static void checkArguments(int argc, char** argv) { 255 | int i; 256 | char* arg; 257 | 258 | action = 0; 259 | 260 | if (argc <= 1) { 261 | return; 262 | } 263 | //skip argument 0 which is the program name 264 | //process all arguments 265 | for (i = 1; i < argc; i++) { 266 | arg = argv[i]; 267 | //all arguments start with dash 268 | if (arg[0] == '-') { 269 | if (strcmp("-h", arg) == 0) { 270 | action = ACTION_PRINT_HELP; 271 | } else 272 | if (strcmp("-v", arg) == 0) { 273 | verbose = 1; 274 | } else 275 | if (strcmp("-debug", arg) == 0) { 276 | debug = 1; 277 | } else 278 | if (strcmp("-t", arg) == 0) { 279 | action = COMMAND_TOGGLE_BLINK; 280 | } else 281 | if (strcmp("-w", arg) == 0) { 282 | checkArgumentValue(i + 1, argc, argv, "-ow: missing blink time value in milli secs\n"); 283 | action = COMMAND_SET_BLINK_TIME; 284 | blinkTime = (int) strtol(argv[++i], NULL, 0); 285 | } else 286 | if (strcmp("-r", arg) == 0) { 287 | action = COMMAND_READ_BLINK_TIME; 288 | } else 289 | if (strcmp("-seq", arg) == 0) { 290 | action = COMMAND_SET_BLINK_SEQUENCE; 291 | } else 292 | if (strcmp("-boot", arg) == 0) { 293 | action = COMMAND_JUMP_TO_BOOTLOADER; 294 | } 295 | 296 | else { 297 | fatal("unknown parameter: %s\n" , arg); 298 | } 299 | } else { 300 | fatal("unknown parameter: %s\n" , arg); 301 | } 302 | } 303 | } 304 | 305 | int main(int argc, char** argv) { 306 | libusb_context* c = NULL; 307 | libusb_device_handle *h; 308 | int offset = 0, size = 0; 309 | int ret; 310 | int i; 311 | 312 | checkArguments(argc, argv); 313 | if (action == 0 || action == ACTION_PRINT_HELP) { 314 | usage(); 315 | } 316 | 317 | //initialize libusb 318 | if (libusb_init(&c)) { 319 | fatal("can not initialise libusb\n"); 320 | } 321 | 322 | //set debugging state 323 | if (debug) { 324 | libusb_set_debug(c, 4); 325 | } 326 | 327 | //get the handle of the connected Glo USB device 328 | h = getDeviceHandle(c); 329 | 330 | //try to detach existing kernel driver if kernel is already handling 331 | //the device 332 | if (libusb_kernel_driver_active(h, 0) == 1) { 333 | if (verbose) { 334 | info("kernel driver active\n"); 335 | } 336 | if (!libusb_detach_kernel_driver(h, 0)) { 337 | if (verbose) { 338 | info("driver detached\n"); 339 | } 340 | } 341 | } 342 | 343 | 344 | //set the first configuration -> initialize USB device 345 | if (libusb_set_configuration (h, 1) != 0) { 346 | fatal("cannot set device configuration\n"); 347 | } 348 | 349 | if (verbose) { 350 | info("device configuration set\n"); 351 | } 352 | usleep(20*1000); 353 | 354 | //get the first interface of the USB configuration 355 | if (libusb_claim_interface(h, 0) < 0) { 356 | fatal("cannot claim interface\n"); 357 | } 358 | 359 | if (verbose) { 360 | info("interface claimed\n"); 361 | } 362 | 363 | if (libusb_set_interface_alt_setting(h, 0, 0) < 0) { 364 | fatal("alt setting failed\n"); 365 | } 366 | 367 | switch(action) { 368 | case COMMAND_SET_BLINK_SEQUENCE : { 369 | int ret; 370 | int len = sizeof(sequence); 371 | if (len > 32) { 372 | fatal("The sequence is longer than 32 bytes - this would fail to play!"); 373 | } 374 | memcpy(outBuf, sequence, len); 375 | ret = sendControlTransfer(h, COMMAND_SET_BLINK_SEQUENCE, 0, 0 , len); 376 | info("Set blink sequence result=%i (%s) \n", ret, ret == len ? "OK" : "Failed"); 377 | } break; 378 | 379 | case COMMAND_READ_BLINK_TIME : { 380 | int ret = recvControlTransfer(h, COMMAND_READ_BLINK_TIME); 381 | if (ret != 2) { 382 | info("Blink time failed. result=%i\n", ret); 383 | } else { 384 | int v = resBuf[1]; 385 | v <<= 8; 386 | v |= resBuf[0]; 387 | info("Blink time: %i\n", v); 388 | } 389 | } break; 390 | 391 | case COMMAND_SET_BLINK_TIME : { 392 | int ret; 393 | ret = sendControlTransfer(h, COMMAND_SET_BLINK_TIME, blinkTime, 0 , 0); 394 | info("Set blink time (%i) result=%i\n", blinkTime, ret); 395 | } break; 396 | 397 | case COMMAND_TOGGLE_BLINK : { 398 | sendControlTransfer(h, COMMAND_TOGGLE_BLINK, 0, 0, 0); 399 | } break; 400 | 401 | case COMMAND_JUMP_TO_BOOTLOADER : { 402 | sendControlTransfer(h, COMMAND_JUMP_TO_BOOTLOADER, 0, 0, 0); 403 | } break; 404 | 405 | 406 | } //end of switch 407 | 408 | libusb_release_interface(h, 0); 409 | libusb_close(h); 410 | libusb_exit(c); 411 | return 0; 412 | } 413 | -------------------------------------------------------------------------------- /projects/include/usb_intr.h: -------------------------------------------------------------------------------- 1 | #ifndef USB_INTR_H 2 | #define USB_INTR_H 3 | 4 | 5 | /******************************************************************************* 6 | * EP0_BUFF_SIZE: endpoint 0 buffer size 7 | *******************************************************************************/ 8 | 9 | #ifndef EP0_BUFF_SIZE 10 | #define EP0_BUFF_SIZE DEFAULT_ENDP0_SIZE 11 | #endif 12 | 13 | /******************************************************************************* 14 | * USB_CUST_VENDOR_ID: user defined VendorId 15 | *******************************************************************************/ 16 | #ifndef USB_CUST_VENDOR_ID 17 | #define USB_CUST_VENDOR_ID 0xFFFF 18 | #endif 19 | 20 | /******************************************************************************* 21 | * USB_CUST_VENDOR_ID: user defined Vendor name 22 | *******************************************************************************/ 23 | #ifndef USB_CUST_VENDOR_NAME 24 | #define USB_CUST_VENDOR_NAME_LEN 6 25 | #define USB_CUST_VENDOR_NAME {'C','H','5','5','x', 0} 26 | #endif 27 | 28 | /******************************************************************************* 29 | * USB_CUST_PRODUCT_ID: user defined ProductId 30 | *******************************************************************************/ 31 | #ifndef USB_CUST_PRODUCT_ID 32 | #define USB_CUST_PRODUCT_ID 0xC551 33 | #endif 34 | 35 | /******************************************************************************* 36 | * USB_CUST_VENDOR_ID: user defined Product name 37 | *******************************************************************************/ 38 | #ifndef USB_CUST_PRODUCT_NAME 39 | #define USB_CUST_PRODUCT_NAME_LEN 11 40 | #define USB_CUST_PRODUCT_NAME {'C','o','o','l','_', 'b', 'o', 'a', 'r', 'd', 0} 41 | #endif 42 | 43 | /******************************************************************************* 44 | * USB_CUST_CONF_POWER: user defined power consumption in milli Amps 45 | *******************************************************************************/ 46 | #ifndef USB_CUST_CONF_POWER 47 | #define USB_CUST_CONF_POWER 100 48 | #endif 49 | 50 | /******************************************************************************* 51 | * USB_CUST_EP_COUNT: number of user defined endpoints 52 | *******************************************************************************/ 53 | #ifndef USB_CUST_EP_COUNT 54 | // 1 default defined endpoint 55 | #define USB_CUST_EP_COUNT 1 56 | #endif 57 | 58 | /******************************************************************************* 59 | * USB_CUST_EP_DEF: definition of user defined endpoints. The number must match 60 | * USB_CUST_EP_COUNT value. 61 | * Example (USB_CUST_EP_COUNT is defined as 2) 62 | USB_EP_DSC ep01o; \ 63 | USB_EP_DSC ep01i; \ 64 | *******************************************************************************/ 65 | #ifndef USB_CUST_EP_DEF 66 | #define USB_CUST_EP_DEF USB_EP_DSC ep01o; 67 | #endif 68 | 69 | /******************************************************************************* 70 | * USB_CUST_EP_DESC: definition of user defined endpoint descriptors. 71 | * Their number must match USB_CUST_EP_COUNT value. 72 | * 73 | * Example of 2 bulk endpoints (USB_CUST_EP_COUNT is defined as 2) 74 | {sizeof(USB_EP_DSC), USB_DESC_EP, USB_EP01_OUT, USB_TRNT_BULK, MY_EP_BUF_SIZE, 0x00}, \ 75 | {sizeof(USB_EP_DSC), USB_DESC_EP, USB_EP01_IN, USB_TRNT_BULK, MY_EP_BUF_SIZE, 0x00} \ 76 | 77 | *******************************************************************************/ 78 | #ifndef USB_CUST_EP_DESC 79 | #define USB_CUST_EP_DESC {sizeof(USB_EP_DSC), USB_DESC_EP, USB_EP01_OUT, USB_TRNT_CTRL, 8 , 0x00} 80 | #endif 81 | 82 | 83 | /******************************************************************************* 84 | * USB_CUST_CONTROL_TRANSFER_HANDLER: user defined handler function of basic 85 | * Vendor type control transfer send on Endpoint 0. Can also setup outgoing 86 | * (MCU -> Host) data in Ep0Buffer and must return the length of outgoing data. 87 | * The defined function should return 0 for no outgoing data and 0xFF for 88 | * unrecognised / unhandled control tranfers. 89 | * It can not handle incoming data (Host -> MCU) - for that purpose use 90 | * a function defined in USB_CUST_CONTROL_DATA_HANDLER. 91 | * Example: 92 | * #define USB_CUST_CONTROL_TRANSFER_HANDLER myUsbControlHandler() 93 | *******************************************************************************/ 94 | #ifndef USB_CUST_CONTROL_TRANSFER_HANDLER 95 | #define USB_CUST_CONTROL_TRANSFER_HANDLER 0xFF 96 | #endif 97 | 98 | /******************************************************************************* 99 | * USB_CUST_CONTROL_DATA_HANDLER: user defined handler function of basic 100 | * Vendor type data transfer sent from the Host to MCU via control Endpoint 0. 101 | * The Ep0Buffer contains data of USB_RX_LEN size. The total data size can not 102 | * be bigger than EP0_BUFF_SIZE which is up to 64 bytes. 103 | * Example: 104 | * #define USB_CUST_CONTROL_DATA_HANDLER myUsbDataInHandler() 105 | *******************************************************************************/ 106 | #ifndef USB_CUST_CONTROL_DATA_HANDLER 107 | #define USB_CUST_CONTROL_DATA_HANDLER 108 | #endif 109 | 110 | 111 | /******************************************************************************/ 112 | 113 | __xdata __at (0x0000) uint8_t Ep0Buffer[EP0_BUFF_SIZE]; //Endpoint 0 OUT&IN buffer, must be an even address 114 | 115 | 116 | 117 | /* Device Descriptor */ 118 | __code USB_DEV_DSC device_dsc = 119 | { 120 | sizeof(USB_DEV_DSC), // Size of this descriptor in bytes 121 | USB_DESC_DEV, // DEVICE descriptor type 122 | 0x0200, // USB Spec Release Number in BCD format 123 | 0xFF, // Class Code 124 | 0x00, // Subclass code 125 | 0x00, // Protocol code 126 | EP0_BUFF_SIZE, // Max packet size for EP0 127 | USB_CUST_VENDOR_ID, // Vendor ID 128 | USB_CUST_PRODUCT_ID, // Product ID 129 | 0x0000, // Device release number in BCD format 130 | 0x01, // Manufacturer string index 131 | 0x02, // Product string index 132 | 0x00, // Device serial number string index 133 | 0x01 // Number of possible configurations 134 | }; 135 | 136 | /* Configuration 1 Descriptor */ 137 | 138 | 139 | #define CFG01 struct \ 140 | { USB_CFG_DSC cd01; \ 141 | USB_INTF_DSC i00a00; \ 142 | USB_CUST_EP_DEF \ 143 | } cfg01 144 | 145 | 146 | __code CFG01 = 147 | { 148 | /* Configuration descriptor */ 149 | { 150 | sizeof(USB_CFG_DSC), // Size of this descriptor in bytes 151 | USB_DESC_CFG, // CONFIGURATION descriptor type 152 | sizeof(cfg01), // Total length of data for this cfg 153 | 1, // Number of interfaces in this cfg 154 | 1, // Index value of this configuration 155 | 0, // Configuration string index 156 | USB_CONF_DEFAULT, // Attributes, see usb_desc.h 157 | (USB_CUST_CONF_POWER) / 2, // Max power consumption (2X mA) 158 | }, 159 | 160 | /* Interface descriptor */ 161 | { 162 | sizeof(USB_INTF_DSC), // Size of this descriptor in bytes 163 | USB_DESC_INTF, // INTERFACE descriptor type 164 | 0, // Interface Number 165 | 0, // Alternate Setting Number 166 | USB_CUST_EP_COUNT, // Number of endpoints in this intf 167 | 0xFF, // Class code 168 | 0x00, // Subclass code 169 | 0x00, // Protocol code 170 | 0, // Interface string index 171 | }, 172 | 173 | /* User defined endpoint descriptors */ 174 | USB_CUST_EP_DESC 175 | 176 | }; 177 | 178 | /* String descriptors */ 179 | __code struct {uint8_t bLength; uint8_t bDscType; uint16_t string[1];} sd000 = 180 | { 181 | sizeof(sd000), USB_DESC_STR, 182 | {0x0409} 183 | }; 184 | 185 | __code struct {uint8_t bLength; uint8_t bDscType; uint16_t string[USB_CUST_VENDOR_NAME_LEN];} sd001 = { 186 | sizeof(sd001), USB_DESC_STR, 187 | USB_CUST_VENDOR_NAME 188 | }; 189 | 190 | __code struct {uint8_t bLength; uint8_t bDscType; uint16_t string[USB_CUST_PRODUCT_NAME_LEN];} sd002 = { 191 | sizeof(sd002), USB_DESC_STR, 192 | USB_CUST_PRODUCT_NAME 193 | }; 194 | 195 | 196 | uint16_t UsbIntrSetupLen; 197 | uint8_t UsbIntrSetupReq; 198 | uint8_t UsbIntrConfig; 199 | const uint8_t* UsbIntrDescr; 200 | 201 | #define UsbSetupBuf ((PUSB_SETUP_REQ)Ep0Buffer) 202 | 203 | 204 | 205 | /******************************************************************************* 206 | * USB device configuration 207 | *******************************************************************************/ 208 | void USBDeviceCfg() 209 | { 210 | USB_CTRL = 0x00; //Clear USB control register 211 | USB_CTRL &= ~bUC_HOST_MODE; //This bit is the device selection mode 212 | USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN; //USB device and internal pull-up enable, automatically return to NAK before interrupt flag is cleared during interrupt 213 | USB_DEV_AD = 0x00; //Device address initialization 214 | #ifdef USB_CUST_LOW_SPEED 215 | USB_CTRL |= bUC_LOW_SPEED; 216 | UDEV_CTRL |= bUD_LOW_SPEED; //Choose low speed 1.5M mode 217 | #else 218 | USB_CTRL &= ~bUC_LOW_SPEED; 219 | UDEV_CTRL &= ~bUD_LOW_SPEED; //Select full speed 12M mode, default mode 220 | #endif 221 | UDEV_CTRL = bUD_PD_DIS; // Disable DP/DM pull-down resistor 222 | UDEV_CTRL |= bUD_PORT_EN; //Enable physical port 223 | 224 | 225 | // USB device mode endpoint configuration 226 | UEP0_DMA = (uint16_t) Ep0Buffer; //Endpoint 0 data transfer address 227 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; //Manual flip, OUT transaction returns ACK, IN transaction returns NAK 228 | 229 | #ifdef USB_CUST_EP_INIT 230 | // call custom initialisation 231 | USB_CUST_EP_INIT ; 232 | #endif 233 | 234 | 235 | // interrupt initialisation 236 | USB_INT_EN |= bUIE_SUSPEND; //Enable device suspen interrupt 237 | USB_INT_EN |= bUIE_TRANSFER; //Enable USB transfer completion interrupt 238 | USB_INT_EN |= bUIE_BUS_RST; //Enable device mode USB bus reset interrupt 239 | USB_INT_FG |= 0x1F; //Clear interrupt flag 240 | IE_USB = 1; //Enable USB interrupt 241 | EA = 1; //Allow microcontroller interrupt 242 | 243 | UEP0_T_LEN = 0; 244 | UEP1_T_LEN = 0; //Pre-use send length must be cleared 245 | UEP2_T_LEN = 0; 246 | UEP3_T_LEN = 0; 247 | } 248 | 249 | 250 | /******************************************************************************* 251 | * CH55xUSB interrupt handler 252 | *******************************************************************************/ 253 | void DeviceInterrupt(void) __interrupt (INT_NO_USB) //USB interrupt service routine, using register set 1 254 | { 255 | uint16_t len; 256 | if(UIF_TRANSFER) //USB transfer completion flag 257 | { 258 | switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) 259 | { 260 | 261 | #ifdef USB_CUST_EP1_IN_HANDLER 262 | case UIS_TOKEN_IN | 1: 263 | // run the Enpoint handler 264 | USB_CUST_EP1_IN_HANDLER ; 265 | break; 266 | #endif 267 | #ifdef USB_CUST_EP1_OUT_HANDLER 268 | case UIS_TOKEN_OUT | 1: 269 | // run the Enpoint handler 270 | USB_CUST_EP1_OUT_HANDLER ; 271 | break; 272 | #endif 273 | #ifdef USB_CUST_EP2_IN_HANDLER 274 | case UIS_TOKEN_IN | 2: 275 | // run the Enpoint handler 276 | USB_CUST_EP2_IN_HANDLER ; 277 | break; 278 | #endif 279 | #ifdef USB_CUST_EP2_OUT_HANDLER 280 | case UIS_TOKEN_OUT | 2: 281 | // run the Enpoint handler 282 | USB_CUST_EP2_OUT_HANDLER ; 283 | break; 284 | #endif 285 | #ifdef USB_CUST_EP3_IN_HANDLER 286 | case UIS_TOKEN_IN | 3: 287 | // run the Enpoint handler 288 | USB_CUST_EP3_IN_HANDLER ; 289 | break; 290 | #endif 291 | #ifdef USB_CUST_EP3_OUT_HANDLER 292 | case UIS_TOKEN_OUT | 3: 293 | // run the Enpoint handler 294 | USB_CUST_EP3_OUT_HANDLER ; 295 | break; 296 | #endif 297 | #ifdef USB_CUST_EP4_IN_HANDLER 298 | case UIS_TOKEN_IN | 4: 299 | // run the Enpoint handler 300 | USB_CUST_EP4_IN_HANDLER ; 301 | break; 302 | #endif 303 | #ifdef USB_CUST_EP4_OUT_HANDLER 304 | case UIS_TOKEN_OUT | 4: 305 | // run the Enpoint handler 306 | USB_CUST_EP4_OUT_HANDLER ; 307 | break; 308 | #endif 309 | 310 | // configuration transfers on EP0 311 | case UIS_TOKEN_SETUP | 0: //SETUP transaction 312 | len = USB_RX_LEN; 313 | if(len == (sizeof(USB_SETUP_REQ))) 314 | { 315 | UsbIntrSetupLen = ((uint16_t)UsbSetupBuf->wLengthH<<8) | (UsbSetupBuf->wLengthL); 316 | len = 0; // The default is success and upload 0 length 317 | UsbIntrSetupReq = UsbSetupBuf->bRequest; 318 | 319 | //handle vendor defined requests 320 | if ((UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK) == USB_REQ_TYP_VENDOR) { 321 | len = USB_CUST_CONTROL_TRANSFER_HANDLER; 322 | } 323 | // handle standard requests 324 | else //Standard request 325 | { 326 | switch(UsbIntrSetupReq) //Request code 327 | { 328 | case USB_GET_DESCRIPTOR: 329 | switch(UsbSetupBuf->wValueH) 330 | { 331 | case 1: //Device descriptor 332 | UsbIntrDescr = (uint8_t*) device_dsc; //set the device descriptor to the buffer to be sent 333 | len = sizeof(device_dsc); 334 | break; 335 | case 2: //Configuration descriptor 336 | UsbIntrDescr = (uint8_t*) cfg01; //set the configuration descriptor to the buffer to be sent 337 | len = sizeof(cfg01); 338 | break; 339 | case 3: 340 | if(UsbSetupBuf->wValueL == 0) 341 | { 342 | UsbIntrDescr = (uint8_t*) sd000; 343 | len = sizeof(sd000); 344 | } 345 | else if(UsbSetupBuf->wValueL == 1) 346 | { 347 | UsbIntrDescr = (uint8_t*) sd001; 348 | len = sizeof(sd001); 349 | } 350 | else if(UsbSetupBuf->wValueL == 2) 351 | { 352 | UsbIntrDescr = (uint8_t*) sd002; 353 | len = sizeof(sd002); 354 | } 355 | else 356 | { 357 | len = 0xFF; 358 | } 359 | break; 360 | default: 361 | len = 0xff; //Unsupported command or error 362 | break; 363 | } 364 | if ( UsbIntrSetupLen > len ) 365 | { 366 | UsbIntrSetupLen = len; //Limit total length 367 | } 368 | len = UsbIntrSetupLen >= EP0_BUFF_SIZE ? EP0_BUFF_SIZE : UsbIntrSetupLen; //This transmission length 369 | memcpy(Ep0Buffer,UsbIntrDescr,len); //copy upload data 370 | UsbIntrSetupLen -= len; 371 | UsbIntrDescr += len; 372 | break; 373 | case USB_SET_ADDRESS: 374 | UsbIntrSetupLen = UsbSetupBuf->wValueL; //Staging USB device address 375 | break; 376 | case USB_GET_CONFIGURATION: 377 | Ep0Buffer[0] = UsbIntrConfig; 378 | if ( UsbIntrSetupLen >= 1 ) 379 | { 380 | len = 1; 381 | } 382 | break; 383 | case USB_SET_CONFIGURATION: 384 | UsbIntrConfig = UsbSetupBuf->wValueL; 385 | break; 386 | case USB_GET_INTERFACE: 387 | break; 388 | case USB_CLEAR_FEATURE: //Clear Feature 389 | if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* Clear device */ 390 | { 391 | if( ( ( ( uint16_t )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 ) 392 | { 393 | if( cfg01.cd01.bmAttributes & 0x20 ) 394 | { 395 | /* wake */ 396 | } 397 | else 398 | { 399 | len = 0xFF; /* operation failed */ 400 | } 401 | } 402 | else 403 | { 404 | len = 0xFF; /* operation failed */ 405 | } 406 | } 407 | else if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP ) // Clear Endpoint 408 | { 409 | switch( UsbSetupBuf->wIndexL ) 410 | { 411 | #if USB_CUST_EP_COUNT >= 4 412 | case 0x84: 413 | UEP4_CTRL = UEP4_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK; 414 | break; 415 | case 0x04: 416 | UEP4_CTRL = UEP4_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK; 417 | break; 418 | #endif 419 | #if USB_CUST_EP_COUNT >= 3 420 | case 0x83: 421 | UEP3_CTRL = UEP3_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK; 422 | break; 423 | case 0x03: 424 | UEP3_CTRL = UEP3_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK; 425 | break; 426 | #endif 427 | 428 | #if USB_CUST_EP_COUNT >= 2 429 | case 0x82: 430 | UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK; 431 | break; 432 | case 0x02: 433 | UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK; 434 | break; 435 | #endif 436 | 437 | case 0x81: 438 | UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK; 439 | break; 440 | case 0x01: 441 | UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK; 442 | break; 443 | default: 444 | len = 0xFF; // Unsupported endpoint 445 | break; 446 | } 447 | } 448 | else 449 | { 450 | len = 0xFF; // anything else is unsupported 451 | } 452 | break; 453 | case USB_SET_FEATURE: /* Set Feature */ 454 | if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_DEVICE ) /* Setting up the device */ 455 | { 456 | if( ( ( ( uint16_t )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 ) 457 | { 458 | if( cfg01.cd01.bmAttributes & 0x20 ) 459 | { 460 | /* Sleep */ 461 | #ifdef DE_PRINTF 462 | printf( "suspend\r\n" ); //Sleep state 463 | #endif 464 | while ( XBUS_AUX & bUART0_TX ) 465 | { 466 | ; //Waiting for transmission to complete 467 | } 468 | SAFE_MOD = 0x55; 469 | SAFE_MOD = 0xAA; 470 | WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB or RXD0/1 activity will exit sleep state 471 | PCON |= PD; //Sleep 472 | SAFE_MOD = 0x55; 473 | SAFE_MOD = 0xAA; 474 | WAKE_CTRL = 0x00; 475 | } 476 | else 477 | { 478 | len = 0xFF; /* operation failed */ 479 | } 480 | } 481 | else 482 | { 483 | len = 0xFF; /* operation failed */ 484 | } 485 | } 486 | else if( ( UsbSetupBuf->bRequestType & 0x1F ) == USB_REQ_RECIP_ENDP ) /* Set endpoint */ 487 | { 488 | if( ( ( ( uint16_t )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 ) 489 | { 490 | switch( ( ( uint16_t )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL ) 491 | { 492 | 493 | #if USB_CUST_EP_COUNT >= 4 494 | case 0x84: 495 | UEP3_CTRL = UEP4_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 4 IN STALL */ 496 | break; 497 | case 0x04: 498 | UEP3_CTRL = UEP4_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 4 OUT Stall */ 499 | break; 500 | #endif 501 | 502 | #if USB_CUST_EP_COUNT >= 3 503 | case 0x83: 504 | UEP3_CTRL = UEP3_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 3 IN STALL */ 505 | break; 506 | case 0x03: 507 | UEP3_CTRL = UEP3_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 3 OUT Stall */ 508 | break; 509 | #endif 510 | 511 | #if USB_CUST_EP_COUNT >= 2 512 | case 0x82: 513 | UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 2 IN STALL */ 514 | break; 515 | case 0x02: 516 | UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 2 OUT Stall */ 517 | break; 518 | #endif 519 | case 0x81: 520 | UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* Set endpoint 1 IN STALL */ 521 | break; 522 | case 0x01: 523 | UEP1_CTRL = UEP1_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* Set endpoint 1 OUT Stall */ 524 | default: 525 | len = 0xFF; /* operation failed */ 526 | break; 527 | } 528 | } 529 | else 530 | { 531 | len = 0xFF; /* operation failed */ 532 | } 533 | } 534 | else 535 | { 536 | len = 0xFF; /* operation failed */ 537 | } 538 | break; 539 | case USB_GET_STATUS: 540 | Ep0Buffer[0] = 0x00; 541 | Ep0Buffer[1] = 0x00; 542 | if ( UsbIntrSetupLen >= 2 ) 543 | { 544 | len = 2; 545 | } 546 | else 547 | { 548 | len = UsbIntrSetupLen; 549 | } 550 | break; 551 | default: 552 | len = 0xff; // operation failed 553 | break; 554 | } 555 | } 556 | } 557 | else 558 | { 559 | len = 0xff; //Wrong packet length 560 | } 561 | if(len == 0xff) 562 | { 563 | UsbIntrSetupReq = 0xFF; 564 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL 565 | } 566 | else if(len <= EP0_BUFF_SIZE) //Upload data or status stage returns 0 length package 567 | { 568 | UEP0_T_LEN = len; 569 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//The default packet is DATA1, which returns a response ACK. 570 | } 571 | else 572 | { 573 | //Although it has not yet reached the status stage, 574 | //it uploads 0 length data packets in advance to prevent the host from entering the status stage in advance. 575 | UEP0_T_LEN = 0; 576 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//The default packet is DATA1, which returns a response ACK. 577 | } 578 | break; 579 | 580 | // control endpoint 0 data tranfers 581 | case UIS_TOKEN_IN | 0: //endpoint0 IN 582 | switch(UsbIntrSetupReq) 583 | { 584 | case USB_GET_DESCRIPTOR: 585 | len = UsbIntrSetupLen >= EP0_BUFF_SIZE ? EP0_BUFF_SIZE : UsbIntrSetupLen; //This transmission length 586 | memcpy( Ep0Buffer, UsbIntrDescr, len ); //set output data 587 | UsbIntrSetupLen -= len; 588 | UsbIntrDescr += len; 589 | UEP0_T_LEN = len; 590 | UEP0_CTRL ^= bUEP_T_TOG; //Sync flag bit flip 591 | break; 592 | case USB_SET_ADDRESS: 593 | USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | UsbIntrSetupLen; 594 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; 595 | break; 596 | default: 597 | //The status phase completes the interrupt or is forced to upload 0 length packet end control transmission 598 | UEP0_T_LEN = 0; 599 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; 600 | break; 601 | } 602 | break; 603 | case UIS_TOKEN_OUT | 0: // endpoint0 OUT from the Host, IN to the MCU 604 | // call custom data handle if it is defined 605 | USB_CUST_CONTROL_DATA_HANDLER; 606 | 607 | UEP0_T_LEN = 0; 608 | UEP0_CTRL |= UEP_R_RES_ACK | UEP_T_RES_ACK; //State stage, responding to NAK in IN 609 | break; 610 | 611 | 612 | 613 | default: 614 | break; 615 | } 616 | UIF_TRANSFER = 0; //Write 0 to clear interrupt 617 | } 618 | if(UIF_BUS_RST) //Device Mode USB Bus Reset Interrupt 619 | { 620 | #ifdef DE_PRINTF 621 | printf( "reset\r\n" ); //reset state 622 | #endif 623 | UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; 624 | UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK; 625 | UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; 626 | USB_DEV_AD = 0x00; 627 | UIF_SUSPEND = 0; 628 | UIF_TRANSFER = 0; 629 | UIF_BUS_RST = 0; //Clear interrupt flag 630 | UsbIntrConfig = 0; //Clear configuration value 631 | #ifdef USB_CUST_RESET_HANDLER 632 | // call custom reset handler function 633 | USB_CUST_RESET_HANDLER ; 634 | #endif 635 | } 636 | if (UIF_SUSPEND) //USB bus suspend/wake up 637 | { 638 | UIF_SUSPEND = 0; 639 | if ( USB_MIS_ST & bUMS_SUSPEND ) //suspend 640 | { 641 | #ifdef DE_PRINTF 642 | printf( "suspend\r\n" ); //suspend state 643 | #endif 644 | while ( XBUS_AUX & bUART0_TX ) 645 | { 646 | ; //Waiting for transmission to complete 647 | } 648 | SAFE_MOD = 0x55; 649 | SAFE_MOD = 0xAA; 650 | WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO | bWAK_RXD1_LO; //USB or RXD0/1 can be woken up when there is a signal 651 | PCON |= PD; //sleep 652 | SAFE_MOD = 0x55; 653 | SAFE_MOD = 0xAA; 654 | WAKE_CTRL = 0x00; 655 | } 656 | } 657 | else { //Unexpected interruption, impossible situation 658 | USB_INT_FG = 0xFF; //Clear interrupt flag 659 | 660 | } 661 | } 662 | 663 | 664 | #endif /* USB_INTR_H */ 665 | 666 | --------------------------------------------------------------------------------