first commit
This commit is contained in:
61
.gitignore
vendored
Normal file
61
.gitignore
vendored
Normal 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
3
.gitmodules
vendored
Normal 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
16
.vscode/c_cpp_properties.json
vendored
Normal 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
116
.vscode/settings.json
vendored
Normal 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
32
Makefile
Normal 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
|
||||||
151
aht20.c
Normal file
151
aht20.c
Normal 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
1
ch32fun
Submodule
Submodule ch32fun added at 4679e076f0
9
funconfig.h
Normal file
9
funconfig.h
Normal 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
40
inc/aht20.h
Normal 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
91
inc/gpib_defs.h
Normal 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
157
inc/i2c_bitbang.h
Normal 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
19
inc/systick.h
Normal 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
180
inc/usb_config.h
Normal 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
|
||||||
|
|
||||||
21
systick.c
Normal file
21
systick.c
Normal 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++;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user