first commit

This commit is contained in:
2025-11-30 04:47:14 +06:00
commit dc5194f1c8
16 changed files with 2599 additions and 0 deletions

61
.gitignore vendored Normal file
View File

@@ -0,0 +1,61 @@
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# debug information files
*.dwo
# z
main.lst
main_ext.bin
main.bin
bin/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "ch32fun"]
path = ch32fun
url = https://github.com/cnlohr/ch32fun.git

16
.vscode/c_cpp_properties.json vendored Normal file
View File

@@ -0,0 +1,16 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "linux-clang-x64"
}
],
"version": 4
}

116
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,116 @@
{
"files.associations": {
"*.rmd": "markdown",
"sys.h": "c",
"cstdio": "c",
"__verbose_abort": "c",
"*.inc": "c",
"ch32fun.h": "c",
"stdio.h": "c",
"systick.h": "c",
"def.h": "c",
"ch32v20xhw.h": "c",
"future": "c",
"compare": "c",
"cstdint": "c",
"snmp.h": "c",
"etharp.h": "c",
"dhcp.h": "c",
"netif.h": "c",
"ch32v307gigabit.h": "c",
"stats.h": "c",
"bitset": "c",
"forward_list": "c",
"functional": "c",
"format": "c",
"fstream": "c",
"istream": "c",
"ranges": "c",
"streambuf": "c",
"variant": "c",
"__hash_table": "c",
"__tree": "c",
"deque": "c",
"iterator": "c",
"list": "c",
"locale": "c",
"regex": "c",
"vector": "c",
"memory_resource": "c",
"__config": "c",
"string": "c",
"atomic": "c",
"__bit_reference": "c",
"err.h": "c",
"httpd.h": "c",
"random": "c",
"limits": "c",
"tuple": "c",
"init.h": "c",
"hw_i2c.h": "c",
"chrono": "c",
"stop_token": "c",
"__locale": "c",
"stdint.h": "c",
"ch32v208_eth.h": "c",
"bit": "c",
"any": "c",
"array": "c",
"hash_map": "c",
"strstream": "c",
"charconv": "c",
"cmath": "c",
"codecvt": "c",
"complex": "c",
"concepts": "c",
"condition_variable": "c",
"coroutine": "c",
"cstddef": "c",
"unordered_map": "c",
"unordered_set": "c",
"exception": "c",
"memory": "c",
"numeric": "c",
"optional": "c",
"ratio": "c",
"string_view": "c",
"system_error": "c",
"type_traits": "c",
"algorithm": "c",
"iomanip": "c",
"mutex": "c",
"ostream": "c",
"semaphore": "c",
"shared_mutex": "c",
"span": "c",
"stacktrace": "c",
"text_encoding": "c",
"thread": "c",
"typeindex": "c",
"typeinfo": "c",
"utility": "c",
"valarray": "c",
"__assert": "c",
"__split_buffer": "c",
"ios": "c",
"map": "c",
"new": "c",
"queue": "c",
"set": "c",
"stack": "c",
"stdexcept": "c",
"__node_handle": "c",
"execution": "c",
"numbers": "c",
"print": "c",
"ha_mqtt.h": "c",
"ethernetif.h": "c",
"tcp_bench.h": "c",
"cstring": "c",
"sfhip.h": "c",
"string.h": "c",
"math.h": "c",
"cctype": "c"
},
"cmake.sourceDirectory": "/home/mira/src/embedded/ch32v208_sens/lwip"
}

32
Makefile Normal file
View File

@@ -0,0 +1,32 @@
TARGET ?= main
TARGET_MCU ?= CH32V203
TARGET_MCU_PACKAGE ?= CH32V203C8T6
CH32V003FUN ?= ./ch32fun/ch32fun
MINICHLINK ?= ./ch32fun/minichlink
PREFIX ?= riscv64-elf
NEWLIB ?= /usr/riscv64-elf/include/
INCLUDE_DIRS += \
-I./inc
PROJECT_C_FILES := $(filter-out ./main.c, $(wildcard ./*.c))
LIB_C_FILES :=
ADDITIONAL_C_FILES := \
$(PROJECT_C_FILES) \
$(LIB_C_FILES)
include $(CH32V003FUN)/ch32fun.mk
CFLAGS := $(filter-out -nostdlib,$(CFLAGS))
LDFLAGS := $(filter-out -nostdlib,$(LDFLAGS))
NANO_FLAGS := -nostartfiles --specs=nano.specs --specs=nosys.specs -lc -lm
CFLAGS += -Wall -Wextra $(INCLUDE_DIRS) $(NANO_FLAGS)
all: flash
flash: cv_flash
clean: cv_clean
.PHONY: all flash clean

0
README.md Normal file
View File

151
aht20.c Normal file
View File

@@ -0,0 +1,151 @@
#include "aht20.h"
#include <stdio.h>
#include "ch32fun.h"
#include "i2c_bitbang.h"
// Polynomial: x^8 + x^5 + x^4 + 1 (0x31)
static uint8_t aht20_calc_crc(const uint8_t* data, size_t len) {
uint8_t crc = 0xFF;
for (size_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 0x80) {
crc = (crc << 1) ^ 0x31;
} else {
crc = (crc << 1);
}
}
}
return crc;
}
static int aht20_get_status(uint8_t* status) {
i2c_start();
if (i2c_write_byte((AHT20_ADDR << 1) | 0) != 0) {
i2c_stop();
return AHT20_ERR_I2C;
}
i2c_write_byte(AHT20_CMD_STATUS);
i2c_stop();
i2c_start();
if (i2c_write_byte((AHT20_ADDR << 1) | 1) != 0) {
i2c_stop();
return AHT20_ERR_I2C;
}
*status = i2c_read_byte(1); // NACK to end read
i2c_stop();
return AHT20_OK;
}
uint8_t aht20_init(void) {
uint8_t status;
// "Before reading the temperature and humidity value, get a byte of status
// word by sending 0x71"
if (aht20_get_status(&status) != AHT20_OK) {
return AHT20_ERR_INIT;
}
// "If the status word and 0x18 are not equal to 0x18..." (Bit 3 CAL, Bit 4
// Retain)
if ((status & STATUS_CAL_BIT) == 0) {
// cal
i2c_start();
if (i2c_write_byte((AHT20_ADDR << 1) | 0) != 0) {
i2c_stop();
return AHT20_ERR_INIT;
}
i2c_write_byte(AHT20_CMD_CALIBRATE);
i2c_write_byte(0x08);
i2c_write_byte(0x00);
i2c_stop();
Delay_Ms(10); // "Wait 10ms to send the 0xAC command"
}
return AHT20_OK;
}
static inline void aht20_parse_data(uint8_t* buf, aht20_data* result) {
// extract 20-bit raw values
// Humidity: Byte 1, Byte 2, Byte 3 (high 4 bits)
uint32_t raw_hum = ((uint32_t)buf[1] << 12) | ((uint32_t)buf[2] << 4) |
((uint32_t)buf[3] >> 4);
// Temperature: Byte 3 (low 4 bits), Byte 4, Byte 5
uint32_t raw_temp = ((uint32_t)(buf[3] & 0x0F) << 16) |
((uint32_t)buf[4] << 8) | (uint32_t)buf[5];
// Humidity
// Target: %RH * 100
// Factor: 10000 / 2^20 == 625 / 2^16
// Shift: >> 16
// Rounding: + (Divisor / 2) = + 32768
uint32_t hum = (raw_hum * 625) + 32768;
result->hum_p_x100 = hum >> 16;
// Temperature
// Target: DegC * 100
// Range Factor: 20000 / 2^20 == 625 / 2^15
// Shift: >> 15
// Rounding: + (Divisor / 2) = + 16384
uint32_t temp = (raw_temp * 625) + 16384;
result->temp_c_x100 = (int32_t)(temp >> 15) - 5000;
}
uint8_t aht20_read(aht20_data* out_data) {
i2c_start();
if (i2c_write_byte((AHT20_ADDR << 1) | 0) != 0) {
i2c_stop();
return AHT20_ERR_I2C;
}
i2c_write_byte(AHT20_CMD_TRIGGER);
i2c_write_byte(0x33);
i2c_write_byte(0x00);
i2c_stop();
// wait for measurement (datasheet says 80ms)
Delay_Ms(80);
uint8_t buf[7]; // status + 5 data + CRC
uint8_t retry = 3;
while (retry--) {
i2c_start();
if (i2c_write_byte((AHT20_ADDR << 1) | 1) != 0) {
i2c_stop();
return AHT20_ERR_I2C;
}
buf[0] = i2c_read_byte(0); // ACK
// check busy bit
if ((buf[0] & STATUS_BUSY_BIT) == 0) {
for (int i = 1; i < 6; i++) {
buf[i] = i2c_read_byte(0); // ACK
}
buf[6] = i2c_read_byte(1); // NACK (last byte)
i2c_stop();
break;
}
// still busy
i2c_read_byte(1); // NACK to end this
i2c_stop();
Delay_Ms(10);
if (retry == 0) return AHT20_ERR_BUSY;
}
if (aht20_calc_crc(buf, 6) != buf[6]) {
return AHT20_ERR_CRC;
}
aht20_parse_data(buf, out_data);
return AHT20_OK;
}

1
ch32fun Submodule

Submodule ch32fun added at 4679e076f0

9
funconfig.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
// #define FUNCONF_USE_HSE 1
// #define FUNCONF_SYSTEM_CORE_CLOCK 120000000
// #define FUNCONF_PLL_MULTIPLIER 15
#define FUNCONF_SYSTICK_USE_HCLK 1
#endif

40
inc/aht20.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef AHT20_H
#define AHT20_H
#include <stdint.h>
#define AHT20_ADDR 0x38 // AHT default i2c address
#define AHT20_CMD_CALIBRATE 0xBE // Calibration command
#define AHT20_CMD_TRIGGER 0xAC // Trigger reading command
#define AHT20_CMD_SOFTRESET 0xBA // Soft reset command
#define AHT20_CMD_STATUS 0x71
#define AHT20_STATUS_BUSY 0x80 // Status bit for busy
#define AHT20_STATUS_CALIBRATED 0x08 // Status bit for calibrated
#define AHT20_OK 0x00
#define AHT20_ERR_INIT 0x01 // Initialization or Calibration failed
#define AHT20_ERR_BUSY 0x02 // Sensor measurement timeout
#define AHT20_ERR_CRC 0x03 // Data corruption detected
#define AHT20_ERR_I2C 0x04 // Generic I2C Bus error (NACK)
#define STATUS_BUSY_BIT (1 << 7)
#define STATUS_CAL_BIT (1 << 3)
typedef struct {
uint32_t hum_p_x100; // %RH * 100
int32_t temp_c_x100; // DegC * 100
} aht20_data;
/**
* Init sensor
* Checks status 0x71 and performs calibration (0xBE) if required
*/
uint8_t aht20_init(void);
/**
* Trigger measurement, wait >80ms, poll busy bit, and read data
* Checks CRC8
*/
uint8_t aht20_read(aht20_data* out_data);
#endif // AHT20_H

91
inc/gpib_defs.h Normal file
View File

@@ -0,0 +1,91 @@
#ifndef GPIB_DEFS_H
#define GPIB_DEFS_H
#include "ch32fun.h"
// #define GPIB_DEBUG 1
// Control Lines (Active LOW)
#define PIN_EOI PB3
#define PIN_REN PB11
#define PIN_ATN PA8
#define PIN_SRQ PA9
#define PIN_IFC PA10
#define PIN_NDAC PA11 // Handshake: Not Data Accepted
#define PIN_NRFD PA12 // Handshake: Not Ready For Data
#define PIN_DAV PA15 // Handshake: Data Valid
// GPIB Commands
// enum cmd_byte {
// GTL = 0x1, /* go to local */
// SDC = 0x4, /* selected device clear */
// PP_CONFIG = 0x5,
// GET = 0x8, /* group execute trigger */
// TCT = 0x9, /* take control */
// LLO = 0x11, /* local lockout */
// DCL = 0x14, /* device clear */
// PPU = 0x15, /* parallel poll unconfigure */
// SPE = 0x18, /* serial poll enable */
// SPD = 0x19, /* serial poll disable */
// CFE = 0x1f, /* configure enable */
// LAD = 0x20, /* value to be 'ored' in to obtain listen address */
// UNL = 0x3F, /* unlisten */
// TAD = 0x40, /* value to be 'ored' in to obtain talk address */
// UNT = 0x5F, /* untalk */
// SAD = 0x60, /* my secondary address (base) */
// PPE = 0x60, /* parallel poll enable (base) */
// PPD = 0x70 /* parallel poll disable */
// };
#define GPIB_CMD_GTL 0x01 /* go to local */
#define GPIB_CMD_SDC 0x04 /* selected device clear */
#define GPIB_CMD_PP_CONFIG 0x05 /* parallel poll configure */
#define GPIB_CMD_GET 0x08 /* group execute trigger */
#define GPIB_CMD_TCT 0x09 /* take control */
#define GPIB_CMD_LLO 0x11 /* local lockout */
#define GPIB_CMD_DCL 0x14 /* device clear */
#define GPIB_CMD_PPU 0x15 /* parallel poll unconfigure */
#define GPIB_CMD_SPE 0x18 /* serial poll enable */
#define GPIB_CMD_SPD 0x19 /* serial poll disable */
#define GPIB_CMD_CFE 0x1F /* configure enable */
#define GPIB_CMD_LAD 0x20 /* listen address (OR with addr) */
#define GPIB_CMD_UNL 0x3F /* unlisten */
#define GPIB_CMD_TAD 0x40 /* talk address (OR with addr) */
#define GPIB_CMD_UNT 0x5F /* untalk */
#define GPIB_CMD_SAD 0x60 /* secondary address base */
#define GPIB_CMD_PPE 0x60 /* parallel poll enable */
#define GPIB_CMD_PPD 0x70 /* parallel poll disable */
// Address Groups
#define GPIB_LAG_BASE 0x20 // Listen Address Group base
#define GPIB_TAG_BASE 0x40 // Talk Address Group base
#define GPIB_SCG_BASE 0x60 // Secondary Command Group base
#define GPIB_ASSERT(pin) funDigitalWrite(pin, 0)
#define GPIB_RELEASE(pin) funDigitalWrite(pin, 1)
#define GPIB_READ(pin) funDigitalRead(pin)
// Data Lines (DIO1-DIO8)
#define PIN_DIO1 PB9
#define PIN_DIO2 PB8
#define PIN_DIO3 PB5
#define PIN_DIO4 PB4
#define PIN_DIO5 PB15
#define PIN_DIO6 PB14
#define PIN_DIO7 PB13
#define PIN_DIO8 PB12
#define MASK_DIO1 (1U << 9)
#define MASK_DIO2 (1U << 8)
#define MASK_DIO3 (1U << 5)
#define MASK_DIO4 (1U << 4)
#define MASK_DIO5 (1U << 15)
#define MASK_DIO6 (1U << 14)
#define MASK_DIO7 (1U << 13)
#define MASK_DIO8 (1U << 12)
static const int DIO_PINS[] = {PIN_DIO1, PIN_DIO2, PIN_DIO3, PIN_DIO4,
PIN_DIO5, PIN_DIO6, PIN_DIO7, PIN_DIO8};
#endif

157
inc/i2c_bitbang.h Normal file
View File

@@ -0,0 +1,157 @@
#ifndef _I2C_BITBANG_H
#define _I2C_BITBANG_H
#include <stdint.h>
#include <stdio.h>
#include "ch32fun.h"
#ifndef I2C_SDA_PIN
#define I2C_SDA_PIN PA1
#endif
#ifndef I2C_SCL_PIN
#define I2C_SCL_PIN PA0
#endif
// decrease to 1 or 0 for Fast Mode (400kHz)
#ifndef I2C_DELAY_US
#define I2C_DELAY_US 3
#endif
#define I2C_ACK 0
#define I2C_NACK 1
#define SCL_HIGH() funDigitalWrite(I2C_SCL_PIN, 1)
#define SCL_LOW() funDigitalWrite(I2C_SCL_PIN, 0)
#define SDA_HIGH() funDigitalWrite(I2C_SDA_PIN, 1)
#define SDA_LOW() funDigitalWrite(I2C_SDA_PIN, 0)
#define SDA_READ() funDigitalRead(I2C_SDA_PIN)
static inline void i2c_delay(void) { Delay_Us(I2C_DELAY_US); }
static inline void i2c_init(void) {
funGpioInitAll();
funPinMode(I2C_SDA_PIN, GPIO_CFGLR_OUT_10Mhz_OD);
funPinMode(I2C_SCL_PIN, GPIO_CFGLR_OUT_10Mhz_OD);
// idle bus state
SDA_HIGH();
SCL_HIGH();
}
static inline void i2c_start(void) {
SDA_HIGH();
SCL_HIGH();
i2c_delay();
SDA_LOW();
i2c_delay();
SCL_LOW();
}
static inline void i2c_stop(void) {
SDA_LOW();
i2c_delay();
SCL_HIGH();
i2c_delay();
SDA_HIGH();
i2c_delay();
}
// returns 0 (I2C_ACK) if acknowledged, 1 (I2C_NACK) if not
static inline uint8_t i2c_write_byte(uint8_t byte) {
for (uint8_t i = 0; i < 8; i++) {
if (byte & 0x80) {
SDA_HIGH();
} else {
SDA_LOW();
}
byte <<= 1;
i2c_delay();
SCL_HIGH();
i2c_delay();
SCL_LOW();
i2c_delay();
}
// ACK/NACK processing
SDA_HIGH(); // release SDA line for slave
i2c_delay();
SCL_HIGH();
i2c_delay();
uint8_t ack = SDA_READ();
SCL_LOW();
i2c_delay();
return ack;
}
// I2C_ACK (0) to request more data, I2C_NACK (1) to end tx
static inline uint8_t i2c_read_byte(uint8_t ack_control) {
uint8_t byte = 0;
SDA_HIGH();
for (uint8_t i = 0; i < 8; i++) {
byte <<= 1;
i2c_delay();
SCL_HIGH(); // slave writes data here
i2c_delay();
if (SDA_READ()) {
byte |= 1;
}
SCL_LOW();
}
// send ACK/NACK to slave
if (ack_control == I2C_ACK) {
SDA_LOW();
} else {
SDA_HIGH();
}
i2c_delay();
SCL_HIGH();
i2c_delay();
SCL_LOW();
SDA_HIGH(); // release bus
i2c_delay();
return byte;
}
static inline void i2c_scan(void) {
printf("--- I2C Scan Start ---\n");
uint8_t found = 0;
for (uint8_t addr = 0x08; addr < 0x78; addr++) {
i2c_start();
// try to write to the address
uint8_t ack = i2c_write_byte((addr << 1) | 0);
i2c_stop();
if (ack == I2C_ACK) {
printf("Device found at 0x%02X\n", addr);
found++;
Delay_Ms(1);
}
}
if (found == 0) {
printf("No I2C devices found.\n");
}
printf("--- I2C Scan End ---\n");
}
#endif // _I2C_BITBANG_H

19
inc/systick.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef SYSTICK_H
#define SYSTICK_H
#include <stdint.h>
#include "ch32fun.h"
#include "ch32v20xhw.h"
#define SYSTICK_ONE_MILLISECOND ((uint32_t)FUNCONF_SYSTEM_CORE_CLOCK / 1000)
#define SYSTICK_ONE_MICROSECOND ((uint32_t)FUNCONF_SYSTEM_CORE_CLOCK / 1000000)
extern volatile uint32_t systick_millis;
#define millis() (systick_millis)
#define micros() (SysTick->CNT / SYSTICK_ONE_MICROSECOND)
void systick_init(void);
#endif // SYSTICK_H

180
inc/usb_config.h Normal file
View File

@@ -0,0 +1,180 @@
#ifndef _USB_CONFIG_H
#define _USB_CONFIG_H
#include "funconfig.h"
#include "ch32fun.h"
#define FUSB_CONFIG_EPS 4 // Include EP0 in this count
#define FUSB_EP1_MODE 1 // TX (IN)
#define FUSB_EP2_MODE -1 // RX (OUT)
#define FUSB_EP3_MODE 1 // TX (IN)
#define FUSB_SUPPORTS_SLEEP 0
#define FUSB_HID_INTERFACES 0
#define FUSB_CURSED_TURBO_DMA 0 // Hacky, but seems fine, shaves 2.5us off filling 64-byte buffers.
#define FUSB_HID_USER_REPORTS 0
#define FUSB_IO_PROFILE 0
#define FUSB_USE_HPE FUNCONF_ENABLE_HPE
#define FUSB_USER_HANDLERS 1
#define FUSB_USE_DMA7_COPY 0
#define FUSB_VDD_5V FUNCONF_USE_5V_VDD
#include "usb_defines.h"
#define FUSB_USB_VID 0x1209
#define FUSB_USB_PID 0x3478
#define FUSB_USB_REV 0x0100
#define FUSB_STR_MANUFACTURER u"Open Source GPIB"
#define FUSB_STR_PRODUCT u"HP3478A Internal Adapter"
#define FUSB_STR_SERIAL u"3478A-USB-001"
//Taken from http://www.usbmadesimple.co.uk/ums_ms_desc_dev.htm
static const uint8_t device_descriptor[] = {
18, //bLength - Length of this descriptor
1, //bDescriptorType - Type (Device)
0x10, 0x01, //bcdUSB - The highest USB spec version this device supports (USB1.1)
0x02, //bDeviceClass - Device Class
0x0, //bDeviceSubClass - Device Subclass
0x0, //bDeviceProtocol - Device Protocol (000 = use config descriptor)
64, //bMaxPacketSize - Max packet size for EP0
(uint8_t)(FUSB_USB_VID), (uint8_t)(FUSB_USB_VID >> 8), //idVendor - ID Vendor
(uint8_t)(FUSB_USB_PID), (uint8_t)(FUSB_USB_PID >> 8), //idProduct - ID Product
(uint8_t)(FUSB_USB_REV), (uint8_t)(FUSB_USB_REV >> 8), //bcdDevice - Device Release Number
1, //iManufacturer - Index of Manufacturer string
2, //iProduct - Index of Product string
3, //iSerialNumber - Index of Serial string
1, //bNumConfigurations - Max number of configurations (if more then 1, you can switch between them)
};
/* Configuration Descriptor Set */
static const uint8_t config_descriptor[ ] =
{
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x43, 0x00, // wTotalLength 67
0x02, // bNumInterfaces 2
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType - Interface
0x00, // bInterfaceNumber - 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints - 1
0x02, // bInterfaceClass - CDC
0x02, // bInterfaceSubClass - Abstract Control Model (Table 4 in CDC120.pdf)
0x01, // bInterfaceProtocol - AT Commands: V.250 etc (Table 5)
0x00, // iInterface (String Index)
// Setting up CDC interface (Table 18)
0x05, // bLength
0x24, // bDescriptorType - CS_INTERFACE (Table 12)
0x00, // bDescriptorSubType - Header Functional Descriptor (Table 13)
0x10, 0x01, // bcdCDC - USB version - USB1.1
// Call Management Functional Descriptor
0x05, // bLength
0x24, // bDescriptorType - CS_INTERFACE
0x01, // bDescriptorSubType - Call Management Functional Descriptor (Table 13)
0x00, // bmCapabilities: (Table 3 in PSTN120.pdf)
// Bit 0 — Device handles call management itself:
// 1 = device handles call management (e.g. call setup, termination, etc.)
// 0 = host handles it
// Bit 1 — Device can send/receive call management information over a Data Class interface:
// 1 = can use the Data Class interface for call management
// 0 = must use the Communication Class interface
0x01, // bDataInterface - Indicates that multiplexed commands are handled via data interface 01h (same value as used in the UNION Functional Descriptor)
// Abstract Control Management Functional Descriptor
0x04, // bLength
0x24, // bDescriptorType - CS_INTERFACE
0x02, // bDescriptorSubType - Abstract Control Management Functional Descriptor (Table 13)
0x02, // bmCapabilities - Device supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State (Table 4 in PSTN120.pdf)
// Union Descriptor Functional Descriptor
0x05, // bLength
0x24, // bDescriptorType - CS_INTERFACE
0x06, // bDescriptorSubType - Union Descriptor Functional Descriptor (Table 13)
0x00, // bControlInterface (Interface number of the control (Communications Class) interface)
0x01, // bSubordinateInterface0 (Interface number of the subordinate (Data Class) interface)
// Setting up EP1 for CDC config interface
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x01, // bInterval 1 (unit depends on device speed)
// Transmission interface with two bulk endpoints
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x01, // bInterfaceNumber 1
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x0A, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol - Transparent
0x00, // iInterface (String Index)
// EP2 - device to host
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
// EP3 - host to device
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x83, // bEndpointAddress (IN/D2H)
0x02, // bmAttributes (Bulk)
0x40, 0x00, // wMaxPacketSize 64
0x00, // bInterval 0 (unit depends on device speed)
// 67 bytes
};
struct usb_string_descriptor_struct {
uint8_t bLength;
uint8_t bDescriptorType;
uint16_t wString[];
};
static const struct usb_string_descriptor_struct language __attribute__((section(".rodata"))) = {
4,
3,
{0x0409} // Language ID - English US (look in USB_LANGIDs)
};
static const struct usb_string_descriptor_struct string1 __attribute__((section(".rodata"))) = {
sizeof(FUSB_STR_MANUFACTURER),
3, // bDescriptorType - String Descriptor (0x03)
FUSB_STR_MANUFACTURER
};
static const struct usb_string_descriptor_struct string2 __attribute__((section(".rodata"))) = {
sizeof(FUSB_STR_PRODUCT),
3,
FUSB_STR_PRODUCT
};
static const struct usb_string_descriptor_struct string3 __attribute__((section(".rodata"))) = {
sizeof(FUSB_STR_SERIAL),
3,
FUSB_STR_SERIAL
};
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static const struct descriptor_list_struct {
uint32_t lIndexValue; // (uint16_t)Index of a descriptor in config or Language ID for string descriptors | (uint8_t)Descriptor type | (uint8_t)Type of string descriptor
const uint8_t *addr;
uint8_t length;
} descriptor_list[] = {
{0x00000100, device_descriptor, sizeof(device_descriptor)},
{0x00000200, config_descriptor, sizeof(config_descriptor)},
// {0x00002100, config_descriptor + 18, 9 }, // Not sure why, this seems to be useful for Windows + Android.
{0x00000300, (const uint8_t *)&language, 4},
{0x04090301, (const uint8_t *)&string1, string1.bLength},
{0x04090302, (const uint8_t *)&string2, string2.bLength},
{0x04090303, (const uint8_t *)&string3, string3.bLength}
};
#define DESCRIPTOR_LIST_ENTRIES ((sizeof(descriptor_list))/(sizeof(struct descriptor_list_struct)) )
#endif

1702
main.c Normal file

File diff suppressed because it is too large Load Diff

21
systick.c Normal file
View File

@@ -0,0 +1,21 @@
#include "systick.h"
volatile uint32_t systick_millis;
void systick_init(void) {
SysTick->CTLR = 0x0000;
SysTick->CMP = SysTick->CNT + SYSTICK_ONE_MILLISECOND;
systick_millis = 0;
SysTick->CTLR = SYSTICK_CTLR_STE | // Enable Counter
SYSTICK_CTLR_STIE | // Enable Interrupts
SYSTICK_CTLR_STCLK; // Set Clock Source to HCLK/1
NVIC_EnableIRQ(SysTick_IRQn);
}
void SysTick_Handler(void) __attribute__((interrupt));
void SysTick_Handler(void) {
SysTick->CMP = SysTick->CNT + SYSTICK_ONE_MILLISECOND;
SysTick->SR = 0;
systick_millis++;
}