├── watch-dmesg.sh ├── watch-libevent.sh ├── .gitignore ├── notes.md ├── src ├── delay.h ├── usb_hid.h ├── usb_multitouch.h ├── neo.h ├── config.h ├── usb_multitouch.c ├── usb_handler.h ├── delay.c ├── usb_hid.c ├── usb_descr.h ├── neo.c ├── usb_descr.c ├── system.h ├── usb.h ├── gpio.h ├── usb_handler.c └── ch554.h ├── LICENSE.md ├── CHANGELOG.md ├── .github └── workflows │ └── build.yml ├── tools ├── readme.md └── chprog.py ├── makefile ├── touch.c └── README.md /watch-dmesg.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | dmesg -w -------------------------------------------------------------------------------- /watch-libevent.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | sudo libinput debug-events -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # output generated files 2 | *.bin 3 | *.hex 4 | # SDCC generated files 5 | *.ihx 6 | *.lk 7 | *.map 8 | *.mem 9 | *.lst 10 | *.rel 11 | *.rst 12 | *.sym 13 | *.asm 14 | *.adb 15 | # This file differs on different machines 16 | .vscode/c_cpp_properties.json 17 | venv/ -------------------------------------------------------------------------------- /notes.md: -------------------------------------------------------------------------------- 1 | # Comma 3 touch points 2 | 3 | bottom left = 0,0 4 | top right = 1080,2160 5 | 6 | ## Bookmark Button 7 | 110/108 8 | 9 | 110/1080 10 | 108/2160 11 | 12 | ## Experimental Toggle Button 13 | 14 | ### First version 15 | 911/2003 16 | 17 | 911/1080 18 | 2003/2160 19 | 20 | ### Second Version 21 | 22 | 875/2030 23 | 24 | hex(int(875/1080*10000)) 25 | hex(int(2030/2160*10000)) 26 | -------------------------------------------------------------------------------- /src/delay.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // Delay Functions for CH551, CH552 and CH554 * v1.1 * 3 | // =================================================================================== 4 | 5 | #pragma once 6 | #include 7 | #include "ch554.h" 8 | 9 | void DLY_us(uint16_t n); // delay in units of us 10 | void DLY_ms(uint16_t n); // delay in units of ms 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | As most of this work is based on the work of a CC-BY-SA 3.0 licensed project (https://github.com/wagiminator/MCU-Templates/blob/main/CH552/LICENSE), this work is also licensed under the same license. 2 | 3 | --- 4 | 5 | This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. 6 | To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send 7 | a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 0.0.4 2 | 3 | * Adjusted Experimental Mode touch point so that it happens to work on offroad too as the experimental mode switch in settings is at the same place. 4 | * Lowered lamp light brightness to minimum to try to match pre-existing car interior lights and prevent distracting point lights. 5 | * Refactored some HID calls to `usb_multitouch` for future upstreaming to wagimator/MCU_Templates. 6 | * Adjusted clock speed from 16Mhz to 6Mhz. Lights and touch functionality still preserved. Power usage now cut down to somewhere below 500mW. 7 | 8 | # 0.0.3 9 | 10 | * Moved the center button to touch slightly left of center for navigational UI compatiability. 11 | 12 | # 0.0.2 13 | 14 | * Renamed to C3 Faux-Touch Keyboard to prevent confusion with "TouchKey", an unrelated functionality. 15 | 16 | # 0.0.1 17 | 18 | * Initial release 19 | -------------------------------------------------------------------------------- /src/usb_hid.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB HID Functions for CH551, CH552 and CH554 * v1.1 * 3 | // =================================================================================== 4 | // 5 | // Functions available: 6 | // -------------------- 7 | // HID_init() init USB-HID 8 | // HID_sendReport(rep, len) send HID report (pointer to report buffer, length) 9 | // 10 | // 2022 by Stefan Wagner: https://github.com/wagiminator 11 | 12 | #pragma once 13 | #include 14 | #include "ch554.h" 15 | #include "usb.h" 16 | #include "usb_descr.h" 17 | #include "usb_handler.h" 18 | 19 | #define HID_IN_buffer EP2_buffer // buffer for incoming HID reports 20 | #define HID_init USB_init // setup USB-HID 21 | void HID_sendReport(__xdata uint8_t* buf, uint8_t len); // send HID report 22 | -------------------------------------------------------------------------------- /src/usb_multitouch.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB HID Multitouch Functions for CH551, CH552 and CH554 * v1.0 * 3 | // =================================================================================== 4 | // 5 | // Functions available: 6 | // -------------------- 7 | // MT_init() init multitouch 8 | // MT_touchDown(c,ci,x,y) send a multitouch report for touch down 9 | // MT_touchUp(c,ci) send a multitouch report for touch up 10 | 11 | 12 | #pragma once 13 | #include 14 | #include "usb_hid.h" 15 | #include "usb_handler.h" 16 | 17 | // Functions 18 | #define MT_init HID_init // init multitouch 19 | void MT_touchDown(uint8_t count, 20 | uint8_t contact_ident, 21 | uint16_t x, uint16_t y); // send a multitouch report for touch down 22 | void MT_touchUp(uint8_t count, 23 | uint8_t contact_ident); // send a multitouch report for touch up 24 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build and/or Release 2 | 3 | on: push 4 | 5 | permissions: 6 | contents: write 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout code 14 | uses: actions/checkout@v4 15 | 16 | - name: Update apt 17 | run: sudo apt-get -y update 18 | 19 | - name: Install sdcc 20 | run: sudo apt-get install -y sdcc 21 | 22 | - name: Run make bin 23 | run: make bin 24 | 25 | - name: Run make hex 26 | run: make hex 27 | 28 | - name: Store artifacts 29 | uses: actions/upload-artifact@v4 30 | with: 31 | name: touchkey-firmware 32 | path: | 33 | touch.bin 34 | touch.hex 35 | 36 | - name: Release 37 | uses: softprops/action-gh-release@v2 38 | if: startsWith(github.ref, 'refs/tags/') 39 | with: 40 | files: | 41 | touch.bin 42 | touch.hex -------------------------------------------------------------------------------- /src/neo.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // NeoPixel (Addressable LED) Functions for CH551, CH552 and CH554 * v1.2 * 3 | // =================================================================================== 4 | // 5 | // Basic control functions for 800kHz addressable LEDs (NeoPixel). A simplified 6 | // protocol is used which should work with most LEDs. 7 | // 8 | // The following must be defined in config.h: 9 | // PIN_NEO - pin connected to DATA-IN of the pixel strip (via a ~330 ohms resistor). 10 | // NEO_GRB - type of pixel: NEO_GRB or NEO_RGB 11 | // NEO_COUNT - total number of pixels 12 | // System clock frequency must be at least 6 MHz. 13 | // 14 | // Further information: https://github.com/wagiminator/ATtiny13-NeoController 15 | // 2023 by Stefan Wagner: https://github.com/wagiminator 16 | 17 | #pragma once 18 | #include 19 | #include "gpio.h" 20 | #include "delay.h" 21 | #include "config.h" 22 | 23 | #define NEO_init() PIN_low(PIN_NEO);PIN_output(PIN_NEO) // init NeoPixels 24 | #define NEO_latch() DLY_us(281) // latch colors 25 | 26 | void NEO_sendByte(uint8_t data); // send a single byte to the pixels 27 | void NEO_clearAll(void); // clear all pixels 28 | void NEO_update(void); // write buffer to pixels 29 | void NEO_writeColor(uint8_t pixel, uint8_t r, uint8_t g, uint8_t b); // write color to pixel in buffer 30 | void NEO_writeHue(uint8_t pixel, uint8_t hue, uint8_t bright); // hue (0..191), brightness (0..2) 31 | void NEO_clearPixel(uint8_t pixel); // clear one pixel in buffer -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // User Configurations for CH55xE Development Stick 3 | // =================================================================================== 4 | 5 | #pragma once 6 | 7 | // Pin definitions 8 | #define PIN_NEO P34 // pin connected to NeoPixel 9 | #define PIN_LED P32 // pin connected to LED 10 | #define PIN_KEY1 P11 // pin connected to key 1 11 | #define PIN_KEY2 P17 // pin connected to key 2 12 | #define PIN_KEY3 P16 // pin connected to key 3 13 | #define PIN_ENC_SW P33 // pin connected to knob switch 14 | #define PIN_ENC_A P31 // pin connected to knob outA 15 | #define PIN_ENC_B P30 // pin connected to knob outB 16 | #define NEO_COUNT 3 // number of NeoPixels 17 | 18 | // NeoPixel configuration 19 | #define NEO_GRB // type of pixel: NEO_GRB or NEO_RGB 20 | 21 | // USB device descriptor 22 | #define USB_VENDOR_ID 0x6666 // VID: Prototype 23 | #define USB_PRODUCT_ID 0x6666 // PID: Prototype 24 | #define USB_DEVICE_VERSION 0x0100 // v1.0 (BCD-format) 25 | 26 | // USB configuration descriptor 27 | #define USB_MAX_POWER_mA 50 // max power in mA 28 | 29 | // USB descriptor strings 30 | #define MANUFACTURER_STR 'm','i','n','d','f','l','a','k','e','s','.','c','o','m' 31 | #define PRODUCT_STR 0xD83E, 0xDDBE, ' ', 'c', 'o', 'm', 'm', 'a', ' ', 't', 'h', 'r', 'e', 'e', ' ', 'F', 'a', 'u', 'x', '-', 'T', 'o', 'u', 'c', 'h', ' ', 'k', 'e', 'y', 'b', 'o', 'a', 'r', 'd' 32 | #define SERIAL_STR '0','0','7' 33 | #define INTERFACE_STR 'H','I','D','-','T','o','u','c','h','s','c','r','e','e','n' -------------------------------------------------------------------------------- /src/usb_multitouch.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB HID Multitouch Functions for CH551, CH552 and CH554 * v1.0 * 3 | // =================================================================================== 4 | 5 | #include "usb_multitouch.h" 6 | 7 | // Handle CLASS SETUP requests 8 | uint8_t MT_control(void) { 9 | switch(USB_SetupReq) { 10 | case HID_GET_REPORT: 11 | EP0_buffer[0] = 10; // 10 fingers max 12 | return 1; 13 | 14 | default: 15 | return 0xff; // failed 16 | } 17 | } 18 | 19 | // Send a multitouch report for touch down 20 | // Keep track of the contact count yourself 21 | // Contact Identifiers should be unique for each contact 22 | // X and Y are the screen dimensions as if it were a 10000x10000 screen 23 | // Tip Switch and In Range currently hardcoded 24 | // Pressure is currently hardcoded to maximum 25 | void MT_touchDown(uint8_t count, uint8_t contact_ident, uint16_t x, uint16_t y) { 26 | __xdata unsigned char touchDownReport[] = { 27 | count, // Contact Count 28 | contact_ident, // Contact Identifier 29 | 0x03, // Tip Switch and In Range 30 | 0x7F, // Pressure 31 | x & 0xff, (x >> 8) & 0xFF, // X 32 | y & 0xff, (y >> 8) & 0xFF // Y 33 | }; 34 | HID_sendReport(touchDownReport, sizeof(touchDownReport)); 35 | } 36 | 37 | void MT_touchUp(uint8_t count, uint8_t contact_ident) { 38 | __xdata unsigned char touchUpReport[] = { 39 | count, // Contact Count 40 | contact_ident, // Contact Identifier 41 | 0x00, // Not in Range 42 | 0x00, // No pressure 43 | 0x00, 0x00, // Disregarded 44 | 0x00, 0x00, // Disregarded 45 | }; 46 | HID_sendReport(touchUpReport, sizeof(touchUpReport)); 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/usb_handler.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB Handler for CH551, CH552 and CH554 * v1.5 * 3 | // =================================================================================== 4 | 5 | #pragma once 6 | #include 7 | #include "ch554.h" 8 | #include "usb_descr.h" 9 | 10 | // =================================================================================== 11 | // Variables 12 | // =================================================================================== 13 | #define USB_SetupBuf ((PUSB_SETUP_REQ)EP0_buffer) 14 | extern volatile uint8_t USB_SetupReq, USB_SetupTyp; 15 | extern volatile uint16_t USB_SetupLen; 16 | extern volatile __bit USB_ENUM_OK; 17 | extern __code uint8_t* USB_pDescr; 18 | 19 | // =================================================================================== 20 | // Custom External USB Handler Functions 21 | // =================================================================================== 22 | uint8_t MT_control(void); 23 | void HID_EP_init(void); 24 | void HID_EP1_IN(void); 25 | 26 | // =================================================================================== 27 | // USB Handler Defines 28 | // =================================================================================== 29 | // Custom USB handler functions 30 | #define USB_INIT_endpoints HID_EP_init // custom USB EP init handler 31 | #define USB_CLASS_SETUP_handler MT_control // handle class setup requests 32 | 33 | // Endpoint callback functions 34 | #define EP0_SETUP_callback USB_EP0_SETUP 35 | #define EP0_IN_callback USB_EP0_IN 36 | #define EP0_OUT_callback USB_EP0_OUT 37 | #define EP1_IN_callback HID_EP1_IN 38 | 39 | // =================================================================================== 40 | // Functions 41 | // =================================================================================== 42 | void USB_init(void); 43 | void USB_interrupt(void); 44 | void USB_EP0_copyDescr(uint8_t len); 45 | -------------------------------------------------------------------------------- /src/delay.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // Delay Functions for CH551, CH552 and CH554 * v1.1 * 3 | // =================================================================================== 4 | 5 | #include "delay.h" 6 | 7 | // =================================================================================== 8 | // Delay in Units of us 9 | // =================================================================================== 10 | void DLY_us(uint16_t n) { // delay in us 11 | #ifdef F_CPU 12 | #if F_CPU <= 6000000 13 | n >>= 2; 14 | #endif 15 | #if F_CPU <= 3000000 16 | n >>= 2; 17 | #endif 18 | #if F_CPU <= 750000 19 | n >>= 4; 20 | #endif 21 | #endif 22 | 23 | while(n) { // total = 12~13 Fsys cycles, 1uS @Fsys=12MHz 24 | __asm__("inc _SAFE_MOD"); // 2 Fsys cycles, for higher Fsys, add operation here 25 | #ifdef F_CPU 26 | #if F_CPU >= 14000000 27 | __asm__("inc _SAFE_MOD"); 28 | #endif 29 | #if F_CPU >= 16000000 30 | __asm__("inc _SAFE_MOD"); 31 | #endif 32 | #if F_CPU >= 18000000 33 | __asm__("inc _SAFE_MOD"); 34 | #endif 35 | #if F_CPU >= 20000000 36 | __asm__("inc _SAFE_MOD"); 37 | #endif 38 | #if F_CPU >= 22000000 39 | __asm__("inc _SAFE_MOD"); 40 | #endif 41 | #if F_CPU >= 24000000 42 | __asm__("inc _SAFE_MOD"); 43 | #endif 44 | #if F_CPU >= 26000000 45 | __asm__("inc _SAFE_MOD"); 46 | #endif 47 | #if F_CPU >= 28000000 48 | __asm__("inc _SAFE_MOD"); 49 | #endif 50 | #if F_CPU >= 30000000 51 | __asm__("inc _SAFE_MOD"); 52 | #endif 53 | #if F_CPU >= 32000000 54 | __asm__("inc _SAFE_MOD"); 55 | #endif 56 | #endif 57 | --n; 58 | } 59 | } 60 | 61 | // =================================================================================== 62 | // Delay in Units of ms 63 | // =================================================================================== 64 | void DLY_ms(uint16_t n) { // delay in ms 65 | while(n) { 66 | while(!(TKEY_CTRL & bTKC_IF)); 67 | while(TKEY_CTRL & bTKC_IF); 68 | --n; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tools/readme.md: -------------------------------------------------------------------------------- 1 | # Programming the MCU using the factory built-in USB Bootloader 2 | ## Installing Drivers for the Bootloader 3 | On Linux you do not need to install a driver. However, by default Linux will not expose enough permission to upload your code with the USB bootloader. In order to fix this, open a terminal and run the following commands: 4 | 5 | ``` 6 | echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="4348", ATTR{idProduct}=="55e0", MODE="666"' | sudo tee /etc/udev/rules.d/99-ch55x.rules 7 | sudo udevadm control --reload-rules 8 | ``` 9 | 10 | For Windows, you need the [CH372 driver](http://www.wch-ic.com/downloads/CH372DRV_EXE.html). Alternatively, you can also use the [Zadig Tool](https://zadig.akeo.ie/) to install the correct driver. Here, click "Options" -> "List All Devices" and select the USB module. Then install the libusb-win32 driver. To do this, the board must be connected and the microcontroller must be in bootloader mode. 11 | 12 | ## Entering Bootloader Mode 13 | The bootloader must be started manually for new uploads. To do this, the board must first be disconnected from the USB port and all voltage sources. Now press the BOOT button and keep it pressed while reconnecting the board to the USB port of your PC. The chip now starts in bootloader mode, the BOOT button can be released and new firmware can be uploaded via USB. Alternatively, you can leave the board connected to the USB port, press and hold the BOOT button, press and release the RESET button and then release the BOOT button to enter the bootloader mode. 14 | 15 | ## WCHISPTool 16 | WCH offers the free but closed-source software [WCHISPTool](https://www.wch.cn/downloads/WCHISPTool_Setup_exe.html) to upload firmware with Windows via the USB bootloader. 17 | 18 | ## chprog.py 19 | You can also use chprog.py, a simple Python tool provided in this folder, to flash the microcontroller via the built-in USB bootloader. In order for this tool to work, Python3 must be installed on your system. To do this, follow these [instructions](https://www.pythontutorial.net/getting-started/install-python/). In addition [PyUSB](https://github.com/pyusb/pyusb) must be installed. On Linux (Debian-based), all of this can be done with the following commands: 20 | 21 | ``` 22 | sudo apt install python3 python3-pip 23 | python3 -m pip install pyusb 24 | ``` 25 | 26 | ``` 27 | Usage example: 28 | python3 chprog.py firmware.bin 29 | ``` 30 | 31 | ## Alternative Software Tools 32 | - [isp55e0](https://github.com/frank-zago/isp55e0) 33 | - [wchisp](https://github.com/ch32-rs/wchisp) 34 | -------------------------------------------------------------------------------- /src/usb_hid.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB HID Functions for CH551, CH552 and CH554 * v1.1 * 3 | // =================================================================================== 4 | 5 | #include "usb_hid.h" 6 | 7 | // =================================================================================== 8 | // Variables and Defines 9 | // =================================================================================== 10 | volatile __bit HID_writeBusyFlag; // upload pointer busy flag 11 | 12 | // =================================================================================== 13 | // Front End Functions 14 | // =================================================================================== 15 | 16 | // Send HID report 17 | void HID_sendReport(__xdata uint8_t* buf, uint8_t len) { 18 | uint8_t i; 19 | while(HID_writeBusyFlag); // wait for ready to write 20 | for(i=0; i respond NAK 51 | HID_writeBusyFlag = 0; // clear busy flag 52 | } 53 | 54 | // Endpoint 2 OUT handler (HID report transfer from host completed) 55 | // No handling is actually necessary here, the auto-ACK is sufficient. 56 | // The current report can be read from the EP2 buffer. 57 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | # =================================================================================== 2 | # Project: Mouse Wiggler for CH551, CH552, CH554 3 | # Author: Stefan Wagner 4 | # Year: 2023 5 | # URL: https://github.com/wagiminator 6 | # =================================================================================== 7 | # Type "make help" in the command line. 8 | # =================================================================================== 9 | 10 | # Files and Folders 11 | MAINFILE = touch.c 12 | TARGET = touch 13 | INCLUDE = src 14 | TOOLS = tools 15 | 16 | # Microcontroller Settings 17 | FREQ_SYS = 6000000 18 | XRAM_LOC = 0x0100 19 | XRAM_SIZE = 0x0300 20 | CODE_SIZE = 0x3800 21 | 22 | # Toolchain 23 | CC = sdcc 24 | OBJCOPY = objcopy 25 | # Override OBJCOPY on macOS 26 | # Install binutils with homebrew on macOS: brew install binutils 27 | ifeq ($(shell uname -s),Darwin) 28 | ifeq ($(shell uname -m),arm64) 29 | OBJCOPY = /opt/homebrew/opt/binutils/bin/gobjcopy 30 | else 31 | OBJCOPY = /usr/local/opt/binutils/bin/gobjcopy 32 | endif 33 | endif 34 | PACK_HEX = packihx 35 | ISPTOOL ?= python3 $(TOOLS)/chprog.py $(TARGET).bin 36 | 37 | # Compiler Flags 38 | CFLAGS = -mmcs51 --model-small --no-xinit-opt -DF_CPU=$(FREQ_SYS) -I$(INCLUDE) -I. 39 | CFLAGS += --xram-size $(XRAM_SIZE) --xram-loc $(XRAM_LOC) --code-size $(CODE_SIZE) 40 | CFILES = $(MAINFILE) $(wildcard $(INCLUDE)/*.c) 41 | RFILES = $(CFILES:.c=.rel) 42 | CLEAN = rm -f *.ihx *.lk *.map *.mem *.lst *.rel *.rst *.sym *.asm *.adb 43 | 44 | # Symbolic Targets 45 | help: 46 | @echo "Use the following commands:" 47 | @echo "make all compile, build and keep all files" 48 | @echo "make hex compile and build $(TARGET).hex" 49 | @echo "make bin compile and build $(TARGET).bin" 50 | @echo "make flash compile, build and upload $(TARGET).bin to device" 51 | @echo "make clean remove all build files" 52 | 53 | %.rel : %.c 54 | @echo "Compiling $< ..." 55 | @$(CC) -c $(CFLAGS) $< 56 | 57 | $(TARGET).ihx: $(RFILES) 58 | @echo "Building $(TARGET).ihx ..." 59 | @$(CC) $(notdir $(RFILES)) $(CFLAGS) -o $(TARGET).ihx 60 | 61 | $(TARGET).hex: $(TARGET).ihx 62 | @echo "Building $(TARGET).hex ..." 63 | @$(PACK_HEX) $(TARGET).ihx > $(TARGET).hex 64 | 65 | $(TARGET).bin: $(TARGET).ihx 66 | @echo "Building $(TARGET).bin ..." 67 | @$(OBJCOPY) -I ihex -O binary $(TARGET).ihx $(TARGET).bin 68 | 69 | flash: $(TARGET).bin size removetemp 70 | @echo "Uploading to CH55x ..." 71 | @$(ISPTOOL) 72 | 73 | all: $(TARGET).bin $(TARGET).hex size 74 | 75 | hex: $(TARGET).hex size removetemp 76 | 77 | bin: $(TARGET).bin size removetemp 78 | 79 | bin-hex: $(TARGET).bin $(TARGET).hex size removetemp 80 | 81 | install: flash 82 | 83 | size: 84 | @echo "------------------" 85 | @echo "FLASH: $(shell awk '$$1 == "ROM/EPROM/FLASH" {print $$4}' $(TARGET).mem) bytes" 86 | @echo "IRAM: $(shell awk '$$1 == "Stack" {print 248-$$10}' $(TARGET).mem) bytes" 87 | @echo "XRAM: $(shell awk '$$1 == "EXTERNAL" {print $(XRAM_LOC)+$$5}' $(TARGET).mem) bytes" 88 | @echo "------------------" 89 | 90 | removetemp: 91 | @echo "Removing temporary files ..." 92 | @$(CLEAN) 93 | 94 | clean: 95 | @echo "Cleaning all up ..." 96 | @$(CLEAN) 97 | @rm -f $(TARGET).hex $(TARGET).bin 98 | -------------------------------------------------------------------------------- /src/usb_descr.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB Descriptors and Definitions 3 | // =================================================================================== 4 | // 5 | // Definition of USB descriptors and endpoint sizes and addresses. 6 | // 7 | // The following must be defined in config.h: 8 | // USB_VENDOR_ID - Vendor ID (16-bit word) 9 | // USB_PRODUCT_ID - Product ID (16-bit word) 10 | // USB_DEVICE_VERSION - Device version (16-bit BCD) 11 | // USB_MAX_POWER_mA - Device max power in mA 12 | // All string descriptors. 13 | // 14 | // In the makefile the following microcontroller settings must be made: 15 | // XRAM_LOC = 0x0100 16 | // XRAM_SIZE = 0x0300 17 | 18 | #pragma once 19 | #include 20 | #include "usb.h" 21 | #include "config.h" 22 | 23 | // =================================================================================== 24 | // USB Endpoint Definitions 25 | // =================================================================================== 26 | #define EP0_SIZE 8 27 | #define EP1_SIZE 8 28 | #define EP2_SIZE 8 29 | 30 | #define EP0_BUF_SIZE EP_BUF_SIZE(EP0_SIZE) 31 | #define EP1_BUF_SIZE EP_BUF_SIZE(EP1_SIZE) 32 | #define EP2_BUF_SIZE EP_BUF_SIZE(EP2_SIZE) 33 | #define EP_BUF_SIZE(x) (x+2<64 ? x+2 : 64) 34 | 35 | #define EP0_ADDR 0 36 | #define EP1_ADDR (EP0_ADDR + EP0_BUF_SIZE) 37 | #define EP2_ADDR (EP1_ADDR + EP1_BUF_SIZE) 38 | 39 | __xdata __at (EP0_ADDR) uint8_t EP0_buffer[EP0_BUF_SIZE]; 40 | __xdata __at (EP1_ADDR) uint8_t EP1_buffer[EP1_BUF_SIZE]; 41 | __xdata __at (EP2_ADDR) uint8_t EP2_buffer[EP2_BUF_SIZE]; 42 | 43 | // =================================================================================== 44 | // Device and Configuration Descriptors 45 | // =================================================================================== 46 | typedef struct _USB_CFG_DESCR_HID { 47 | USB_CFG_DESCR config; 48 | USB_ITF_DESCR interface0; 49 | USB_HID_DESCR hid0; 50 | USB_ENDP_DESCR ep1IN; 51 | USB_ENDP_DESCR ep2OUT; 52 | } USB_CFG_DESCR_HID, *PUSB_CFG_DESCR_HID; 53 | typedef USB_CFG_DESCR_HID __xdata *PXUSB_CFG_DESCR_HID; 54 | 55 | extern __code USB_DEV_DESCR DevDescr; 56 | extern __code USB_CFG_DESCR_HID CfgDescr; 57 | 58 | // =================================================================================== 59 | // HID Report Descriptors 60 | // =================================================================================== 61 | extern __code uint8_t ReportDescr[]; 62 | extern __code uint8_t ReportDescrLen; 63 | 64 | #define USB_REPORT_DESCR ReportDescr 65 | #define USB_REPORT_DESCR_LEN ReportDescrLen 66 | 67 | // =================================================================================== 68 | // String Descriptors 69 | // =================================================================================== 70 | extern __code uint16_t LangDescr[]; 71 | extern __code uint16_t ManufDescr[]; 72 | extern __code uint16_t ProdDescr[]; 73 | extern __code uint16_t SerDescr[]; 74 | extern __code uint16_t InterfDescr[]; 75 | 76 | #define USB_STR_DESCR_i0 (uint8_t*)LangDescr 77 | #define USB_STR_DESCR_i1 (uint8_t*)ManufDescr 78 | #define USB_STR_DESCR_i2 (uint8_t*)ProdDescr 79 | #define USB_STR_DESCR_i3 (uint8_t*)SerDescr 80 | #define USB_STR_DESCR_i4 (uint8_t*)InterfDescr 81 | #define USB_STR_DESCR_ix (uint8_t*)SerDescr 82 | -------------------------------------------------------------------------------- /touch.c: -------------------------------------------------------------------------------- 1 | // Libraries 2 | #include "src/config.h" // user configurations 3 | #include "src/delay.h" // delay functions 4 | #include "src/gpio.h" // GPIO functions 5 | #include "src/neo.h" // NeoPixel functions 6 | #include "src/system.h" // system functions 7 | #include "usb_multitouch.h" 8 | 9 | // Prototypes for used interrupts 10 | void USB_interrupt(void); 11 | void USB_ISR(void) __interrupt(INT_NO_USB) { USB_interrupt(); } 12 | 13 | // =================================================================================== 14 | // Main Function 15 | // =================================================================================== 16 | void main(void) { 17 | __idata uint8_t i; // temp variable 18 | 19 | NEO_init(); // init NeoPixels 20 | 21 | // Boot Flash if key 1 is held 22 | if (!PIN_read(PIN_KEY1)) { // key 1 pressed? 23 | NEO_latch(); // make sure pixels are ready 24 | for (i = 9; i; i--) 25 | NEO_sendByte(127); // light up all pixels 26 | BOOT_now(); // enter bootloader 27 | } 28 | 29 | // Setup 30 | CLK_config(); // configure system clock 31 | MT_init(); 32 | DLY_ms(10); // wait for clock to settle 33 | PIN_low(PIN_LED); // light up LED - blocking activated 34 | 35 | __xdata unsigned int touchCount = 0; 36 | __xdata int lampLight = 0; 37 | __xdata int keysChanged = 0; 38 | // Track key states. Only send updates if the key state has changed. 39 | __xdata int key1Pressed = 0; 40 | __xdata int key2Pressed = 0; 41 | __xdata int key3Pressed = 0; 42 | // 0 for clockwise, 1 for counter-clockwise 43 | __xdata int knobDirection = 0; 44 | __xdata int keyDirty = 0; 45 | 46 | NEO_clearAll(); // clear NeoPixels 47 | 48 | // Loop 49 | while (1) { 50 | keyDirty = 0; 51 | touchCount = 0; 52 | 53 | PIN_toggle(PIN_LED); // toggle LED and function state 54 | 55 | DLY_ms(10); // debounce 56 | 57 | // Check if PIN_KEY1 is pressed 58 | if (!PIN_read(PIN_KEY1)) { // key 1 pressed? 59 | if (!key1Pressed) { 60 | key1Pressed = 1; 61 | keyDirty = 1; 62 | touchCount += 1; 63 | } 64 | } else { 65 | if (key1Pressed) { 66 | key1Pressed = 0; 67 | keyDirty = 1; 68 | } 69 | } 70 | // Check if PIN_KEY2 is pressed 71 | if (!PIN_read(PIN_KEY2)) { // key 2 pressed? 72 | if (!key2Pressed) { 73 | key2Pressed = 1; 74 | keyDirty = 1; 75 | touchCount += 1; 76 | } 77 | } else { 78 | if (key2Pressed) { 79 | key2Pressed = 0; 80 | keyDirty = 1; 81 | } 82 | } 83 | // Check if PIN_KEY3 or PIN_ENC_SW is pressed 84 | if (!PIN_read(PIN_KEY3) || !PIN_read(PIN_ENC_SW)) { 85 | // key 3 / encoder switch pressed? 86 | if (!key3Pressed) { 87 | key3Pressed = 1; 88 | keyDirty = 1; 89 | touchCount += 1; 90 | } 91 | } else { 92 | if (key3Pressed) { 93 | key3Pressed = 0; 94 | keyDirty = 1; 95 | } 96 | } 97 | 98 | // Check if PIN_ENC_A, PIN_ENC_B is pressed or not and update knobDirection 99 | if (!PIN_read(PIN_ENC_A)) { 100 | if(PIN_read(PIN_ENC_B)) { 101 | lampLight = 1; // clockwise? 102 | } 103 | else { 104 | lampLight = 0; // counter-clockwise? 105 | } 106 | DLY_ms(10); // debounce 107 | while(!PIN_read(PIN_ENC_A)); // wait until next detent 108 | keyDirty = 1; 109 | } 110 | 111 | if (keyDirty) { 112 | if (key1Pressed) { 113 | NEO_writeColor(0, 25, 19, 0); 114 | MT_touchDown(touchCount, 1, 0x03fa, 0x01f4); 115 | } else { 116 | if (lampLight) { 117 | NEO_writeColor(0, 5, 1, 0); 118 | } else { 119 | NEO_clearPixel(0); 120 | } 121 | MT_touchUp(touchCount, 1); 122 | } 123 | if (key2Pressed) { 124 | NEO_writeColor(1, 25, 19, 0); 125 | MT_touchDown(touchCount, 2, 0x1388, 0x0fa0); 126 | } else { 127 | if (lampLight) { 128 | NEO_writeColor(1, 5, 1, 0); 129 | } else { 130 | NEO_clearPixel(1); 131 | } 132 | MT_touchUp(touchCount, 2); 133 | } 134 | if (key3Pressed) { 135 | NEO_writeColor(2, 25, 19, 0); 136 | MT_touchDown(touchCount, 3, 0x1fa5, 0x24b6); 137 | } else { 138 | if (lampLight) { 139 | NEO_writeColor(2, 5, 1, 0); 140 | } else { 141 | NEO_clearPixel(2); 142 | } 143 | MT_touchUp(touchCount, 3); 144 | } 145 | } 146 | NEO_update(); // update NeoPixels 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/neo.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // NeoPixel (Addressable LED) Functions for CH551, CH552 and CH554 * v1.2 * 3 | // =================================================================================== 4 | // 5 | // Basic control functions for 800kHz addressable LEDs (NeoPixel). A simplified 6 | // protocol is used which should work with most LEDs. 7 | // 8 | // The following must be defined in config.h: 9 | // PIN_NEO - pin connected to DATA-IN of the pixel strip (via a ~330 ohms resistor). 10 | // NEO_GRB - type of pixel: NEO_GRB or NEO_RGB 11 | // NEO_COUNT - total number of pixels 12 | // System clock frequency must be at least 6 MHz. 13 | // 14 | // Further information: https://github.com/wagiminator/ATtiny13-NeoController 15 | // 2023 by Stefan Wagner: https://github.com/wagiminator 16 | 17 | // =================================================================================== 18 | // Libraries, Variables and Constants 19 | // =================================================================================== 20 | #include "neo.h" 21 | 22 | #define NEOPIN PIN_asm(PIN_NEO) // convert PIN_NEO for inline assembly 23 | __xdata uint8_t NEO_buffer[3 * NEO_COUNT]; // pixel buffer 24 | __xdata uint8_t *ptr; // pixel buffer pointer 25 | 26 | // =================================================================================== 27 | // Protocol Delays 28 | // =================================================================================== 29 | // There are three essential conditions: 30 | // - T0H (HIGH-time for "0"-bit) must be max. 500ns 31 | // - T1H (HIGH-time for "1"-bit) must be min. 625ns 32 | // - TCT (total clock time) must be min. 1150ns 33 | // The bit transmission loop takes 11 clock cycles. 34 | #if F_CPU == 24000000 // 24 MHz system clock 35 | #define T1H_DELAY \ 36 | nop \ 37 | nop \ 38 | nop \ 39 | nop \ 40 | nop \ 41 | nop \ 42 | nop \ 43 | nop \ 44 | nop \ 45 | nop \ 46 | nop // 15 - 4 = 11 clock cycles for min 625ns 47 | #define TCT_DELAY \ 48 | nop \ 49 | nop \ 50 | nop \ 51 | nop \ 52 | nop \ 53 | nop // 28 - 11 - 11 = 6 clock cycles for min 1150ns 54 | #elif F_CPU == 16000000 // 16 MHz system clock 55 | #define T1H_DELAY \ 56 | nop \ 57 | nop \ 58 | nop \ 59 | nop \ 60 | nop \ 61 | nop // 10 - 4 = 6 clock cycles for min 625ns 62 | #define TCT_DELAY \ 63 | nop \ 64 | nop // 19 - 6 - 11 = 2 clock cycles for min 1150ns 65 | #elif F_CPU == 12000000 // 12 MHz system clock 66 | #define T1H_DELAY \ 67 | nop \ 68 | nop \ 69 | nop \ 70 | nop // 8 - 4 = 4 clock cycles for min 625ns 71 | #define TCT_DELAY // 14 - 4 - 11 < 0 clock cycles for min 1150ns 72 | #elif F_CPU == 6000000 // 13 MHz system clock 73 | #define T1H_DELAY // 4 - 4 = 0 clock cycles for min 625ns 74 | #define TCT_DELAY // 7 - 0 - 11 < 0 clock cycles for min 1150ns 75 | #else 76 | #error Unsupported system clock frequency for NeoPixels! 77 | #endif 78 | 79 | // =================================================================================== 80 | // Send a Data Byte to the Pixels String 81 | // =================================================================================== 82 | // This is the most time sensitive part. Outside of the function, it must be 83 | // ensured that interrupts are disabled and that the time between the 84 | // transmission of the individual bytes is less than the pixel's latch time. 85 | void NEO_sendByte(uint8_t data) { 86 | data; // stop unreferenced argument warning 87 | __asm 88 | .even 89 | mov r7, #8 ; 2 CLK - 8 bits to transfer 90 | xch a, dpl ; 2 CLK - data byte -> accu 91 | 01$: 92 | rlc a ; 1 CLK - data bit -> carry (MSB first) 93 | setb NEOPIN ; 2 CLK - NEO pin HIGH 94 | mov NEOPIN, c ; 2 CLK - "0"-bit? -> NEO pin LOW now 95 | T1H_DELAY ; x CLK - TH1 delay 96 | clr NEOPIN ; 2 CLK - "1"-bit? -> NEO pin LOW a little later 97 | TCT_DELAY ; y CLK - TCT delay 98 | djnz r7, 01$ ; 2/4|5|6 CLK - repeat for all bits 99 | __endasm; 100 | } 101 | 102 | // =================================================================================== 103 | // Write Buffer to Pixels 104 | // =================================================================================== 105 | void NEO_update(void) { 106 | uint8_t i; 107 | ptr = NEO_buffer; 108 | EA = 0; 109 | for(i=3*NEO_COUNT; i; i--) NEO_sendByte(*ptr++); 110 | EA = 1; 111 | NEO_latch(); 112 | } 113 | 114 | // =================================================================================== 115 | // Clear all Pixels 116 | // =================================================================================== 117 | void NEO_clearAll(void) { 118 | uint8_t i; 119 | ptr = NEO_buffer; 120 | for(i=3*NEO_COUNT; i; i--) *ptr++ = 0; 121 | NEO_update(); 122 | } 123 | 124 | // =================================================================================== 125 | // Write Color to a Single Pixel in Buffer 126 | // =================================================================================== 127 | void NEO_writeColor(uint8_t pixel, uint8_t r, uint8_t g, uint8_t b) { 128 | ptr = NEO_buffer + (3 * pixel); 129 | #if defined (NEO_GRB) 130 | *ptr++ = g; *ptr++ = r; *ptr = b; 131 | #elif defined (NEO_RGB) 132 | *ptr++ = r; *ptr++ = g; *ptr = b; 133 | #else 134 | #error Wrong or missing NeoPixel type definition! 135 | #endif 136 | } 137 | 138 | // =================================================================================== 139 | // Write Hue Value (0..191) and Brightness (0..2) to a Single Pixel in Buffer 140 | // =================================================================================== 141 | void NEO_writeHue(uint8_t pixel, uint8_t hue, uint8_t bright) { 142 | uint8_t phase = hue >> 6; 143 | uint8_t step = (hue & 63) << bright; 144 | uint8_t nstep = (63 << bright) - step; 145 | switch(phase) { 146 | case 0: NEO_writeColor(pixel, nstep, step, 0); break; 147 | case 1: NEO_writeColor(pixel, 0, nstep, step); break; 148 | case 2: NEO_writeColor(pixel, step, 0, nstep); break; 149 | default: break; 150 | } 151 | } 152 | 153 | // =================================================================================== 154 | // Clear Single Pixel in Buffer 155 | // =================================================================================== 156 | void NEO_clearPixel(uint8_t pixel) { 157 | NEO_writeColor(pixel, 0, 0, 0); 158 | } -------------------------------------------------------------------------------- /src/usb_descr.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB Descriptors 3 | // =================================================================================== 4 | 5 | #include "usb_descr.h" 6 | 7 | // =================================================================================== 8 | // Device Descriptor 9 | // =================================================================================== 10 | __code USB_DEV_DESCR DevDescr = { 11 | .bLength = sizeof(DevDescr), // size of the descriptor in bytes: 18 12 | .bDescriptorType = USB_DESCR_TYP_DEVICE, // device descriptor: 0x01 13 | .bcdUSB = 0x0110, // USB specification: USB 1.1 14 | .bDeviceClass = 0, // interface will define class 15 | .bDeviceSubClass = 0, // unused 16 | .bDeviceProtocol = 0, // unused 17 | .bMaxPacketSize0 = EP0_SIZE, // maximum packet size for Endpoint 0 18 | .idVendor = USB_VENDOR_ID, // VID 19 | .idProduct = USB_PRODUCT_ID, // PID 20 | .bcdDevice = USB_DEVICE_VERSION, // device version 21 | .iManufacturer = 1, // index of Manufacturer String Descr 22 | .iProduct = 2, // index of Product String Descriptor 23 | .iSerialNumber = 3, // index of Serial Number String Descr 24 | .bNumConfigurations = 1 // number of possible configurations 25 | }; 26 | 27 | // =================================================================================== 28 | // Configuration Descriptor 29 | // =================================================================================== 30 | __code USB_CFG_DESCR_HID CfgDescr = { 31 | 32 | // Configuration Descriptor 33 | .config = 34 | { 35 | .bLength = sizeof(USB_CFG_DESCR), // size of the descriptor in bytes 36 | .bDescriptorType = 37 | USB_DESCR_TYP_CONFIG, // configuration descriptor: 0x02 38 | .wTotalLength = sizeof(CfgDescr), // total length in bytes 39 | .bNumInterfaces = 1, // number of interfaces: 1 40 | .bConfigurationValue = 1, // value to select this configuration 41 | .iConfiguration = 0, // no configuration string descriptor 42 | .bmAttributes = 0x80, // attributes = bus powered, no wakeup 43 | .MaxPower = USB_MAX_POWER_mA / 2 // in 2mA units 44 | }, 45 | 46 | // Interface Descriptor 47 | .interface0 = 48 | { 49 | .bLength = 50 | sizeof(USB_ITF_DESCR), // size of the descriptor in bytes: 9 51 | .bDescriptorType = 52 | USB_DESCR_TYP_INTERF, // interface descriptor: 0x04 53 | .bInterfaceNumber = 0, // number of this interface: 0 54 | .bAlternateSetting = 0, // value used to select alternative setting 55 | .bNumEndpoints = 2, // number of endpoints used: 2 56 | .bInterfaceClass = USB_DEV_CLASS_HID, // interface class: HID (0x03) 57 | .bInterfaceSubClass = 1, // boot interface 58 | .bInterfaceProtocol = 1, // keyboard 59 | .iInterface = 4 // interface string descriptor 60 | }, 61 | 62 | // HID Descriptor 63 | .hid0 = 64 | { 65 | .bLength = 66 | sizeof(USB_HID_DESCR), // size of the descriptor in bytes: 9 67 | .bDescriptorType = USB_DESCR_TYP_HID, // HID descriptor: 0x21 68 | .bcdHID = 0x0110, // HID class spec version (BCD: 1.1) 69 | .bCountryCode = 33, // country code: US 70 | .bNumDescriptors = 1, // number of report descriptors: 1 71 | .bDescriptorTypeX = 72 | USB_DESCR_TYP_REPORT, // descriptor type: report (0x22) 73 | .wDescriptorLength = sizeof(ReportDescr) // report descriptor length 74 | }, 75 | 76 | // Endpoint Descriptor: Endpoint 1 (IN, Interrupt) 77 | .ep1IN = 78 | { 79 | .bLength = 80 | sizeof(USB_ENDP_DESCR), // size of the descriptor in bytes: 7 81 | .bDescriptorType = USB_DESCR_TYP_ENDP, // endpoint descriptor: 0x05 82 | .bEndpointAddress = 83 | USB_ENDP_ADDR_EP1_IN, // endpoint: 1, direction: IN (0x81) 84 | .bmAttributes = 85 | USB_ENDP_TYPE_INTER, // transfer type: interrupt (0x03) 86 | .wMaxPacketSize = EP1_SIZE, // max packet size 87 | .bInterval = 10 // polling intervall in ms 88 | }, 89 | 90 | // Endpoint Descriptor: Endpoint 2 (OUT, Interrupt) 91 | .ep2OUT = { 92 | .bLength = sizeof(USB_ENDP_DESCR), // size of the descriptor in bytes: 7 93 | .bDescriptorType = USB_DESCR_TYP_ENDP, // endpoint descriptor: 0x05 94 | .bEndpointAddress = 95 | USB_ENDP_ADDR_EP2_OUT, // endpoint: 2, direction: OUT (0x02) 96 | .bmAttributes = USB_ENDP_TYPE_INTER, // transfer type: interrupt (0x03) 97 | .wMaxPacketSize = EP2_SIZE, // max packet size 98 | .bInterval = 10 // polling intervall in ms 99 | }}; 100 | 101 | // =================================================================================== 102 | // HID Report Descriptor 103 | // =================================================================================== 104 | __code uint8_t ReportDescr[] = { 105 | 0x05, 0x0D, // USAGE_PAGE(Digitizers) 106 | 0x09, 0x04, // USAGE (Touch Screen) 107 | 0xA1, 0x01, // COLLECTION(Application) 108 | 109 | // define the actual amount of fingers that are concurrently touching the 110 | // screen 111 | 0x09, 0x54, // USAGE (Contact count) 112 | 0x25, 0x7f, // LOGICAL_MAXIMUM (128) 113 | 0x95, 0x01, // REPORT_COUNT(1) 114 | 0x75, 0x08, // REPORT_SIZE (8) 115 | 0x81, 0x02, // INPUT (Data,Var,Abs) 116 | // declare a finger collection 117 | 0x05, 0x0D, // USAGE_PAGE(Digitizers) 118 | 0x09, 0x22, // USAGE (Finger) 119 | 0xA1, 0x02, // COLLECTION (Logical) 120 | 121 | // declare an identifier for the finger 122 | 0x09, 0x51, // USAGE (Contact Identifier) 123 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 124 | 0x75, 0x08, // REPORT_SIZE (8) 125 | 0x95, 0x01, // REPORT_COUNT (1) 126 | 0x81, 0x02, // INPUT (Data,Var,Abs) 127 | 128 | // declare Tip Switch & In range 129 | 0x09, 0x42, // USAGE (Tip Switch) 130 | 0x09, 0x32, // USAGE (In Range) 131 | 0x15, 0x00, // LOGICAL_MINIMUM (0) 132 | 0x25, 0x01, // LOGICAL_MAXIMUM (1) 133 | 0x75, 0x01, // REPORT_SIZE (1) 134 | 0x95, 0x02, // REPORT_COUNT(2) 135 | 0x81, 0x02, // INPUT (Data,Var,Abs) 136 | // declare the 6 padding bits as constant so the driver will ignore them 137 | 0x95, 0x06, // REPORT_COUNT (6) 138 | 0x81, 0x03, // INPUT (Cnst,Ary,Abs) 139 | 140 | // declare pressure 141 | 0x09, 0x30, // USAGE (Pressure) 142 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 143 | 0x75, 0x08, // REPORT_SIZE (8) 144 | 0x95, 0x01, // REPORT_COUNT (1) 145 | 0x81, 0x02, // INPUT (Data,Var,Abs) 146 | 147 | // define absolute X and Y coordinates of 16 bit each (percent values 148 | // multiplied with 100) 149 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 150 | 0x09, 0x30, // Usage (X) 151 | 0x09, 0x31, // Usage (Y) 152 | 0x16, 0x00, 0x00, // Logical Minimum (0) 153 | 0x26, 0x10, 0x27, // Logical Maximum (10000) 154 | 0x36, 0x00, 0x00, // Physical Minimum (0) 155 | 0x46, 0x10, 0x27, // Physical Maximum (10000) 156 | 0x66, 0x00, 0x00, // UNIT (None) 157 | 0x75, 0x10, // Report Size (16), 158 | 0x95, 0x02, // Report Count (2), 159 | 0x81, 0x02, // Input (Data,Var,Abs) 160 | 0xC0, // END_COLLECTION 161 | // define the maximum amount of fingers that the device supports 162 | 0x05, 0x0D, // USAGE_PAGE(Digitizers) 163 | 0x09, 0x55, // USAGE (Contact Count Maximum) 164 | 0x25, 0x7f, // LOGICAL_MAXIMUM (127) 165 | 0xB1, 0x02, // FEATURE (Data,Var,Abs) 166 | 167 | 0xC0 // END_COLLECTION 168 | }; 169 | 170 | __code uint8_t ReportDescrLen = sizeof(ReportDescr); 171 | 172 | // =================================================================================== 173 | // String Descriptors 174 | // =================================================================================== 175 | 176 | // Language Descriptor (Index 0) 177 | __code uint16_t LangDescr[] = {((uint16_t)USB_DESCR_TYP_STRING << 8) | 178 | sizeof(LangDescr), 179 | 0x0409}; // US English 180 | 181 | // Manufacturer String Descriptor (Index 1) 182 | __code uint16_t ManufDescr[] = {((uint16_t)USB_DESCR_TYP_STRING << 8) | 183 | sizeof(ManufDescr), 184 | MANUFACTURER_STR}; 185 | 186 | // Product String Descriptor (Index 2) 187 | __code uint16_t ProdDescr[] = { 188 | ((uint16_t)USB_DESCR_TYP_STRING << 8) | sizeof(ProdDescr), PRODUCT_STR}; 189 | 190 | // Serial String Descriptor (Index 3) 191 | __code uint16_t SerDescr[] = { 192 | ((uint16_t)USB_DESCR_TYP_STRING << 8) | sizeof(SerDescr), SERIAL_STR}; 193 | 194 | // Interface String Descriptor (Index 4) 195 | __code uint16_t InterfDescr[] = { 196 | ((uint16_t)USB_DESCR_TYP_STRING << 8) | sizeof(InterfDescr), INTERFACE_STR}; 197 | -------------------------------------------------------------------------------- /src/system.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // Basic System Functions for CH551, CH552 and CH554 * v1.6 * 3 | // =================================================================================== 4 | // 5 | // System clock (CLK)functions available: 6 | // -------------------------------------- 7 | // CLK_config() set system clock frequency according to F_CPU 8 | // CLK_external() set external crystal as clock source 9 | // CLK_internal() set internal oscillator as clock source 10 | // 11 | // Watchdog Timer (WDT) functions available: 12 | // ----------------------------------------- 13 | // WDT_start() start watchdog timer with full period 14 | // WDT_stop() stop watchdog timer 15 | // WDT_reset() reload watchdog timer with full period 16 | // WDT_set(time) reload watchdog timer with specified time in ms 17 | // WDT_feed(value) reload watchdog timer with specified value 18 | // 19 | // Reset (RST) and bootloader functions available: 20 | // ----------------------------------------------- 21 | // RST_now() perform software reset 22 | // RST_keep(value) keep this value after RESET 23 | // RST_getKeep() read the keeped value 24 | // RST_wasWDT() check if last RESET was caused by watchdog timer 25 | // RST_wasPIN() check if last RESET was caused by RST PIN 26 | // RST_wasPWR() check if last RESET was caused by power-on 27 | // RST_wasSOFT() check if last RESET was caused by software 28 | // 29 | // BOOT_now() enter bootloader 30 | // 31 | // Sleep functions available: 32 | // -------------------------- 33 | // SLEEP_now() put device into sleep 34 | // 35 | // WAKE_enable(source) enable wake-up from sleep source (sources see below) 36 | // WAKE_disable(source) disable wake-up from sleep source 37 | // WAKE_all_disable() disable all wake-up sources 38 | // 39 | // WAKE_USB_enable() enable wake-up by USB event 40 | // WAKE_RXD0_enable() enable wake-up by RXD0 low level 41 | // WAKE_RXD1_enable() enable wake-up by RXD1 low level 42 | // WAKE_P13_enable() enable wake-up by pin P1.3 low level 43 | // WAKE_P14_enable() enable wake-up by pin P1.4 low level 44 | // WAKE_P15_enable() enable wake-up by pin P1.5 low level 45 | // WAKE_RST_enable() enable wake-up by pin RST high level 46 | // WAKE_INT_enable() enable wake-up by pin P3.2 edge or pin P3.3 low level 47 | // 48 | // WAKE_USB_disable() disable wake-up by USB event 49 | // WAKE_RXD0_disable() disable wake-up by RXD0 low level 50 | // WAKE_RXD1_disable() disable wake-up by RXD1 low level 51 | // WAKE_P13_disable() disable wake-up by pin P1.3 low level 52 | // WAKE_P14_disable() disable wake-up by pin P1.4 low level 53 | // WAKE_P15_disable() disable wake-up by pin P1.5 low level 54 | // WAKE_RST_disable() disable wake-up by pin RST high level 55 | // WAKE_INT_disable() disable wake-up by pin P3.2 edge or pin P3.3 low level 56 | // 57 | // Wake-up from SLEEP sources: 58 | // --------------------------- 59 | // WAKE_USB wake-up by USB event 60 | // WAKE_RXD0 wake-up by RXD0 low level 61 | // WAKE_RXD1 wake-up by RXD1 low level 62 | // WAKE_P13 wake-up by pin P1.3 low level 63 | // WAKE_P14 wake-up by pin P1.4 low level 64 | // WAKE_P15 wake-up by pin P1.5 low level 65 | // WAKE_RST wake-up by pin RST high level 66 | // WAKE_INT wake-up by pin P3.2 edge or pin P3.3 low level 67 | // 68 | // Interrupt (INT) functions available: 69 | // ------------------------------------ 70 | // INT_enable() global interrupt enable 71 | // INT_disable() global interrupt disable 72 | // INT_ATOMIC_BLOCK { } execute block without being interrupted 73 | // 74 | // 2023 by Stefan Wagner: https://github.com/wagiminator 75 | 76 | #pragma once 77 | #include 78 | #include "ch554.h" 79 | 80 | // =================================================================================== 81 | // System Clock (CLK) Functions 82 | // =================================================================================== 83 | inline void CLK_config(void) { 84 | SAFE_MOD = 0x55; 85 | SAFE_MOD = 0xAA; // enter safe mode 86 | 87 | #if F_CPU == 32000000 88 | __asm__("orl _CLOCK_CFG, #0b00000111"); // 32MHz 89 | #elif F_CPU == 24000000 90 | __asm__("anl _CLOCK_CFG, #0b11111000"); 91 | __asm__("orl _CLOCK_CFG, #0b00000110"); // 24MHz 92 | #elif F_CPU == 16000000 93 | __asm__("anl _CLOCK_CFG, #0b11111000"); 94 | __asm__("orl _CLOCK_CFG, #0b00000101"); // 16MHz 95 | #elif F_CPU == 12000000 96 | __asm__("anl _CLOCK_CFG, #0b11111000"); 97 | __asm__("orl _CLOCK_CFG, #0b00000100"); // 12MHz 98 | #elif F_CPU == 6000000 99 | __asm__("anl _CLOCK_CFG, #0b11111000"); 100 | __asm__("orl _CLOCK_CFG, #0b00000011"); // 6MHz 101 | #elif F_CPU == 3000000 102 | __asm__("anl _CLOCK_CFG, #0b11111000"); 103 | __asm__("orl _CLOCK_CFG, #0b00000010"); // 3MHz 104 | #elif F_CPU == 750000 105 | __asm__("anl _CLOCK_CFG, #0b11111000"); 106 | __asm__("orl _CLOCK_CFG, #0b00000001"); // 750kHz 107 | #elif F_CPU == 187500 108 | __asm__("anl _CLOCK_CFG, #0b11111000"); // 187.5kHz 109 | #else 110 | #warning F_CPU invalid or not set 111 | #endif 112 | 113 | SAFE_MOD = 0x00; // terminate safe mode 114 | } 115 | 116 | inline void CLK_external(void) { 117 | SAFE_MOD = 0x55; 118 | SAFE_MOD = 0xAA; // enter safe mode 119 | CLOCK_CFG |= bOSC_EN_XT; // enable external crystal 120 | CLOCK_CFG &= ~bOSC_EN_INT; // turn off internal oscillator 121 | SAFE_MOD = 0x00; // terminate safe mode 122 | } 123 | 124 | inline void CLK_inernal(void) { 125 | SAFE_MOD = 0x55; 126 | SAFE_MOD = 0xAA; // enter safe mode 127 | CLOCK_CFG |= bOSC_EN_INT; // turn on internal oscillator 128 | CLOCK_CFG &= ~bOSC_EN_XT; // disable external crystal 129 | SAFE_MOD = 0x00; // terminate safe mode 130 | } 131 | 132 | // =================================================================================== 133 | // Watchdog Timer (WDT) Functions 134 | // =================================================================================== 135 | #define WDT_reset() WDOG_COUNT = 0 136 | #define WDT_feed(value) WDOG_COUNT = value 137 | #define WDT_set(time) WDOG_COUNT = (uint8_t)(256 - ((F_CPU / 1000) * time / 65536)) 138 | 139 | inline void WDT_start(void) { 140 | WDOG_COUNT = 0; 141 | SAFE_MOD = 0x55; 142 | SAFE_MOD = 0xAA; 143 | GLOBAL_CFG |= bWDOG_EN; 144 | SAFE_MOD = 0x00; 145 | } 146 | 147 | inline void WDT_stop(void) { 148 | SAFE_MOD = 0x55; 149 | SAFE_MOD = 0xAA; 150 | GLOBAL_CFG &= ~bWDOG_EN; 151 | SAFE_MOD = 0x00; 152 | } 153 | 154 | // =================================================================================== 155 | // Reset (RST) Functions 156 | // =================================================================================== 157 | #define RST_keep(value) RESET_KEEP = value 158 | #define RST_getKeep() (RESET_KEEP) 159 | #define RST_wasWDT() ((PCON & MASK_RST_FLAG) == RST_FLAG_WDOG) 160 | #define RST_wasPIN() ((PCON & MASK_RST_FLAG) == RST_FLAG_PIN) 161 | #define RST_wasPWR() ((PCON & MASK_RST_FLAG) == RST_FLAG_POR) 162 | #define RST_wasSOFT() ((PCON & MASK_RST_FLAG) == RST_FLAG_SW) 163 | 164 | inline void RST_now(void) { 165 | SAFE_MOD = 0x55; 166 | SAFE_MOD = 0xAA; 167 | GLOBAL_CFG |= bSW_RESET; 168 | } 169 | 170 | // =================================================================================== 171 | // Bootloader (BOOT) Functions 172 | // =================================================================================== 173 | inline void BOOT_now(void) { 174 | __asm 175 | ljmp #BOOT_LOAD_ADDR 176 | __endasm; 177 | } 178 | 179 | inline void BOOT_prepare(void) { 180 | ES = 0; 181 | PS = 0; 182 | TMOD = 0; 183 | P1_DIR_PU = 0; 184 | P1_MOD_OC = 0; 185 | P1 = 0xFF; 186 | USB_INT_EN = 0; 187 | USB_CTRL = 0x06; 188 | EA = 0; 189 | } 190 | 191 | // =================================================================================== 192 | // Sleep Functions 193 | // =================================================================================== 194 | #define SLEEP_now() PCON |= PD 195 | 196 | #define WAKE_USB bWAK_BY_USB // wake-up by USB event 197 | #define WAKE_RXD0 bWAK_RXD0_LO // wake-up by RXD0 low level 198 | #define WAKE_RXD1 bWAK_RXD1_LO // wake-up by RXD1 low level 199 | #define WAKE_P13 bWAK_P1_3_LO // wake-up by pin P1.3 low level 200 | #define WAKE_P14 bWAK_P1_4_LO // wake-up by pin P1.4 low level 201 | #define WAKE_P15 bWAK_P1_5_LO // wake-up by pin P1.5 low level 202 | #define WAKE_RST bWAK_RST_HI // wake-up by pin RST high level 203 | #define WAKE_INT bWAK_P3_2E_3L // wake-up by pin P3.2 (INT0) edge or pin P3.3 (INT1) low level 204 | 205 | #define WAKE_enable(source) WAKE_CTRL |= source 206 | #define WAKE_disable(source) WAKE_CTRL &= ~source 207 | #define WAKE_all_disable() WAKE_CTRL = 0 208 | 209 | #define WAKE_USB_enable() WAKE_CTRL |= bWAK_BY_USB 210 | #define WAKE_RXD0_enable() WAKE_CTRL |= bWAK_RXD0_LO 211 | #define WAKE_RXD1_enable() WAKE_CTRL |= bWAK_RXD1_LO 212 | #define WAKE_P13_enable() WAKE_CTRL |= bWAK_P1_3_LO 213 | #define WAKE_P14_enable() WAKE_CTRL |= bWAK_P1_4_LO 214 | #define WAKE_P15_enable() WAKE_CTRL |= bWAK_P1_5_LO 215 | #define WAKE_RST_enable() WAKE_CTRL |= bWAK_RST_HI 216 | #define WAKE_INT_enable() WAKE_CTRL |= bWAK_P3_2E_3L 217 | 218 | #define WAKE_USB_disable() WAKE_CTRL &= ~bWAK_BY_USB 219 | #define WAKE_RXD0_disable() WAKE_CTRL &= ~bWAK_RXD0_LO 220 | #define WAKE_RXD1_disable() WAKE_CTRL &= ~bWAK_RXD1_LO 221 | #define WAKE_P13_disable() WAKE_CTRL &= ~bWAK_P1_3_LO 222 | #define WAKE_P14_disable() WAKE_CTRL &= ~bWAK_P1_4_LO 223 | #define WAKE_P15_disable() WAKE_CTRL &= ~bWAK_P1_5_LO 224 | #define WAKE_RST_disable() WAKE_CTRL &= ~bWAK_RST_HI 225 | #define WAKE_INT_disable() WAKE_CTRL &= ~bWAK_P3_2E_3L 226 | 227 | // =================================================================================== 228 | // Interrupt (INT) Functions 229 | // =================================================================================== 230 | #define INT_enable() EA = 1 231 | #define INT_disable() EA = 0 232 | #define INT_ATOMIC_BLOCK for(EA=0;!EA;EA=1) 233 | -------------------------------------------------------------------------------- /src/usb.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB Constant and Structure Define 3 | // =================================================================================== 4 | 5 | #pragma once 6 | #include 7 | 8 | // USB PID 9 | #ifndef USB_PID_SETUP 10 | #define USB_PID_NULL 0x00 // reserved PID 11 | #define USB_PID_SOF 0x05 12 | #define USB_PID_SETUP 0x0D 13 | #define USB_PID_IN 0x09 14 | #define USB_PID_OUT 0x01 15 | #define USB_PID_ACK 0x02 16 | #define USB_PID_NAK 0x0A 17 | #define USB_PID_STALL 0x0E 18 | #define USB_PID_DATA0 0x03 19 | #define USB_PID_DATA1 0x0B 20 | #define USB_PID_PRE 0x0C 21 | #endif 22 | 23 | // USB standard device request code 24 | #ifndef USB_GET_DESCRIPTOR 25 | #define USB_GET_STATUS 0x00 26 | #define USB_CLEAR_FEATURE 0x01 27 | #define USB_SET_FEATURE 0x03 28 | #define USB_SET_ADDRESS 0x05 29 | #define USB_GET_DESCRIPTOR 0x06 30 | #define USB_SET_DESCRIPTOR 0x07 31 | #define USB_GET_CONFIGURATION 0x08 32 | #define USB_SET_CONFIGURATION 0x09 33 | #define USB_GET_INTERFACE 0x0A 34 | #define USB_SET_INTERFACE 0x0B 35 | #define USB_SYNCH_FRAME 0x0C 36 | #endif 37 | 38 | // USB hub class request code 39 | #ifndef HUB_GET_DESCRIPTOR 40 | #define HUB_GET_STATUS 0x00 41 | #define HUB_CLEAR_FEATURE 0x01 42 | #define HUB_GET_STATE 0x02 43 | #define HUB_SET_FEATURE 0x03 44 | #define HUB_GET_DESCRIPTOR 0x06 45 | #define HUB_SET_DESCRIPTOR 0x07 46 | #endif 47 | 48 | // USB HID class request code 49 | #ifndef HID_GET_REPORT 50 | #define HID_GET_REPORT 0x01 51 | #define HID_GET_IDLE 0x02 52 | #define HID_GET_PROTOCOL 0x03 53 | #define HID_SET_REPORT 0x09 54 | #define HID_SET_IDLE 0x0A 55 | #define HID_SET_PROTOCOL 0x0B 56 | #endif 57 | 58 | // Bit define for USB request type 59 | #ifndef USB_REQ_TYP_MASK 60 | #define USB_REQ_TYP_IN 0x80 // control IN, device to host 61 | #define USB_REQ_TYP_OUT 0x00 // control OUT, host to device 62 | #define USB_REQ_TYP_READ 0x80 // control read, device to host 63 | #define USB_REQ_TYP_WRITE 0x00 // control write, host to device 64 | #define USB_REQ_TYP_MASK 0x60 // bit mask of request type 65 | #define USB_REQ_TYP_STANDARD 0x00 66 | #define USB_REQ_TYP_CLASS 0x20 67 | #define USB_REQ_TYP_VENDOR 0x40 68 | #define USB_REQ_TYP_RESERVED 0x60 69 | #define USB_REQ_RECIP_MASK 0x1F // bit mask of request recipient 70 | #define USB_REQ_RECIP_DEVICE 0x00 71 | #define USB_REQ_RECIP_INTERF 0x01 72 | #define USB_REQ_RECIP_ENDP 0x02 73 | #define USB_REQ_RECIP_OTHER 0x03 74 | #endif 75 | 76 | // USB request type for hub class request 77 | #ifndef HUB_GET_HUB_DESCRIPTOR 78 | #define HUB_CLEAR_HUB_FEATURE 0x20 79 | #define HUB_CLEAR_PORT_FEATURE 0x23 80 | #define HUB_GET_BUS_STATE 0xA3 81 | #define HUB_GET_HUB_DESCRIPTOR 0xA0 82 | #define HUB_GET_HUB_STATUS 0xA0 83 | #define HUB_GET_PORT_STATUS 0xA3 84 | #define HUB_SET_HUB_DESCRIPTOR 0x20 85 | #define HUB_SET_HUB_FEATURE 0x20 86 | #define HUB_SET_PORT_FEATURE 0x23 87 | #endif 88 | 89 | // Hub class feature selectors 90 | #ifndef HUB_PORT_RESET 91 | #define HUB_C_HUB_LOCAL_POWER 0 92 | #define HUB_C_HUB_OVER_CURRENT 1 93 | #define HUB_PORT_CONNECTION 0 94 | #define HUB_PORT_ENABLE 1 95 | #define HUB_PORT_SUSPEND 2 96 | #define HUB_PORT_OVER_CURRENT 3 97 | #define HUB_PORT_RESET 4 98 | #define HUB_PORT_POWER 8 99 | #define HUB_PORT_LOW_SPEED 9 100 | #define HUB_C_PORT_CONNECTION 16 101 | #define HUB_C_PORT_ENABLE 17 102 | #define HUB_C_PORT_SUSPEND 18 103 | #define HUB_C_PORT_OVER_CURRENT 19 104 | #define HUB_C_PORT_RESET 20 105 | #endif 106 | 107 | // USB descriptor type 108 | #ifndef USB_DESCR_TYP_DEVICE 109 | #define USB_DESCR_TYP_DEVICE 0x01 110 | #define USB_DESCR_TYP_CONFIG 0x02 111 | #define USB_DESCR_TYP_STRING 0x03 112 | #define USB_DESCR_TYP_INTERF 0x04 113 | #define USB_DESCR_TYP_ENDP 0x05 114 | #define USB_DESCR_TYP_QUALIF 0x06 115 | #define USB_DESCR_TYP_SPEED 0x07 116 | #define USB_DESCR_TYP_OTG 0x09 117 | #define USB_DESCR_TYP_IAD 0x0B 118 | #define USB_DESCR_TYP_HID 0x21 119 | #define USB_DESCR_TYP_REPORT 0x22 120 | #define USB_DESCR_TYP_PHYSIC 0x23 121 | #define USB_DESCR_TYP_CS_INTF 0x24 122 | #define USB_DESCR_TYP_CS_ENDP 0x25 123 | #define USB_DESCR_TYP_HUB 0x29 124 | #endif 125 | 126 | // USB device class 127 | #ifndef USB_DEV_CLASS_HUB 128 | #define USB_DEV_CLASS_RESERVED 0x00 129 | #define USB_DEV_CLASS_AUDIO 0x01 130 | #define USB_DEV_CLASS_COMM 0x02 131 | #define USB_DEV_CLASS_HID 0x03 132 | #define USB_DEV_CLASS_MONITOR 0x04 133 | #define USB_DEV_CLASS_PHYSIC_IF 0x05 134 | #define USB_DEV_CLASS_POWER 0x06 135 | #define USB_DEV_CLASS_PRINTER 0x07 136 | #define USB_DEV_CLASS_STORAGE 0x08 137 | #define USB_DEV_CLASS_HUB 0x09 138 | #define USB_DEV_CLASS_DATA 0x0A 139 | #define USB_DEV_CLASS_MISC 0xEF 140 | #define USB_DEV_CLASS_VENDOR 0xFF 141 | #endif 142 | 143 | // USB endpoint type and attributes 144 | #ifndef USB_ENDP_TYPE_MASK 145 | #define USB_ENDP_DIR_MASK 0x80 146 | #define USB_ENDP_ADDR_MASK 0x0F 147 | #define USB_ENDP_TYPE_MASK 0x03 148 | #define USB_ENDP_TYPE_CTRL 0x00 149 | #define USB_ENDP_TYPE_ISOCH 0x01 150 | #define USB_ENDP_TYPE_BULK 0x02 151 | #define USB_ENDP_TYPE_INTER 0x03 152 | #define USB_ENDP_ADDR_EP1_OUT 0x01 153 | #define USB_ENDP_ADDR_EP1_IN 0x81 154 | #define USB_ENDP_ADDR_EP2_OUT 0x02 155 | #define USB_ENDP_ADDR_EP2_IN 0x82 156 | #define USB_ENDP_ADDR_EP3_OUT 0x03 157 | #define USB_ENDP_ADDR_EP3_IN 0x83 158 | #define USB_ENDP_ADDR_EP4_OUT 0x04 159 | #define USB_ENDP_ADDR_EP4_IN 0x84 160 | #endif 161 | 162 | #ifndef USB_DEVICE_ADDR 163 | #define USB_DEVICE_ADDR 0x02 // default USB device address 164 | #endif 165 | #ifndef DEFAULT_ENDP0_SIZE 166 | #define DEFAULT_ENDP0_SIZE 8 // default maximum packet size for endpoint 0 167 | #endif 168 | #ifndef DEFAULT_ENDP1_SIZE 169 | #define DEFAULT_ENDP1_SIZE 8 // default maximum packet size for endpoint 1 170 | #endif 171 | #ifndef MAX_PACKET_SIZE 172 | #define MAX_PACKET_SIZE 64 // maximum packet size 173 | #endif 174 | #ifndef USB_BO_CBW_SIZE 175 | #define USB_BO_CBW_SIZE 0x1F // total length of command block CBW 176 | #define USB_BO_CSW_SIZE 0x0D // total length of command status block CSW 177 | #endif 178 | #ifndef USB_BO_CBW_SIG0 179 | #define USB_BO_CBW_SIG0 0x55 // command block CBW identification flag 'USBC' 180 | #define USB_BO_CBW_SIG1 0x53 181 | #define USB_BO_CBW_SIG2 0x42 182 | #define USB_BO_CBW_SIG3 0x43 183 | #define USB_BO_CSW_SIG0 0x55 // command status block CSW identification flag 'USBS' 184 | #define USB_BO_CSW_SIG1 0x53 185 | #define USB_BO_CSW_SIG2 0x42 186 | #define USB_BO_CSW_SIG3 0x53 187 | #endif 188 | 189 | // USB descriptor type defines 190 | typedef struct _USB_SETUP_REQ { 191 | uint8_t bRequestType; 192 | uint8_t bRequest; 193 | uint8_t wValueL; 194 | uint8_t wValueH; 195 | uint8_t wIndexL; 196 | uint8_t wIndexH; 197 | uint8_t wLengthL; 198 | uint8_t wLengthH; 199 | } USB_SETUP_REQ, *PUSB_SETUP_REQ; 200 | typedef USB_SETUP_REQ __xdata *PXUSB_SETUP_REQ; 201 | 202 | typedef struct _USB_DEVICE_DESCR { 203 | uint8_t bLength; 204 | uint8_t bDescriptorType; 205 | uint16_t bcdUSB; 206 | uint8_t bDeviceClass; 207 | uint8_t bDeviceSubClass; 208 | uint8_t bDeviceProtocol; 209 | uint8_t bMaxPacketSize0; 210 | uint16_t idVendor; 211 | uint16_t idProduct; 212 | uint16_t bcdDevice; 213 | uint8_t iManufacturer; 214 | uint8_t iProduct; 215 | uint8_t iSerialNumber; 216 | uint8_t bNumConfigurations; 217 | } USB_DEV_DESCR, *PUSB_DEV_DESCR; 218 | typedef USB_DEV_DESCR __xdata *PXUSB_DEV_DESCR; 219 | 220 | typedef struct _USB_CONFIG_DESCR { 221 | uint8_t bLength; 222 | uint8_t bDescriptorType; 223 | uint16_t wTotalLength; 224 | uint8_t bNumInterfaces; 225 | uint8_t bConfigurationValue; 226 | uint8_t iConfiguration; 227 | uint8_t bmAttributes; 228 | uint8_t MaxPower; 229 | } USB_CFG_DESCR, *PUSB_CFG_DESCR; 230 | typedef USB_CFG_DESCR __xdata *PXUSB_CFG_DESCR; 231 | 232 | typedef struct _USB_INTERF_DESCR { 233 | uint8_t bLength; 234 | uint8_t bDescriptorType; 235 | uint8_t bInterfaceNumber; 236 | uint8_t bAlternateSetting; 237 | uint8_t bNumEndpoints; 238 | uint8_t bInterfaceClass; 239 | uint8_t bInterfaceSubClass; 240 | uint8_t bInterfaceProtocol; 241 | uint8_t iInterface; 242 | } USB_ITF_DESCR, *PUSB_ITF_DESCR; 243 | typedef USB_ITF_DESCR __xdata *PXUSB_ITF_DESCR; 244 | 245 | typedef struct _USB_ITF_ASS_DESCR { 246 | uint8_t bLength; 247 | uint8_t bDescriptorType; 248 | uint8_t bFirstInterface; 249 | uint8_t bInterfaceCount; 250 | uint8_t bFunctionClass; 251 | uint8_t bFunctionSubClass; 252 | uint8_t bFunctionProtocol; 253 | uint8_t iFunction; 254 | } USB_IAD_DESCR, *PUSB_IAD_DESCR; 255 | typedef USB_IAD_DESCR __xdata *PXUSB_IAD_DESCR; 256 | 257 | typedef struct _USB_ENDPOINT_DESCR { 258 | uint8_t bLength; 259 | uint8_t bDescriptorType; 260 | uint8_t bEndpointAddress; 261 | uint8_t bmAttributes; 262 | uint16_t wMaxPacketSize; 263 | uint8_t bInterval; 264 | } USB_ENDP_DESCR, *PUSB_ENDP_DESCR; 265 | typedef USB_ENDP_DESCR __xdata *PXUSB_ENDP_DESCR; 266 | 267 | typedef struct _USB_CONFIG_DESCR_LONG { 268 | USB_CFG_DESCR cfg_descr; 269 | USB_ITF_DESCR itf_descr; 270 | USB_ENDP_DESCR endp_descr[1]; 271 | } USB_CFG_DESCR_LONG, *PUSB_CFG_DESCR_LONG; 272 | typedef USB_CFG_DESCR_LONG __xdata *PXUSB_CFG_DESCR_LONG; 273 | 274 | typedef struct _USB_HUB_DESCR { 275 | uint8_t bDescLength; 276 | uint8_t bDescriptorType; 277 | uint8_t bNbrPorts; 278 | uint16_t wHubCharacteristics; 279 | uint8_t bPwrOn2PwrGood; 280 | uint8_t bHubContrCurrent; 281 | uint8_t DeviceRemovable; 282 | uint8_t PortPwrCtrlMask; 283 | } USB_HUB_DESCR, *PUSB_HUB_DESCR; 284 | typedef USB_HUB_DESCR __xdata *PXUSB_HUB_DESCR; 285 | 286 | typedef struct _USB_HID_DESCR { 287 | uint8_t bLength; 288 | uint8_t bDescriptorType; 289 | uint16_t bcdHID; 290 | uint8_t bCountryCode; 291 | uint8_t bNumDescriptors; 292 | uint8_t bDescriptorTypeX; 293 | uint16_t wDescriptorLength; 294 | } USB_HID_DESCR, *PUSB_HID_DESCR; 295 | typedef USB_HID_DESCR __xdata *PXUSB_HID_DESCR; 296 | 297 | typedef struct _UDISK_BOC_CBW { // command of BulkOnly USB-FlashDisk 298 | uint8_t mCBW_Sig0; 299 | uint8_t mCBW_Sig1; 300 | uint8_t mCBW_Sig2; 301 | uint8_t mCBW_Sig3; 302 | uint8_t mCBW_Tag0; 303 | uint8_t mCBW_Tag1; 304 | uint8_t mCBW_Tag2; 305 | uint8_t mCBW_Tag3; 306 | uint8_t mCBW_DataLen0; 307 | uint8_t mCBW_DataLen1; 308 | uint8_t mCBW_DataLen2; 309 | uint8_t mCBW_DataLen3; // uppest byte of data length, always is 0 310 | uint8_t mCBW_Flag; // transfer direction and etc. 311 | uint8_t mCBW_LUN; 312 | uint8_t mCBW_CB_Len; // length of command block 313 | uint8_t mCBW_CB_Buf[16]; // command block buffer 314 | } UDISK_BOC_CBW, *PUDISK_BOC_CBW; 315 | typedef UDISK_BOC_CBW __xdata *PXUDISK_BOC_CBW; 316 | 317 | typedef struct _UDISK_BOC_CSW { // status of BulkOnly USB-FlashDisk 318 | uint8_t mCSW_Sig0; 319 | uint8_t mCSW_Sig1; 320 | uint8_t mCSW_Sig2; 321 | uint8_t mCSW_Sig3; 322 | uint8_t mCSW_Tag0; 323 | uint8_t mCSW_Tag1; 324 | uint8_t mCSW_Tag2; 325 | uint8_t mCSW_Tag3; 326 | uint8_t mCSW_Residue0; // return: remainder bytes 327 | uint8_t mCSW_Residue1; 328 | uint8_t mCSW_Residue2; 329 | uint8_t mCSW_Residue3; // uppest byte of remainder length, always is 0 330 | uint8_t mCSW_Status; // return: result status 331 | } UDISK_BOC_CSW, *PUDISK_BOC_CSW; 332 | typedef UDISK_BOC_CSW __xdata *PXUDISK_BOC_CSW; 333 | -------------------------------------------------------------------------------- /src/gpio.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // Basic GPIO, PWM and ADC Functions for CH551, CH552 and CH554 * v1.5 * 3 | // =================================================================================== 4 | // 5 | // Pins must be defined as P10, P11, P12, etc. - e.g.: 6 | // #define PIN_LED P33 // LED on pin P3.3 7 | // 8 | // Functions available: 9 | // -------------------- 10 | // PIN_input(PIN) set PIN as INPUT (high impedance, no pullup) 11 | // PIN_input_PU(PIN) set PIN as INPUT with internal PULLUP 12 | // PIN_output(PIN) set PIN as OUTPUT (push-pull) 13 | // PIN_output_OD(PIN) set PIN as OUTPUT (open-drain) 14 | // 15 | // PIN_low(PIN) set PIN output value to LOW 16 | // PIN_high(PIN) set PIN output value to HIGH 17 | // PIN_toggle(PIN) TOGGLE PIN output value 18 | // PIN_read(PIN) read PIN input value 19 | // PIN_write(PIN, val) write PIN output value (0 = LOW / 1 = HIGH) 20 | // 21 | // PIN_asm(PIN) convert PIN for inline assembly: setb PIN_asm(PIN_LED) 22 | // PIN_set(PIN) convert PIN for direct manipulation: PIN_set(PIN_LED) = 1; 23 | // 24 | // PIN_WAKE_enable(PIN) enable wake-up from sleep by PIN low (P13, P14, P15 only) 25 | // PIN_WAKE_disable(PIN) disable wake-up from sleep by PIN low 26 | // 27 | // PWM_start(PIN) start PWM output on PIN, can be (P15 or P30) and (P34 or P31) 28 | // PWM_stop(PIN) stop PWM output on PIN 29 | // PWM_write(PIN, val) set PWM output active level duty cycle on PIN 30 | // 31 | // PWM_pol_normal(PIN) set normal PWM polarity on PIN (default low and active high) 32 | // PWM_pol_reverse(PIN) set reverse PWM polarity on PIN (default high and active low) 33 | // PWM_set_freq(FREQ) set global PWM frequency (in Hertz) 34 | // 35 | // ADC_enable() enable ADC 36 | // ADC_disable() disable ADC 37 | // ADC_fast() set ADC fast mode ( 96 clock cycles per sample, less accurate) 38 | // ADC_slow() set ADC slow mode (384 clock cycles per sample, more accurate) 39 | // ADC_input(PIN) set ADC input pin (P11, P14, P15, P32 only) 40 | // ADC_read() sample and read ADC value (0..255) 41 | // 42 | // CMP_enable() enable comparator 43 | // CMP_disable() disable comparator 44 | // CMP_positive(PIN) set CMP non-inverting input pin (P11, P14, P15, P32 only) 45 | // CMP_negative(PIN) set CMP inverting input pin (P14, P32 only) 46 | // CMP_read() read CMP output (0: pos < neg, 1: pos > neg) 47 | // 48 | // Notes: 49 | // ------ 50 | // Pins used for PWM should be set as OUTPUT beforehand. 51 | // Pins used for ADC or CMP must have been set as INPUT (high impedance) beforehand. 52 | // 53 | // 2022 by Stefan Wagner: https://github.com/wagiminator 54 | 55 | #pragma once 56 | #include 57 | #include "ch554.h" 58 | 59 | // =================================================================================== 60 | // Enumerate pin designators (use these designators to define pins) 61 | // =================================================================================== 62 | 63 | enum{P10, P11, P12, P13, P14, P15, P16, P17, P30, P31, P32, P33, P34, P35, P36, P37}; 64 | 65 | // =================================================================================== 66 | // Helper Defines (these are for internal use only) 67 | // =================================================================================== 68 | 69 | // Define pins for direct bit manipulation 70 | SBIT(PP10, 0x90, 0); 71 | SBIT(PP11, 0x90, 1); 72 | SBIT(PP12, 0x90, 2); 73 | SBIT(PP13, 0x90, 3); 74 | SBIT(PP14, 0x90, 4); 75 | SBIT(PP15, 0x90, 5); 76 | SBIT(PP16, 0x90, 6); 77 | SBIT(PP17, 0x90, 7); 78 | SBIT(PP30, 0xB0, 0); 79 | SBIT(PP31, 0xB0, 1); 80 | SBIT(PP32, 0xB0, 2); 81 | SBIT(PP33, 0xB0, 3); 82 | SBIT(PP34, 0xB0, 4); 83 | SBIT(PP35, 0xB0, 5); 84 | SBIT(PP36, 0xB0, 6); 85 | SBIT(PP37, 0xB0, 7); 86 | 87 | // 2nd-stage glue defines 88 | #define PIN_h_a(PIN) _P##PIN 89 | #define PIN_h_s(PIN) P##PIN 90 | 91 | #define PORT_h_i(PORT, PIN) (P##PORT##_DIR_PU &= ~(1<=P10)&&(PIN<=P17) ? (P1_DIR_PU &= ~(1<<(PIN&7)), P1_MOD_OC &= ~(1<<(PIN&7))) : \ 107 | ((PIN>=P30)&&(PIN<=P37) ? (P3_DIR_PU &= ~(1<<(PIN&7)), P3_MOD_OC &= ~(1<<(PIN&7))) : \ 108 | (0))) 109 | 110 | #define PIN_input_HI PIN_input 111 | #define PIN_input_FL PIN_input 112 | 113 | // =================================================================================== 114 | // Set pin as INPUT with internal PULLUP resistor (also open-drain output, 115 | // when output changes from LOW to HIGH, it will drive HIGH for 2 clock cycles) 116 | // =================================================================================== 117 | #define PIN_input_PU(PIN) \ 118 | ((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC |= (1<<(PIN&7)), P1_DIR_PU |= (1<<(PIN&7))) : \ 119 | ((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC |= (1<<(PIN&7)), P3_DIR_PU |= (1<<(PIN&7))) : \ 120 | (0))) 121 | 122 | // =================================================================================== 123 | // Set pin as OUTPUT (push-pull) 124 | // =================================================================================== 125 | #define PIN_output(PIN) \ 126 | ((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC &= ~(1<<(PIN&7)), P1_DIR_PU |= (1<<(PIN&7))) : \ 127 | ((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC &= ~(1<<(PIN&7)), P3_DIR_PU |= (1<<(PIN&7))) : \ 128 | (0))) 129 | 130 | #define PIN_output_PP PIN_output 131 | 132 | // =================================================================================== 133 | // Set pin as OPEN-DRAIN OUTPUT (also high-impedance input, no pullup) 134 | // =================================================================================== 135 | #define PIN_output_OD(PIN) \ 136 | ((PIN>=P10)&&(PIN<=P17) ? (P1_MOD_OC |= (1<<(PIN&7)), P1_DIR_PU &= ~(1<<(PIN&7))) : \ 137 | ((PIN>=P30)&&(PIN<=P37) ? (P3_MOD_OC |= (1<<(PIN&7)), P3_DIR_PU &= ~(1<<(PIN&7))) : \ 138 | (0))) 139 | 140 | // =================================================================================== 141 | // Pin manipulation macros 142 | // =================================================================================== 143 | #define PIN_low(PIN) PIN_h_s(PIN) = 0 // set pin to LOW 144 | #define PIN_high(PIN) PIN_h_s(PIN) = 1 // set pin to HIGH 145 | #define PIN_toggle(PIN) PIN_h_s(PIN) = !PIN_h_s(PIN) // TOGGLE pin 146 | #define PIN_read(PIN) (PIN_h_s(PIN)) // READ pin 147 | #define PIN_write(PIN, val) PIN_h_s(PIN) = val // WRITE pin value 148 | 149 | // =================================================================================== 150 | // (PORT, PIN) manipulation macros 151 | // =================================================================================== 152 | #define PORT_input(PORT, PIN) PORT_h_i(PORT, PIN) // set pin as INPUT 153 | #define PORT_input_PU(PORT, PIN) PORT_h_iP(PORT, PIN) // set pin as INPUT PULLUP 154 | #define PORT_output(PORT, PIN) PORT_h_o(PORT, PIN) // set pin as OUTPUT 155 | #define PORT_output_OD(PORT, PIN) PORT_h_oO(PORT, PIN) // set pin as OUTPUT OPEN-DRAIN 156 | 157 | #define PORT_low(PORT, PIN) PORT_h_l(PORT, PIN) // set pin to LOW 158 | #define PORT_high(PORT, PIN) PORT_h_h(PORT, PIN) // set pin to HIGH 159 | #define PORT_toggle(PORT, PIN) PORT_h_t(PORT, PIN) // TOGGLE pin 160 | #define PORT_read(PORT, PIN) PORT_h_r(PORT, PIN) // READ pin 161 | #define PORT_write(PORT,PIN,val) PORT_h_w(PORT, PIN, val) // WRITE pin value 162 | 163 | // =================================================================================== 164 | // Convert pin for inline assembly and direct manipulation 165 | // =================================================================================== 166 | #define PIN_asm(PIN) PIN_h_a(PIN) 167 | #define PIN_set(PIN) PIN_h_s(PIN) 168 | 169 | // =================================================================================== 170 | // Enable/disable WAKE-up from sleep by pin LOW (P13, P14, P15 only) 171 | // =================================================================================== 172 | #define WAKE_PIN_enable(PIN) \ 173 | ((PIN == P13) ? (WAKE_CTRL |= bWAK_P1_3_LO) : \ 174 | ((PIN == P14) ? (WAKE_CTRL |= bWAK_P1_4_LO) : \ 175 | ((PIN == P15) ? (WAKE_CTRL |= bWAK_P1_5_LO) : \ 176 | (0))))) 177 | 178 | #define WAKE_PIN_disable(PIN) \ 179 | ((PIN == P13) ? (WAKE_CTRL &= ~bWAK_P1_3_LO) : \ 180 | ((PIN == P14) ? (WAKE_CTRL &= ~bWAK_P1_4_LO) : \ 181 | ((PIN == P15) ? (WAKE_CTRL &= ~bWAK_P1_5_LO) : \ 182 | (0))))) 183 | 184 | // =================================================================================== 185 | // Start PWM on pin, must be a PWM-capable pin: (P15 or P30) and (P34 or P31) 186 | // =================================================================================== 187 | #define PWM_start(PIN) \ 188 | ((PIN == P15) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC &= ~bPWM1_PIN_X, PWM_CTRL |= bPWM1_OUT_EN) : \ 189 | ((PIN == P34) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC &= ~bPWM2_PIN_X, PWM_CTRL |= bPWM2_OUT_EN) : \ 190 | ((PIN == P30) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC |= bPWM1_PIN_X, PWM_CTRL |= bPWM1_OUT_EN) : \ 191 | ((PIN == P31) ? (PWM_CTRL &= ~bPWM_CLR_ALL, PIN_FUNC |= bPWM2_PIN_X, PWM_CTRL |= bPWM2_OUT_EN) : \ 192 | (0))))) 193 | 194 | // =================================================================================== 195 | // Set PWM output active level duty cycle on pin 196 | // =================================================================================== 197 | #define PWM_write(PIN, val) \ 198 | ((PIN == P15) ? (PWM_DATA1 = val) : \ 199 | ((PIN == P34) ? (PWM_DATA2 = val) : \ 200 | ((PIN == P30) ? (PWM_DATA1 = val) : \ 201 | ((PIN == P31) ? (PWM_DATA2 = val) : \ 202 | (0))))) 203 | 204 | // =================================================================================== 205 | // Stop PWM on pin 206 | // =================================================================================== 207 | #define PWM_stop(PIN) \ 208 | ((PIN == P15) ? (PWM_CTRL &= ~bPWM1_OUT_EN) : \ 209 | ((PIN == P34) ? (PWM_CTRL &= ~bPWM2_OUT_EN) : \ 210 | ((PIN == P30) ? (PWM_CTRL &= ~bPWM1_OUT_EN) : \ 211 | ((PIN == P31) ? (PWM_CTRL &= ~bPWM2_OUT_EN) : \ 212 | (0))))) 213 | 214 | // =================================================================================== 215 | // Set normal PWM polarity on pin (default low and active high) 216 | // =================================================================================== 217 | #define PWM_pol_normal(PIN) \ 218 | ((PIN == P15) ? (PWM_CTRL &= ~bPWM1_POLAR) : \ 219 | ((PIN == P34) ? (PWM_CTRL &= ~bPWM2_POLAR) : \ 220 | ((PIN == P30) ? (PWM_CTRL &= ~bPWM1_POLAR) : \ 221 | ((PIN == P31) ? (PWM_CTRL &= ~bPWM2_POLAR) : \ 222 | (0))))) 223 | 224 | // =================================================================================== 225 | // Set reverse PWM polarity on pin (default high and active low) 226 | // =================================================================================== 227 | #define PWM_pol_reverse(PIN) \ 228 | ((PIN == P15) ? (PWM_CTRL |= bPWM1_POLAR) : \ 229 | ((PIN == P34) ? (PWM_CTRL |= bPWM2_POLAR) : \ 230 | ((PIN == P30) ? (PWM_CTRL |= bPWM1_POLAR) : \ 231 | ((PIN == P31) ? (PWM_CTRL |= bPWM2_POLAR) : \ 232 | (0))))) 233 | 234 | // =================================================================================== 235 | // Set global PWM frequency (in Hertz, range: F_CPU/65536 - F_CPU/256) 236 | // =================================================================================== 237 | #define PWM_set_freq(FREQ) \ 238 | (((FREQ) >= F_CPU / 256) ? (PWM_CK_SE = 0) : \ 239 | (((F_CPU / 256 / (FREQ) - 1) > 255) ? (PWM_CK_SE = 255) : \ 240 | (PWM_CK_SE = (uint8_t)(F_CPU / 256 / (FREQ) - 1)) \ 241 | )) 242 | 243 | // =================================================================================== 244 | // Pin to ADC channel conversion (P11, P14, P15, P32 only) 245 | // =================================================================================== 246 | #define ADC_channel(PIN) \ 247 | ((PIN == P11) ? (0) : \ 248 | ((PIN == P14) ? (1) : \ 249 | ((PIN == P15) ? (2) : \ 250 | ((PIN == P32) ? (3) : \ 251 | (0))))) 252 | 253 | // =================================================================================== 254 | // ADC functions (P11, P14, P15, P32 only) 255 | // =================================================================================== 256 | #define ADC_enable() ADC_CFG |= bADC_EN 257 | #define ADC_disable() ADC_CFG &= ~bADC_EN 258 | #define ADC_fast() ADC_CFG |= bADC_CLK 259 | #define ADC_slow() ADC_CFG &= ~bADC_CLK 260 | 261 | #define ADC_input(PIN) \ 262 | ((PIN == P11) ? (ADC_CHAN1 = 0, ADC_CHAN0 = 0) : \ 263 | ((PIN == P14) ? (ADC_CHAN1 = 0, ADC_CHAN0 = 1) : \ 264 | ((PIN == P15) ? (ADC_CHAN1 = 1, ADC_CHAN0 = 0) : \ 265 | ((PIN == P32) ? (ADC_CHAN1 = 1, ADC_CHAN0 = 1) : \ 266 | (0))))) 267 | 268 | inline uint8_t ADC_read(void) { 269 | ADC_START = 1; 270 | while(ADC_START); 271 | return ADC_DATA; 272 | } 273 | 274 | // =================================================================================== 275 | // Pin to comparator inverting input conversion (P14, P32 only) 276 | // =================================================================================== 277 | #define CMP_channel(PIN) \ 278 | ((PIN == P14) ? (0) : \ 279 | ((PIN == P32) ? (1) : \ 280 | (0))) 281 | 282 | // =================================================================================== 283 | // Comparator functions (positive: P11, P14, P15, P32, negative: P14, P32 only) 284 | // =================================================================================== 285 | #define CMP_enable() ADC_CFG |= bCMP_EN 286 | #define CMP_disable() ADC_CFG &= ~bCMP_EN 287 | #define CMP_read() (CMPO) 288 | 289 | #define CMP_positive(PIN) ADC_input(PIN) 290 | #define CMP_negative(PIN) \ 291 | ((PIN == P14) ? (CMP_CHAN = 0) : \ 292 | ((PIN == P32) ? (CMP_CHAN = 1) : \ 293 | (0))) 294 | -------------------------------------------------------------------------------- /tools/chprog.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # =================================================================================== 3 | # Project: chprog - Programming Tool for CH55x Microcontrollers 4 | # Version: v1.2 5 | # Year: 2022 6 | # Author: Stefan Wagner 7 | # Github: https://github.com/wagiminator 8 | # License: MIT License 9 | # =================================================================================== 10 | # 11 | # Description: 12 | # ------------ 13 | # Simple Python tool for flashing CH55x series microcontrollers with bootloader 14 | # versions 1.x and 2.x.x. 15 | # 16 | # References: 17 | # ----------- 18 | # chprog is based on chflasher and wchprog: 19 | # - https://ATCnetz.de (Aaron Christophel) 20 | # - https://github.com/atc1441/chflasher (Aaron Christophel) 21 | # - https://github.com/juliuswwj/wchprog 22 | # 23 | # Dependencies: 24 | # ------------- 25 | # - pyusb 26 | # 27 | # Operating Instructions: 28 | # ----------------------- 29 | # You need to install PyUSB to use chprog. Install it via "python -m pip install pyusb". 30 | # 31 | # Linux users need permission to access the device. Run: 32 | # echo 'SUBSYSTEM=="usb", ATTR{idVendor}=="4348", ATTR{idProduct}=="55e0", MODE="666"' | sudo tee /etc/udev/rules.d/99-ch55x.rules 33 | # sudo udevadm control --reload-rules 34 | # 35 | # On Windows you will need the Zadig tool (https://zadig.akeo.ie/) to install the 36 | # correct driver. Click "Options" and "List All Devices" to select the USB module. 37 | # Then install the libusb-win32 driver. 38 | # 39 | # Connect the CH55x via USB to your PC. The CH55x must be in bootloader mode! 40 | # Run "python3 chprog.py firmware.bin". 41 | 42 | 43 | import usb.core 44 | import usb.util 45 | import sys 46 | 47 | 48 | # =================================================================================== 49 | # Main Function 50 | # =================================================================================== 51 | 52 | def _main(): 53 | if len(sys.argv) != 2: 54 | sys.stderr.write('ERROR: No bin file selected!\n') 55 | sys.exit(1) 56 | 57 | try: 58 | print('Connecting to device ...') 59 | isp = Programmer() 60 | isp.detect() 61 | print('FOUND:', isp.chipname, 'with bootloader v' + isp.bootloader + '.') 62 | print('Erasing chip ...') 63 | isp.erase() 64 | print('Flashing', sys.argv[1], 'to', isp.chipname, '...') 65 | with open(sys.argv[1], 'rb') as f: data = f.read() 66 | isp.flash_data(data) 67 | print('SUCCESS:', len(data), 'bytes written.') 68 | print('Verifying ...') 69 | isp.verify_data(data) 70 | print('SUCCESS:', len(data), 'bytes verified.') 71 | isp.exit() 72 | except Exception as ex: 73 | sys.stderr.write('ERROR: ' + str(ex) + '!\n') 74 | sys.exit(1) 75 | print('DONE.') 76 | sys.exit(0) 77 | 78 | # =================================================================================== 79 | # Programmer Class 80 | # =================================================================================== 81 | 82 | class Programmer: 83 | def __init__(self): 84 | # Find device 85 | dev = usb.core.find(idVendor = CH_USB_VENDOR_ID, idProduct = CH_USB_PRODUCT_ID) 86 | if dev is None: 87 | raise Exception('CH55x not found. Check if device is in BOOT mode') 88 | 89 | # Set configuration, find endpoints 90 | try: 91 | dev.set_configuration() 92 | except: 93 | raise Exception('Failed to access USB Device. Check permissions') 94 | cfg = dev.get_active_configuration() 95 | intf = cfg[(0,0)] 96 | self.epout = usb.util.find_descriptor(intf, custom_match = lambda e: \ 97 | usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_OUT) 98 | self.epin = usb.util.find_descriptor(intf, custom_match = lambda e: \ 99 | usb.util.endpoint_direction(e.bEndpointAddress) == usb.util.ENDPOINT_IN) 100 | assert self.epout is not None 101 | assert self.epin is not None 102 | 103 | # Clear USB receive buffer 104 | try: self.epin.read(CH_USB_PACKET_SIZE, 1) 105 | except: None 106 | 107 | # Set initial chip parameters 108 | self.device = None 109 | self.xorkey = bytearray(CH_XOR_KEY_LEN) 110 | 111 | # Detect, identify and setup chip 112 | def detect(self): 113 | # Identify chip 114 | identanswer = self.__sendcmd(CH_STR_CHIP_DETECT_V2) 115 | if len(identanswer) == 2: 116 | self.chipversion = 1 117 | self.__identchipv1() 118 | elif len(identanswer) == 6: 119 | self.chipversion = 2 120 | self.__identchipv2() 121 | else: 122 | raise Exception('Failed to identify chip') 123 | 124 | # Find device in dictionary 125 | self.chipid = (self.chipfamily << 8) + self.chiptype 126 | for d in DEVICES: 127 | if d['id'] == self.chipid: 128 | self.device = d 129 | if self.device is None: 130 | raise Exception('Unsupported chip (ID: 0x%04x)' % self.chipid) 131 | 132 | # Set parameters according to dictionary 133 | self.chipname = self.device['name'] 134 | self.code_flash_size = self.device['code_size'] 135 | self.data_flash_size = self.device['data_size'] 136 | 137 | # Erase code flash 138 | def erase(self): 139 | if self.chipversion == 1: 140 | self.__erasev1() 141 | else: 142 | self.__erasev2() 143 | 144 | # Write binary file to code flash 145 | def flash_bin(self, filename): 146 | with open(filename, 'rb') as f: data = f.read() 147 | self.erase() 148 | self.flash_data(data) 149 | return len(data) 150 | 151 | # Compare binary file with code flash 152 | def verify_bin(self, filename): 153 | with open(filename, 'rb') as f: data = f.read() 154 | self.verify_data(data) 155 | return len(data) 156 | 157 | # Write data stream to code flash 158 | def flash_data(self, data): 159 | if len(data) > self.code_flash_size: 160 | raise Exception('Not enough memory') 161 | if self.chipversion == 1: 162 | self.__writev1(data, CH_CMD_CODE_WRITE_V1) 163 | else: 164 | self.__writev2(data, CH_CMD_CODE_WRITE_V2) 165 | 166 | # Verify data stream in code flash 167 | def verify_data(self, data): 168 | if len(data) > self.code_flash_size: 169 | raise Exception('Not enough memory') 170 | if self.chipversion == 1: 171 | self.__writev1(data, CH_CMD_CODE_VERIFY_V1) 172 | else: 173 | self.__writev2(data, CH_CMD_CODE_VERIFY_V2) 174 | 175 | # Reboot and exit 176 | def exit(self): 177 | if self.chipversion == 1: 178 | self.__exitv1() 179 | else: 180 | self.__exitv2() 181 | 182 | 183 | # Send command and return reply 184 | def __sendcmd(self, cmd): 185 | self.epout.write(cmd) 186 | try: return self.epin.read(CH_USB_PACKET_SIZE, CH_USB_TIMEOUT) 187 | except: return None 188 | 189 | def __identchipv1(self): 190 | # Read type of chip 191 | identanswer = self.__sendcmd(CH_STR_CHIP_DETECT_V1) 192 | if len(identanswer) != 2: 193 | raise Exception('Failed to identify chip') 194 | 195 | # Read configuration 196 | cfganswer = self.__sendcmd(CH_STR_CONFIG_READ_V1) 197 | if len(cfganswer) != 2: 198 | raise Exception('Failed to read chip configuration') 199 | 200 | # Set chip and configuration values 201 | self.chiptype = identanswer[0] 202 | self.chipfamily = identanswer[1] 203 | self.bootloader = str(cfganswer[0] >> 4) + '.' + str(cfganswer[0] & 0xf) 204 | 205 | def __identchipv2(self): 206 | # Read type of chip 207 | identanswer = self.__sendcmd(CH_STR_CHIP_DETECT_V2) 208 | if len(identanswer) != 6: 209 | raise Exception('Failed to identify chip') 210 | 211 | # Read configuration 212 | cfganswer = self.__sendcmd(CH_STR_CONFIG_READ_V2) 213 | if len(cfganswer) != 30: 214 | raise Exception('Failed to read chip configuration') 215 | 216 | # Set chip and configuration values 217 | self.chiptype = identanswer[4] 218 | self.chipfamily = identanswer[5] 219 | self.configdata = cfganswer[6:18] 220 | self.chipuid = cfganswer[22:26] 221 | self.bootloader = '%d.%d.%d' % (cfganswer[19], cfganswer[20], cfganswer[21]) 222 | if self.chipfamily != 0x11: 223 | raise Exception('Unsupported chip (ID: 0x%02x%02x)' % (self.chipfamily, self.chiptype)) 224 | 225 | # Create local encryption key 226 | sum = 0 227 | for x in range(4): 228 | sum += self.chipuid[x] 229 | for x in range(CH_XOR_KEY_LEN - 1): 230 | self.xorkey[x] = sum & 0xff 231 | self.xorkey[CH_XOR_KEY_LEN - 1] = (sum + self.chiptype) & 0xff 232 | 233 | # Send encryption key 234 | sum = 0 235 | for x in range(CH_XOR_KEY_LEN): 236 | sum += self.xorkey[x] 237 | stream = bytes((CH_CMD_KEY_SET_V2, 0x1e, 0x00)) + bytes(0x1e) 238 | reply = self.__sendcmd(stream) 239 | if reply[4] != (sum & 0xff): 240 | raise Exception('Failed to set encryption key') 241 | 242 | def __erasev1(self): 243 | self.__sendcmd((0xa6, 0x04, 0x00, 0x00, 0x00, 0x00)) 244 | for x in range(self.code_flash_size // 1024): 245 | reply = __sendcmd((0xa9, 0x02, 0x00, x * 4)) 246 | if reply[0] != 0x00: 247 | raise Exception('Failed to erase chip') 248 | 249 | def __erasev2(self): 250 | reply = self.__sendcmd((0xa4, 0x01, 0x00, self.code_flash_size // 1024)) 251 | if reply[4] != 0x00: 252 | raise Exception('Failed to erase chip') 253 | 254 | def __exitv1(self): 255 | self.epout.write(CH_STR_REBOOT_V1) 256 | 257 | def __exitv2(self): 258 | self.epout.write(CH_STR_REBOOT_V2) 259 | 260 | def __writev1(self, data, mode): 261 | # Send data in chunks of 60 bytes 262 | data = bytearray(data) 263 | rest = len(data) 264 | offset = 0 265 | while rest > 0: 266 | if rest >= 0x3c: pkt_len = 0x3c 267 | else: pkt_len = rest 268 | stream = bytes((mode, pkt_len)) 269 | stream += offset.to_bytes(2, byteorder='little') 270 | stream += data[offset:(offset + pkt_len)] 271 | reply = self.__sendcmd(stream) 272 | if reply[0] != 0x00: 273 | if mode == CH_CMD_CODE_WRITE_V1: 274 | raise Exception('Failed to write at offset 0x%08x' % offset) 275 | elif mode == CH_CMD_CODE_VERIFY_V1: 276 | raise Exception('Failed to verify at offset 0x%08x' % offset) 277 | offset += pkt_len 278 | rest -= pkt_len 279 | 280 | def __writev2(self, data, mode): 281 | # Encrypt data 282 | if (len(data) % CH_XOR_KEY_LEN) > 0: 283 | data += b'0xff' * (CH_XOR_KEY_LEN - (len(data) % CH_XOR_KEY_LEN)) 284 | data = bytearray(data) 285 | for x in range(len(data)): 286 | data[x] ^= self.xorkey[x % CH_XOR_KEY_LEN] 287 | 288 | # Send data in chunks of 56 bytes 289 | rest = len(data) 290 | offset = 0 291 | while rest > 0: 292 | if rest >= 0x38: pkt_len = 0x38 293 | else: pkt_len = rest 294 | stream = bytes((mode, pkt_len + 5, 0)) 295 | stream += offset.to_bytes(4, byteorder='little') 296 | stream += (rest & 0xff).to_bytes(1, byteorder='little') 297 | stream += data[offset:(offset + pkt_len)] 298 | reply = self.__sendcmd(stream) 299 | if reply[4] != 0x00 and reply[4] != 0xfe and reply[4] != 0xf5: 300 | if mode == CH_CMD_CODE_WRITE_V2: 301 | raise Exception('Failed to write at offset 0x%08x' % offset) 302 | elif mode == CH_CMD_CODE_VERIFY_V2: 303 | raise Exception('Failed to verify at offset 0x%08x' % offset) 304 | offset += pkt_len 305 | rest -= pkt_len 306 | 307 | # =================================================================================== 308 | # CH55x Protocol Constants 309 | # =================================================================================== 310 | 311 | CH_USB_VENDOR_ID = 0x4348 # VID 312 | CH_USB_PRODUCT_ID = 0x55e0 # PID 313 | CH_USB_PACKET_SIZE = 64 # packet size 314 | CH_USB_TIMEOUT = 5000 # timeout for USB operations 315 | 316 | CH_CMD_CHIP_TYPE_V2 = 0xa2 317 | CH_CMD_REBOOT_V2 = 0xa5 318 | CH_CMD_CODE_ERASE_V2 = 0xa6 319 | CH_CMD_CODE_VERIFY_V1 = 0xa7 320 | CH_CMD_CODE_WRITE_V1 = 0xa8 321 | 322 | CH_CMD_CHIP_TYPE_V2 = 0xa1 323 | CH_CMD_REBOOT_V2 = 0xa2 324 | CH_CMD_KEY_SET_V2 = 0xa3 325 | CH_CMD_CODE_ERASE_V2 = 0xa4 326 | CH_CMD_CODE_WRITE_V2 = 0xa5 327 | CH_CMD_CODE_VERIFY_V2 = 0xa6 328 | 329 | CH_STR_CHIP_DETECT_V1 = (0xa2, 0x13, 0x55, 0x53, 0x42, 0x20, 0x44, 0x42, 0x47, 0x20, 0x43, 330 | 0x48, 0x35, 0x35, 0x39, 0x20, 0x26, 0x20, 0x49, 0x53, 0x50, 0x00) 331 | CH_STR_CONFIG_READ_V1 = (0xbb, 0x00) 332 | CH_STR_CODE_ERASE_V1 = (0xa6, 0x04, 0x00, 0x00, 0x00, 0x00) 333 | CH_STR_REBOOT_V1 = (0xa5, 0x02, 0x01, 0x00) 334 | 335 | CH_STR_CHIP_DETECT_V2 = (0xa1, 0x12, 0x00, 0x52, 0x11, 0x4d, 0x43, 0x55, 0x20, 0x49, 0x53, 336 | 0x50, 0x20, 0x26, 0x20, 0x57, 0x43, 0x48, 0x2e, 0x43, 0x4e) 337 | CH_STR_CONFIG_READ_V2 = (0xa7, 0x02, 0x00, 0x1f, 0x00) 338 | CH_STR_CODE_ERASE_V2 = (0xa4, 0x04, 0x00, 0x08, 0x00, 0x00, 0x00) 339 | CH_STR_REBOOT_V2 = (0xa2, 0x01, 0x00, 0x01) 340 | 341 | CH_XOR_KEY_LEN = 8 342 | 343 | # =================================================================================== 344 | # Device definitions 345 | # =================================================================================== 346 | 347 | DEVICES = [ 348 | {'name': 'CH551', 'id': 0x1151, 'code_size': 10240, 'data_size': 128}, 349 | {'name': 'CH552', 'id': 0x1152, 'code_size': 14336, 'data_size': 128}, 350 | {'name': 'CH554', 'id': 0x1154, 'code_size': 14336, 'data_size': 128}, 351 | {'name': 'CH555', 'id': 0x1155, 'code_size': 61440, 'data_size': 1024}, 352 | {'name': 'CH556', 'id': 0x1156, 'code_size': 61440, 'data_size': 1024}, 353 | {'name': 'CH557', 'id': 0x1157, 'code_size': 61440, 'data_size': 1024}, 354 | {'name': 'CH558', 'id': 0x1158, 'code_size': 61440, 'data_size': 1024}, 355 | {'name': 'CH559', 'id': 0x1159, 'code_size': 61440, 'data_size': 1024} 356 | ] 357 | 358 | # =================================================================================== 359 | 360 | if __name__ == "__main__": 361 | _main() 362 | -------------------------------------------------------------------------------- /src/usb_handler.c: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // USB Handler for CH551, CH552 and CH554 * v1.5 * 3 | // =================================================================================== 4 | 5 | #include "usb_handler.h" 6 | 7 | // =================================================================================== 8 | // Variables 9 | // =================================================================================== 10 | volatile uint8_t USB_SetupReq, USB_SetupTyp, USB_Config, USB_Addr; 11 | volatile uint16_t USB_SetupLen; 12 | volatile __bit USB_ENUM_OK; 13 | __code uint8_t* USB_pDescr; 14 | 15 | // =================================================================================== 16 | // Setup/Reset Endpoints 17 | // =================================================================================== 18 | void USB_EP_init(void) { 19 | UEP0_DMA = (uint16_t)EP0_buffer; // EP0 data transfer address 20 | UEP0_CTRL = UEP_R_RES_ACK // EP0 Manual flip, OUT transaction returns ACK 21 | | UEP_T_RES_NAK; // EP0 IN transaction returns NAK 22 | UEP0_T_LEN = 0; // must be zero at start 23 | USB_ENUM_OK = 0; // reset ENUM flag 24 | 25 | #ifdef USB_INIT_endpoints 26 | USB_INIT_endpoints(); // custom EP init handler 27 | #endif 28 | } 29 | 30 | // =================================================================================== 31 | // USB Init Function 32 | // =================================================================================== 33 | void USB_init(void) { 34 | USB_CTRL = bUC_DEV_PU_EN // USB internal pull-up enable 35 | | bUC_INT_BUSY // return NAK if USB INT flag not clear 36 | | bUC_DMA_EN; // DMA enable 37 | UDEV_CTRL = bUD_PD_DIS // disable UDP/UDM pulldown resistor 38 | | bUD_PORT_EN; // enable port, full-speed 39 | 40 | USB_EP_init(); // setup endpoints 41 | 42 | USB_INT_EN = bUIE_SUSPEND // enable device hang interrupt 43 | | bUIE_TRANSFER // enable USB transfer completion interrupt 44 | | bUIE_BUS_RST; // enable device mode USB bus reset interrupt 45 | 46 | USB_INT_FG = 0x1f; // clear interrupt flags 47 | IE_USB = 1; // enable USB interrupt 48 | EA = 1; // enable global interrupts 49 | } 50 | 51 | // =================================================================================== 52 | // Fast Copy Function 53 | // =================================================================================== 54 | // Copy descriptor *USB_pDescr to EP0_buffer using double pointer 55 | // (Thanks to Ralph Doncaster) 56 | #pragma callee_saves USB_EP0_copyDescr 57 | void USB_EP0_copyDescr(uint8_t len) { 58 | len; // stop unreferenced argument warning 59 | __asm 60 | push acc ; acc -> stack 61 | push ar7 ; r7 -> stack 62 | mov r7, dpl ; r7 <- len 63 | inc _XBUS_AUX ; select dptr1 64 | mov dptr, #_EP0_buffer ; dptr1 <- EP0_buffer 65 | dec _XBUS_AUX ; select dptr0 66 | mov dpl, _USB_pDescr ; dptr0 <- *USB_pDescr 67 | mov dph, (_USB_pDescr + 1) 68 | 01$: 69 | clr a ; acc <- #0 70 | movc a, @a+dptr ; acc <- *USB_pDescr[dptr0] 71 | inc dptr ; inc dptr0 72 | .db 0xA5 ; acc -> EP0_buffer[dptr1] & inc dptr1 73 | djnz r7, 01$ ; repeat len times 74 | mov _USB_pDescr, dpl ; USB_pDescr += len 75 | mov (_USB_pDescr + 1), dph 76 | pop ar7 ; r7 <- stack 77 | pop acc ; acc <- stack 78 | __endasm; 79 | } 80 | 81 | // =================================================================================== 82 | // Endpoint EP0 Handlers 83 | // =================================================================================== 84 | 85 | // Endpoint 0 SETUP handler 86 | void USB_EP0_SETUP(void) { 87 | uint8_t len = 0; // default is success and upload 0 length 88 | USB_SetupLen = ((uint16_t)USB_SetupBuf->wLengthH<<8) | (USB_SetupBuf->wLengthL); 89 | USB_SetupReq = USB_SetupBuf->bRequest; 90 | USB_SetupTyp = USB_SetupBuf->bRequestType; 91 | 92 | if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_STANDARD) { 93 | switch(USB_SetupReq) { // request type 94 | case USB_GET_DESCRIPTOR: 95 | switch(USB_SetupBuf->wValueH) { 96 | 97 | case USB_DESCR_TYP_DEVICE: // Device Descriptor 98 | USB_pDescr = (uint8_t*)&DevDescr; // put descriptor into out buffer 99 | len = sizeof(DevDescr); // descriptor length 100 | break; 101 | 102 | case USB_DESCR_TYP_CONFIG: // Configuration Descriptor 103 | USB_pDescr = (uint8_t*)&CfgDescr; // put descriptor into out buffer 104 | len = sizeof(CfgDescr); // descriptor length 105 | break; 106 | 107 | case USB_DESCR_TYP_STRING: 108 | switch(USB_SetupBuf->wValueL) { // String Descriptor Index 109 | case 0: USB_pDescr = USB_STR_DESCR_i0; break; 110 | case 1: USB_pDescr = USB_STR_DESCR_i1; break; 111 | case 2: USB_pDescr = USB_STR_DESCR_i2; break; 112 | case 3: USB_pDescr = USB_STR_DESCR_i3; break; 113 | #ifdef USB_STR_DESCR_i4 114 | case 4: USB_pDescr = USB_STR_DESCR_i4; break; 115 | #endif 116 | #ifdef USB_STR_DESCR_i5 117 | case 5: USB_pDescr = USB_STR_DESCR_i5; break; 118 | #endif 119 | #ifdef USB_STR_DESCR_i6 120 | case 6: USB_pDescr = USB_STR_DESCR_i6; break; 121 | #endif 122 | #ifdef USB_STR_DESCR_i7 123 | case 7: USB_pDescr = USB_STR_DESCR_i7; break; 124 | #endif 125 | #ifdef USB_STR_DESCR_i8 126 | case 8: USB_pDescr = USB_STR_DESCR_i8; break; 127 | #endif 128 | #ifdef USB_STR_DESCR_i9 129 | case 9: USB_pDescr = USB_STR_DESCR_i9; break; 130 | #endif 131 | #ifdef USB_STR_DESCR_ixee 132 | case 0xee: USB_pDescr = USB_STR_DESCR_ixee; break; 133 | #endif 134 | default: USB_pDescr = USB_STR_DESCR_ix; break; 135 | } 136 | len = USB_pDescr[0]; // descriptor length 137 | break; 138 | 139 | #ifdef USB_REPORT_DESCR 140 | case USB_DESCR_TYP_REPORT: 141 | if(USB_SetupBuf->wValueL == 0) { 142 | USB_pDescr = USB_REPORT_DESCR; 143 | len = USB_REPORT_DESCR_LEN; 144 | } 145 | else len = 0xff; 146 | break; 147 | #endif 148 | 149 | default: 150 | len = 0xff; // unsupported descriptors or error 151 | break; 152 | } 153 | 154 | if(len != 0xff) { 155 | if(USB_SetupLen > len) USB_SetupLen = len; // limit length 156 | len = USB_SetupLen >= EP0_SIZE ? EP0_SIZE : USB_SetupLen; 157 | USB_EP0_copyDescr(len); // copy descriptor to EP0 158 | } 159 | break; 160 | 161 | case USB_SET_ADDRESS: 162 | USB_Addr = USB_SetupBuf->wValueL; // save the assigned address 163 | break; 164 | 165 | case USB_GET_CONFIGURATION: 166 | EP0_buffer[0] = USB_Config; 167 | if(USB_SetupLen > 1) USB_SetupLen = 1; 168 | len = USB_SetupLen; 169 | break; 170 | 171 | case USB_SET_CONFIGURATION: 172 | USB_Config = USB_SetupBuf->wValueL; 173 | USB_ENUM_OK = 1; 174 | break; 175 | 176 | case USB_GET_INTERFACE: 177 | break; 178 | 179 | case USB_SET_INTERFACE: 180 | break; 181 | 182 | case USB_GET_STATUS: 183 | EP0_buffer[0] = 0x00; 184 | EP0_buffer[1] = 0x00; 185 | if(USB_SetupLen > 2) USB_SetupLen = 2; 186 | len = USB_SetupLen; 187 | break; 188 | 189 | case USB_CLEAR_FEATURE: 190 | if((USB_SetupTyp & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { 191 | if(USB_SetupBuf->wValueL == 0x01) { 192 | if(((uint8_t*)&CfgDescr)[7] & 0x20) { 193 | // wake up 194 | } 195 | else len = 0xff; // failed 196 | } 197 | else len = 0xff; // failed 198 | } 199 | else if((USB_SetupTyp & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { 200 | switch(USB_SetupBuf->wIndexL) { 201 | #ifdef EP1_OUT_callback 202 | case 0x01: 203 | UEP1_CTRL = (UEP1_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; 204 | break; 205 | #endif 206 | #ifdef EP1_IN_callback 207 | case 0x81: 208 | UEP1_CTRL = (UEP1_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; 209 | break; 210 | #endif 211 | #ifdef EP2_OUT_callback 212 | case 0x02: 213 | UEP2_CTRL = (UEP2_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; 214 | break; 215 | #endif 216 | #ifdef EP2_IN_callback 217 | case 0x82: 218 | UEP2_CTRL = (UEP2_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; 219 | break; 220 | #endif 221 | #ifdef EP3_OUT_callback 222 | case 0x03: 223 | UEP3_CTRL = (UEP3_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; 224 | break; 225 | #endif 226 | #ifdef EP3_IN_callback 227 | case 0x83: 228 | UEP3_CTRL = (UEP3_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; 229 | break; 230 | #endif 231 | #ifdef EP4_OUT_callback 232 | case 0x04: 233 | UEP4_CTRL = (UEP4_CTRL & ~(bUEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; 234 | break; 235 | #endif 236 | #ifdef EP4_IN_callback 237 | case 0x84: 238 | UEP4_CTRL = (UEP4_CTRL & ~(bUEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; 239 | break; 240 | #endif 241 | default: 242 | len = 0xff; // unsupported endpoint 243 | break; 244 | } 245 | } 246 | else len = 0xff; // unsupported for non-endpoint 247 | break; 248 | 249 | case USB_SET_FEATURE: 250 | if((USB_SetupTyp & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_DEVICE) { 251 | if(USB_SetupBuf->wValueL == 0x01) { 252 | if( !(((uint8_t*)&CfgDescr)[7] & 0x20) ) len = 0xff; // failed 253 | } 254 | else len = 0xff; // failed 255 | } 256 | else if((USB_SetupTyp & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) { 257 | if(USB_SetupBuf->wValueL == 0x00) { 258 | switch(USB_SetupBuf->wIndexL) { 259 | #ifdef EP1_OUT_callback 260 | case 0x01: 261 | UEP1_CTRL = (UEP1_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; 262 | break; 263 | #endif 264 | #ifdef EP1_IN_callback 265 | case 0x81: 266 | UEP1_CTRL = (UEP1_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; 267 | break; 268 | #endif 269 | #ifdef EP2_OUT_callback 270 | case 0x02: 271 | UEP2_CTRL = (UEP2_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; 272 | break; 273 | #endif 274 | #ifdef EP2_IN_callback 275 | case 0x82: 276 | UEP2_CTRL = (UEP2_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; 277 | break; 278 | #endif 279 | #ifdef EP3_OUT_callback 280 | case 0x03: 281 | UEP3_CTRL = (UEP3_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; 282 | break; 283 | #endif 284 | #ifdef EP3_IN_callback 285 | case 0x83: 286 | UEP3_CTRL = (UEP3_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; 287 | break; 288 | #endif 289 | #ifdef EP4_OUT_callback 290 | case 0x04: 291 | UEP4_CTRL = (UEP4_CTRL & ~bUEP_R_TOG) | UEP_R_RES_STALL; 292 | break; 293 | #endif 294 | #ifdef EP4_IN_callback 295 | case 0x84: 296 | UEP4_CTRL = (UEP4_CTRL & ~bUEP_T_TOG) | UEP_T_RES_STALL; 297 | break; 298 | #endif 299 | default: 300 | len = 0xff; // failed 301 | break; 302 | } 303 | } 304 | else len = 0xff; // failed 305 | } 306 | else len = 0xff; // failed 307 | break; 308 | 309 | default: 310 | len = 0xff; // failed 311 | break; 312 | } 313 | } 314 | 315 | #ifdef USB_CLASS_SETUP_handler 316 | else if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_CLASS) { 317 | len = USB_CLASS_SETUP_handler(); 318 | } 319 | #endif 320 | 321 | #ifdef USB_VENDOR_SETUP_handler 322 | else if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_VENDOR) { 323 | len = USB_VENDOR_SETUP_handler(); 324 | } 325 | #endif 326 | 327 | else len = 0xff; 328 | 329 | if(len == 0xff) { // stall 330 | USB_SetupReq = 0xff; 331 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL 332 | } 333 | else { // transmit data to host or send 0-length packet 334 | USB_SetupLen -= len; 335 | UEP0_T_LEN = len; 336 | UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; 337 | } 338 | } 339 | 340 | // Endpoint 0 IN handler 341 | void USB_EP0_IN(void) { 342 | uint8_t len; 343 | 344 | #ifdef USB_CLASS_IN_handler 345 | if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_CLASS) { 346 | USB_CLASS_IN_handler(); 347 | return; 348 | } 349 | #endif 350 | 351 | #ifdef USB_VENDOR_IN_handler 352 | if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_VENDOR) { 353 | USB_VENDOR_IN_handler(); 354 | return; 355 | } 356 | #endif 357 | 358 | switch(USB_SetupReq) { 359 | case USB_GET_DESCRIPTOR: 360 | len = USB_SetupLen >= EP0_SIZE ? EP0_SIZE : USB_SetupLen; 361 | USB_EP0_copyDescr(len); // copy descriptor to EP0 362 | USB_SetupLen -= len; 363 | UEP0_T_LEN = len; 364 | UEP0_CTRL ^= bUEP_T_TOG; // switch between DATA0 and DATA1 365 | break; 366 | 367 | case USB_SET_ADDRESS: 368 | USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | USB_Addr; 369 | UEP0_CTRL = bUEP_R_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; 370 | break; 371 | 372 | default: 373 | UEP0_CTRL = bUEP_R_TOG | UEP_T_RES_NAK | UEP_R_RES_ACK; 374 | break; 375 | } 376 | 377 | 378 | } 379 | 380 | // Endpoint 0 OUT handler 381 | void USB_EP0_OUT(void) { 382 | #ifdef USB_CLASS_OUT_handler 383 | if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_CLASS) { 384 | USB_CLASS_OUT_handler(); 385 | return; 386 | } 387 | #endif 388 | 389 | #ifdef USB_VENDOR_OUT_handler 390 | if((USB_SetupTyp & USB_REQ_TYP_MASK) == USB_REQ_TYP_VENDOR) { 391 | USB_VENDOR_OUT_handler(); 392 | return; 393 | } 394 | #endif 395 | 396 | UEP0_CTRL = bUEP_T_TOG | UEP_T_RES_ACK | UEP_R_RES_ACK; 397 | } 398 | 399 | // =================================================================================== 400 | // USB Interrupt Service Routine 401 | // =================================================================================== 402 | #pragma save 403 | #pragma nooverlay 404 | void USB_interrupt(void) { 405 | 406 | // USB transfer completed interrupt 407 | if(UIF_TRANSFER) { 408 | // Dispatch to service functions 409 | uint8_t callIndex = USB_INT_ST & MASK_UIS_ENDP; 410 | switch (USB_INT_ST & MASK_UIS_TOKEN) { 411 | 412 | case UIS_TOKEN_SETUP: 413 | EP0_SETUP_callback(); 414 | break; 415 | 416 | case UIS_TOKEN_IN: 417 | switch (callIndex) { 418 | case 0: EP0_IN_callback(); break; 419 | #ifdef EP1_IN_callback 420 | case 1: EP1_IN_callback(); break; 421 | #endif 422 | #ifdef EP2_IN_callback 423 | case 2: EP2_IN_callback(); break; 424 | #endif 425 | #ifdef EP3_IN_callback 426 | case 3: EP3_IN_callback(); break; 427 | #endif 428 | #ifdef EP4_IN_callback 429 | case 4: EP4_IN_callback(); break; 430 | #endif 431 | default: break; 432 | } 433 | break; 434 | 435 | case UIS_TOKEN_OUT: 436 | switch (callIndex) { 437 | case 0: EP0_OUT_callback(); break; 438 | #ifdef EP1_OUT_callback 439 | case 1: EP1_OUT_callback(); break; 440 | #endif 441 | #ifdef EP2_OUT_callback 442 | case 2: EP2_OUT_callback(); break; 443 | #endif 444 | #ifdef EP3_OUT_callback 445 | case 3: EP3_OUT_callback(); break; 446 | #endif 447 | #ifdef EP4_OUT_callback 448 | case 4: EP4_OUT_callback(); break; 449 | #endif 450 | default: break; 451 | } 452 | break; 453 | } 454 | UIF_TRANSFER = 0; // clear interrupt flag 455 | } 456 | 457 | // USB bus suspend or wakeup event interrupt 458 | if(UIF_SUSPEND) { 459 | UIF_SUSPEND = 0; // clear interrupt flag 460 | #ifdef USB_SUSPEND_handler 461 | if(USB_MIS_ST & bUMS_SUSPEND) { 462 | SAFE_MOD = 0x55; 463 | SAFE_MOD = 0xAA; 464 | WAKE_CTRL |= bWAK_BY_USB; // enable wakeup by USB 465 | USB_SUSPEND_handler(); // custom suspend handler (PCON |= PD;) 466 | SAFE_MOD = 0x55; 467 | SAFE_MOD = 0xAA; 468 | WAKE_CTRL &= ~bWAK_BY_USB; // disable wakeup by USB 469 | } 470 | #endif 471 | } 472 | 473 | // USB bus reset event interrupt 474 | if(UIF_BUS_RST) { 475 | #ifdef USB_RESET_handler 476 | USB_RESET_handler(); // custom reset handler 477 | #endif 478 | USB_EP_init(); // reset endpoints 479 | USB_DEV_AD = 0x00; // reset device address 480 | USB_INT_FG = 0x1f; // clear all interrupt flags 481 | } 482 | } 483 | #pragma restore 484 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🦾 comma three Faux-Touch keyboard 2 | 3 | *Long arms for those of us with short arms from birth or those who can't afford arm extension surgery!* 4 | 5 | aka. macropad or comma macropad (but not from comma!) 6 | 7 | ![touchkey keyboard demo](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/d9617916-2442-4287-b430-709dad173da8) 8 | 9 | These are instructions and firmware for a relatively cheap off-the-shelf macro keyboard off AliExpress/Amazon (that has many copies/clones) to control a comma three running [openpilot](https://github.com/commaai/openpilot) from an accessible and comfortable driver's position. 10 | 11 | No more this and reaching out when you want to bookmark a segment or toggle experimental mode: 12 | 13 | ![touch](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/d6085e3b-109d-4347-a9d0-cbc847b3c234) 14 | 15 | The macro keyboard we will be using looks like this and comes in this configuration: 16 | 17 | ![Picture of keyboard](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/bf44187f-1143-46d3-bb61-b068b7270087) 18 | 19 | The default configuration software and firmware on these kinds of keyboards is notoriously bad, sketchy in origin, and may not be trustworthy. Most importantly, it won't work for our use case where we need to send touchscreen input. So, don't bother downloading and don't install the configuration software. We will be throwing that all out. 20 | 21 | Instead, we are flashing the keyboard's microprocessor to pretend to be a USB touchscreen digitizer, and the buttons to send touch events to the comma three. The new firmware touch areas are currently hardcoded to the bottom left corner for bookmark, the slight-left of center for hide/show menu, and the top right corner for experimental mode toggling. The knob is used to control the LEDs to be a "lamp" light for night driving use and pressing down on it is an alternative button for the top right corner button pressing. 22 | 23 | On some forks such as [FrogPilot](https://github.com/FrogAi/FrogPilot), the keyboard can also be used to press optional on-screen widgets such as distance adjustment which happens to also be in the bottom-left. This useful for vehicles lacking equivalent physical buttons such as Non-ACC Bolts or Volts. Traffic Mode in FrogPilot can also be activated by a long touch and as this keyboard can faithfully translate touch down and touch up from button presses down and button presses up, the keyboard can do that too. 24 | 25 | These keyboards are built around the [`CH552G`][ch552info] microcontroller. By shorting two pads together on initial power, the keyboard can be put into bootloader mode, and the new touchscreen-emulation firmware can then be flashed over USB. It is very easy to take apart the keyboard and to short these two pads. 26 | 27 | Restoring the original vendor firmware is not possible without the original manufacturer's firmware which I haven't been able to find yet. That said, somewhat similar functional firmwares to the original functionality without the sketchy vendor software can be found here if you want to "reverse" the process and restore the keyboard to something like its original functionality as a macro keyboard: 28 | 29 | * https://github.com/biemster/3keys_1knob 30 | * https://github.com/eccherda/ch552g_mini_keyboard/ 31 | * https://github.com/semickolon/fak (This one is pretty hardcore!) 32 | 33 | ## User Groups 34 | 35 | * [Frogpilot Discord](https://github.com/FrogAi/FrogPilot?tab=readme-ov-file#discord) 36 | * ["macropad enjoyers" thread](https://discord.com/channels/1137853399715549214/1235731637573259284) 37 | 38 | ## Bill of Materials 39 | 40 | Cost: Expect the cost to be about $3-20 for the keyboard, $2-10 for the male USB-C to female USB-A adapter, and an optional $6-10 for nicities like 90 degree USB-C angle adapters for a cleaner look. You may also need a USB-C extension cable. The rest of the materials you probably have lying around. The cost can be $14 to $40 depending on how long you want to wait for the materials to arrive from AliExpress, if you're in a hurry and want to buy from Amazon, or how clean you want the install to look. 41 | 42 | ### Keyboard 43 | 44 | ![3Keys-Mechanical-Keyboard-For-Photoshop-USB-Macro-Custom-Keyboard-RGB-Gaming-Custom-Programming-Knob-Mini-Keyboard jpg_](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/9c643f4a-c5e8-464b-b5f0-c03f875083f7) 45 | 46 | A specific type of mass-produced macro keyboard with a [`CH552G`][ch552info] microcontroller. The one this project supports and what I used was this: 47 | 48 | * https://www.aliexpress.us/item/3256806441586710.html 49 | 50 | * Note that sometimes these keyboards are on sale for $5 from vendors. 51 | * https://www.aliexpress.us/item/3256806441586710.html 52 | * image 53 | 54 | * https://amzn.to/3Q7Mw5c 55 | 56 | Go for AliExpress if you want to save money and don't mind waiting. Go for Amazon if you want it faster and have Prime. 57 | 58 | As there are many vendors of this keyboard, there is no steady name other than a similar look, so keep an eye for these traits when looking for an equivalent keyboard: 59 | 60 | * Looks like the keyboard in those links I have above. 61 | * Shows up when you search for "3 keys 1 knob keyboard" 62 | * 3 keys in a row 63 | * 1 knob, metal-looking usually 64 | * Acryllic layered construction with rounded corners 65 | * Exposed screws heads on bottom and top 66 | * Multi-color LEDs 67 | * USB-C is offset a bit torwards the knob side of the keyboard and not in the center. 68 | * Comes with a male USB-A to male USB-C cable 69 | * No wireless. 70 | * A link to a sketchy file hosting site for configuration software, "email us for software" call to action, or even **no** instruction 71 | * Has a black or white variant. Color doesn't matter, choose your preference. 72 | * Tends to come with red switches 73 | 74 | These will usually guarantee you get a keyboard with the `CH552G` microcontroller present in the manner we need. 75 | 76 | The keyboard will also come with a 1 meter long male USB-A to male USB-C cable. 77 | 78 | #### Optional Customizations 79 | 80 | It is a mechanical keyboard! You can replace the stock red switches with whatever you like along with the keycaps. Tactile or clickly switch replacement is popular. Keycaps/Switches are also sold on Amazon, AliExpress, and wherever you want to buy them. You might spend more on switches and keycaps than the keyboard. 81 | 82 | ### Male USB-C to Female USB-A cable 83 | 84 | Unfortunately, the keyboard is not perfect. It is missing two resistors in it that allow it to be powered by a USB-C port in a USB-C to USB-C setup. However, we need to power it from the comma three's USB-C port. While it is theoretically possible to solder in the right resistors, it is easier to just use a cable to convert the comma three USB-C port to a USB-A port. The longer, the better and here are some examples: 85 | 86 | * https://amzn.to/4aFOj9I 87 | 88 | * https://www.aliexpress.us/item/3256806084714064.html 89 | 90 | ### Right Angle Adapters 91 | 92 | These are optional, but they help reduce cable strain on the cable at the comma three's USB-C port and clean up the cables in the area with the keyboard attached to your car. 93 | 94 | * https://amzn.to/3U3WtSu - This is a pack of 5 adapters with 3 of them being useful to get the angles right to reduce strain and clean up the cables. 95 | * https://www.aliexpress.us/item/3256805061903701.html 96 | * Purchase "Color": 1, 4, 5 97 | 98 | ### Male USB-C to Female USB-C Extension Cable 99 | 100 | This is optional. Without it, the setup barely fits in my Corolla. If you got the 5 pack of adapters from Amazon above, there's a female to female adapter you can use to extend the cable with a male USB-C to male USB-C cable alternatively if you'll like. 101 | 102 | Search on Amazon or AliExpress for "USB-C extension cable". 103 | 104 | ### Mounting Tape 105 | 106 | You can attach the keyboard to your car however you like. I used large 3M Command Picture Hanging Strips to attach the keyboard in front of my gear shifter. They are strong enough to hold the keyboard in place and can be fully removed without damaging the car. The strips are also velcro-like so you can remove the keyboard to change it or reprogram it away from the car without disturbing the tape too. 107 | 108 | https://amzn.to/49Nm87A 109 | 110 | Of course, you can use whatever else you like for mounting. 111 | 112 | AliExpress has command strip-like products as well, but I haven't tried them yet: 113 | 114 | https://www.aliexpress.us/w/wholesale-3m-command-picture-hanging-strips.html 115 | 116 | ### Shorting Tools 117 | 118 | Some tape can be helpful in covering up stuff you don't want to short out on the keyboard. This is optional. 119 | 120 | ## Instructions 121 | 122 | ### (Windows) Preparing your Windows computer to flash 123 | 124 | You will need to use Zadig to make the device when it is in bootloader mode available to flashing software. 125 | 126 | 1. Download Zadig from https://zadig.akeo.ie/ 127 | 2. Run Zadig 128 | 3. Under devices, select `Create New Device`. 129 | 1. ![zadig_create_new_device](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/5fad813d-7202-4c03-9d69-1e5a01985c0e) 130 | 4. Fill in three fields. The first field is just a description and you can fill in anything. The next two fields are very important. Fill them in with 4348 and 55e0 respectively. Press "Install Driver" and give it a few minutes to install. 131 | 1. ![fill it in this way](https://github.com/nelsonjchen/c3-touchkey-keyboard/assets/5363/c0280b31-646e-43bc-a01b-6269a9c0be70) 132 | 133 | If you still have issues, try other machines, Macs, Linux machines, Chromebooks, or even an Android phone. 134 | 135 | ### (Ubuntu Linux) Preparing Ubuntu Linux to allow the device to flash via a Chromium-based browser 136 | 137 | You will need to create a udev rule to allow your user account to access the device when it is in bootloader mode. 138 | 139 | 1. Open a terminal and enter the following commands to create the udev rule: 140 | 141 | ```bash 142 | sudo tee /etc/udev/rules.d/50-ch552-flash.rules < B 253 | B[Straight USB-C Male to Female USB-A] --> C 254 | C[Angle and Twisted USB-C Male to USB-C Female Adapter] --> D 255 | D[Male USB-C to Female USB-A Cable] --> E 256 | E["(Came with Keyboard) Male-USB-A to Male USB-C Cable"] --> F 257 | F[Angled Female USB-C to Male USB-C adapter] --> G 258 | E --> H 259 | H["(Optional) Male USB-C to Female USB-C Extension Cable"] --> F 260 | C --> I 261 | I["(Optional) Male USB-C to Female USB-C Extension Cable"] --> D 262 | G[Keyboard] 263 | 264 | ``` 265 | 266 | ## Updating the firmware with the new firmware 267 | 268 | If you ever need to update the firmware with the new firmware, the old firmware can be put into bootloader mode by holding the key furthest away from the knob while plugging it into the computer. All the LEDs should light up in full white when this is done. The new firmware can then be flashed without shorting the pins using the web flasher. 269 | 270 | ## Known Issues 271 | 272 | * There is iffy support in Windows. Testing the keyboard on Windows may yield weird behaviors but as it is not the target of this project, those bugs are left as-is. Bugs may include touch-down and touch-up emulation. It is best to test on a Linux-based device. 273 | * Do not disconnect the keyboard during normal operation. The C3 itself may crash or kernel panic. It's unknown what causes this but touchscreen hot-removal in the C3 OS and environment might not be as well tested. As this is not a normal thing to do, this is left as-is. 274 | 275 | ## Development 276 | 277 | See the Makefile and try to get `make flash` going. You'll need sdcc, Python with pyusb, and build tools. 278 | 279 | `sudo libinput debug-events` is your friend. You may need to `apt update -y` and `apt install -y libinput-tools` to get it. 280 | 281 | ## Inspirations and References 282 | 283 | This firmware is based on the work of the following projects: 284 | 285 | * https://github.com/biemster/3keys_1knob/ - Showed me the possibility of flashing these keyboards and some implementation reference. 286 | * https://github.com/wagiminator/MCU-Templates - the basis for `3keys_1knob` and a good reference for clean CH55X code. 287 | * https://github.com/eccherda/ch552g_mini_keyboard/blob/master/readme.md#setting-up-the-keyboard-in-bootloader-mode - Bootloader mode instructions about the R12 resistor pad come from there 288 | 289 | ## License 290 | 291 | CC-BY-SA 3.0 as it is mostly based on https://github.com/wagiminator/MCU-Templates/blob/main/CH552/LICENSE . See LICENSE.md for more details. 292 | 293 | [ch552info]: https://hackaday.com/2019/02/17/how-to-program-a-really-cheap-microcontroller/ 294 | -------------------------------------------------------------------------------- /src/ch554.h: -------------------------------------------------------------------------------- 1 | // =================================================================================== 2 | // Header File for CH551, CH552 and CH554 Microcontrollers * v1.0 * 3 | // =================================================================================== 4 | // This contains a copy of CH554.H 5 | /*************************************** 6 | ** Copyright (C) W.ch 1999-2014 ** 7 | ** Web: http://wch.cn ** 8 | ***************************************/ 9 | 10 | #pragma once 11 | #include 12 | 13 | typedef unsigned char volatile __xdata UINT8XV; 14 | typedef unsigned char volatile __pdata UINT8PV; 15 | 16 | #define SBIT(name, addr, bit) __sbit __at(addr+bit) name 17 | #define SFR(name, addr) __sfr __at(addr) name 18 | #define SFRX(name, addr) __xdata volatile unsigned char __at(addr) name 19 | #define SFR16(name, addr) __sfr16 __at(((addr+1U)<<8) | addr) name 20 | #define SFR16E(name, fulladdr) __sfr16 __at(fulladdr) name 21 | #define SFR32(name, addr) __sfr32 __at(((addr+3UL)<<24) | ((addr+2UL)<<16) | ((addr+1UL)<<8) | addr) name 22 | #define SFR32E(name, fulladdr) __sfr32 __at(fulladdr) name 23 | 24 | /*----- SFR --------------------------------------------------------------*/ 25 | /* sbit are bit addressable, others are byte addressable */ 26 | 27 | /* System Registers */ 28 | SFR(PSW, 0xD0); // program status word 29 | SBIT(CY, 0xD0, 7); // carry flag 30 | SBIT(AC, 0xD0, 6); // auxiliary carry flag 31 | SBIT(F0, 0xD0, 5); // bit addressable general purpose flag 0 32 | SBIT(RS1, 0xD0, 4); // register R0-R7 bank selection high bit 33 | SBIT(RS0, 0xD0, 3); // register R0-R7 bank selection low bit 34 | #define MASK_PSW_RS 0x18 // bit mask of register R0-R7 bank selection 35 | // RS1 & RS0: register R0-R7 bank selection 36 | // 00 - bank 0, R0-R7 @ address 0x00-0x07 37 | // 01 - bank 1, R0-R7 @ address 0x08-0x0F 38 | // 10 - bank 2, R0-R7 @ address 0x10-0x17 39 | // 11 - bank 3, R0-R7 @ address 0x18-0x1F 40 | SBIT(OV, 0xD0, 2); // overflow flag 41 | SBIT(F1, 0xD0, 1); // bit addressable general purpose flag 1 42 | SBIT(P, 0xD0, 0); // ReadOnly: parity flag 43 | SFR(ACC, 0xE0); // accumulator 44 | SFR(B, 0xF0); // general purpose register B 45 | SFR(SP, 0x81); // stack pointer 46 | //sfr16 DPTR = 0x82; // DPTR pointer, little-endian 47 | SFR(DPL, 0x82); // data pointer low 48 | SFR(DPH, 0x83); // data pointer high 49 | SFR(SAFE_MOD, 0xA1); // WriteOnly: writing safe mode 50 | //sfr CHIP_ID = 0xA1; // ReadOnly: reading chip ID 51 | #define CHIP_ID SAFE_MOD 52 | SFR(GLOBAL_CFG, 0xB1); // global config, Write@SafeMode 53 | #define bBOOT_LOAD 0x20 // ReadOnly: boot loader status for discriminating BootLoader or Application: set 1 by power on reset, clear 0 by software reset 54 | #define bSW_RESET 0x10 // software reset bit, auto clear by hardware 55 | #define bCODE_WE 0x08 // enable flash-ROM (include code & Data-Flash) being program or erasing: 0=writing protect, 1=enable program and erase 56 | #define bDATA_WE 0x04 // enable Data-Flash (flash-ROM data area) being program or erasing: 0=writing protect, 1=enable program and erase 57 | #define bLDO3V3_OFF 0x02 // disable 5V->3.3V LDO: 0=enable LDO for USB and internal oscillator under 5V power, 1=disable LDO, V33 pin input external 3.3V power 58 | #define bWDOG_EN 0x01 // enable watch-dog reset if watch-dog timer overflow: 0=as timer only, 1=enable reset if timer overflow 59 | 60 | /* Clock and Sleep and Power Registers */ 61 | SFR(PCON, 0x87); // power control and reset flag 62 | #define SMOD 0x80 // baud rate selection for UART0 mode 1/2/3: 0=slow(Fsys/128 @mode2, TF1/32 @mode1/3, no effect for TF2), 63 | // 1=fast(Fsys/32 @mode2, TF1/16 @mode1/3, no effect for TF2) 64 | #define bRST_FLAG1 0x20 // ReadOnly: recent reset flag high bit 65 | #define bRST_FLAG0 0x10 // ReadOnly: recent reset flag low bit 66 | #define MASK_RST_FLAG 0x30 // ReadOnly: bit mask of recent reset flag 67 | #define RST_FLAG_SW 0x00 68 | #define RST_FLAG_POR 0x10 69 | #define RST_FLAG_WDOG 0x20 70 | #define RST_FLAG_PIN 0x30 71 | // bPC_RST_FLAG1 & bPC_RST_FLAG0: recent reset flag 72 | // 00 - software reset, by bSW_RESET=1 @(bBOOT_LOAD=0 or bWDOG_EN=1) 73 | // 01 - power on reset 74 | // 10 - watch-dog timer overflow reset 75 | // 11 - external input manual reset by RST pin 76 | #define GF1 0x08 // general purpose flag bit 1 77 | #define GF0 0x04 // general purpose flag bit 0 78 | #define PD 0x02 // power-down enable bit, auto clear by wake-up hardware 79 | SFR(CLOCK_CFG, 0xB9); // system clock config: lower 3 bits for system clock Fsys, Write@SafeMode 80 | #define bOSC_EN_INT 0x80 // internal oscillator enable and original clock selection: 1=enable & select internal clock, 0=disable & select external clock 81 | #define bOSC_EN_XT 0x40 // external oscillator enable, need quartz crystal or ceramic resonator between XI and XO pins 82 | #define bWDOG_IF_TO 0x20 // ReadOnly: watch-dog timer overflow interrupt flag, cleared by reload watch-dog count or auto cleared when MCU enter interrupt routine 83 | #define bROM_CLK_FAST 0x10 // flash-ROM clock frequency selection: 0=normal(for Fosc>=16MHz), 1=fast(for Fosc<16MHz) 84 | #define bRST 0x08 // ReadOnly: pin RST input 85 | #define bT2EX_ 0x08 // alternate pin for T2EX 86 | #define bCAP2_ 0x08 // alternate pin for CAP2 87 | #define MASK_SYS_CK_SEL 0x07 // bit mask of system clock Fsys selection 88 | /* 89 | Fxt = 24MHz(8MHz~25MHz for non-USB application), from external oscillator @XI&XO 90 | Fosc = bOSC_EN_INT ? 24MHz : Fxt 91 | Fpll = Fosc * 4 => 96MHz (32MHz~100MHz for non-USB application) 92 | Fusb4x = Fpll / 2 => 48MHz (Fixed) 93 | MASK_SYS_CK_SEL[2] [1] [0] 94 | Fsys = Fpll/3 = 32MHz: 1 1 1 95 | Fsys = Fpll/4 = 24MHz: 1 1 0 96 | Fsys = Fpll/6 = 16MHz: 1 0 1 97 | Fsys = Fpll/8 = 12MHz: 1 0 0 98 | Fsys = Fpll/16 = 6MHz: 0 1 1 99 | Fsys = Fpll/32 = 3MHz: 0 1 0 100 | Fsys = Fpll/128 = 750KHz: 0 0 1 101 | Fsys = Fpll/512 =187.5KHz: 0 0 0 102 | */ 103 | SFR(WAKE_CTRL, 0xA9); // wake-up control, Write@SafeMode 104 | #define bWAK_BY_USB 0x80 // enable wake-up by USB event 105 | #define bWAK_RXD1_LO 0x40 // enable wake-up by RXD1 low level 106 | #define bWAK_P1_5_LO 0x20 // enable wake-up by pin P1.5 low level 107 | #define bWAK_P1_4_LO 0x10 // enable wake-up by pin P1.4 low level 108 | #define bWAK_P1_3_LO 0x08 // enable wake-up by pin P1.3 low level 109 | #define bWAK_RST_HI 0x04 // enable wake-up by pin RST high level 110 | #define bWAK_P3_2E_3L 0x02 // enable wake-up by pin P3.2 (INT0) edge or pin P3.3 (INT1) low level 111 | #define bWAK_RXD0_LO 0x01 // enable wake-up by RXD0 low level 112 | SFR(RESET_KEEP, 0xFE); // value keeper during reset 113 | SFR(WDOG_COUNT, 0xFF); // watch-dog count, count by clock frequency Fsys/65536 114 | 115 | /* Interrupt Registers */ 116 | SFR(IE, 0xA8); // interrupt enable 117 | SBIT(EA, 0xA8, 7); // enable global interrupts: 0=disable, 1=enable if E_DIS=0 118 | SBIT(E_DIS, 0xA8, 6); // disable global interrupts, intend to inhibit interrupt during some flash-ROM operation: 0=enable if EA=1, 1=disable 119 | SBIT(ET2, 0xA8, 5); // enable timer2 interrupt 120 | SBIT(ES, 0xA8, 4); // enable UART0 interrupt 121 | SBIT(ET1, 0xA8, 3); // enable timer1 interrupt 122 | SBIT(EX1, 0xA8, 2); // enable external interrupt INT1 123 | SBIT(ET0, 0xA8, 1); // enable timer0 interrupt 124 | SBIT(EX0, 0xA8, 0); // enable external interrupt INT0 125 | SFR(IP, 0xB8); // interrupt priority and current priority 126 | SBIT(PH_FLAG, 0xB8, 7); // ReadOnly: high level priority action flag 127 | SBIT(PL_FLAG, 0xB8, 6); // ReadOnly: low level priority action flag 128 | // PH_FLAG & PL_FLAG: current interrupt priority 129 | // 00 - no interrupt now 130 | // 01 - low level priority interrupt action now 131 | // 10 - high level priority interrupt action now 132 | // 11 - unknown error 133 | SBIT(PT2, 0xB8, 5); // timer2 interrupt priority level 134 | SBIT(PS, 0xB8, 4); // UART0 interrupt priority level 135 | SBIT(PT1, 0xB8, 3); // timer1 interrupt priority level 136 | SBIT(PX1, 0xB8, 2); // external interrupt INT1 priority level 137 | SBIT(PT0, 0xB8, 1); // timer0 interrupt priority level 138 | SBIT(PX0, 0xB8, 0); // external interrupt INT0 priority level 139 | SFR(IE_EX, 0xE8); // extend interrupt enable 140 | SBIT(IE_WDOG, 0xE8, 7); // enable watch-dog timer interrupt 141 | SBIT(IE_GPIO, 0xE8, 6); // enable GPIO input interrupt 142 | SBIT(IE_PWMX, 0xE8, 5); // enable PWM1/2 interrupt 143 | SBIT(IE_UART1, 0xE8, 4); // enable UART1 interrupt 144 | SBIT(IE_ADC, 0xE8, 3); // enable ADC interrupt 145 | SBIT(IE_USB, 0xE8, 2); // enable USB interrupt 146 | SBIT(IE_TKEY, 0xE8, 1); // enable touch-key timer interrupt 147 | SBIT(IE_SPI0, 0xE8, 0); // enable SPI0 interrupt 148 | SFR(IP_EX, 0xE9); // extend interrupt priority 149 | #define bIP_LEVEL 0x80 // ReadOnly: current interrupt nested level: 0=no interrupt or two levels, 1=one level 150 | #define bIP_GPIO 0x40 // GPIO input interrupt priority level 151 | #define bIP_PWMX 0x20 // PWM1/2 interrupt priority level 152 | #define bIP_UART1 0x10 // UART1 interrupt priority level 153 | #define bIP_ADC 0x08 // ADC interrupt priority level 154 | #define bIP_USB 0x04 // USB interrupt priority level 155 | #define bIP_TKEY 0x02 // touch-key timer interrupt priority level 156 | #define bIP_SPI0 0x01 // SPI0 interrupt priority level 157 | SFR(GPIO_IE, 0xC7); // GPIO interrupt enable 158 | #define bIE_IO_EDGE 0x80 // enable GPIO edge interrupt: 0=low/high level, 1=falling/rising edge 159 | #define bIE_RXD1_LO 0x40 // enable interrupt by RXD1 low level / falling edge 160 | #define bIE_P1_5_LO 0x20 // enable interrupt by pin P1.5 low level / falling edge 161 | #define bIE_P1_4_LO 0x10 // enable interrupt by pin P1.4 low level / falling edge 162 | #define bIE_P1_3_LO 0x08 // enable interrupt by pin P1.3 low level / falling edge 163 | #define bIE_RST_HI 0x04 // enable interrupt by pin RST high level / rising edge 164 | #define bIE_P3_1_LO 0x02 // enable interrupt by pin P3.1 low level / falling edge 165 | #define bIE_RXD0_LO 0x01 // enable interrupt by RXD0 low level / falling edge 166 | 167 | /* FlashROM and Data-Flash Registers */ 168 | SFR16(ROM_ADDR, 0x84); // address for flash-ROM, little-endian 169 | SFR(ROM_ADDR_L, 0x84); // address low byte for flash-ROM 170 | SFR(ROM_ADDR_H, 0x85); // address high byte for flash-ROM 171 | SFR16(ROM_DATA, 0x8E); // data for flash-ROM writing, little-endian 172 | SFR(ROM_DATA_L, 0x8E); // data low byte for flash-ROM writing, data byte for Data-Flash reading/writing 173 | SFR(ROM_DATA_H, 0x8F); // data high byte for flash-ROM writing 174 | SFR(ROM_CTRL, 0x86); // WriteOnly: flash-ROM control 175 | #define ROM_CMD_WRITE 0x9A // WriteOnly: flash-ROM word or Data-Flash byte write operation command 176 | #define ROM_CMD_READ 0x8E // WriteOnly: Data-Flash byte read operation command 177 | //sfr ROM_STATUS = 0x86; // ReadOnly: flash-ROM status 178 | #define ROM_STATUS ROM_CTRL 179 | #define bROM_ADDR_OK 0x40 // ReadOnly: flash-ROM writing operation address valid flag, can be reviewed before or after operation: 0=invalid parameter, 1=address valid 180 | #define bROM_CMD_ERR 0x02 // ReadOnly: flash-ROM operation command error flag: 0=command accepted, 1=unknown command 181 | 182 | /* Port Registers */ 183 | SFR(P1, 0x90); // port 1 input & output 184 | SBIT(SCK, 0x90, 7); // serial clock for SPI0 185 | SBIT(TXD1, 0x90, 7); // TXD output for UART1 186 | SBIT(TIN5, 0x90, 7); // TIN5 for Touch-Key 187 | SBIT(MISO, 0x90, 6); // master serial data input or slave serial data output for SPI0 188 | SBIT(RXD1, 0x90, 6); // RXD input for UART1 189 | SBIT(TIN4, 0x90, 6); // TIN4 for Touch-Key 190 | SBIT(MOSI, 0x90, 5); // master serial data output or slave serial data input for SPI0 191 | SBIT(PWM1, 0x90, 5); // PWM output for PWM1 192 | SBIT(TIN3, 0x90, 5); // TIN3 for Touch-Key 193 | SBIT(UCC2, 0x90, 5); // CC2 for USB type-C 194 | SBIT(AIN2, 0x90, 5); // AIN2 for ADC 195 | SBIT(T2_, 0x90, 4); // alternate pin for T2 196 | SBIT(CAP1_, 0x90, 4); // alternate pin for CAP1 197 | SBIT(SCS, 0x90, 4); // slave chip-selection input for SPI0 198 | SBIT(TIN2, 0x90, 4); // TIN2 for Touch-Key 199 | SBIT(UCC1, 0x90, 4); // CC1 for USB type-C 200 | SBIT(AIN1, 0x90, 4); // AIN1 for ADC 201 | SBIT(TXD_, 0x90, 3); // alternate pin for TXD of UART0 202 | SBIT(RXD_, 0x90, 2); // alternate pin for RXD of UART0 203 | SBIT(T2EX, 0x90, 1); // external trigger input for timer2 reload & capture 204 | SBIT(CAP2, 0x90, 1); // capture2 input for timer2 205 | SBIT(TIN1, 0x90, 1); // TIN1 for Touch-Key 206 | SBIT(VBUS2, 0x90, 1); // VBUS2 for USB type-C 207 | SBIT(AIN0, 0x90, 1); // AIN0 for ADC 208 | SBIT(T2, 0x90, 0); // external count input 209 | SBIT(CAP1, 0x90, 0); // capture1 input for timer2 210 | SBIT(TIN0, 0x90, 0); // TIN0 for Touch-Key 211 | SFR(P1_MOD_OC, 0x92); // port 1 output mode: 0=push-pull, 1=open-drain 212 | SFR(P1_DIR_PU, 0x93); // port 1 direction for push-pull or pullup enable for open-drain 213 | // Pn_MOD_OC & Pn_DIR_PU: pin input & output configuration for Pn (n=1/3) 214 | // 0 0: float input only, without pullup resistance 215 | // 0 1: push-pull output, strong driving high level and low level 216 | // 1 0: open-drain output and input without pullup resistance 217 | // 1 1: quasi-bidirectional (standard 8051 mode), open-drain output and input with pullup resistance, just driving high level strongly for 2 clocks if turning output level from low to high 218 | #define bSCK 0x80 // serial clock for SPI0 219 | #define bTXD1 0x80 // TXD output for UART1 220 | #define bMISO 0x40 // master serial data input or slave serial data output for SPI0 221 | #define bRXD1 0x40 // RXD input for UART1 222 | #define bMOSI 0x20 // master serial data output or slave serial data input for SPI0 223 | #define bPWM1 0x20 // PWM output for PWM1 224 | #define bUCC2 0x20 // CC2 for USB type-C 225 | #define bAIN2 0x20 // AIN2 for ADC 226 | #define bT2_ 0x10 // alternate pin for T2 227 | #define bCAP1_ 0x10 // alternate pin for CAP1 228 | #define bSCS 0x10 // slave chip-selection input for SPI0 229 | #define bUCC1 0x10 // CC1 for USB type-C 230 | #define bAIN1 0x10 // AIN1 for ADC 231 | #define bTXD_ 0x08 // alternate pin for TXD of UART0 232 | #define bRXD_ 0x04 // alternate pin for RXD of UART0 233 | #define bT2EX 0x02 // external trigger input for timer2 reload & capture 234 | #define bCAP2 bT2EX // capture2 input for timer2 235 | #define bVBUS2 0x02 // VBUS2 for USB type-C 236 | #define bAIN0 0x02 // AIN0 for ADC 237 | #define bT2 0x01 // external count input or clock output for timer2 238 | #define bCAP1 bT2 // capture1 input for timer2 239 | SFR(P2, 0xA0); // port 2 240 | SFR(P3, 0xB0); // port 3 input & output 241 | SBIT(UDM, 0xB0, 7); // ReadOnly: pin UDM input 242 | SBIT(UDP, 0xB0, 6); // ReadOnly: pin UDP input 243 | SBIT(T1, 0xB0, 5); // external count input for timer1 244 | SBIT(PWM2, 0xB0, 4); // PWM output for PWM2 245 | SBIT(RXD1_, 0xB0, 4); // alternate pin for RXD1 246 | SBIT(T0, 0xB0, 4); // external count input for timer0 247 | SBIT(INT1, 0xB0, 3); // external interrupt 1 input 248 | SBIT(TXD1_, 0xB0, 2); // alternate pin for TXD1 249 | SBIT(INT0, 0xB0, 2); // external interrupt 0 input 250 | SBIT(VBUS1, 0xB0, 2); // VBUS1 for USB type-C 251 | SBIT(AIN3, 0xB0, 2); // AIN3 for ADC 252 | SBIT(PWM2_, 0xB0, 1); // alternate pin for PWM2 253 | SBIT(TXD, 0xB0, 1); // TXD output for UART0 254 | SBIT(PWM1_, 0xB0, 0); // alternate pin for PWM1 255 | SBIT(RXD, 0xB0, 0); // RXD input for UART0 256 | SFR(P3_MOD_OC, 0x96); // port 3 output mode: 0=push-pull, 1=open-drain 257 | SFR(P3_DIR_PU, 0x97); // port 3 direction for push-pull or pullup enable for open-drain 258 | #define bUDM 0x80 // ReadOnly: pin UDM input 259 | #define bUDP 0x40 // ReadOnly: pin UDP input 260 | #define bT1 0x20 // external count input for timer1 261 | #define bPWM2 0x10 // PWM output for PWM2 262 | #define bRXD1_ 0x10 // alternate pin for RXD1 263 | #define bT0 0x10 // external count input for timer0 264 | #define bINT1 0x08 // external interrupt 1 input 265 | #define bTXD1_ 0x04 // alternate pin for TXD1 266 | #define bINT0 0x04 // external interrupt 0 input 267 | #define bVBUS1 0x04 // VBUS1 for USB type-C 268 | #define bAIN3 0x04 // AIN3 for ADC 269 | #define bPWM2_ 0x02 // alternate pin for PWM2 270 | #define bTXD 0x02 // TXD output for UART0 271 | #define bPWM1_ 0x01 // alternate pin for PWM1 272 | #define bRXD 0x01 // RXD input for UART0 273 | SFR(PIN_FUNC, 0xC6); // pin function selection 274 | #define bUSB_IO_EN 0x80 // USB UDP/UDM I/O pin enable: 0=P3.6/P3.7 as GPIO, 1=P3.6/P3.7 as USB 275 | #define bIO_INT_ACT 0x40 // ReadOnly: GPIO interrupt request action status 276 | #define bUART1_PIN_X 0x20 // UART1 alternate pin enable: 0=RXD1/TXD1 on P1.6/P1.7, 1=RXD1/TXD1 on P3.4/P3.2 277 | #define bUART0_PIN_X 0x10 // UART0 alternate pin enable: 0=RXD0/TXD0 on P3.0/P3.1, 1=RXD0/TXD0 on P1.2/P1.3 278 | #define bPWM2_PIN_X 0x08 // PWM2 alternate pin enable: 0=PWM2 on P3.4, 1=PWM2 on P3.1 279 | #define bPWM1_PIN_X 0x04 // PWM1 alternate pin enable: 0=PWM1 on P1.5, 1=PWM1 on P3.0 280 | #define bT2EX_PIN_X 0x02 // T2EX/CAP2 alternate pin enable: 0=T2EX/CAP2 on P1.1, 1=T2EX/CAP2 on RST 281 | #define bT2_PIN_X 0x01 // T2/CAP1 alternate pin enable: 0=T2/CAP1 on P1.1, 1=T2/CAP1 on P1.4 282 | SFR(XBUS_AUX, 0xA2); // xBUS auxiliary setting 283 | #define bUART0_TX 0x80 // ReadOnly: indicate UART0 transmittal status 284 | #define bUART0_RX 0x40 // ReadOnly: indicate UART0 receiving status 285 | #define bSAFE_MOD_ACT 0x20 // ReadOnly: safe mode action status 286 | #define GF2 0x08 // general purpose flag bit 2 287 | #define bDPTR_AUTO_INC 0x04 // enable DPTR auto increase if finished MOVX_@DPTR instruction 288 | #define DPS 0x01 // dual DPTR selection: 0=DPTR0 selected, 1=DPTR1 selected 289 | 290 | /* Timer0/1 Registers */ 291 | SFR(TCON, 0x88); // timer 0/1 control and external interrupt control 292 | SBIT(TF1, 0x88, 7); // timer1 overflow & interrupt flag, auto cleared when MCU enter interrupt routine 293 | SBIT(TR1, 0x88, 6); // timer1 run enable 294 | SBIT(TF0, 0x88, 5); // timer0 overflow & interrupt flag, auto cleared when MCU enter interrupt routine 295 | SBIT(TR0, 0x88, 4); // timer0 run enable 296 | SBIT(IE1, 0x88, 3); // INT1 interrupt flag, auto cleared when MCU enter interrupt routine 297 | SBIT(IT1, 0x88, 2); // INT1 interrupt type: 0=low level action, 1=falling edge action 298 | SBIT(IE0, 0x88, 1); // INT0 interrupt flag, auto cleared when MCU enter interrupt routine 299 | SBIT(IT0, 0x88, 0); // INT0 interrupt type: 0=low level action, 1=falling edge action 300 | SFR(TMOD, 0x89); // timer 0/1 mode 301 | #define bT1_GATE 0x80 // gate control of timer1: 0=timer1 run enable while TR1=1, 1=timer1 run enable while P3.3 (INT1) pin is high and TR1=1 302 | #define bT1_CT 0x40 // counter or timer mode selection for timer1: 0=timer, use internal clock, 1=counter, use P3.5 (T1) pin falling edge as clock 303 | #define bT1_M1 0x20 // timer1 mode high bit 304 | #define bT1_M0 0x10 // timer1 mode low bit 305 | #define MASK_T1_MOD 0x30 // bit mask of timer1 mode 306 | // bT1_M1 & bT1_M0: timer1 mode 307 | // 00: mode 0, 13-bit timer or counter by cascaded TH1 and lower 5 bits of TL1, the upper 3 bits of TL1 are ignored 308 | // 01: mode 1, 16-bit timer or counter by cascaded TH1 and TL1 309 | // 10: mode 2, TL1 operates as 8-bit timer or counter, and TH1 provide initial value for TL1 auto-reload 310 | // 11: mode 3, stop timer1 311 | #define bT0_GATE 0x08 // gate control of timer0: 0=timer0 run enable while TR0=1, 1=timer0 run enable while P3.2 (INT0) pin is high and TR0=1 312 | #define bT0_CT 0x04 // counter or timer mode selection for timer0: 0=timer, use internal clock, 1=counter, use P3.4 (T0) pin falling edge as clock 313 | #define bT0_M1 0x02 // timer0 mode high bit 314 | #define bT0_M0 0x01 // timer0 mode low bit 315 | #define MASK_T0_MOD 0x03 // bit mask of timer0 mode 316 | // bT0_M1 & bT0_M0: timer0 mode 317 | // 00: mode 0, 13-bit timer or counter by cascaded TH0 and lower 5 bits of TL0, the upper 3 bits of TL0 are ignored 318 | // 01: mode 1, 16-bit timer or counter by cascaded TH0 and TL0 319 | // 10: mode 2, TL0 operates as 8-bit timer or counter, and TH0 provide initial value for TL0 auto-reload 320 | // 11: mode 3, TL0 is 8-bit timer or counter controlled by standard timer0 bits, TH0 is 8-bit timer using TF1 and controlled by TR1, timer1 run enable if it is not mode 3 321 | SFR(TL0, 0x8A); // low byte of timer 0 count 322 | SFR(TL1, 0x8B); // low byte of timer 1 count 323 | SFR(TH0, 0x8C); // high byte of timer 0 count 324 | SFR(TH1, 0x8D); // high byte of timer 1 count 325 | 326 | /* UART0 Registers */ 327 | SFR(SCON, 0x98); // UART0 control (serial port control) 328 | SBIT(SM0, 0x98, 7); // UART0 mode bit0, selection data bit: 0=8 bits data, 1=9 bits data 329 | SBIT(SM1, 0x98, 6); // UART0 mode bit1, selection baud rate: 0=fixed, 1=variable 330 | // SM0 & SM1: UART0 mode 331 | // 00 - mode 0, shift Register, baud rate fixed at: Fsys/12 332 | // 01 - mode 1, 8-bit UART, baud rate = variable by timer1 or timer2 overflow rate 333 | // 10 - mode 2, 9-bit UART, baud rate fixed at: Fsys/128@SMOD=0, Fsys/32@SMOD=1 334 | // 11 - mode 3, 9-bit UART, baud rate = variable by timer1 or timer2 overflow rate 335 | SBIT(SM2, 0x98, 5); // enable multi-device communication in mode 2/3 336 | #define MASK_UART0_MOD 0xE0 // bit mask of UART0 mode 337 | SBIT(REN, 0x98, 4); // enable UART0 receiving 338 | SBIT(TB8, 0x98, 3); // the 9th transmitted data bit in mode 2/3 339 | SBIT(RB8, 0x98, 2); // 9th data bit received in mode 2/3, or stop bit received for mode 1 340 | SBIT(TI, 0x98, 1); // transmit interrupt flag, set by hardware after completion of a serial transmittal, need software clear 341 | SBIT(RI, 0x98, 0); // receive interrupt flag, set by hardware after completion of a serial receiving, need software clear 342 | SFR(SBUF, 0x99); // UART0 data buffer: reading for receiving, writing for transmittal 343 | 344 | /* Timer2/Capture2 Registers */ 345 | SFR(T2CON, 0xC8); // timer 2 control 346 | SBIT(TF2, 0xC8, 7); // timer2 overflow & interrupt flag, need software clear, the flag will not be set when either RCLK=1 or TCLK=1 347 | SBIT(CAP1F, 0xC8, 7); // timer2 capture 1 interrupt flag, set by T2 edge trigger if bT2_CAP1_EN=1, need software clear 348 | SBIT(EXF2, 0xC8, 6); // timer2 external flag, set by T2EX edge trigger if EXEN2=1, need software clear 349 | SBIT(RCLK, 0xC8, 5); // selection UART0 receiving clock: 0=timer1 overflow pulse, 1=timer2 overflow pulse 350 | SBIT(TCLK, 0xC8, 4); // selection UART0 transmittal clock: 0=timer1 overflow pulse, 1=timer2 overflow pulse 351 | SBIT(EXEN2, 0xC8, 3); // enable T2EX trigger function: 0=ignore T2EX, 1=trigger reload or capture by T2EX edge 352 | SBIT(TR2, 0xC8, 2); // timer2 run enable 353 | SBIT(C_T2, 0xC8, 1); // timer2 clock source selection: 0=timer base internal clock, 1=external edge counter base T2 falling edge 354 | SBIT(CP_RL2, 0xC8, 0); // timer2 function selection (force 0 if RCLK=1 or TCLK=1): 0=timer and auto reload if count overflow or T2EX edge, 1=capture by T2EX edge 355 | SFR(T2MOD, 0xC9); // timer 2 mode and timer 0/1/2 clock mode 356 | #define bTMR_CLK 0x80 // fastest internal clock mode for timer 0/1/2 under faster clock mode: 0=use divided clock, 1=use original Fsys as clock without dividing 357 | #define bT2_CLK 0x40 // timer2 internal clock frequency selection: 0=standard clock, Fsys/12 for timer mode, Fsys/4 for UART0 clock mode, 358 | // 1=faster clock, Fsys/4 @bTMR_CLK=0 or Fsys @bTMR_CLK=1 for timer mode, Fsys/2 @bTMR_CLK=0 or Fsys @bTMR_CLK=1 for UART0 clock mode 359 | #define bT1_CLK 0x20 // timer1 internal clock frequency selection: 0=standard clock, Fsys/12, 1=faster clock, Fsys/4 if bTMR_CLK=0 or Fsys if bTMR_CLK=1 360 | #define bT0_CLK 0x10 // timer0 internal clock frequency selection: 0=standard clock, Fsys/12, 1=faster clock, Fsys/4 if bTMR_CLK=0 or Fsys if bTMR_CLK=1 361 | #define bT2_CAP_M1 0x08 // timer2 capture mode high bit 362 | #define bT2_CAP_M0 0x04 // timer2 capture mode low bit 363 | // bT2_CAP_M1 & bT2_CAP_M0: timer2 capture point selection 364 | // x0: from falling edge to falling edge 365 | // 01: from any edge to any edge (level changing) 366 | // 11: from rising edge to rising edge 367 | #define T2OE 0x02 // enable timer2 generated clock output: 0=disable output, 1=enable clock output at T2 pin, frequency = TF2/2 368 | #define bT2_CAP1_EN 0x01 // enable T2 trigger function for capture 1 of timer2 if RCLK=0 & TCLK=0 & CP_RL2=1 & C_T2=0 & T2OE=0 369 | SFR16(RCAP2, 0xCA); // reload & capture value, little-endian 370 | SFR(RCAP2L, 0xCA); // low byte of reload & capture value 371 | SFR(RCAP2H, 0xCB); // high byte of reload & capture value 372 | SFR16(T2COUNT, 0xCC); // counter, little-endian 373 | SFR(TL2, 0xCC); // low byte of timer 2 count 374 | SFR(TH2, 0xCD); // high byte of timer 2 count 375 | SFR16(T2CAP1, 0xCE); // ReadOnly: capture 1 value for timer2 376 | SFR(T2CAP1L, 0xCE); // ReadOnly: capture 1 value low byte for timer2 377 | SFR(T2CAP1H, 0xCF); // ReadOnly: capture 1 value high byte for timer2 378 | 379 | /* PWM1/2 Registers */ 380 | SFR(PWM_DATA2, 0x9B); // PWM data for PWM2 381 | SFR(PWM_DATA1, 0x9C); // PWM data for PWM1 382 | SFR(PWM_CTRL, 0x9D); // PWM 1/2 control 383 | #define bPWM_IE_END 0x80 // enable interrupt for PWM mode cycle end 384 | #define bPWM2_POLAR 0x40 // PWM2 output polarity: 0=default low and high action, 1=default high and low action 385 | #define bPWM1_POLAR 0x20 // PWM1 output polarity: 0=default low and high action, 1=default high and low action 386 | #define bPWM_IF_END 0x10 // interrupt flag for cycle end, write 1 to clear or write PWM_CYCLE or load new data to clear 387 | #define bPWM2_OUT_EN 0x08 // PWM2 output enable 388 | #define bPWM1_OUT_EN 0x04 // PWM1 output enable 389 | #define bPWM_CLR_ALL 0x02 // force clear FIFO and count of PWM1/2 390 | SFR(PWM_CK_SE, 0x9E); // clock divisor setting 391 | 392 | /* SPI0/Master0/Slave Registers */ 393 | SFR(SPI0_STAT, 0xF8); // SPI 0 status 394 | SBIT(S0_FST_ACT, 0xF8, 7); // ReadOnly: indicate first byte received status for SPI0 395 | SBIT(S0_IF_OV, 0xF8, 6); // interrupt flag for slave mode FIFO overflow, direct bit address clear or write 1 to clear 396 | SBIT(S0_IF_FIRST, 0xF8, 5); // interrupt flag for first byte received, direct bit address clear or write 1 to clear 397 | SBIT(S0_IF_BYTE, 0xF8, 4); // interrupt flag for a byte data exchanged, direct bit address clear or write 1 to clear or accessing FIFO to clear if bS0_AUTO_IF=1 398 | SBIT(S0_FREE, 0xF8, 3); // ReadOnly: SPI0 free status 399 | SBIT(S0_T_FIFO, 0xF8, 2); // ReadOnly: tx FIFO count for SPI0 400 | SBIT(S0_R_FIFO, 0xF8, 0); // ReadOnly: rx FIFO count for SPI0 401 | SFR(SPI0_DATA, 0xF9); // FIFO data port: reading for receiving, writing for transmittal 402 | SFR(SPI0_CTRL, 0xFA); // SPI 0 control 403 | #define bS0_MISO_OE 0x80 // SPI0 MISO output enable 404 | #define bS0_MOSI_OE 0x40 // SPI0 MOSI output enable 405 | #define bS0_SCK_OE 0x20 // SPI0 SCK output enable 406 | #define bS0_DATA_DIR 0x10 // SPI0 data direction: 0=out(master_write), 1=in(master_read) 407 | #define bS0_MST_CLK 0x08 // SPI0 master clock mode: 0=mode 0 with default low, 1=mode 3 with default high 408 | #define bS0_2_WIRE 0x04 // enable SPI0 two wire mode: 0=3 wire (SCK+MOSI+MISO), 1=2 wire (SCK+MISO) 409 | #define bS0_CLR_ALL 0x02 // force clear FIFO and count of SPI0 410 | #define bS0_AUTO_IF 0x01 // enable FIFO accessing to auto clear S0_IF_BYTE interrupt flag 411 | SFR(SPI0_CK_SE, 0xFB); // clock divisor setting 412 | //sfr SPI0_S_PRE = 0xFB; // preset value for SPI slave 413 | #define SPI0_S_PRE SPI0_CK_SE 414 | SFR(SPI0_SETUP, 0xFC); // SPI 0 setup 415 | #define bS0_MODE_SLV 0x80 // SPI0 slave mode: 0=master, 1=slave 416 | #define bS0_IE_FIFO_OV 0x40 // enable interrupt for slave mode FIFO overflow 417 | #define bS0_IE_FIRST 0x20 // enable interrupt for first byte received for SPI0 slave mode 418 | #define bS0_IE_BYTE 0x10 // enable interrupt for a byte received 419 | #define bS0_BIT_ORDER 0x08 // SPI0 bit data order: 0=MSB first, 1=LSB first 420 | #define bS0_SLV_SELT 0x02 // ReadOnly: SPI0 slave mode chip selected status: 0=unselected, 1=selected 421 | #define bS0_SLV_PRELOAD 0x01 // ReadOnly: SPI0 slave mode data pre-loading status just after chip-selection 422 | 423 | /* UART1 Registers */ 424 | SFR(SCON1, 0xC0); // UART1 control (serial port control) 425 | SBIT(U1SM0, 0xC0, 7); // UART1 mode, selection data bit: 0=8 bits data, 1=9 bits data 426 | SBIT(U1SMOD, 0xC0, 5); // UART1 2X baud rate selection: 0=slow(Fsys/32/(256-SBAUD1)), 1=fast(Fsys/16/(256-SBAUD1)) 427 | SBIT(U1REN, 0xC0, 4); // enable UART1 receiving 428 | SBIT(U1TB8, 0xC0, 3); // the 9th transmitted data bit in 9 bits data mode 429 | SBIT(U1RB8, 0xC0, 2); // 9th data bit received in 9 bits data mode, or stop bit received for 8 bits data mode 430 | SBIT(U1TI, 0xC0, 1); // transmit interrupt flag, set by hardware after completion of a serial transmittal, need software clear 431 | SBIT(U1RI, 0xC0, 0); // receive interrupt flag, set by hardware after completion of a serial receiving, need software clear 432 | SFR(SBUF1, 0xC1); // UART1 data buffer: reading for receiving, writing for transmittal 433 | SFR(SBAUD1, 0xC2); // UART1 baud rate setting 434 | 435 | /* ADC and comparator Registers */ 436 | SFR(ADC_CTRL, 0x80); // ADC control 437 | SBIT(CMPO, 0x80, 7); // ReadOnly: comparator result input 438 | SBIT(CMP_IF, 0x80, 6); // flag for comparator result changed, direct bit address clear 439 | SBIT(ADC_IF, 0x80, 5); // interrupt flag for ADC finished, direct bit address clear 440 | SBIT(ADC_START, 0x80, 4); // set 1 to start ADC, auto cleared when ADC finished 441 | SBIT(CMP_CHAN, 0x80, 3); // comparator IN- input channel selection: 0=AIN1, 1=AIN3 442 | SBIT(ADC_CHAN1, 0x80, 1); // ADC/comparator IN+ channel selection high bit 443 | SBIT(ADC_CHAN0, 0x80, 0); // ADC/comparator IN+ channel selection low bit 444 | // ADC_CHAN1 & ADC_CHAN0: ADC/comparator IN+ channel selection 445 | // 00: AIN0(P1.1) 446 | // 01: AIN1(P1.4) 447 | // 10: AIN2(P1.5) 448 | // 11: AIN3(P3.2) 449 | SFR(ADC_CFG, 0x9A); // ADC config 450 | #define bADC_EN 0x08 // control ADC power: 0=shut down ADC, 1=enable power for ADC 451 | #define bCMP_EN 0x04 // control comparator power: 0=shut down comparator, 1=enable power for comparator 452 | #define bADC_CLK 0x01 // ADC clock frequency selection: 0=slow clock, 384 Fosc cycles for each ADC, 1=fast clock, 96 Fosc cycles for each ADC 453 | SFR(ADC_DATA, 0x9F); // ReadOnly: ADC data 454 | 455 | /* Touch-key timer Registers */ 456 | SFR(TKEY_CTRL, 0xC3); // touch-key control 457 | #define bTKC_IF 0x80 // ReadOnly: interrupt flag for touch-key timer, cleared by writing touch-key control or auto cleared when start touch-key checking 458 | #define bTKC_2MS 0x10 // touch-key timer cycle selection: 0=1mS, 1=2mS 459 | #define bTKC_CHAN2 0x04 // touch-key channel selection high bit 460 | #define bTKC_CHAN1 0x02 // touch-key channel selection middle bit 461 | #define bTKC_CHAN0 0x01 // touch-key channel selection low bit 462 | // bTKC_CHAN2 & bTKC_CHAN1 & bTKC_CHAN0: touch-key channel selection 463 | // 000: disable touch-key 464 | // 001: TIN0(P1.0) 465 | // 010: TIN1(P1.1) 466 | // 011: TIN2(P1.4) 467 | // 100: TIN3(P1.5) 468 | // 101: TIN4(P1.6) 469 | // 110: TIN5(P1.7) 470 | // 111: enable touch-key but disable all channel 471 | SFR16(TKEY_DAT, 0xC4); // ReadOnly: touch-key data, little-endian 472 | SFR(TKEY_DATL, 0xC4); // ReadOnly: low byte of touch-key data 473 | SFR(TKEY_DATH, 0xC5); // ReadOnly: high byte of touch-key data 474 | #define bTKD_CHG 0x80 // ReadOnly: indicate control changed, current data maybe invalid 475 | 476 | /* USB/Host/Device Registers */ 477 | SFR(USB_C_CTRL, 0x91); // USB type-C control 478 | #define bVBUS2_PD_EN 0x80 // USB VBUS2 10K pulldown resistance: 0=disable, 1=enable pullup 479 | #define bUCC2_PD_EN 0x40 // USB CC2 5.1K pulldown resistance: 0=disable, 1=enable pulldown 480 | #define bUCC2_PU1_EN 0x20 // USB CC2 pullup resistance control high bit 481 | #define bUCC2_PU0_EN 0x10 // USB CC2 pullup resistance control low bit 482 | #define bVBUS1_PD_EN 0x08 // USB VBUS1 10K pulldown resistance: 0=disable, 1=enable pullup 483 | #define bUCC1_PD_EN 0x04 // USB CC1 5.1K pulldown resistance: 0=disable, 1=enable pulldown 484 | #define bUCC1_PU1_EN 0x02 // USB CC1 pullup resistance control high bit 485 | #define bUCC1_PU0_EN 0x01 // USB CC1 pullup resistance control low bit 486 | // bUCC?_PU1_EN & bUCC?_PU0_EN: USB CC pullup resistance selection 487 | // 00: disable pullup resistance 488 | // 01: enable 56K pullup resistance for default USB power 489 | // 10: enable 22K pullup resistance for 1.5A USB power 490 | // 11: enable 10K pullup resistance for 3A USB power 491 | SFR(UDEV_CTRL, 0xD1); // USB device physical port control 492 | #define bUD_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable 493 | #define bUD_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level 494 | #define bUD_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level 495 | #define bUD_LOW_SPEED 0x04 // enable USB physical port low speed: 0=full speed, 1=low speed 496 | #define bUD_GP_BIT 0x02 // general purpose bit 497 | #define bUD_PORT_EN 0x01 // enable USB physical port I/O: 0=disable, 1=enable 498 | //sfr UHOST_CTRL = 0xD1; // USB host physical port control 499 | #define UHOST_CTRL UDEV_CTRL 500 | #define bUH_PD_DIS 0x80 // disable USB UDP/UDM pulldown resistance: 0=enable pulldown, 1=disable 501 | #define bUH_DP_PIN 0x20 // ReadOnly: indicate current UDP pin level 502 | #define bUH_DM_PIN 0x10 // ReadOnly: indicate current UDM pin level 503 | #define bUH_LOW_SPEED 0x04 // enable USB port low speed: 0=full speed, 1=low speed 504 | #define bUH_BUS_RESET 0x02 // control USB bus reset: 0=normal, 1=force bus reset 505 | #define bUH_PORT_EN 0x01 // enable USB port: 0=disable, 1=enable port, automatic disabled if USB device detached 506 | SFR(UEP1_CTRL, 0xD2); // endpoint 1 control 507 | #define bUEP_R_TOG 0x80 // expected data toggle flag of USB endpoint X receiving (OUT): 0=DATA0, 1=DATA1 508 | #define bUEP_T_TOG 0x40 // prepared data toggle flag of USB endpoint X transmittal (IN): 0=DATA0, 1=DATA1 509 | #define bUEP_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion on endpoint 1/2/3: 0=manual toggle, 1=automatic toggle 510 | #define bUEP_R_RES1 0x08 // handshake response type high bit for USB endpoint X receiving (OUT) 511 | #define bUEP_R_RES0 0x04 // handshake response type low bit for USB endpoint X receiving (OUT) 512 | #define MASK_UEP_R_RES 0x0C // bit mask of handshake response type for USB endpoint X receiving (OUT) 513 | #define UEP_R_RES_ACK 0x00 514 | #define UEP_R_RES_TOUT 0x04 515 | #define UEP_R_RES_NAK 0x08 516 | #define UEP_R_RES_STALL 0x0C 517 | // bUEP_R_RES1 & bUEP_R_RES0: handshake response type for USB endpoint X receiving (OUT) 518 | // 00: ACK (ready) 519 | // 01: no response, time out to host, for non-zero endpoint isochronous transactions 520 | // 10: NAK (busy) 521 | // 11: STALL (error) 522 | #define bUEP_T_RES1 0x02 // handshake response type high bit for USB endpoint X transmittal (IN) 523 | #define bUEP_T_RES0 0x01 // handshake response type low bit for USB endpoint X transmittal (IN) 524 | #define MASK_UEP_T_RES 0x03 // bit mask of handshake response type for USB endpoint X transmittal (IN) 525 | #define UEP_T_RES_ACK 0x00 526 | #define UEP_T_RES_TOUT 0x01 527 | #define UEP_T_RES_NAK 0x02 528 | #define UEP_T_RES_STALL 0x03 529 | // bUEP_T_RES1 & bUEP_T_RES0: handshake response type for USB endpoint X transmittal (IN) 530 | // 00: DATA0 or DATA1 then expecting ACK (ready) 531 | // 01: DATA0 or DATA1 then expecting no response, time out from host, for non-zero endpoint isochronous transactions 532 | // 10: NAK (busy) 533 | // 11: STALL (error) 534 | SFR(UEP1_T_LEN, 0xD3); // endpoint 1 transmittal length 535 | SFR(UEP2_CTRL, 0xD4); // endpoint 2 control 536 | SFR(UEP2_T_LEN, 0xD5); // endpoint 2 transmittal length 537 | SFR(UEP3_CTRL, 0xD6); // endpoint 3 control 538 | SFR(UEP3_T_LEN, 0xD7); // endpoint 3 transmittal length 539 | SFR(USB_INT_FG, 0xD8); // USB interrupt flag 540 | SBIT(U_IS_NAK, 0xD8, 7); // ReadOnly: indicate current USB transfer is NAK received 541 | SBIT(U_TOG_OK, 0xD8, 6); // ReadOnly: indicate current USB transfer toggle is OK 542 | SBIT(U_SIE_FREE, 0xD8, 5); // ReadOnly: indicate USB SIE free status 543 | SBIT(UIF_FIFO_OV, 0xD8, 4); // FIFO overflow interrupt flag for USB, direct bit address clear or write 1 to clear 544 | SBIT(UIF_HST_SOF, 0xD8, 3); // host SOF timer interrupt flag for USB host, direct bit address clear or write 1 to clear 545 | SBIT(UIF_SUSPEND, 0xD8, 2); // USB suspend or resume event interrupt flag, direct bit address clear or write 1 to clear 546 | SBIT(UIF_TRANSFER, 0xD8, 1); // USB transfer completion interrupt flag, direct bit address clear or write 1 to clear 547 | SBIT(UIF_DETECT, 0xD8, 0); // device detected event interrupt flag for USB host mode, direct bit address clear or write 1 to clear 548 | SBIT(UIF_BUS_RST, 0xD8, 0); // bus reset event interrupt flag for USB device mode, direct bit address clear or write 1 to clear 549 | SFR(USB_INT_ST, 0xD9); // ReadOnly: USB interrupt status 550 | #define bUIS_IS_NAK 0x80 // ReadOnly: indicate current USB transfer is NAK received for USB device mode 551 | #define bUIS_TOG_OK 0x40 // ReadOnly: indicate current USB transfer toggle is OK 552 | #define bUIS_TOKEN1 0x20 // ReadOnly: current token PID code bit 1 received for USB device mode 553 | #define bUIS_TOKEN0 0x10 // ReadOnly: current token PID code bit 0 received for USB device mode 554 | #define MASK_UIS_TOKEN 0x30 // ReadOnly: bit mask of current token PID code received for USB device mode 555 | #define UIS_TOKEN_OUT 0x00 556 | #define UIS_TOKEN_SOF 0x10 557 | #define UIS_TOKEN_IN 0x20 558 | #define UIS_TOKEN_SETUP 0x30 559 | // bUIS_TOKEN1 & bUIS_TOKEN0: current token PID code received for USB device mode 560 | // 00: OUT token PID received 561 | // 01: SOF token PID received 562 | // 10: IN token PID received 563 | // 11: SETUP token PID received 564 | #define MASK_UIS_ENDP 0x0F // ReadOnly: bit mask of current transfer endpoint number for USB device mode 565 | #define MASK_UIS_H_RES 0x0F // ReadOnly: bit mask of current transfer handshake response for USB host mode: 0000=no response, time out from device, others=handshake response PID received 566 | SFR(USB_MIS_ST, 0xDA); // ReadOnly: USB miscellaneous status 567 | #define bUMS_SOF_PRES 0x80 // ReadOnly: indicate host SOF timer presage status 568 | #define bUMS_SOF_ACT 0x40 // ReadOnly: indicate host SOF timer action status for USB host 569 | #define bUMS_SIE_FREE 0x20 // ReadOnly: indicate USB SIE free status 570 | #define bUMS_R_FIFO_RDY 0x10 // ReadOnly: indicate USB receiving FIFO ready status (not empty) 571 | #define bUMS_BUS_RESET 0x08 // ReadOnly: indicate USB bus reset status 572 | #define bUMS_SUSPEND 0x04 // ReadOnly: indicate USB suspend status 573 | #define bUMS_DM_LEVEL 0x02 // ReadOnly: indicate UDM level saved at device attached to USB host 574 | #define bUMS_DEV_ATTACH 0x01 // ReadOnly: indicate device attached status on USB host 575 | SFR(USB_RX_LEN, 0xDB); // ReadOnly: USB receiving length 576 | SFR(UEP0_CTRL, 0xDC); // endpoint 0 control 577 | SFR(UEP0_T_LEN, 0xDD); // endpoint 0 transmittal length 578 | SFR(UEP4_CTRL, 0xDE); // endpoint 4 control 579 | SFR(UEP4_T_LEN, 0xDF); // endpoint 4 transmittal length 580 | SFR(USB_INT_EN, 0xE1); // USB interrupt enable 581 | #define bUIE_DEV_SOF 0x80 // enable interrupt for SOF received for USB device mode 582 | #define bUIE_DEV_NAK 0x40 // enable interrupt for NAK responded for USB device mode 583 | #define bUIE_FIFO_OV 0x10 // enable interrupt for FIFO overflow 584 | #define bUIE_HST_SOF 0x08 // enable interrupt for host SOF timer action for USB host mode 585 | #define bUIE_SUSPEND 0x04 // enable interrupt for USB suspend or resume event 586 | #define bUIE_TRANSFER 0x02 // enable interrupt for USB transfer completion 587 | #define bUIE_DETECT 0x01 // enable interrupt for USB device detected event for USB host mode 588 | #define bUIE_BUS_RST 0x01 // enable interrupt for USB bus reset event for USB device mode 589 | SFR(USB_CTRL, 0xE2); // USB base control 590 | #define bUC_HOST_MODE 0x80 // enable USB host mode: 0=device mode, 1=host mode 591 | #define bUC_LOW_SPEED 0x40 // enable USB low speed: 0=full speed, 1=low speed 592 | #define bUC_DEV_PU_EN 0x20 // USB device enable and internal pullup resistance enable 593 | #define bUC_SYS_CTRL1 0x20 // USB system control high bit 594 | #define bUC_SYS_CTRL0 0x10 // USB system control low bit 595 | #define MASK_UC_SYS_CTRL 0x30 // bit mask of USB system control 596 | // bUC_HOST_MODE & bUC_SYS_CTRL1 & bUC_SYS_CTRL0: USB system control 597 | // 0 00: disable USB device and disable internal pullup resistance 598 | // 0 01: enable USB device and disable internal pullup resistance, need external pullup resistance 599 | // 0 1x: enable USB device and enable internal pullup resistance 600 | // 1 00: enable USB host and normal status 601 | // 1 01: enable USB host and force UDP/UDM output SE0 state 602 | // 1 10: enable USB host and force UDP/UDM output J state 603 | // 1 11: enable USB host and force UDP/UDM output resume or K state 604 | #define bUC_INT_BUSY 0x08 // enable automatic responding busy for device mode or automatic pause for host mode during interrupt flag UIF_TRANSFER valid 605 | #define bUC_RESET_SIE 0x04 // force reset USB SIE, need software clear 606 | #define bUC_CLR_ALL 0x02 // force clear FIFO and count of USB 607 | #define bUC_DMA_EN 0x01 // DMA enable and DMA interrupt enable for USB 608 | SFR(USB_DEV_AD, 0xE3); // USB device address, lower 7 bits for USB device address 609 | #define bUDA_GP_BIT 0x80 // general purpose bit 610 | #define MASK_USB_ADDR 0x7F // bit mask for USB device address 611 | SFR16(UEP2_DMA, 0xE4); // endpoint 2 buffer start address, little-endian 612 | SFR(UEP2_DMA_L, 0xE4); // endpoint 2 buffer start address low byte 613 | SFR(UEP2_DMA_H, 0xE5); // endpoint 2 buffer start address high byte 614 | SFR16(UEP3_DMA, 0xE6); // endpoint 3 buffer start address, little-endian 615 | SFR(UEP3_DMA_L, 0xE6); // endpoint 3 buffer start address low byte 616 | SFR(UEP3_DMA_H, 0xE7); // endpoint 3 buffer start address high byte 617 | SFR(UEP4_1_MOD, 0xEA); // endpoint 4/1 mode 618 | #define bUEP1_RX_EN 0x80 // enable USB endpoint 1 receiving (OUT) 619 | #define bUEP1_TX_EN 0x40 // enable USB endpoint 1 transmittal (IN) 620 | #define bUEP1_BUF_MOD 0x10 // buffer mode of USB endpoint 1 621 | // bUEPn_RX_EN & bUEPn_TX_EN & bUEPn_BUF_MOD: USB endpoint 1/2/3 buffer mode, buffer start address is UEPn_DMA 622 | // 0 0 x: disable endpoint and disable buffer 623 | // 1 0 0: 64 bytes buffer for receiving (OUT endpoint) 624 | // 1 0 1: dual 64 bytes buffer by toggle bit bUEP_R_TOG selection for receiving (OUT endpoint), total=128bytes 625 | // 0 1 0: 64 bytes buffer for transmittal (IN endpoint) 626 | // 0 1 1: dual 64 bytes buffer by toggle bit bUEP_T_TOG selection for transmittal (IN endpoint), total=128bytes 627 | // 1 1 0: 64 bytes buffer for receiving (OUT endpoint) + 64 bytes buffer for transmittal (IN endpoint), total=128bytes 628 | // 1 1 1: dual 64 bytes buffer by bUEP_R_TOG selection for receiving (OUT endpoint) + dual 64 bytes buffer by bUEP_T_TOG selection for transmittal (IN endpoint), total=256bytes 629 | #define bUEP4_RX_EN 0x08 // enable USB endpoint 4 receiving (OUT) 630 | #define bUEP4_TX_EN 0x04 // enable USB endpoint 4 transmittal (IN) 631 | // bUEP4_RX_EN & bUEP4_TX_EN: USB endpoint 4 buffer mode, buffer start address is UEP0_DMA 632 | // 0 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) 633 | // 1 0: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 receiving (OUT endpoint), total=128bytes 634 | // 0 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=128bytes 635 | // 1 1: single 64 bytes buffer for endpoint 0 receiving & transmittal (OUT & IN endpoint) 636 | // + 64 bytes buffer for endpoint 4 receiving (OUT endpoint) + 64 bytes buffer for endpoint 4 transmittal (IN endpoint), total=192bytes 637 | SFR(UEP2_3_MOD, 0xEB); // endpoint 2/3 mode 638 | #define bUEP3_RX_EN 0x80 // enable USB endpoint 3 receiving (OUT) 639 | #define bUEP3_TX_EN 0x40 // enable USB endpoint 3 transmittal (IN) 640 | #define bUEP3_BUF_MOD 0x10 // buffer mode of USB endpoint 3 641 | #define bUEP2_RX_EN 0x08 // enable USB endpoint 2 receiving (OUT) 642 | #define bUEP2_TX_EN 0x04 // enable USB endpoint 2 transmittal (IN) 643 | #define bUEP2_BUF_MOD 0x01 // buffer mode of USB endpoint 2 644 | SFR16(UEP0_DMA, 0xEC); // endpoint 0 buffer start address, little-endian 645 | SFR(UEP0_DMA_L, 0xEC); // endpoint 0 buffer start address low byte 646 | SFR(UEP0_DMA_H, 0xED); // endpoint 0 buffer start address high byte 647 | SFR16(UEP1_DMA, 0xEE); // endpoint 1 buffer start address, little-endian 648 | SFR(UEP1_DMA_L, 0xEE); // endpoint 1 buffer start address low byte 649 | SFR(UEP1_DMA_H, 0xEF); // endpoint 1 buffer start address high byte 650 | //sfr UH_SETUP = 0xD2; // host aux setup 651 | #define UH_SETUP UEP1_CTRL 652 | #define bUH_PRE_PID_EN 0x80 // USB host PRE PID enable for low speed device via hub 653 | #define bUH_SOF_EN 0x40 // USB host automatic SOF enable 654 | //sfr UH_RX_CTRL = 0xD4; // host receiver endpoint control 655 | #define UH_RX_CTRL UEP2_CTRL 656 | #define bUH_R_TOG 0x80 // expected data toggle flag of host receiving (IN): 0=DATA0, 1=DATA1 657 | #define bUH_R_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle 658 | #define bUH_R_RES 0x04 // prepared handshake response type for host receiving (IN): 0=ACK (ready), 1=no response, time out to device, for isochronous transactions 659 | //sfr UH_EP_PID = 0xD5; // host endpoint and token PID, lower 4 bits for endpoint number, upper 4 bits for token PID 660 | #define UH_EP_PID UEP2_T_LEN 661 | #define MASK_UH_TOKEN 0xF0 // bit mask of token PID for USB host transfer 662 | #define MASK_UH_ENDP 0x0F // bit mask of endpoint number for USB host transfer 663 | //sfr UH_TX_CTRL = 0xD6; // host transmittal endpoint control 664 | #define UH_TX_CTRL UEP3_CTRL 665 | #define bUH_T_TOG 0x40 // prepared data toggle flag of host transmittal (SETUP/OUT): 0=DATA0, 1=DATA1 666 | #define bUH_T_AUTO_TOG 0x10 // enable automatic toggle after successful transfer completion: 0=manual toggle, 1=automatic toggle 667 | #define bUH_T_RES 0x01 // expected handshake response type for host transmittal (SETUP/OUT): 0=ACK (ready), 1=no response, time out from device, for isochronous transactions 668 | //sfr UH_TX_LEN = 0xD7; // host transmittal endpoint transmittal length 669 | #define UH_TX_LEN UEP3_T_LEN 670 | //sfr UH_EP_MOD = 0xEB; // host endpoint mode 671 | #define UH_EP_MOD UEP2_3_MOD 672 | #define bUH_EP_TX_EN 0x40 // enable USB host OUT endpoint transmittal 673 | #define bUH_EP_TBUF_MOD 0x10 // buffer mode of USB host OUT endpoint 674 | // bUH_EP_TX_EN & bUH_EP_TBUF_MOD: USB host OUT endpoint buffer mode, buffer start address is UH_TX_DMA 675 | // 0 x: disable endpoint and disable buffer 676 | // 1 0: 64 bytes buffer for transmittal (OUT endpoint) 677 | // 1 1: dual 64 bytes buffer by toggle bit bUH_T_TOG selection for transmittal (OUT endpoint), total=128bytes 678 | #define bUH_EP_RX_EN 0x08 // enable USB host IN endpoint receiving 679 | #define bUH_EP_RBUF_MOD 0x01 // buffer mode of USB host IN endpoint 680 | // bUH_EP_RX_EN & bUH_EP_RBUF_MOD: USB host IN endpoint buffer mode, buffer start address is UH_RX_DMA 681 | // 0 x: disable endpoint and disable buffer 682 | // 1 0: 64 bytes buffer for receiving (IN endpoint) 683 | // 1 1: dual 64 bytes buffer by toggle bit bUH_R_TOG selection for receiving (IN endpoint), total=128bytes 684 | //sfr16 UH_RX_DMA = 0xE4; // host rx endpoint buffer start address, little-endian 685 | #define UH_RX_DMA UEP2_DMA 686 | //sfr UH_RX_DMA_L = 0xE4; // host rx endpoint buffer start address low byte 687 | #define UH_RX_DMA_L UEP2_DMA_L 688 | //sfr UH_RX_DMA_H = 0xE5; // host rx endpoint buffer start address high byte 689 | #define UH_RX_DMA_H UEP2_DMA_H 690 | //sfr16 UH_TX_DMA = 0xE6; // host tx endpoint buffer start address, little-endian 691 | #define UH_TX_DMA UEP3_DMA 692 | //sfr UH_TX_DMA_L = 0xE6; // host tx endpoint buffer start address low byte 693 | #define UH_TX_DMA_L UEP3_DMA_L 694 | //sfr UH_TX_DMA_H = 0xE7; // host tx endpoint buffer start address high byte 695 | #define UH_TX_DMA_H UEP3_DMA_H 696 | 697 | /*----- XDATA: xRAM ------------------------------------------*/ 698 | 699 | #define XDATA_RAM_SIZE 0x0400 // size of expanded xRAM, xdata SRAM embedded chip 700 | 701 | /*----- Reference Information --------------------------------------------*/ 702 | #define ID_CH554 0x54 // chip ID 703 | 704 | /* Interrupt routine address and interrupt number */ 705 | #define INT_ADDR_INT0 0x0003 // interrupt vector address for INT0 706 | #define INT_ADDR_TMR0 0x000B // interrupt vector address for timer0 707 | #define INT_ADDR_INT1 0x0013 // interrupt vector address for INT1 708 | #define INT_ADDR_TMR1 0x001B // interrupt vector address for timer1 709 | #define INT_ADDR_UART0 0x0023 // interrupt vector address for UART0 710 | #define INT_ADDR_TMR2 0x002B // interrupt vector address for timer2 711 | #define INT_ADDR_SPI0 0x0033 // interrupt vector address for SPI0 712 | #define INT_ADDR_TKEY 0x003B // interrupt vector address for touch-key timer 713 | #define INT_ADDR_USB 0x0043 // interrupt vector address for USB 714 | #define INT_ADDR_ADC 0x004B // interrupt vector address for ADC 715 | #define INT_ADDR_UART1 0x0053 // interrupt vector address for UART1 716 | #define INT_ADDR_PWMX 0x005B // interrupt vector address for PWM1/2 717 | #define INT_ADDR_GPIO 0x0063 // interrupt vector address for GPIO 718 | #define INT_ADDR_WDOG 0x006B // interrupt vector address for watch-dog timer 719 | #define INT_NO_INT0 0 // interrupt number for INT0 720 | #define INT_NO_TMR0 1 // interrupt number for timer0 721 | #define INT_NO_INT1 2 // interrupt number for INT1 722 | #define INT_NO_TMR1 3 // interrupt number for timer1 723 | #define INT_NO_UART0 4 // interrupt number for UART0 724 | #define INT_NO_TMR2 5 // interrupt number for timer2 725 | #define INT_NO_SPI0 6 // interrupt number for SPI0 726 | #define INT_NO_TKEY 7 // interrupt number for touch-key timer 727 | #define INT_NO_USB 8 // interrupt number for USB 728 | #define INT_NO_ADC 9 // interrupt number for ADC 729 | #define INT_NO_UART1 10 // interrupt number for UART1 730 | #define INT_NO_PWMX 11 // interrupt number for PWM1/2 731 | #define INT_NO_GPIO 12 // interrupt number for GPIO 732 | #define INT_NO_WDOG 13 // interrupt number for watch-dog timer 733 | 734 | /* Special Program Space */ 735 | #define DATA_FLASH_ADDR 0xC000 // start address of Data-Flash 736 | #define BOOT_LOAD_ADDR 0x3800 // start address of boot loader program 737 | #define ROM_CFG_ADDR 0x3FF8 // chip configuration information address 738 | #define ROM_CHIP_ID_HX 0x3FFA // chip ID number highest byte (only low byte valid) 739 | #define ROM_CHIP_ID_LO 0x3FFC // chip ID number low word 740 | #define ROM_CHIP_ID_HI 0x3FFE // chip ID number high word 741 | 742 | /* 743 | New Instruction: MOVX @DPTR1,A 744 | Instruction Code: 0xA5 745 | Instruction Cycle: 1 746 | Instruction Operation: 747 | step-1. write ACC @DPTR1 into xdata SRAM embedded chip 748 | step-2. increase DPTR1 749 | ASM example: 750 | INC XBUS_AUX 751 | MOV DPTR,#TARGET_ADDR ;DPTR1 752 | DEC XBUS_AUX 753 | MOV DPTR,#SOURCE_ADDR ;DPTR0 754 | MOV R7,#xxH 755 | LOOP: MOVX A,@DPTR ;DPTR0 756 | INC DPTR ;DPTR0, if need 757 | .DB 0xA5 ;MOVX @DPTR1,A & INC DPTR1 758 | DJNZ R7,LOOP 759 | */ 760 | --------------------------------------------------------------------------------