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

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