Compare commits

...

57 Commits

Author SHA1 Message Date
f7f5a16d64 start work on EPR support 2026-05-05 22:32:51 +02:00
5e12e9a4a0 state machine encoder logic and first simple menu 2026-05-04 00:47:57 +02:00
65ac37fd62 fix logic errors 2026-05-01 23:54:30 +02:00
364e62f933 reduced i2c timeout 2026-05-01 23:32:22 +02:00
f0dfc95910 reverted pwm frequency to 100khz
Also recompile on header change
2026-05-01 19:08:18 +02:00
7aa3e0c3e5 moved pd negotiation to owm module 2026-05-01 18:57:25 +02:00
14a33963b0 moved defines to funconfig.h 2026-04-30 22:27:48 +02:00
ba23e42050 first temperature controller 2026-04-30 02:19:24 +02:00
246183e9a3 removed usb commands 2026-04-28 19:35:36 +02:00
7cf89e9e45 changed _k to _c to reflect reality, tip temperature approx 2026-04-28 19:34:43 +02:00
4ffb554d43 pwm generation and tip driving 2026-04-26 22:11:19 +02:00
adcf08f236 comment on adc conversion 2026-04-25 11:36:40 +02:00
2ccf069e15 Add SC7A20 accelerometer support
!!! AI GENERATED MESSAGE !!!
This commit introduces support for the SC7A20 accelerometer.
The accelerometer readings can now be displayed on the screen,
and the display mode can be toggled using the encoder.
Additionally, the EMA filter constants for voltage and current
readings have been updated from K2 to K4 for potentially smoother
readings.
2026-04-24 22:42:18 +02:00
48f1656540 const qualifier for sendBytes 2026-04-24 01:55:20 +02:00
f5dfa7960b removed allucinated functions 2026-04-24 01:45:12 +02:00
de32bd245c parallel compilation with redefined make rules 2026-04-23 20:13:06 +02:00
5828ecfb48 print highest voltage and select 9v with button 2026-04-22 21:02:21 +02:00
8adfe875cd started work on PD negotiation 2026-04-22 00:39:46 +02:00
a38c71674b removed unused command 2026-04-21 21:59:30 +02:00
1fdf6d2cca i2c at 400kHz 2026-04-21 21:56:23 +02:00
7b1be30a6c ADC conversion and DMA
Setup ADC conversions to happen automatically, transferring results to a buffer
using DMA, also set up channel injection, where instead the tip temperature is
read sinchronously
2026-04-21 21:51:24 +02:00
0023394615 correct use of #if defined check 2026-04-19 23:46:18 +02:00
2a38ba36b0 indentation to tabs 2026-04-19 23:07:36 +02:00
4820010ef1 use ssd1312 display (soldered) 2026-04-19 21:26:22 +02:00
a1590577d2 added fixed point exponential average filters 2026-04-19 18:54:44 +02:00
2c82d8d42e draw useful info on screen 2026-04-19 16:46:54 +02:00
1ba352af4e Refactor ADC reading and conversion
Introduce `VCC_MV` to `funconfig.h` for consistent voltage readings.
Add `get_current_ma` function to `main.c` for clearer current
calculations.
Remove unused `PIN_LED` and `Delay_Ms(5000)` from `main.c`.
Update VBUS voltage calculation to use `VCC_MV`.
Print TIP sensor voltage in millivolts instead of raw ADC values.
2026-04-19 14:05:06 +02:00
ab5e54a9dd scan correct I2C bus 2026-04-19 00:26:36 +02:00
77701636b5 moved i2c setup to it's own function 2026-04-18 22:40:26 +02:00
55bee1a5d8 push script to generate NTC lut 2026-04-17 22:21:42 +02:00
4591e6e04a try to set higher contrast 2026-04-17 21:09:49 +02:00
dae0fbcbda i2c test and display 2026-04-16 13:10:52 +02:00
9e254e0fb1 interrupt-based encoder 2026-04-11 21:40:33 +02:00
90a94a533b more work on basic functions 2026-04-10 17:10:39 +02:00
e1528385c2 read some adcs 2026-04-10 00:58:53 +02:00
a75570e67b it talks 2026-04-09 20:51:51 +02:00
043fbba67e firmware not working 2026-04-09 17:16:19 +02:00
6bc4087474 project start 2026-04-06 00:06:45 +02:00
821380d21c independent programmer 2026-04-05 20:08:18 +02:00
03bf92f505 refined implementation 2026-04-05 17:00:53 +02:00
5a6488535d Merge branch 'programmer' into external-handle 2026-04-05 01:34:53 +02:00
920d0a46c3 technical manuals of the mcu 2026-04-05 01:32:08 +02:00
a51793e529 better ignore 2026-04-05 01:31:47 +02:00
6cd3815d5a first (non working) programmer 2026-04-05 01:31:11 +02:00
887f05a8ec updated to kicad 10.0 2026-03-25 18:51:47 +01:00
4ad28fe1f5 some todos 2026-03-25 18:48:32 +01:00
686724770c test new outline 2026-03-25 18:47:57 +01:00
d79565b10d firmware setup 2026-03-25 18:47:44 +01:00
ab1063aa27 3D model of first enclosure 2026-03-21 23:13:42 +01:00
d8e14fb3a2 lcsc order bom 2026-03-11 15:51:04 +01:00
513d5e2f1f minor tweaks 2026-03-11 15:29:40 +01:00
868bf18b0b different current sensor 2026-03-10 21:59:10 +01:00
8d16bdf96e silkscreen 2026-03-10 19:48:33 +01:00
9fc3f98d84 switch-off simulations and in-stock capacitors 2026-03-09 21:33:50 +01:00
9605d1db0e finished pcb 2026-03-08 23:22:34 +01:00
6007b5d9e2 test pads 2026-03-07 17:13:10 +01:00
11e71d7539 boxed version 2026-03-06 21:33:07 +01:00
51 changed files with 466854 additions and 9933 deletions

6
.gitmodules vendored Normal file
View File

@ -0,0 +1,6 @@
[submodule "fw/ch32fun"]
path = fw/ch32fun
url = https://github.com/cnlohr/ch32fun
[submodule "fw/u8g2"]
path = fw/u8g2
url = https://github.com/olikraus/u8g2

Binary file not shown.

BIN
3D/board_outline_v2.FCStd Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

245995
3D/extenal-handle/I2C_OLED.step Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

177258
3D/extenal-handle/main_pcb.step Normal file

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -2,4 +2,14 @@
Repo for a cool usb-c soldering iron that uses C245 cartridges and power up to 130W.
Read the [project report](doc/report/README.md) (in italian).
Read the [project report](doc/report/README.md) (in italian).
# IDEAS
* USB-C connector on the edge of the PCB like the [alientek T90B](https://youtu.be/Xl0IKpvlF3Y?si=ecKIGLwI0vSPZbJ4&t=7) (clamping plate)
* OLED Screen on a separate PCB, same project with a V-Cut
* More compact tip recess, stabilized by a, aluminium ring, maybe bought at the hardware store
* Single screw disassembly
* 13mm grip dimensions and 18mm otherwise
* 1mm walls in PETG
* Add a ~small~ button to the bootsel line

12
fw/.gitignore vendored Normal file
View File

@ -0,0 +1,12 @@
.zen
.vscode
.ccls-cache
.cache
*.bin
*.lst
*.map
*.elf
*.hex
*.o
.build
compile_commands.json

BIN
fw/CH32X035DS0.pdf Normal file

Binary file not shown.

BIN
fw/CH32X035RM.pdf Normal file

Binary file not shown.

46
fw/Makefile Normal file
View File

@ -0,0 +1,46 @@
all : build
TARGET := main
TARGET_MCU := CH32X035
TARGET_MCU_PACKAGE := CH32X035F8U6
BUILD_DIR := .build
DISPLAY := ssd1312
# include u8g2
U8G2_DIR:=u8g2/csrc
U8G2_SRC:=$(U8G2_DIR)/u8x8_d_$(DISPLAY).c $(filter-out $(U8G2_DIR)/u8x8_d_%.c, \
$(filter-out $(U8G2_DIR)/mui%.c, $(wildcard $(U8G2_DIR)/*.c)))
EXTRA_CFLAGS += -I$(U8G2_DIR)
ADDITIONAL_C_FILES += lib_i2c.c display.c sc7a20.c pd.c
HEADER_FILES := $(wildcard *.h)
include ch32fun/ch32fun/ch32fun.mk
FLASH_COMMAND=$(MINICHLINK)/minichlink -C isp -w $< $(WRITE_SECTION) -b
# create build directory
$(BUILD_DIR):
mkdir -p $(BUILD_DIR)
# build u8g2
U8G2_OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(U8G2_SRC:.c=.o)))
$(BUILD_DIR)/%.o : $(U8G2_DIR)/%.c | $(BUILD_DIR)
$(PREFIX)-gcc $(CFLAGS) -c $< -o $@
# build target
TARGET_OBJS := $(addprefix $(BUILD_DIR)/, $(filter-out ch32fun.o, $(notdir $(FILES_TO_COMPILE:.c=.o))))
$(BUILD_DIR)/%.o : %.c $(HEADER_FILES) | $(BUILD_DIR)
$(PREFIX)-gcc $(CFLAGS) -c $< -o $@
# link target, the rest of the build is specified in ch32fun.mk
$(TARGET).elf : $(FILES_TO_COMPILE) $(LINKER_SCRIPT) $(EXTRA_ELF_DEPENDENCIES) $(U8G2_OBJS) $(TARGET_OBJS) ch32fun.o
$(PREFIX)-gcc -o $@ $(U8G2_OBJS) $(TARGET_OBJS) ch32fun.o $(CFLAGS) $(LDFLAGS)
flash : cv_flash
clean : cv_clean
rm -f $(BUILD_DIR)/*.o *.o || true
monitor :
picocom --imap lfcrlf /dev/ttyACM0

1
fw/ch32fun Submodule

@ -0,0 +1 @@
Subproject commit cfffff6d6bd9bd97d7348d044a1de145f4548072

177
fw/display.c Normal file
View File

@ -0,0 +1,177 @@
#include <u8g2.h>
#include <ch32fun.h>
#include <stdio.h>
#include "display.h"
#include "lib_i2c.h"
/*
* GPIO and delay callback for u8g2/u8x8 display driver
*/
static u8g2_t u8g2;
uint8_t u8x8_gpio_and_delay(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
switch(msg) {
case U8X8_MSG_GPIO_AND_DELAY_INIT:
// called once during init phase of u8g2/u8x8
// can be used to setup pins
printf("TODO: U8X8_MSG_GPIO_AND_DELAY_INIT\n");
break;
case U8X8_MSG_DELAY_NANO:
// delay arg_int * 1 nano second
// at 48MHz 1 cycle = 20ns, 1 nop = 1 cycle
// the for lopp takes about 2 cycles per iteration
for (int i = 0; i < (arg_int/(20*3)); i++) {
asm("nop");
}
break;
case U8X8_MSG_DELAY_100NANO:
// delay arg_int * 100 nano seconds
// at 48MHz 1 cycle = 20ns, 1 nop = 1 cycle
// the for lopp takes about 2 cycles per iteration
for (int i = 0; i < ((arg_int*100)/(20*3)); i++) {
asm("nop");
}
break;
case U8X8_MSG_DELAY_10MICRO:
// delay arg_int * 10 micro seconds
Delay_Us(arg_int*10);
break;
case U8X8_MSG_DELAY_MILLI:
// delay arg_int * 1 milli second
Delay_Ms(arg_int);
break;
case U8X8_MSG_DELAY_I2C:
// arg_int is the I2C speed in 100KHz, e.g. 4 = 400 KHz
// arg_int=1: delay by 5us, arg_int = 4: delay by 1.25us
printf("TODO: U8X8_MSG_DELAY_I2C\n");
break;
case U8X8_MSG_GPIO_D0:
// D0 or SPI clock pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_CLOCK:
break;
case U8X8_MSG_GPIO_D1:
// D1 or SPI data pin: Output level in arg_int
//case U8X8_MSG_GPIO_SPI_DATA:
break;
case U8X8_MSG_GPIO_D2:
// D2 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D3:
// D3 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D4:
// D4 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D5:
// D5 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D6:
// D6 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_D7:
// D7 pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_E:
// E/WR pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS:
// CS (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_DC:
// DC (data/cmd, A0, register select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_RESET:
funDigitalWrite(PIN_DISP_RST, arg_int);
// Reset pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS1:
// CS1 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_CS2:
// CS2 (chip select) pin: Output level in arg_int
break;
case U8X8_MSG_GPIO_I2C_CLOCK:
// arg_int=0: Output low at I2C clock pin
// arg_int=1: Input dir with pullup high for I2C clock pin
break;
case U8X8_MSG_GPIO_I2C_DATA:
// arg_int=0: Output low at I2C data pin
// arg_int=1: Input dir with pullup high for I2C data pin
break;
case U8X8_MSG_GPIO_MENU_SELECT:
// get menu select pin state
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_NEXT:
// get menu next pin state
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_PREV:
// get menu prev pin state
u8x8_SetGPIOResult(u8x8, 0);
break;
case U8X8_MSG_GPIO_MENU_HOME:
// get menu home pin state
u8x8_SetGPIOResult(u8x8, 0);
break;
default:
// default return value
u8x8_SetGPIOResult(u8x8, 1);
break;
}
return 1;
}
uint8_t u8x8_byte_i2c(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{
static uint8_t buffer[32];
static uint8_t buffer_idx;
uint8_t *data;
switch(msg) {
case U8X8_MSG_BYTE_INIT:
break;
case U8X8_MSG_BYTE_SEND:
data = (uint8_t*)arg_ptr;
while (arg_int > 0) {
buffer[buffer_idx++] = *data;
data++;
arg_int--;
}
break;
case U8X8_MSG_BYTE_START_TRANSFER:
buffer_idx = 0;
break;
case U8X8_MSG_BYTE_END_TRANSFER:
i2c_sendBytes(I2C_TARGET, u8x8_GetI2CAddress(u8x8) >> 1, buffer, buffer_idx);
break;
default:
return 0;
}
return 1;
}
u8g2_t* display_init(void)
{
#if defined(SSD1306_128X32) && SSD1306_128X32
u8g2_Setup_ssd1306_i2c_128x32_univision_f(&u8g2, U8G2_R0, u8x8_byte_i2c, u8x8_gpio_and_delay);
#elif defined(SSD1312_96X16) && SSD1312_96X16
// NOTE: display size is wrong, hardware is 96x16, but driver is configured for 120x28
u8g2_Setup_ssd1312_i2c_128x32_f(&u8g2, U8G2_R0, u8x8_byte_i2c, u8x8_gpio_and_delay);
#else
static_assert(0, "unsupported display size");
#endif
// TODO: log errors and return NULL on failure
u8g2_InitDisplay(&u8g2);
u8g2_SetPowerSave(&u8g2, 0);
u8g2_SetContrast(&u8g2, 255);
return &u8g2;
}

12
fw/display.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _DISPLAY_H
#define _DISPLAY_H
#include <u8g2.h>
// #define SSD1306_128X32 1
#define SSD1312_96X16 1
#define PIN_DISP_RST PA7 // display reset
u8g2_t* display_init(void);
#endif // _DISPLAY_H

20
fw/filter.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _FILTER_H
#define _FILTER_H
// Fixed-Point Exponential Moving Average
// alpha = 1/2^k
// x: output value
// s: current sample
#define U16_FP_EMA_K2(x, s) (u16)((((u32)(x)<<2) - (x) + (s)) >> 2)
#define U16_FP_EMA_K4(x, s) (u16)((((u32)(x)<<4) - (x) + (s)) >> 4)
#define U16_FP_EMA_K8(x, s) (u16)((((u32)(x)<<8) - (x) + (s)) >> 8)
#define U16_FP_EMA_K16(x, s) (u16)((((u32)(x)<<16) - (x) + (s)) >> 16)
#define I16_FP_EMA_K2(x, s) (s16)((((s32)(x)<<2) - (x) + (s)) >> 2)
#define I16_FP_EMA_K4(x, s) (s16)((((s32)(x)<<4) - (x) + (s)) >> 4)
#define I16_FP_EMA_K8(x, s) (s16)((((s32)(x)<<8) - (x) + (s)) >> 8)
#define I16_FP_EMA_K16(x, s) (s16)((((s32)(x)<<16) - (x) + (s)) >> 16)
#endif // _FILTER_H

45
fw/funconfig.h Normal file
View File

@ -0,0 +1,45 @@
#ifndef _FUNCONFIG_H
#define _FUNCONFIG_H
#define FUNCONF_USE_DEBUGPRINTF 0 // can only have one printf
#define FUNCONF_USE_USBPRINTF 1
#define FUNCONF_DEBUG_HARDFAULT 0
#define CH32X035 1
#define I2C_TARGET I2C1
#define VCC_MV 3480
#define FRAME_TIME_MS 20 // 50Hz
#define PWM_FREQ_HZ 100000 // TIM3 PWM frequency
// Pin definitions
#define PIN_VBUS PA0 // vbus voltage feedback
#define PIN_CURRENT PA1 // current feedback
#define PIN_NTC PA2 // ntc temperature sensor
#define PIN_TEMP PA3 // thermocouple amplifier
#define PIN_12V PA5 // 12V regulator enable
#define PIN_HEATER PA6 // power mosfet gate control
#define PIN_ENC_A PB3 // rotary encoder A
#define PIN_ENC_B PB11 // rotary encoder B
#define PIN_BTN PB1 // rotary encoder button
// Analog channel definitions
#define VBUS_ADC_CHANNEL ANALOG_0 // PA0
#define CURRENT_ADC_CHANNEL ANALOG_1 // PA1
#define NTC_ADC_CHANNEL ANALOG_2 // PA2
#define TEMP_ADC_CHANNEL ANALOG_3 // PA3
#define ENCODER_DEBOUNCE 6000
// TODO: these need to be calibrated
// Tip mV to deg C conversion factor numerator
#define TC_CONV_NOM 151
// Tip mV to deg C conversion factor denumerator
#define TC_CONV_DEN 1000
#define MAX_BOARD_TEMP 50
#define MAX_TIP_TEMP 500
#define TURN_OFF_DELAY 2
#define CYCLES_PER_MEASURE 2
#define BOARD_MAX_VOLTAGE 28000
#endif // _FUNCONFIG_H

231
fw/lib_i2c.c Normal file
View File

@ -0,0 +1,231 @@
// MIT License
// Copyright (c) 2025 UniTheCat
// Tested with Ch32X03x and CH32V30x
#include "lib_i2c.h"
//! ####################################
//! I2C INIT FUNCTIONS
//! ####################################
void i2c_init(I2C_TypeDef* I2Cx, u32 PCLK, u32 i2cSpeed_Hz) {
// Enable I2C clock
if (I2Cx == I2C1) {
RCC->APB1PCENR |= RCC_APB1Periph_I2C1;
}
#ifdef I2C2
else if (I2Cx == I2C2) {
RCC->APB1PCENR |= RCC_APB1Periph_I2C2;
}
#endif
// Disable I2C before configuration
I2Cx->CTLR1 &= ~I2C_CTLR1_PE;
// configure I2C clock
I2Cx->CTLR2 = (PCLK / 1000000);
I2Cx->CKCFGR = PCLK / (i2cSpeed_Hz << 1); // PeripheralClock / (100KHz * 2)
// Enable I2C
I2Cx->CTLR1 |= I2C_CTLR1_PE;
// Enable ACK
I2Cx->CTLR1 |= I2C_CTLR1_ACK;
}
u8 i2c_start(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 isRead) {
//# Wait while BUSY, when BUSY is set to 0 then continue
u32 timeout = I2C_DEFAULT_TIMEOUT;
while((I2Cx->STAR2 & I2C_STAR2_BUSY) && --timeout);
// if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x11; }
//# Generate START condition
I2Cx->CTLR1 |= I2C_CTLR1_START;
//# Wait while SB is 0, when SB is set to 1 then continue
timeout = I2C_DEFAULT_TIMEOUT;
while(!(I2Cx->STAR1 & I2C_STAR1_SB) && --timeout);
if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x12; }
// printf("timeoutB: %d\n", I2C_DEFAULT_TIMEOUT - timeout);
//# Send address + read/write. Write = 0, Read = 1
I2Cx->DATAR = (i2cAddress << 1) | isRead;
//# Wait while ADDR is 0, if ADDR is set to 1 then continue
timeout = I2C_DEFAULT_TIMEOUT;
while(!(I2Cx->STAR1 & I2C_STAR1_ADDR) && --timeout);
if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x13; }
// printf("timeoutC: %d\n", I2C_DEFAULT_TIMEOUT - timeout);
//! REQUIRED. Clear ADDR by reading STAR1 then STAR2
(void)I2Cx->STAR1;
(void)I2Cx->STAR2;
return 0;
}
void i2c_stop(I2C_TypeDef* I2Cx)
{
//# Generate STOP condition
I2Cx->CTLR1 |= I2C_CTLR1_STOP;
}
void i2c_scan(I2C_TypeDef* I2Cx, void (*onPingFound)(u8 address)) {
// mininum 0x08 to 0x77 (0b1110111)
for (int i = 0x08; i < 0x77; i++) {
u8 ping = i2c_start(I2Cx, i, 1);
//# Generate STOP condition
I2Cx->CTLR1 |= I2C_CTLR1_STOP;
if (ping == 0) onPingFound(i);
}
}
//! ####################################
//! I2C SEND FUNCTION
//! ####################################
u8 i2c_sendBytes_noStop(I2C_TypeDef* I2Cx, u8 i2cAddress, const u8* buffer, u8 len) {
u8 err = i2c_start(I2Cx, i2cAddress, 0); // Write mode
if (err) return err;
u32 timeout;
for(u8 i = 0; i < len; i++) {
//# Wait for register empty
timeout = I2C_DEFAULT_TIMEOUT;
while(!(I2Cx->STAR1 & I2C_STAR1_TXE) && --timeout);
if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x21; }
I2Cx->DATAR = buffer[i]; // Send data
}
//# Wait for transmission complete. Wait while BTF is 0, when set to 1 continue
timeout = I2C_DEFAULT_TIMEOUT;
while(!(I2Cx->STAR1 & I2C_STAR1_BTF) && --timeout);
if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x22; }
return 0;
}
u8 i2c_sendBytes(I2C_TypeDef* I2Cx, u8 i2cAddress, const u8* buffer, u8 len) {
u8 err = i2c_sendBytes_noStop(I2Cx, i2cAddress, buffer, len);
//# Generate STOP condition
I2Cx->CTLR1 |= I2C_CTLR1_STOP;
return err;
}
u8 i2c_sendByte(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 data) {
return i2c_sendBytes(I2Cx, i2cAddress, &data, 1);
}
//! ####################################
//! I2C RECEIVE FUNCTIONS
//! ####################################
u8 i2c_readBytes(I2C_TypeDef* I2Cx, u8 i2cAddress, u8* buffer, u8 len) {
u8 err = i2c_start(I2Cx, i2cAddress, 1); // Read mode
if (err) return err;
//# Enable ACK at the beginning
I2Cx->CTLR1 |= I2C_CTLR1_ACK;
for(u8 i = 0; i < len; i++) {
//# Before reading the last bytes, disable ACK to signal the slave to stop sending
if(i == len-1) I2Cx->CTLR1 &= ~I2C_CTLR1_ACK;
//# Wait for data. Wait while RxNE is 0, when set to 1 continue
u32 timeout = I2C_DEFAULT_TIMEOUT;
while(!(I2Cx->STAR1 & I2C_STAR1_RXNE) && --timeout);
if (timeout == 0) { I2Cx->CTLR1 |= I2C_CTLR1_STOP; return 0x31; }
//# Read data
buffer[i] = I2Cx->DATAR;
}
//# Generate STOP condition
I2Cx->CTLR1 |= I2C_CTLR1_STOP;
return 0;
}
// Write to register and then do read data, no stop inbetween
u8 i2c_readRegTx_buffer(I2C_TypeDef* I2Cx, u8 i2cAddress,
u8 *tx_buf, u8 tx_len, u8 *rx_buf, u8 rx_len
) {
u8 err = i2c_sendBytes_noStop(I2Cx, i2cAddress, tx_buf, tx_len); // Send register address
if (err) return err;
err = i2c_readBytes(I2Cx, i2cAddress, rx_buf, rx_len); // Read data
return err;
}
//! ####################################
//! I2C SLAVE FUNCTIONS
//! ####################################
void i2c_slave_init(I2C_TypeDef* I2Cx, u16 self_addr, u32 PCLK, u32 i2cSpeed_Hz) {
i2c_init(I2Cx, PCLK, i2cSpeed_Hz);
// Configure the CH32 I2C slave address to make it an I2C slave
I2Cx->OADDR1 = (self_addr << 1);
I2Cx->OADDR2 = 0;
I2Cx->CTLR2 |= I2C_CTLR2_ITEVTEN | I2C_CTLR2_ITERREN | I2C_CTLR2_ITBUFEN;
// Enable Event and Error Interrupts
if (I2Cx == I2C1) {
NVIC_EnableIRQ(I2C1_EV_IRQn); // I2C Event interrupt
NVIC_EnableIRQ(I2C1_ER_IRQn); // I2C Error interrupt
}
#ifdef I2C2
else if (I2Cx == I2C2) {
NVIC_EnableIRQ(I2C2_EV_IRQn); // I2C Event interrupt
NVIC_EnableIRQ(I2C2_ER_IRQn); // I2C Error interrupt
}
#endif
}
void I2C1_ER_IRQHandler(void) __attribute__((interrupt));
void I2C1_ER_IRQHandler(void) {
// get I2C status
uint16_t STAR1 = I2C1->STAR1;
// Obtain and clear Bus error
if (STAR1 & I2C_STAR1_BERR) {
I2C1->STAR1 &= ~(I2C_STAR1_BERR);
}
// Obtain and clear Arbitration lost error
if (STAR1 & I2C_STAR1_ARLO) {
I2C1->STAR1 &= ~(I2C_STAR1_ARLO);
}
// Obtain and clear Acknowledge failure error
if (STAR1 & I2C_STAR1_AF) {
I2C1->STAR1 &= ~(I2C_STAR1_AF);
}
}
#ifdef I2C2
void I2C2_ER_IRQHandler(void) __attribute__((interrupt));
void I2C2_ER_IRQHandler(void) {
// get I2C status
uint16_t STAR1 = I2C2->STAR1;
// Obtain and clear Bus error
if (STAR1 & I2C_STAR1_BERR) {
I2C2->STAR1 &= ~(I2C_STAR1_BERR);
}
// Obtain and clear Arbitration lost error
if (STAR1 & I2C_STAR1_ARLO) {
I2C2->STAR1 &= ~(I2C_STAR1_ARLO);
}
// Obtain and clear Acknowledge failure error
if (STAR1 & I2C_STAR1_AF) {
I2C2->STAR1 &= ~(I2C_STAR1_AF);
}
}
#endif

51
fw/lib_i2c.h Normal file
View File

@ -0,0 +1,51 @@
#ifndef _LIB_I2C_H
#define _LIB_I2C_H
// MIT License
// Copyright (c) 2025 UniTheCat
// Tested with Ch32X03x and CH32V30x
#include <ch32fun.h>
#define I2C_DEFAULT_TIMEOUT 50000
//! ####################################
//! I2C INIT FUNCTIONS
//! ####################################
void i2c_init(I2C_TypeDef* I2Cx, u32 PCLK, u32 i2cSpeed_Hz);
u8 i2c_start(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 isRead);
void i2c_stop(I2C_TypeDef* I2Cx);
void i2c_scan(I2C_TypeDef* I2Cx, void (*onPingFound)(u8 address));
//! ####################################
//! I2C SEND FUNCTION
//! ####################################
u8 i2c_sendBytes_noStop(I2C_TypeDef* I2Cx, u8 i2cAddress, const u8* buffer, u8 len);
u8 i2c_sendBytes(I2C_TypeDef* I2Cx, u8 i2cAddress, const u8* buffer, u8 len);
u8 i2c_sendByte(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 data);
//! ####################################
//! I2C RECEIVE FUNCTIONS
//! ####################################
u8 i2c_readBytes(I2C_TypeDef* I2Cx, u8 i2cAddress, u8* buffer, u8 len);
u8 i2c_readByte(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 reg, u8* buffer);
// Write to register and then do read data, no stop inbetween
u8 i2c_readRegTx_buffer(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 *tx_buf, u8 tx_len, u8 *rx_buf, u8 rx_len);
inline u8 i2c_readReg_buffer(I2C_TypeDef* I2Cx, u8 i2cAddress, u8 reg, u8 *rx_buf, u8 rx_len)
{
return i2c_readRegTx_buffer(I2Cx, i2cAddress, &reg, 1, rx_buf, rx_len);
}
//! ####################################
//! I2C SLAVE FUNCTIONS
//! ####################################
void i2c_slave_init(I2C_TypeDef* I2Cx, u16 self_addr, u32 PCLK, u32 i2cSpeed_Hz);
#endif // _LIB_I2C_H

22
fw/lincal.h Normal file
View File

@ -0,0 +1,22 @@
#ifndef _LINCAL_H
#define _LINCAL_H
#include <ch32fun.h>
// Fixed-point number in 8.8 format
typedef int16_t fp16_t;
#define F32_TO_FP16(f) ((fp16_t)((f) * 256.0f))
// Intger part of fp16_t
#define I(f) ((f) >> 8)
// Decimal part of fp16_t
#define D(f) ((f) & 0xFF)
// v * a + b for signed 16-bit
#define I16_LINCAL(v, a, b) ((int16_t)((((int32_t)(v) * (a)) >> 8) + (b)))
// v * a + b for unsigned 16-bit
#define U16_LINCAL(v, a, b) ((uint16_t)((((uint32_t)(v) * (a)) >> 8) + (b)))
#endif

612
fw/main.c Normal file
View File

@ -0,0 +1,612 @@
#include <ch32fun.h>
#include <stdint.h>
#include <stdio.h>
#include <fsusb.h>
#include "funconfig.h"
#include "lib_i2c.h"
#include "display.h"
#include "filter.h"
#include "sc7a20.h"
#include "pd.h"
// constants
// LUT for converting NTC readings to degrees celsius
// Nominal: 1kOhm, Beta: 3380, Step: 64
const uint8_t ntc_step_size = 64;
const int16_t ntc_lut[] = {
1316, 197, 155, 133, 119, 108, 100, 93, 87, 82, 77, 73, 69, 66, 63, 60,
57, 54, 52, 50, 47, 45, 43, 41, 39, 37, 35, 34, 32, 30, 28, 27,
25, 23, 22, 20, 19, 17, 15, 14, 12, 11, 9, 7, 6, 4, 2, 0,
-1, -3, -5, -7, -9, -11, -14, -16, -19, -22, -25, -28, -32, -38, -44, -55,
-55 // extra value to not have an extra if statement
};
u8g2_t *u8g2;
int16_t encoder = 0; // rotary encoder counter
uint32_t last_interrupt = 0; // last time the encoder interrupt was triggered
struct pd_profile_t pd_profile;
static const int8_t x_off = 0;
static const int8_t y_off = 8;
// Convert the raw adc reading to a temperature in celsius with the ntc lut,
// linearly interpolating between positions
static inline int16_t get_temp_c(uint16_t adc_reading)
{
if (adc_reading > 4095) return 0;
uint8_t index = adc_reading / ntc_step_size;
uint8_t remainder = adc_reading % ntc_step_size;
int16_t temp_base = index < 64 ? ntc_lut[index] : 0;
int16_t temp_next = ntc_lut[index + 1];
return temp_base + ((temp_next - temp_base) * remainder)/ntc_step_size;
}
// convert the raw TPA191 adc reading to a current in milliamps
static inline int16_t get_current_ma(uint16_t adc_reading)
{
// Rshunt = 4 milliOhm
// Gain = 100
u32 mv = ((u32)adc_reading * VCC_MV) / 4096;
return (mv * 10) / 4;
}
void print_i2c_device(uint8_t addr)
{
printf("Device found at 0x%02X\n", addr);
}
// this callback is mandatory when FUNCONF_USE_USBPRINTF is defined,
// can be empty though
void handle_usbfs_input(int numbytes, uint8_t *data)
{
(void)numbytes;
(void)data;
}
/*
* __ ____ ____
* A: |____| |____| |____
* ____ ____ __
* B: ____| |____| |____|
* ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
* f r r f f r r f f r
*/
void update_encoder(void)
{
// 0 = 00, 1 = 01, 2 = 10, 3 = 11
static uint8_t last_state = 0;
// Lookup table: state_table[last_state][current_state]
// 0 = invalid move or bounce (ignore)
// 1 = valid forward step
// -1 = valid backward step
static const int8_t state_table[4][4] = {
{ 0, 1, -1, 0}, // from 00
{-1, 0, 0, 1}, // from 01
{ 1, 0, 0, -1}, // from 10
{ 0, -1, 1, 0} // from 11
};
// FIXME: even with interrupts disabled and debounce, a single detent triggers
// multiple interrupts, leading to multiple encoder updates in a short time.
bool a = funDigitalRead(PIN_ENC_A);
bool b = funDigitalRead(PIN_ENC_B);
Delay_Us(100);
if (a != funDigitalRead(PIN_ENC_A) || b != funDigitalRead(PIN_ENC_B))
return; // debounce
uint8_t current_state = (a << 1) | b;
// Find the movement direction based on transition
encoder += state_table[last_state][current_state];
// Save current state for the next interrupt
last_state = current_state;
}
// Attached to PIN_ENC_A rising and falling edges
void EXTI7_0_IRQHandler(void) __attribute__((interrupt));
void EXTI7_0_IRQHandler(void)
{
__disable_irq();
update_encoder();
EXTI->INTFR = EXTI_Line3;
__enable_irq();
}
// Attached to PIN_ENC_B rising and falling edges
void EXTI15_8_IRQHandler(void) __attribute__((interrupt));
void EXTI15_8_IRQHandler(void)
{
__disable_irq();
update_encoder();
EXTI->INTFR = EXTI_Line11;
__enable_irq();
}
// Procedure to get hardware I2C working on the CH32X035F8U6
static inline void setup_i2c(void)
{
// Order here matters, first initialize the AFIO and I2C subsystems then
// change register values, do that the other way around and the configuration
// wont take effect
// Enable AFIO (Alternate Function IO)
RCC->APB2PCENR |= RCC_AFIOEN;
// Init I2C
i2c_init(I2C_TARGET, FUNCONF_SYSTEM_CORE_CLOCK, 400000);
// To utilize the I2C bus we need to disable SWD first, since the pins overlap
AFIO->PCFR1 &= ~(0b0111 << 24);
AFIO->PCFR1 |= 0b0100 << 24;
// Map SCL to PC18 and SDA to PC19
AFIO->PCFR1 |= 0b0101 << 2;
// Manually set the I2C pins to Alternate Function IO, CNF=10b, MODE=10b
GPIOC->CFGXR &= ~((0xF << 8) | (0xF << 12)); // first clear the bits
// then set them
GPIOC->CFGXR |= 0b1010 << 8; // PC18
GPIOC->CFGXR |= 0b1010 << 12; // PC19
}
// FIXME: this holds the max number of ADC channels, ideally this would be lower
volatile uint16_t adc_buffer[16];
// Set-up the adc to perform continous conversion of enabled channels, enable
// channel injection and setup DMA to automatically transfer conversion results
// to a buffer
static inline void setup_adc_and_dma(uint8_t *channels, uint8_t ch_size, uint8_t *injected, uint8_t in_size)
{
if (channels == NULL || ch_size == 0) return;
// FIXME: for now only support a single configuration register, so at max 6 channels
// I don't want to implement logic to switch registers right now
// TODO: report an error
if (ch_size > 6) return;
// General ADC initialization, I use this only for enabling clocks and such
funAnalogInit(); // general initialization
// Set the SCAN and CONT bits to enter continous conversion mode
// Do not set the IAUTO bit to ensure injected channels are converted only
// when specified by software
// Set the regular channel trigger mode to software (EXTSEL = 0b111) to ensure
// conversion starts in sync with DMA (this should already be done by funAnalogInit())
ADC1->CTLR1 |= ADC_SCAN;
ADC1->CTLR2 |= ADC_CONT | ADC_EXTSEL;
// Setup regular channels (scanned continously)
// TODO: setup sampling time
for (uint8_t i = 0; i < ch_size; i++) {
// Increase sampling time to have less cross talk between channels
// 0b111 means 11 ADC clock cycles (max)
if (channels[i] < 10) {
ADC1->SAMPTR2 |= 0b111 << (channels[i]*3);
} else {
ADC1->SAMPTR1 |= 0b111 << ((channels[i]-10)*3);
}
ADC1->RSQR3 |= channels[i] << (i*5);
}
// Set the number of normal conversion channels
ADC1->RSQR1 |= (ch_size-1) << 20;
// Set-up injection channels
// The injection channel register allows for up to 4 channels, if the buffer is larger
// skip this step
// TODO: report an error
if (injected != NULL && in_size != 0 && in_size <= 4) {
// enable injection group
// JEXTSEL = 0b111 (software trigger)
ADC1->CTLR2 |= ADC_JEXTSEL;
for (uint8_t i = 0; i < in_size; i++) {
ADC1->ISQR |= injected[i] << ((4-in_size+i)*5);
}
// Set the number of injection channels
ADC1->ISQR |= (in_size-1) << 20;
}
// Set-up DMA, ADC is connected only to channel 1
// Turn on DMA
RCC->AHBPCENR |= RCC_AHBPeriph_DMA1;
// 1. Set the address of the source peripheral, in this case the output
// register of the ADC
DMA1_Channel1->PADDR = (uint32_t)&(ADC1->RDATAR);
// 2. Set the destination (base) address of the data
DMA1_Channel1->MADDR = (uint32_t)adc_buffer;
// 3. Set the number of transfers to be done each cycle, in this case it's
// the same as the number of regular conversion cycles
DMA1_Channel1->CNTR = ch_size;
// 4. Set mode: Peripheral to Memory, MEM2MEM=0 DIR=0
// Circular mode CIRC=1, restart after CNTR transfers
// Max priority to not lose conversions and offset values in the buffer
DMA1_Channel1->CFGR =
DMA_M2M_Disable |
DMA_Priority_VeryHigh |
DMA_MemoryDataSize_HalfWord |
DMA_PeripheralDataSize_HalfWord |
DMA_MemoryInc_Enable |
DMA_Mode_Circular |
DMA_DIR_PeripheralSRC;
// Turn on DMA channel 1
DMA1_Channel1->CFGR |= DMA_CFGR1_EN;
// Enable DMA requests from the ADC
ADC1->CTLR2 |= ADC_DMA;
// Power up ADC again
ADC1->CTLR2 |= ADC_ADON;
// start conversion
ADC1->CTLR2 |= ADC_SWSTART;
}
// Perform a conversion on the injected ADC channels, this is synchronous and
// halts conversion on the normal channels until it completes
volatile uint16_t injection_results[4];
static inline bool adc_injection_conversion() {
// Clear any pending flags
ADC1->STATR &= ~(ADC_JEOC);
// Start injection conversion using external trigger method
ADC1->CTLR2 |= ADC_JSWSTART;
// Wait for all conversions to complete
s32 timeout = 1000000;
while(!(ADC1->STATR & ADC_JEOC) && timeout--) {}
if (timeout <= 0) return false;
// Read all results
injection_results[0] = ADC1->IDATAR1 & 0x0FFF;
injection_results[1] = ADC1->IDATAR2 & 0x0FFF;
injection_results[2] = ADC1->IDATAR3 & 0x0FFF;
injection_results[3] = ADC1->IDATAR4 & 0x0FFF;
// Clear JEOC flag
ADC1->STATR &= ~ADC_JEOC;
return true;
}
// mask for the CCxP bits
// when set PWM outputs are held HIGH by default and pulled LOW
// when zero PWM outputs are held LOW by default and pulled HIGH
// #define TIM3_DEFAULT 0xff
#define TIM3_DEFAULT 0x00
static inline void setup_pwm(void)
{
// Enable TIM3 clock
RCC->APB1PCENR |= RCC_APB1Periph_TIM3;
// Since TIM3 is enabled with TIM3->SMCFGR.SMS = 0b000 (default value) the
// clock source is the internal clock
// The internal clock goes through the HBB prescaler RCC->CFGR0.HPRE which
// by default is disabled
// Reset TIM3 to init all regs
RCC->APB1PRSTR |= RCC_APB1Periph_TIM3;
RCC->APB1PRSTR &= ~RCC_APB1Periph_TIM3;
// set TIM3 clock prescaler divider
TIM3->PSC = 0x0000; // no prescaler
// set PWM total cycle width
static_assert((FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1) < 0xffff, "PWM_FREQ_HZ too low for TIM3");
TIM3->ATRLR = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1;
// for channel 1 let CCxS stay 00 (output), set OC1M to 110 (PWM 1)
// enabling preload (OC1PE) causes the new pulse width in compare capture
// register only to come into effect when UG bit in SWEVGR is set
// (= initiate update) (auto-clears)
TIM3->CHCTLR1 |= TIM_OC1M_2 | TIM_OC1M_1 | TIM_OC1PE;
// Enable channel 1 output (PA6)
TIM3->CCER |= TIM_CC1E | ( TIM_CC1P & TIM3_DEFAULT );
// CTLR1: default is up, events generated, edge align
// enable auto-reload of preload
TIM3->CTLR1 |= TIM_ARPE;
}
static inline void pwm_on(void)
{
// initialize counter
TIM3->SWEVGR |= TIM_UG;
// Enable TIM3
TIM3->CTLR1 |= TIM_CEN;
}
static inline void pwm_off(void)
{
// Disable TIM3
TIM3->CTLR1 &= ~TIM_CEN;
TIM3->CH1CVR = 0;
}
static inline void pwm_set(uint16_t pulse_width)
{
TIM3->CH1CVR = pulse_width;
}
// Integer square root (binary search)
// https://en.wikipedia.org/wiki/Integer_square_root
static inline uint16_t isqrt(uint32_t x)
{
uint16_t l = 0; // lower bound of the square root
uint16_t r = x + 1; // upper bound of the square root
while (l != r - 1) {
uint32_t m = (l + r) / 2; // midpoint to test
if (m * m <= x) {
l = m;
} else {
r = m;
}
}
return l;
}
#define MIN(a, b) ((a) < (b) ? (a) : (b))
__attribute__((noreturn)) int main(void)
{
SystemInit();
funGpioInitAll();
USBFSSetup();
funPinMode(PIN_VBUS, GPIO_CFGLR_IN_ANALOG);
funPinMode(PIN_CURRENT, GPIO_CFGLR_IN_ANALOG);
funPinMode(PIN_NTC, GPIO_CFGLR_IN_ANALOG);
funPinMode(PIN_TEMP, GPIO_CFGLR_IN_ANALOG);
uint8_t adc_channels[3] = {
VBUS_ADC_CHANNEL,
CURRENT_ADC_CHANNEL,
NTC_ADC_CHANNEL
};
uint8_t adc_injected[1] = {
TEMP_ADC_CHANNEL
};
setup_adc_and_dma(adc_channels, 3, adc_injected, 1);
funPinMode(PIN_12V, GPIO_CFGLR_OUT_10Mhz_PP);
funDigitalWrite(PIN_12V, 0);
funPinMode(PIN_HEATER, GPIO_CFGLR_OUT_10Mhz_AF_PP);
funDigitalWrite(PIN_HEATER, 0);
funPinMode(PIN_DISP_RST, GPIO_CFGLR_OUT_10Mhz_PP);
funDigitalWrite(PIN_DISP_RST, 1); // start with display disabled
funPinMode(PIN_ENC_A, GPIO_CFGLR_IN_PUPD); // enable pull-up/down
funDigitalWrite(PIN_ENC_A, 1); // specify pull-up
funPinMode(PIN_ENC_B, GPIO_CFGLR_IN_PUPD); // enable pull-up/down
funDigitalWrite(PIN_ENC_B, 1); // specify pull-up
funPinMode(PIN_BTN, GPIO_CFGLR_IN_FLOAT);
setup_pwm();
pwm_off();
setup_i2c();
// Configure the IO as an interrupt.
// PIN_ENC_B is on port B, channel 11
AFIO->EXTICR1 |= AFIO_EXTICR1_EXTI11_PB; // Port B channel (pin) 11
EXTI->INTENR |= EXTI_INTENR_MR11; // Enable EXT11
EXTI->FTENR |= EXTI_FTENR_TR11; // Falling edge trigger
EXTI->RTENR |= EXTI_RTENR_TR11; // Rising edge trigger
// enable interrupt
NVIC_EnableIRQ(EXTI15_8_IRQn);
// PIN_ENC_A is on port B, channel 3
AFIO->EXTICR1 |= AFIO_EXTICR1_EXTI3_PB; // Port B channel (pin) 3
EXTI->INTENR |= EXTI_INTENR_MR3; // Enable EXT3
EXTI->FTENR |= EXTI_FTENR_TR3; // Falling edge trigger
EXTI->RTENR |= EXTI_RTENR_TR3; // Rising edge trigger
// enable interrupt
NVIC_EnableIRQ(EXTI7_0_IRQn);
Delay_Ms(500);
u8g2 = display_init();
sc7a20_init();
u8g2_ClearBuffer(u8g2);
u8g2_SetBitmapMode(u8g2, 1);
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "Negotiating...");
u8g2_SendBuffer(u8g2);
// Init USBPD
bool has_pd = pd_negotiate(eUSBPD_VCC_3V3);
if (has_pd == false) {
u8g2_ClearBuffer(u8g2);
u8g2_SetBitmapMode(u8g2, 1);
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "Negotiation FAILED");
u8g2_DrawStr(u8g2, x_off+0, y_off+14, USBPD_ResultToStr(pd_get_result()));
u8g2_SendBuffer(u8g2);
Delay_Ms(5000);
} else {
pd_get_profile(&pd_profile, 60);
// TODO: let the user decide the power profile
pd_profile.set_temp = 200;
pd_profile.set_power = 60; // Slightly below max power to avoid overloading
pd_profile.tip_r = 2500; // TODO: tip check and resistance calculator
pd_profile.max_duty = MIN(
(100*(u32)isqrt((
MIN(pd_profile.set_power, pd_profile.power_avail)*pd_profile.tip_r)/1000) * 1000) / pd_profile.voltage
, 100);
u8g2_ClearBuffer(u8g2);
u8g2_SetBitmapMode(u8g2, 1);
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
// Display tip temperature
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "A:");
u8g2_DrawStr(u8g2, x_off+10, y_off+7, u8g2_u16toa(pd_profile.max_current, 4));
// Display bus voltage
u8g2_DrawStr(u8g2, x_off+45, y_off+7, "V:");
u8g2_DrawStr(u8g2, x_off+55, y_off+7, u8g2_u16toa(pd_profile.voltage, 5));
// Display power
u8g2_DrawStr(u8g2, x_off+0, y_off+15, "W:");
u8g2_DrawStr(u8g2, x_off+10, y_off+15, u8g2_u16toa(pd_profile.power_avail, 3));
// Display current
u8g2_DrawStr(u8g2, x_off+45, y_off+15, "D:");
u8g2_DrawStr(u8g2, x_off+55, y_off+15, u8g2_u16toa(pd_profile.max_duty, 3));
u8g2_SendBuffer(u8g2);
Delay_Ms(5000);
}
enum {
STATE_MENU,
STATE_HEATING,
} state = STATE_MENU;
for (;;) {
u32 start = funSysTick32();
poll_input(); // usb
u8g2_ClearBuffer(u8g2);
u8g2_SetBitmapMode(u8g2, 1);
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
static bool pwm = false; // PWM status
static bool enabled = false; // Power electronics enabled
static uint8_t count = 0; // Loop cycles with PWM on
static s32 elapsed = 0;
static bool prev_btn = true;
bool btn = funDigitalRead(PIN_BTN);
if (has_pd) {
static uint16_t vbus_mv, current_ma;
static int16_t temp_c, tip_temp_c;
static uint16_t power;
vbus_mv = U16_FP_EMA_K4(vbus_mv, ((u32)adc_buffer[0]*VCC_MV*11)/4096);
current_ma = U16_FP_EMA_K4(current_ma, get_current_ma(adc_buffer[1]));
temp_c = I16_FP_EMA_K4(temp_c, get_temp_c(adc_buffer[2]));
power = ((u32)vbus_mv*current_ma)/1000000;
// Update the tip temperature only when the PWM is not running
if (!pwm || !enabled) {
Delay_Ms(TURN_OFF_DELAY);
adc_injection_conversion();
u32 tip_mv = ((u32)injection_results[0]*VCC_MV)/4096;
tip_temp_c = I16_FP_EMA_K2(tip_temp_c, (tip_mv*TC_CONV_NOM)/TC_CONV_DEN) + temp_c;
}
switch (state) {
case STATE_MENU:
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TEMP:");
u8g2_DrawStr(u8g2, x_off+25, y_off+7, u8g2_u16toa(pd_profile.set_temp, 4));
if (encoder != 0) {
pd_profile.set_temp += encoder;
encoder = 0;
#define MIN_TEMP 100
#define MAX_TEMP 360
if (pd_profile.set_temp < MIN_TEMP) pd_profile.set_temp = MIN_TEMP;
if (pd_profile.set_temp > MAX_TEMP) pd_profile.set_temp = MAX_TEMP;
}
if (btn == 0 && prev_btn == 1) {
state = STATE_HEATING;
enabled = false;
}
break;
case STATE_HEATING:
// Display tip temperature
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "TIP:");
u8g2_DrawStr(u8g2, x_off+20, y_off+7, u8g2_u16toa(tip_temp_c, 4));
// Display bus voltage
u8g2_DrawStr(u8g2, x_off+45, y_off+7, "V:");
u8g2_DrawStr(u8g2, x_off+55, y_off+7, u8g2_u16toa(vbus_mv/1000, 2));
// Display power
u8g2_DrawStr(u8g2, x_off+0, y_off+15, "W:");
u8g2_DrawStr(u8g2, x_off+10, y_off+15, u8g2_u16toa(power, 3));
// Display current
u8g2_DrawStr(u8g2, x_off+45, y_off+15, "A:");
u8g2_DrawStr(u8g2, x_off+55, y_off+15, u8g2_u16toa(current_ma, 5));
if (enabled) {
funDigitalWrite(PIN_12V, 1);
if (count > CYCLES_PER_MEASURE) {
pwm = false;
count = 0;
} else {
pwm = true;
count++;
}
// Safety logic
if (current_ma > pd_profile.max_current + pd_profile.max_current/10) {
pwm = false;
}
if (temp_c > MAX_BOARD_TEMP) {
enabled = false;
pwm = false;
}
if (tip_temp_c > MAX_TIP_TEMP) {
enabled = false;
pwm = false;
}
if (pwm) {
const uint16_t tim_max = FUNCONF_SYSTEM_CORE_CLOCK / PWM_FREQ_HZ - 1;
int16_t delta = pd_profile.set_temp - tip_temp_c;
uint16_t duty = MIN((25*pd_profile.max_duty*delta)/(pd_profile.set_temp*10), pd_profile.max_duty);
pwm_set(((u32)duty*tim_max)/100);
u8g2_DrawBox(u8g2, x_off+92, y_off+12, 4, 4);
} else {
pwm_set(0);
}
} else {
funDigitalWrite(PIN_12V, 0);
}
// move to menu mode when encoder is turned
if (encoder != 0) {
state = STATE_MENU;
funDigitalWrite(PIN_12V, 0);
pwm_set(0);
}
// Check button to toggle enable
if (btn == 0 && prev_btn == 1) {
enabled = !enabled;
if (enabled) {
pwm_on();
} else {
pwm_off();
}
}
break;
}
} else {
// No PD capability, just display a message
u8g2_DrawStr(u8g2, x_off+0, y_off+7, "NO PD");
}
u8g2_SendBuffer(u8g2);
prev_btn = btn;
elapsed = funSysTick32() - start;
if (elapsed > 0 && elapsed < Ticks_from_Ms(FRAME_TIME_MS)) {
DelaySysTick(Ticks_from_Ms(FRAME_TIME_MS) - elapsed);
}
}
}

127
fw/pd.c Normal file
View File

@ -0,0 +1,127 @@
#include <ch32fun.h>
#define USBPD_IMPLEMENTATION
#include "usbpd.h"
#include "funconfig.h"
#include "display.h"
#include "pd.h"
extern u8g2_t *u8g2;
static size_t cap_count = 0;
static USBPD_SPR_CapabilitiesMessage_t *capabilities = NULL;
static USBPD_Result_e result;
USBPD_Result_e pd_get_result()
{
return result;
}
// Initializes the Power Delivery peripheral and starts the Power Delivery
// negotiation, returns true if successful, indicating the board is connected to
// a Power Delivery source.
// As a side effect, fills the capabilities buffer with the source's capabilities.
bool pd_negotiate(USBPD_VCC_e vcc)
{
result = USBPD_Init(vcc);
if (result != eUSBPD_OK) {
return false;
}
Delay_Ms(100);
u32 start = funSysTick32();
while (eUSBPD_BUSY == (result = USBPD_SinkNegotiate())) {
u32 now = funSysTick32();
if (now - start > Ticks_from_Ms(5000)) {
break;
}
u8g2_ClearBuffer(u8g2);
u8g2_SetBitmapMode(u8g2, 1);
u8g2_SetFontMode(u8g2, 1);
u8g2_SetFont(u8g2, u8g2_font_5x8_tr);
u8g2_DrawStr(u8g2, 0, 8+7, USBPD_StateToStr(USBPD_GetState()));
u8g2_SendBuffer(u8g2);
Delay_Ms(1);
}
if (result != eUSBPD_OK) {
return false;
}
cap_count = USBPD_GetCapabilities(&capabilities);
if (capabilities == NULL || cap_count == 0) {
return false;
}
return true;
}
bool pd_get_profile(struct pd_profile_t *profile, uint16_t min_power)
{
if (profile == NULL || min_power == 0 || min_power > 140) {
return false;
}
if (capabilities == NULL || cap_count == 0) {
return false;
}
u16 voltage = 0, current = 0, power = 0;
for (u32 i = 0; i < cap_count; i++) {
USBPD_SinkPDO_t *pdo = &capabilities->Sink[i];
switch (pdo->Header.PDOType) {
case eUSBPD_PDO_FIXED:
voltage = pdo->FixedSupply.VoltageIn50mV * 50;
current = pdo->FixedSupply.CurrentIn10mA * 10;
power = ((u32)voltage * current) / (u32)1000000;
break;
case eUSBPD_PDO_BATTERY:
voltage = pdo->BatterySupply.MaxVoltageIn50mV * 50;
power = pdo->BatterySupply.MaxPowerIn250mW / 4;
current = ((u32)power * 1000) / voltage;
break;
case eUSBPD_PDO_VARIABLE:
// TODO: PPS
// if (pdo->VariableSupply.MaxVoltageIn50mV/20 > max_v) {
// max_v = pdo->VariableSupply.MaxVoltageIn50mV/20;
// }
break;
case eUSBPD_PDO_AUGMENTED:
switch (pdo->Header.AugmentedType) {
case eUSBPD_APDO_SPR_PPS:
// TODO: SPR_PPS
break;
case eUSBPD_APDO_SPR_AVS:
// TODO: SPR AVS
break;
case eUSBPD_APDO_EPR_AVS:
/* TODO: EPR AVS
voltage = pdo->EPR_AVS.MaxVoltageIn100mV * 100;
current = pdo->EPR_AVS.PeakCurrent * 1000;
power = pdo->EPR_AVS.PDPIn1W;
*/
break;
default:
break;
}
break;
}
// Selects the first PDO that meets the minimum power requirement
if (power >= min_power && voltage <= BOARD_MAX_VOLTAGE) {
if (USBPD_SelectPDO(i, 0) != eUSBPD_OK) {
return false;
}
profile->voltage = voltage;
profile->max_current = current;
profile->power_avail = power;
return true;
}
}
return false;
}

25
fw/pd.h Normal file
View File

@ -0,0 +1,25 @@
#ifndef _PD_H
#define _PD_H
#include <stdint.h>
#include "usbpd.h"
struct pd_profile_t {
uint16_t voltage; // Vbus Voltage in millivolts
uint16_t max_current; // Maximum current in milliamps
uint16_t power_avail; // Available power (from supply) in watts
uint16_t set_power; // Maximum power in watts, set by the user
uint16_t set_temp; // Set temperature in celsius, set by the user
uint16_t tip_r; // Tip resistance in milliOhms
uint8_t max_duty; // Maximum duty cycle (0-100) to stay within the power limit
};
USBPD_Result_e pd_get_result();
bool pd_negotiate(USBPD_VCC_e vcc);
bool pd_get_profile(struct pd_profile_t *profile, uint16_t min_power);
#endif // _PD_H

5
fw/programmer/.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.pio
.zed
.vscode
.cache
compile_commands.json

View File

@ -0,0 +1,14 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:default]
platform = https://github.com/maxgerhardt/platform-raspberrypi
framework = arduino
board = rpipico

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,197 @@
#include <hardware/gpio.h>
#include <pico/time.h>
#include "bitbang_rvswdio.h"
#include "hardware/timer.h"
#include "lwipopts.h"
#include "pico.h"
#define PIN_SWDIO 10
#define PIN_SWCLK 11
// wait time between line transitions
#define SWD_DELAY() busy_wait_us(2);
// microseconds between each register read/write
#define STOP_WAIT 8
// Single wire debug (SWDIO and SWCLK)
static inline void ConfigureIOForRVSWD(void)
{
// SWCLK forced, starts at 1
gpio_init(PIN_SWCLK);
gpio_set_pulls(PIN_SWCLK, false, false);
gpio_put(PIN_SWCLK, 1);
gpio_set_dir(PIN_SWCLK, GPIO_OUT);
// SWDIO, open drain (emulated) with pull-up
gpio_init(PIN_SWDIO);
gpio_set_pulls(PIN_SWDIO, true, false);
gpio_put(PIN_SWDIO, 1);
gpio_set_dir(PIN_SWDIO, GPIO_IN);
}
// Single wire input-output SDI (just SWDIO)
static inline void ConfigureIOForRVSWIO(void)
{
//BB_PRINTF_DEBUG( "TODO: add support for SWIO\n" );
}
void rvswd_write_bit(bool value)
{
gpio_put(PIN_SWCLK, 0);
gpio_put(PIN_SWDIO, value);
gpio_set_dir(PIN_SWDIO, GPIO_OUT);
gpio_set_dir(PIN_SWDIO, GPIO_IN);
SWD_DELAY();
gpio_put(PIN_SWCLK, 1); // Data is sampled on rising edge of clock
SWD_DELAY();
}
bool rvswd_read_bit(void)
{
gpio_put(PIN_SWDIO, 1);
gpio_set_dir(PIN_SWDIO, GPIO_IN);
gpio_put(PIN_SWCLK, 0);
SWD_DELAY();
bool bit = gpio_get(PIN_SWDIO);
gpio_put(PIN_SWCLK, 1); // Data is output on rising edge of clock
SWD_DELAY();
return bit;
}
static inline void rvswd_stop(void)
{
gpio_put(PIN_SWCLK, 0);
SWD_DELAY();
gpio_put(PIN_SWDIO, 0);
gpio_set_dir(PIN_SWDIO, GPIO_OUT);
SWD_DELAY();
gpio_put(PIN_SWCLK, 1);
SWD_DELAY();
gpio_put(PIN_SWDIO, 1);
gpio_set_dir(PIN_SWDIO, GPIO_IN);
}
static void MCFWriteReg32( struct SWIOState * state, uint8_t command, uint32_t value )
{
// only supported mode is SWD
if (state->opmode != 2) {
//BB_PRINTF_DEBUG( "TODO: add support for SWIO\n" );
return;
}
noInterrupts();
// start transaction
gpio_put(PIN_SWDIO, 0);
gpio_set_dir(PIN_SWDIO, GPIO_OUT);
SWD_DELAY();
// ADDR HOST
bool parity = true;
for (uint32_t mask = 1<<6; mask; mask >>= 1) {
bool bit = !!(command & mask);
parity ^= bit;
rvswd_write_bit(bit);
}
rvswd_write_bit(1); // Operation: write
rvswd_write_bit(parity);
rvswd_read_bit(); // ???
rvswd_read_bit(); // Seems only need to be set for first transaction (We are ignoring that though)
rvswd_read_bit(); // ???
rvswd_write_bit(0); // 0 for register, 1 for value.
rvswd_write_bit(0); // ??? Seems to have something to do with halting.
// DATA
parity = false; // This time it's even parity?
for (uint32_t mask = 1<<31; mask; mask >>= 1) {
bool bit = !!(value & mask);
parity ^= bit;
rvswd_write_bit(bit);
}
// Parity bit
rvswd_write_bit(parity);
rvswd_read_bit(); // ???
rvswd_read_bit(); // ???
rvswd_read_bit(); // ???
rvswd_write_bit(1); // 0 for register, 1 for value
rvswd_write_bit(0); // ??? Seems to have something to do with halting?
rvswd_stop();
interrupts();
sleep_us(STOP_WAIT);
}
static int MCFReadReg32( struct SWIOState * state, uint8_t command, uint32_t * value )
{
// only supported mode is SWD
if (state->opmode != 2) {
//BB_PRINTF_DEBUG( "TODO: add support for SWIO\n" );
return -1;
}
noInterrupts();
// start transaction
gpio_put(PIN_SWDIO, 0);
gpio_set_dir(PIN_SWDIO, GPIO_OUT);
SWD_DELAY();
// ADDR HOST
bool parity = false;
for (uint8_t mask = 1<<6; mask; mask >>= 1) {
bool bit = !!(command & mask);
parity ^= bit;
rvswd_write_bit(bit);
}
rvswd_write_bit(0); // Operation: read
rvswd_write_bit(parity);
rvswd_read_bit(); // ??
rvswd_read_bit(); // ??
rvswd_read_bit(); // ??
rvswd_write_bit(0); // 0 for register, 1 for value
rvswd_write_bit(0); // ??? Seems to have something to do with halting?
// DATA
*value = 0;
parity = false;
uint32_t rval = 0;
for (uint8_t position = 0; position < 32; position++) {
bool bit = rvswd_read_bit();
rval <<= 1;
rval |= bit;
parity ^= bit;
}
*value = rval;
// Parity bit
bool parity_read = rvswd_read_bit();
if (parity_read != parity) goto read_end;
rvswd_read_bit(); // ??
rvswd_read_bit(); // ??
rvswd_read_bit(); // ??
rvswd_write_bit(1); // 0 for register, 1 for value
rvswd_write_bit(0); // ??? Seems to have something to do with halting?
rvswd_stop();
read_end:
interrupts();
sleep_us(STOP_WAIT);
BB_PRINTF_DEBUG("wrong parity: %d\n", parity_read);
return (parity == parity_read) ? 0 : -1;
}

View File

@ -0,0 +1,59 @@
#include "pico/time.h"
#include <Arduino.h>
#include <SerialUSB.h>
#define BB_PRINTF_DEBUG(...) Serial.printf(__VA_ARGS__)
//#define BB_PRINTF_DEBUG(...)
#include "bitbang_rvswdio.h"
#include "bitbang_rvswdio_pico.h"
SWIOState state = {.opmode = 2};
void setup() {
Serial.begin(115200);
Serial.setTimeout(100);
}
void setup1()
{
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
if (Serial.available() > 0) {
char cmd = Serial.read();
int ret = 0;
uint8_t reg;
switch (cmd) {
case '!':
state = {};
ret = InitializeSWDSWIO(&state);
if (ret != 0) {
Serial.printf("error initializing SWD: %d\n", ret);
break;
}
ret = DetermineChipTypeAndSectorInfo(&state, NULL);
if (ret != 0) {
Serial.printf("failed to determine chip type: %d\n", ret);
break;
}
Serial.printf("chip type is %x\n", state.target_chip_type);
break;
default:
Serial.printf("unknown command '%c'\n", cmd);
break;
}
}
}
void loop1()
{
digitalWrite(LED_BUILTIN, 1);
delay(200);
digitalWrite(LED_BUILTIN, 0);
delay(200);
}

199
fw/programmer/test/rvswd.c Normal file
View File

@ -0,0 +1,199 @@
#include "rvswd.h"
#include <inttypes.h>
#include <stdint.h>
#include <hardware/gpio.h>
#include <pico/time.h>
// adapted from https://github.com/Nicolai-Electronics/esp32-component-rvswd
rvswd_result_t rvswd_init(rvswd_handle_t* handle) {
//gpio_config_t swio_cfg = {
// .pin_bit_mask = BIT64(handle->swdio),
// .mode = GPIO_MODE_INPUT_OUTPUT_OD,
// .pull_up_en = true,
// .pull_down_en = false,
// .intr_type = GPIO_INTR_DISABLE,
//};
gpio_init(handle->swdio);
gpio_set_pulls(handle->swdio, true, false);
gpio_put(handle->swdio, 0);
gpio_set_dir(handle->swdio, GPIO_IN);
//gpio_config_t swck_cfg = {
// .pin_bit_mask = BIT64(handle->swclk),
// .mode = GPIO_MODE_OUTPUT,
// .pull_up_en = false,
// .pull_down_en = false,
// .intr_type = GPIO_INTR_DISABLE,
//};
gpio_init(handle->swclk);
gpio_set_pulls(handle->swclk, false, false);
gpio_put(handle->swclk, 0);
gpio_set_dir(handle->swclk, GPIO_OUT);
return RVSWD_OK;
}
rvswd_result_t rvswd_start(rvswd_handle_t* handle) {
// Start with both lines high
// open drain emulation, input for high (pulled up) and out for low (forced)
gpio_set_dir(handle->swdio, GPIO_IN); // high
gpio_put(handle->swclk, 1);
sleep_us(2);
// Pull data low
gpio_set_dir(handle->swdio, GPIO_OUT); // low
gpio_put(handle->swclk, 1);
sleep_us(1);
// Pull clock low
gpio_set_dir(handle->swdio, GPIO_OUT); // low
gpio_put(handle->swclk, 0);
sleep_us(1);
return RVSWD_OK;
}
rvswd_result_t rvswd_stop(rvswd_handle_t* handle) {
// Pull data low
gpio_set_dir(handle->swdio, GPIO_OUT);
sleep_us(1);
gpio_put(handle->swclk, 1);
sleep_us(2);
// Let data float high
gpio_set_dir(handle->swdio, GPIO_IN);
sleep_us(1);
return RVSWD_OK;
}
rvswd_result_t rvswd_reset(rvswd_handle_t* handle) {
// set data floating high
gpio_set_dir(handle->swdio, GPIO_IN);
sleep_us(1);
// let clock go brrr
for (uint8_t i = 0; i < 100; i++) {
gpio_put(handle->swclk, 0);
sleep_us(1);
gpio_put(handle->swclk, 1);
sleep_us(1);
}
return rvswd_stop(handle);
}
#define OD_PULL(pin, value) gpio_set_dir((pin), (value) ? GPIO_IN : GPIO_OUT)
void rvswd_write_bit(rvswd_handle_t* handle, bool value) {
OD_PULL(handle->swdio, value);
gpio_put(handle->swclk, 0);
// FIXME: does this need a delay?
gpio_put(handle->swclk, 1); // Data is sampled on rising edge of clock
}
bool rvswd_read_bit(rvswd_handle_t* handle) {
// let data float high
gpio_set_dir(handle->swdio, GPIO_IN);
// pulse clock
gpio_put(handle->swclk, 0);
gpio_put(handle->swclk, 1); // Data is output on rising edge of clock
// FIXME: does this need a delay?
return gpio_get(handle->swdio);
}
rvswd_result_t rvswd_write(rvswd_handle_t* handle, uint8_t reg, uint32_t value) {
rvswd_start(handle);
// ADDR HOST
bool parity = false; // This time it's odd parity?
for (uint8_t position = 0; position < 7; position++) {
bool bit = (reg >> (6 - position)) & 1;
rvswd_write_bit(handle, bit);
if (bit) parity = !parity;
}
// Operation: write
rvswd_write_bit(handle, true);
parity = !parity;
// Parity bit (even)
rvswd_write_bit(handle, parity);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
// Data
parity = false; // This time it's even parity?
for (uint8_t position = 0; position < 32; position++) {
bool bit = (value >> (31 - position)) & 1;
rvswd_write_bit(handle, bit);
if (bit) parity = !parity;
}
// Parity bit
rvswd_write_bit(handle, parity);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 1);
rvswd_stop(handle);
return RVSWD_OK;
}
rvswd_result_t rvswd_read(rvswd_handle_t* handle, uint8_t reg, uint32_t* value) {
bool parity;
rvswd_start(handle);
// ADDR HOST
parity = false;
for (uint8_t position = 0; position < 7; position++) {
bool bit = (reg >> (6 - position)) & 1;
rvswd_write_bit(handle, bit);
if (bit) parity = !parity;
}
// Operation: read
rvswd_write_bit(handle, false);
// Parity bit (even)
rvswd_write_bit(handle, parity);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
*value = 0;
// Data
parity = false;
for (uint8_t position = 0; position < 32; position++) {
bool bit = rvswd_read_bit(handle);
if (bit) {
*value |= 1 << (31 - position);
}
if (bit) parity = !parity;
}
// Parity bit
bool parity_read = rvswd_read_bit(handle);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 0);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 1);
rvswd_write_bit(handle, 1);
rvswd_stop(handle);
return (parity == parity_read) ? RVSWD_OK : RVSWD_FAIL;
}

View File

@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
typedef struct rvswd_handle {
int swdio;
int swclk;
} rvswd_handle_t;
typedef enum rvswd_result {
RVSWD_OK = 0,
RVSWD_FAIL = 1,
RVSWD_INVALID_ARGS = 2,
RVSWD_PARITY_ERROR = 3,
} rvswd_result_t;
rvswd_result_t rvswd_init(rvswd_handle_t* handle);
rvswd_result_t rvswd_reset(rvswd_handle_t* handle);
rvswd_result_t rvswd_write(rvswd_handle_t* handle, uint8_t reg, uint32_t value);
rvswd_result_t rvswd_read(rvswd_handle_t* handle, uint8_t reg, uint32_t* value);

54
fw/sc7a20.c Normal file
View File

@ -0,0 +1,54 @@
#include <ch32fun.h>
#include "lib_i2c.h"
#include "sc7a20.h"
// Initialization values for control registers, in reg-value pairs
// Basically setup the unit to run, and enable 4D orientation detection
// TODO: Make better comments and define values
static const uint8_t i2c_registers[][2] = {
{ SC7A20_CTRL_REG1, 0b01100111}, // 200Hz, XYZ enabled
{ SC7A20_CTRL_REG2, 0b00000000}, // Setup filter to 0x00 ??
{ SC7A20_CTRL_REG3, 0b00000000}, // INT1 off
{ SC7A20_CTRL_REG4, 0b00001000}, // Block mode off,little-endian,2G,High-pres,self test off
{ SC7A20_CTRL_REG5, 0b00000100}, // fifo off, D4D on INT1
{ SC7A20_CTRL_REG6, 0x00}, // INT2 off
{ SC7A20_INT2_CFG, 0b01111110}, // setup for movement detection
{ SC7A20_INT2_THS, 0x28}, //
{SC7A20_INT2_DURATION, 64}, //
{ SC7A20_INT1_CFG, 0b01111110}, //
{ SC7A20_INT1_THS, 0x28}, //
{SC7A20_INT1_DURATION, 64}
};
void sc7a20_init()
{
// Setup acceleration readings
// 2G range
// bandwidth = 250Hz
// High pass filter on (Slow compensation)
// Turn off IRQ output pins
// Orientation recognition in symmetrical mode
// Hysteresis is set to ~ 16 counts
// Theta blocking is set to 0b10
for (uint8_t i = 0; i < sizeof(i2c_registers) / sizeof(i2c_registers[0]); i++) {
uint8_t bytes[2] = {i2c_registers[i][0], i2c_registers[i][1]};
i2c_sendBytes(I2C_TARGET, SC7A20_ADDRESS, bytes, 2);
}
}
void sc7a20_get_readings(int16_t *x, int16_t *y, int16_t *z)
{
// We can tell the accelerometer to output in LE mode which makes this simple
int16_t sensorData[3] = {0};
i2c_sendByte(I2C_TARGET, SC7A20_ADDRESS, SC7A20_OUT_X_L | 0x80);
i2c_readBytes(I2C_TARGET, SC7A20_ADDRESS, (u8*)sensorData, 6);
// Lower byte is sent first
*x = (int16_t)sensorData[0];
*y = (int16_t)sensorData[1];
*z = (int16_t)sensorData[2];
}

56
fw/sc7a20.h Normal file
View File

@ -0,0 +1,56 @@
/*
* SC7A20_defines.h
*
* Created on: 18 Sep. 2020
* Author: Ralim
*/
#ifndef _SC7A20_H_
#define _SC7A20_H_
#include <ch32fun.h>
#define SC7A20_ADDRESS 0x18
#define SC7A20_WHO_AM_I_VALUE (0b00010001)
#define SC7A20_WHO_AMI_I 0x0F
#define SC7A20_CTRL_REG1 0x20
#define SC7A20_CTRL_REG2 0x21
#define SC7A20_CTRL_REG3 0x22
#define SC7A20_CTRL_REG4 0x23
#define SC7A20_CTRL_REG5 0x24
#define SC7A20_CTRL_REG6 0x25
#define SC7A20_REFERENCE 0x26
#define SC7A20_STATUS_REG 0x27
#define SC7A20_OUT_X_L 0x28
#define SC7A20_OUT_X_L_ALT 0xA8
#define SC7A20_OUT_X_H 0x29
#define SC7A20_OUT_Y_L 0x2A
#define SC7A20_OUT_Y_H 0x2B
#define SC7A20_OUT_Z_L 0x2C
#define SC7A20_OUT_Z_H 0x2D
#define SC7A20_FIFO_CTRL 0x2E
#define SC7A20_FIFO_SRC 0x2F
#define SC7A20_INT1_CFG 0x30
#define SC7A20_INT1_SOURCE 0x31
#define SC7A20_INT1_THS 0x32
#define SC7A20_INT1_DURATION 0x33
#define SC7A20_INT2_CFG 0x34
#define SC7A20_INT2_SOURCE 0x35
#define SC7A20_INT2_THS 0x36
#define SC7A20_INT2_DURATION 0x37
#define SC7A20_CLICK_CFG 0x38
#define SC7A20_CLICK_SRC 0x39
#define SC7A20_CLICK_THS 0x3A
#define SC7A20_TIME_LIMIT 0x3B
#define SC7A20_TIME_LATENCY 0x3C
#define SC7A20_TIME_WINDOW 0x3D
#define SC7A20_ACT_THS 0x3E
#define SC7A20_ACT_DURATION 0x3F
void sc7a20_init(void);
void sc7a20_get_readings(int16_t *x, int16_t *y, int16_t *z);
#endif /* CORE_DRIVERS_BMA223_DEFINES_H_ */

59
fw/script/ntc_lut.py Executable file
View File

@ -0,0 +1,59 @@
#!/usr/bin/env python3
import math
# Script to generate NTC lookup table
# ^ Vcc
# |
# [RES]
# |
# +-- Vadc
# |
# [NTC]
# |
# _|_ GND
# ///
adc_res = 12
ntc_value = 10_000 # at 25°C
resistor_value = 10_000
ntc_beta = 3380 # at 25°C
steps = 64
# NTC resistance to temperature (°C) conversion
def resistance_to_t(ntc_r):
# Standard B-parameter equation
# T = 1 / (1/T0 + 1/B * ln(R/R0))
inv_t = 1/(25 + 273.15) + math.log(ntc_r/ntc_value)/ntc_beta
return 1/inv_t - 273.15
# Resistor divider percentage to NTC resistance conversion
# x = NTC / (NTC + RES) => NTC = RES * x / (1 - x)
def x_to_r(x):
x = max(0.0001, min(0.9999, x))
return resistor_value * x / (1 - x)
# Use 4096 for cleaner divisions
adc_max = 2**adc_res
step_size = adc_max // steps
values = []
for i in range(steps):
adc_val = i * step_size
x = adc_val / adc_max
r = x_to_r(adc_val / adc_max)
t = resistance_to_t(r)
values.append(int(round(t)))
def to_c_array(values, ctype="float", name="table", formatter=str, colcount=8):
# apply formatting to each element
values = [formatter(v) for v in values]
# split into rows with up to `colcount` elements per row
rows = [values[i:i+colcount] for i in range(0, len(values), colcount)]
# separate elements with commas, separate rows with newlines
body = ',\n '.join([', '.join(r) for r in rows])
# assemble components into the complete string
return '{} {}[] = {{\n {}}};'.format(ctype, name, body)
print("uint8_t ntc_step_size = {};".format(int(step_size)))
print(to_c_array(values, ctype="int16_t", name="ntc_lut", formatter=str, colcount=16))

1
fw/u8g2 Submodule

@ -0,0 +1 @@
Subproject commit 3b8939cd015d6aca6a19f761df84859916f1f7d9

182
fw/usb_config.h Normal file
View File

@ -0,0 +1,182 @@
#ifndef _USB_CONFIG_H
#define _USB_CONFIG_H
#include "funconfig.h"
#include "ch32fun.h"
// Endpoint numbers, at least one (EP0)
#define FUSB_CONFIG_EPS 4
// Endpoint configuration for CDC TTY
#define FUSB_EP1_MODE 1 // TX (IN), CDC Interrupt Endpoint
#define FUSB_EP2_MODE -1 // RX (OUT), CDC Data OUT
#define FUSB_EP3_MODE 1 // TX (IN), CDC Data IN
// Other hardware configuration
#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 0 // 3.3V
#include "usb_defines.h"
#define FUSB_USB_VID 0x1209
#define FUSB_USB_PID 0xd035
#define FUSB_USB_REV 0x0007
#define FUSB_STR_MANUFACTURER u"ch32fun"
#define FUSB_STR_PRODUCT u"USB TTY"
#define FUSB_STR_SERIAL u"007"
//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[];
};
const static struct usb_string_descriptor_struct language __attribute__((section(".rodata"))) = {
4,
3,
{0x0409} // Language ID - English US (look in USB_LANGIDs)
};
const static struct usb_string_descriptor_struct string1 __attribute__((section(".rodata"))) = {
sizeof(FUSB_STR_MANUFACTURER),
3, // bDescriptorType - String Descriptor (0x03)
FUSB_STR_MANUFACTURER
};
const static struct usb_string_descriptor_struct string2 __attribute__((section(".rodata"))) = {
sizeof(FUSB_STR_PRODUCT),
3,
FUSB_STR_PRODUCT
};
const static 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).
const static 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

937
fw/usbpd.h Normal file
View File

@ -0,0 +1,937 @@
/* USB PD Library
* 2025-06-21 Bogdan Ionescu
* Configuration:
* - USBPD_IMPLEMENTATION: Enable USB PD implementation
* - FUNCONF_USBPD_NO_STR: Disable string conversion functions
* Notes:
* - This library is based on the USB Power Delivery Specification.
* https://www.usb.org/document-library/usb-power-delivery
* - Packed bitfield structs are used for de/serialization of USB PD messages and
* are taken directly from the spec above.
* - Not all messages are implemented.
* - Formatting macros are provided next to the struct deffinitions.
* Basic usage:
* USBPD_VCC_e vcc = eUSBPD_VCC_5V0; // set the VCC voltage
* USBPD_Result_e result = USBPD_Init( vcc ); // initialize the peripheral
*
* // wait for negotiation to complete.
* while ( eUSBPD_BUSY == ( result = USBPD_SinkNegotiate() ) );
*
* USBPD_SPR_CapabilitiesMessage_t *capabilities;
* const size_t count = USBPD_GetCapabilities( &capabilities );
* USBPD_SelectPDO( count - 1, voltage ); // select the last supply (voltage is only used for PPS)
*
* The above is not a complete example, check the funtion declarations below for more details.
*/
#pragma once
#include "ch32fun.h"
#include "funconfig.h"
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifndef PACKED
#define PACKED __attribute__( ( packed ) )
#endif
// USB PD spec type definitions
typedef enum PACKED
{
eUSBPD_PORTDATAROLE_DFP = 0, // Downstream Facing Port
eUSBPD_PORTDATAROLE_UFP = 1, // Upstream Facing Port
} USBPD_PortDataRole_e;
typedef enum PACKED
{
eUSBPD_PORTPOWEROLE_SINK = 0, // Sink Power Role
eUSBPD_PORTPOWEROLE_SOURCE = 1, // Source Power Role
} USBPD_PortPowerRole_e;
typedef enum PACKED
{
eUSBPD_REV_10 = 0x00u, // Revision 1.0
eUSBPD_REV_20 = 0x01u, // Revision 2.0
eUSBPD_REV_30 = 0x02u, // Revision 3.0
} USBPD_SpecificationRevision_e;
typedef enum PACKED
{
eUSBPD_CTRL_MSG_GOODCRC = 0x01u,
eUSBPD_CTRL_MSG_GOTOMIN = 0x02u, // Depracated
eUSBPD_CTRL_MSG_ACCEPT = 0x03u,
eUSBPD_CTRL_MSG_REJECT = 0x04u,
eUSBPD_CTRL_MSG_PING = 0x05u, // Deprecated
eUSBPD_CTRL_MSG_PS_RDY = 0x06u,
eUSBPD_CTRL_MSG_GET_SOURCE_CAP = 0x07u,
eUSBPD_CTRL_MSG_GET_SINK_CAP = 0x08u,
eUSBPD_CTRL_MSG_DR_SWAP = 0x09u,
eUSBPD_CTRL_MSG_PR_SWAP = 0x0Au,
eUSBPD_CTRL_MSG_VCONN_SWAP = 0x0Bu,
eUSBPD_CTRL_MSG_WAIT = 0x0Cu,
eUSBPD_CTRL_MSG_SOFT_RESET = 0x0Du,
eUSBPD_CTRL_MSG_DATA_RESET = 0x0Eu,
eUSBPD_CTRL_MSG_DATA_RESET_COMPLETE = 0x0Fu,
eUSBPD_CTRL_MSG_NOT_SUPPORTED = 0x10u,
eUSBPD_CTRL_MSG_GET_SOURCE_CAPEXT = 0x11u,
eUSBPD_CTRL_MSG_GET_STATUS = 0x12u,
eUSBPD_CTRL_MSG_FR_SWAP = 0x13u,
eUSBPD_CTRL_MSG_GET_PPS_STATUS = 0x14u,
eUSBPD_CTRL_MSG_GET_COUNTRY_CODES = 0x15u,
eUSBPD_CTRL_MSG_GET_SINK_CAPEXT = 0x16u,
eUSBPD_CTRL_MSG_GET_SOURCE_INFO = 0x17u,
eUSBPD_CTRL_MSG_GET_REVISION = 0x18u,
} USBPD_ControlMessage_e;
typedef enum PACKED
{
eUSBPD_DATA_MSG_SOURCE_CAP = 0x01u,
eUSBPD_DATA_MSG_REQUEST = 0x02u,
eUSBPD_DATA_MSG_BIST = 0x03u,
eUSBPD_DATA_MSG_SINK_CAP = 0x04u,
eUSBPD_DATA_MSG_BATTERY_STATUS = 0x05u,
eUSBPD_DATA_MSG_ALERT = 0x06u,
eUSBPD_DATA_MSG_GET_COUNTRY_INFO = 0x07u,
eUSBPD_DATA_MSG_ENTER_USB = 0x08u,
eUSBPD_DATA_MSG_EPR_REUEST = 0x09u,
eUSBPD_DATA_MSG_EPR_MODE = 0x0Au,
eUSBPD_DATA_MSG_SOURCE_INFO = 0x0Bu,
eUSBPD_DATA_MSG_REVISION = 0x0Cu,
eUSBPD_DATA_MSG_VENDOR_DEFINED = 0x0Fu
} USBPD_DataMessage_e;
typedef union
{
uint16_t data;
struct
{
uint16_t MessageType : 5u; // USBPD_ControlMessage_t | USBPD_DataMessage_t
USBPD_PortDataRole_e PortDataRole : 1u;
USBPD_SpecificationRevision_e SpecificationRevision : 2u;
USBPD_PortPowerRole_e PortPowerRole : 1u;
uint16_t MessageID : 3u;
uint16_t NumberOfDataObjects : 3u; // 0: Control Message, >0: Data Message
uint16_t Extended : 1u;
};
} USBPD_MessageHeader_t;
typedef USBPD_MessageHeader_t USBPD_ControlMessage_t;
static_assert( sizeof( USBPD_MessageHeader_t ) == sizeof( uint16_t ), "USBPD_MessageHeader_t size mismatch" );
typedef enum PACKED
{
eUSBPD_PDO_FIXED = 0,
eUSBPD_PDO_BATTERY = 1,
eUSBPD_PDO_VARIABLE = 2,
eUSBPD_PDO_AUGMENTED = 3,
} USBPD_PowerDataObject_e;
typedef enum PACKED
{
eUSBPD_APDO_SPR_PPS = 0, // Standard Power Range Programmable Power Supply
eUSBPD_APDO_EPR_AVS = 1, // Extended Power Range Adjustable Voltage Supply
eUSBPD_APDO_SPR_AVS = 2, // Standard Power Range Adjustable Voltage Supply
eUSBPD_APDO_RESERVED = 3,
} USBPD_AugmentedPDO_e;
typedef enum PACKED
{
eUSBPD_PEAK_CURRENT_0 = 0, /* Peak Current equals IoC */
eUSBPD_PEAK_CURRENT_1 = 1, /* 150% IoC for 1ms @ 5% duty cycle
125% IoC for 2ms @ 10% duty cycle
110% IoC for 10ms @ 50% duty cycle */
eUSBPD_PEAK_CURRENT_2 = 2, /* 200% IoC for 1ms @ 5% duty cycle
150% IoC for 2ms @ 10% duty cycle
125% IoC for 10ms @ 50% duty cycle */
eUSBPD_PEAK_CURRENT_3 = 3, /* 200% IoC for 1ms @ 5% duty cycle
175% IoC for 2ms @ 10% duty cycle
150% IoC for 10ms @ 50% duty cycle */
} USBPD_PeakCurrent_e;
typedef struct
{
uint32_t data : 28u; // PDO specific data based on PDO type
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_PPS
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
} USBPD_PDOHeader_t;
typedef struct
{
uint32_t MaxCurrentIn10mA : 10u;
uint32_t VoltageIn50mV : 10u;
USBPD_PeakCurrent_e PeakCurrent : 2u;
uint32_t Reserved_22bit : 1u;
uint32_t EPRModeCapable : 1u;
uint32_t UnchunkedExtendedMessage : 1u;
uint32_t DualRoleData : 1u;
uint32_t USBCommunicationsCapable : 1u;
uint32_t UnconstrainedPower : 1u;
uint32_t USBSuspendSupported : 1u;
uint32_t DualRolePower : 1u;
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_FIXED
} USBPD_SourceFixedSupplyPDO_t;
#define FIXED_SUPPLY_FMT \
"\nFixed Supply:\n" \
"\tMax Current: %d mA\n" \
"\tVoltage: %d mV\n" \
"\tPeak Current: %d\n" \
"\tEPR Mode Capable: %s\n" \
"\tUnchunked Extended Message: %s\n" \
"\tDual Role Data: %s\n" \
"\tUSB Communications Capable: %s\n" \
"\tUnconstrained Power: %s\n" \
"\tUSB Suspend Supported: %s\n" \
"\tDual Role Power: %s\n"
#define FIXED_SUPPLY_FMT_ARGS( pdo ) \
( ( pdo )->FixedSupply.MaxCurrentIn10mA * 10 ), ( ( pdo )->FixedSupply.VoltageIn50mV * 50 ), \
( ( pdo )->FixedSupply.PeakCurrent ), ( ( pdo )->FixedSupply.EPRModeCapable ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.UnchunkedExtendedMessage ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.DualRoleData ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.USBCommunicationsCapable ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.UnconstrainedPower ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.USBSuspendSupported ? "Yes" : "No" ), \
( ( pdo )->FixedSupply.DualRolePower ? "Yes" : "No" )
typedef struct
{
uint32_t MaxCurrentIn10mA : 10u;
uint32_t MinVoltageIn50mV : 10u;
uint32_t MaxVoltageIn50mV : 10u;
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_VARIABLE
} USBPD_VariablePDO_t;
#define VARIABLE_SUPPLY_FMT \
"\nVariable Supply:\n" \
"\tMax Current: %d mA\n" \
"\tMin Voltage: %d mV\n" \
"\tMax Voltage: %d mV\n"
#define VARIABLE_SUPPLY_FMT_ARGS( pdo ) \
( ( pdo )->VariableSupply.MaxCurrentIn10mA * 10 ), ( ( pdo )->VariableSupply.MinVoltageIn50mV * 50 ), \
( ( pdo )->VariableSupply.MaxVoltageIn50mV * 50 )
typedef struct
{
uint32_t MaxPowerIn250mW : 10u;
uint32_t MinVoltageIn50mV : 10u;
uint32_t MaxVoltageIn50mV : 10u;
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_BATTERY
} USBPD_BatteryPDO_t;
#define BATTERY_SUPPLY_FMT \
"\nBattery Supply:\n" \
"\tMax Power: %d mW\n" \
"\tMin Voltage: %d mV\n" \
"\tMax Voltage: %d mV\n"
#define BATTERY_SUPPLY_FMT_ARGS( pdo ) \
( ( pdo )->BatterySupply.MaxPowerIn250mW * 250 ), ( ( pdo )->BatterySupply.MinVoltageIn50mV * 50 ), \
( ( pdo )->BatterySupply.MaxVoltageIn50mV * 50 )
typedef struct
{
uint32_t MaxCurrentIn50mA : 7u;
uint32_t Reserved_7bit : 1u; // shall be set to zero
uint32_t MinVoltageIn100mV : 8u;
uint32_t Reserved_16bit : 1u; // shall be set to zero
uint32_t MaxVoltageIn100mV : 8u;
uint32_t Reserved_25_26bit : 2u; // shall be set to zero
uint32_t PPSpowerLimited : 1u;
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_PPS
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
} USBPD_SPR_PPS_APDO_t;
#define SPR_PPS_FMT \
"\nPPS Supply:\n" \
"\tMax Current: %d mA\n" \
"\tMin Voltage: %d mV\n" \
"\tMax Voltage: %d mV\n" \
"\tPPS Power Limited: %s\n"
#define SPR_PPS_FMT_ARGS( pdo ) \
( ( pdo )->SPR_PPS.MaxCurrentIn50mA * 50 ), ( ( pdo )->SPR_PPS.MinVoltageIn100mV * 100 ), \
( ( pdo )->SPR_PPS.MaxVoltageIn100mV * 100 ), ( ( pdo )->SPR_PPS.PPSpowerLimited ? "Yes" : "No" )
typedef struct
{
uint32_t PDPIn1W : 8u;
uint32_t MinVoltageIn100mV : 8u;
uint32_t Reserved_16bit : 1u; // shall be set to zero
uint32_t MaxVoltageIn100mV : 9u;
USBPD_PeakCurrent_e PeakCurrent : 2u;
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_EPR_AVS
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
} USBPD_EPR_AVS_APDO_t;
#define EPR_AVS_FMT \
"\nEPR AVS Supply:\n" \
"\tPDP: %d W\n" \
"\tMin Voltage: %d mV\n" \
"\tMax Voltage: %d mV\n" \
"\tPeak Current: %d\n"
#define EPR_AVS_FMT_ARGS( pdo ) \
( ( pdo )->EPR_AVS.PDPIn1W ), ( ( pdo )->EPR_AVS.MinVoltageIn100mV * 100 ), \
( ( pdo )->EPR_AVS.MaxVoltageIn100mV * 100 ), ( ( pdo )->EPR_AVS.PeakCurrent )
typedef struct
{
uint32_t MaxCurrent15To20VIn10mA : 10u;
uint32_t MaxCurrent9to15VIn10mA : 10u;
uint32_t Reserved_20_25bit : 6u; // shall be set to zero
USBPD_PeakCurrent_e PeakCurrent : 2u;
USBPD_AugmentedPDO_e AugmentedType : 2u; // shall be eUSBPD_APDO_SPR_AVS
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_AUGMENTED
} USBPD_SPR_AVS_APDO_t;
#define SPR_AVS_FMT \
"\nSPR AVS Supply:\n" \
"\tMax Current 15-20V: %d mA\n" \
"\tMax Current 9-15V: %d mA\n" \
"\tPeak Current: %d\n"
#define SPR_AVS_FMT_ARGS( pdo ) \
( ( pdo )->SPR_AVS.MaxCurrent15To20VIn10mA * 10 ), ( ( pdo )->SPR_AVS.MaxCurrent9to15VIn10mA * 10 ), \
( ( pdo )->SPR_AVS.PeakCurrent )
typedef union
{
USBPD_PDOHeader_t Header;
USBPD_SourceFixedSupplyPDO_t FixedSupply;
USBPD_VariablePDO_t VariableSupply;
USBPD_BatteryPDO_t BatterySupply;
USBPD_SPR_PPS_APDO_t SPR_PPS;
USBPD_EPR_AVS_APDO_t EPR_AVS;
USBPD_SPR_AVS_APDO_t SPR_AVS;
} USBPD_SourcePDO_t;
static_assert( sizeof( USBPD_SourcePDO_t ) == sizeof( uint32_t ), "USBPD_SourcePDO_t size mismatch" );
typedef enum // Do not PACK, messes up alignment
{
eUSBPD_FAST_ROLE_SWAP_NOT_SUPPORTED = 0,
eUSBPD_FAST_ROLE_SWAP_DEFAULT = 1,
eUSBPD_FAST_ROLE_SWAP_1A5 = 2, // 1.5A @ 5V
eUSBPD_FAST_ROLE_SWAP_3A = 3, // 3A @ 5V
} USBPD_FastRoleSwapRequiredCurrent_e;
typedef struct
{
uint32_t CurrentIn10mA : 10u;
uint32_t VoltageIn50mV : 10u;
uint32_t Reserved_20_22bit : 3u; // shall be set to zero
USBPD_FastRoleSwapRequiredCurrent_e FastRoleSwap : 2u;
uint32_t DualRoleData : 1u;
uint32_t USBComsCapable : 1u;
uint32_t UnconstrainedPower : 1u;
uint32_t HigherCapability : 1u;
uint32_t DualRolePower : 1u;
USBPD_PowerDataObject_e PDOType : 2u; // shall be eUSBPD_PDO_FIXED
} USBPD_SinkFixedSupplyPDO_t;
typedef union
{
USBPD_PDOHeader_t Header;
USBPD_SinkFixedSupplyPDO_t FixedSupply;
USBPD_VariablePDO_t VariableSupply;
USBPD_BatteryPDO_t BatterySupply;
USBPD_SPR_PPS_APDO_t SPR_PPS;
USBPD_EPR_AVS_APDO_t EPR_AVS;
USBPD_SPR_AVS_APDO_t SPR_AVS;
} USBPD_SinkPDO_t;
static_assert( sizeof( USBPD_SourcePDO_t ) == sizeof( uint32_t ), "USBPD_SourcePDO_t size mismatch" );
static_assert( sizeof( USBPD_SinkPDO_t ) == sizeof( uint32_t ), "USBPD_SinkPDO_t size mismatch" );
typedef union
{
USBPD_SourcePDO_t Source[7];
USBPD_SinkPDO_t Sink[7];
} USBPD_SPR_CapabilitiesMessage_t;
static_assert( sizeof( USBPD_SPR_CapabilitiesMessage_t ) == ( 7 * sizeof( uint32_t ) ),
"USBPD_SPR_CapabilitiesMessage_t size mismatch" );
typedef struct
{
uint32_t MaxCurrentIn10mA : 10u;
uint32_t OperatingCurrentIn10mA : 10u;
uint32_t Reserved_20_21bit : 2u; // shall be set to zero
uint32_t ERPCapable : 1u;
uint32_t UnchunkedExtendedMessage : 1u;
uint32_t NoUSBSuspended : 1u;
uint32_t USBComsCapable : 1u;
uint32_t CapabilityMissmatch : 1u;
uint32_t Giveback : 1u; // Deprecated, shall be set to zero
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
} USBPD_FixedAndVariableRDO_t;
typedef struct
{
uint32_t MaxPowerIn250mW : 10u;
uint32_t OperatingPowerIn250mW : 10u;
uint32_t Reserved_20_21bit : 2u; // shall be set to zero
uint32_t ERPCapable : 1u;
uint32_t UnchunkedExtendedMessage : 1u;
uint32_t NoUSBSuspended : 1u;
uint32_t USBComsCapable : 1u;
uint32_t CapabilityMissmatch : 1u;
uint32_t Giveback : 1u; // Deprecated, shall be set to zero
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
} USBPD_BatteryRDO_t;
typedef struct
{
uint32_t OperatingCurrentIn50mA : 7u;
uint32_t Reserved_7_8bit : 2u; // shall be set to zero
uint32_t OutputVoltageIn20mV : 12u;
uint32_t Reserved_21bit : 1u; // shall be set to zero
uint32_t ERPCapable : 1u;
uint32_t UnchunkedExtendedMessage : 1u;
uint32_t NoUSBSuspended : 1u;
uint32_t USBComsCapable : 1u;
uint32_t CapabilityMissmatch : 1u;
uint32_t Reserved_27bit : 1u; // Deprecated, shall be set to zero
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
} USBPD_PPS_RDO_t;
typedef struct
{
uint32_t OperatingCurrentIn50mA : 7u;
uint32_t Reserved_7_8bit : 2u; // shall be set to zero
uint32_t OutputVoltageIn100mV : 12u; // NOTE: Output voltage in 25mV units, the least two significant bits Shall
// be set to zero making the effective voltage step size 100mV.
uint32_t Reserved_21bit : 1u; // shall be set to zero
uint32_t ERPCapable : 1u;
uint32_t UnchunkedExtendedMessage : 1u;
uint32_t NoUSBSuspended : 1u;
uint32_t USBComsCapable : 1u;
uint32_t CapabilityMissmatch : 1u;
uint32_t Reserved_27bit : 1u; // Deprecated, shall be set to zero
uint32_t ObjectPosition : 4u; // Reserved and shall not be used
} USBPD_AVS_RDO_t;
typedef union
{
USBPD_FixedAndVariableRDO_t FixedAndVariable;
USBPD_BatteryRDO_t Battery;
USBPD_PPS_RDO_t PPS;
} USBPD_RequestDataObject_t;
static_assert( sizeof( USBPD_RequestDataObject_t ) == sizeof( uint32_t ), "USBPD_RequestDataObject_t size mismatch" );
// TODO: Define the rest of the message types sections 6.4.3 -> 6.5.16
typedef enum
{
eUSBPD_MAX_EXTENDED_MSG_LEN = 260,
eUSBPD_MAX_EXTENDED_MSG_CHUNK_LEN = 26,
eUSBPD_MAX_EXTENDED_MSG_LEGACY_LEN = 26,
} USBPD_ValueParameters_t;
typedef enum
{
eUSBPD_OK = 0,
eUSBPD_BUSY,
eUSBPD_ERROR,
eUSBPD_ERROR_ARGS,
eUSBPD_ERROR_NOT_SUPPORTED,
eUSBPD_ERROR_TIMEOUT,
} USBPD_Result_e;
typedef enum
{
eUSBPD_VCC_3V3 = 0,
eUSBPD_VCC_5V0 = 1,
} USBPD_VCC_e;
typedef enum
{
eUSBPD_CCNONE = 0,
eUSBPD_CC1 = 1,
eUSBPD_CC2 = 2,
} USBPD_CC_e;
typedef enum
{
eSTATE_IDLE,
eSTATE_CABLE_DETECT,
eSTATE_SOURCE_CAP,
eSTATE_WAIT_ACCEPT,
eSTATE_WAIT_PS_RDY,
eSTATE_PS_RDY,
eSTATE_MAX,
} USBPD_State_e;
/**
* @brief Initialize the USB PD module
* @param vcc: VCC voltage level (3.3V or 5V)
* @return USBPD_Result_e
*/
USBPD_Result_e USBPD_Init( USBPD_VCC_e vcc );
/**
* @brief Negotiate with the USB PD Source, must be called periodically
* @param None
* @return USBPD_BUSY if negotiation is in progress, eUSBPD_OK if successful, or an error code
*/
USBPD_Result_e USBPD_SinkNegotiate( void );
/**
* @brief Reset the USB PD module
* @param None
* @return None
*/
void USBPD_Reset( void );
/**
* @brief Get the current state of the USB PD module
* @param None
* @return USBPD_State_e representing the current state of the module
*/
USBPD_State_e USBPD_GetState( void );
/**
* @brief Convert USB PD state to string
* @param state: USBPD_State_e to convert
* @return Pointer to a string representing the state
*/
const char *USBPD_StateToStr( USBPD_State_e state );
/**
* @brief Convert USB PD result to string
* @param result: USBPD_Result_e to convert
* @return Pointer to a string representing the result
*/
const char *USBPD_ResultToStr( USBPD_Result_e result );
/**
* @brief Select a new Power Data Object (PDO) to be used. No re-negotiation is needed.
* @param index: Index of the PDO to select (0-based)
* @param voltageIn100mV: Desired output voltage in 100mV units (e.g., 500 for 5V) (only applicable for PPS)
* @return USBPD_Result_e
*/
USBPD_Result_e USBPD_SelectPDO( uint8_t index, uint32_t voltageIn100mV );
/**
* @brief Get the capabilities of the USB PD Source
* @param[out] capabilities: Pointer to a pointer where the capabilities message structure is stored
* @return Number of Power Data Objects (PDOs) in the capabilities message
*/
size_t USBPD_GetCapabilities( USBPD_SPR_CapabilitiesMessage_t **capabilities );
/**
* @brief Check if the Power Data Object is a Programmable Power Supply (PPS)
* @param[in] pdo: Pointer to the Power Data Object to check
* @return true if the PDO is a PPS, false otherwise
*/
bool USBPD_IsPPS( const USBPD_SourcePDO_t *pdo );
/**
* @brief Get the USB PD Specification Revision
* @param None
* @return USBPD_SpecificationRevision_e representing the USB PD specification revision
*/
USBPD_SpecificationRevision_e USBPD_GetVersion( void );
#if defined( USBPD_IMPLEMENTATION )
#include <string.h>
typedef struct
{
uint32_t ccCount;
volatile USBPD_State_e state;
USBPD_SpecificationRevision_e pdVersion;
USBPD_CC_e lastCCLine;
USBPD_SPR_CapabilitiesMessage_t caps;
uint8_t messageID;
uint8_t pdoCount;
bool gotSourceGoodCRC;
} USBPD_Instance_t;
static __attribute__( ( aligned( 4 ) ) ) uint8_t s_buffer[34];
static USBPD_Instance_t s_instance = {
.pdVersion = eUSBPD_REV_30,
};
static USBPD_CC_e GetActiveCCLine( void );
static void SwitchRXMode( void );
static void SendMessage( uint8_t size );
static void ParsePacket( void );
USBPD_Result_e USBPD_Init( USBPD_VCC_e vcc )
{
RCC->APB2PCENR |= RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO;
RCC->AHBPCENR |= RCC_USBPD;
GPIOC->CFGHR &= ~( 0xf << ( ( 14 & 7 ) << 2 ) );
GPIOC->CFGHR |= ( GPIO_Speed_10MHz | GPIO_CNF_OUT_OD ) << ( ( 14 & 7 ) << 2 );
GPIOC->CFGHR &= ~( 0xf << ( ( 15 & 7 ) << 2 ) );
GPIOC->CFGHR |= ( GPIO_Speed_10MHz | GPIO_CNF_OUT_OD ) << ( ( 15 & 7 ) << 2 );
AFIO->CTLR |= USBPD_IN_HVT;
if ( vcc == eUSBPD_VCC_3V3 )
{
AFIO->CTLR |= USBPD_PHY_V33;
}
USBPD->DMA = (uint32_t)s_buffer;
USBPD->CONFIG = IE_RX_ACT | IE_RX_RESET | IE_TX_END | PD_DMA_EN | PD_FILT_EN;
USBPD->STATUS = BUF_ERR | IF_RX_BIT | IF_RX_BYTE | IF_RX_ACT | IF_RX_RESET | IF_TX_END;
// disable CC comparators
USBPD->PORT_CC1 &= ~( CC_CMP_MASK | PA_CC_AI );
USBPD->PORT_CC2 &= ~( CC_CMP_MASK | PA_CC_AI );
// set CC comparator voltage
USBPD->PORT_CC1 |= CC_CMP_66;
USBPD->PORT_CC2 |= CC_CMP_66;
return eUSBPD_OK;
}
USBPD_Result_e USBPD_SinkNegotiate( void )
{
switch ( s_instance.state )
{
case eSTATE_IDLE:;
const uint8_t ccLine = GetActiveCCLine();
if ( ccLine == eUSBPD_CCNONE )
{
s_instance.ccCount = 0;
s_instance.lastCCLine = eUSBPD_CCNONE;
break;
}
if ( s_instance.lastCCLine != ccLine )
{
s_instance.lastCCLine = ccLine;
s_instance.ccCount = 0;
}
else
{
s_instance.ccCount++;
}
if ( s_instance.ccCount > 10 )
{
if ( ccLine == eUSBPD_CC2 )
{
USBPD->CONFIG |= CC_SEL;
}
else
{
USBPD->CONFIG &= ~CC_SEL;
}
s_instance.ccCount = 0;
s_instance.state = eSTATE_CABLE_DETECT;
SwitchRXMode();
// NVIC_SetPriority(USBPD_IRQn, 0x00); // TODO: Is this needed?
NVIC_EnableIRQ( USBPD_IRQn );
}
break;
case eSTATE_SOURCE_CAP:
USBPD_SelectPDO( 0, 0 ); // Select the first PDO by default
s_instance.state = eSTATE_WAIT_ACCEPT;
break;
case eSTATE_PS_RDY: return eUSBPD_OK;
default: break;
}
return eUSBPD_BUSY;
}
void USBPD_Reset( void )
{
NVIC_DisableIRQ( USBPD_IRQn );
s_instance = ( USBPD_Instance_t ){
.pdVersion = eUSBPD_REV_30,
};
}
USBPD_State_e USBPD_GetState( void )
{
return s_instance.state;
}
#if FUNCONF_USBPD_NO_STR
const char *USBPD_StateToStr( USBPD_State_e state )
{
(void)state;
return "";
}
const char *USBPD_ResultToStr( USBPD_Result_e result )
{
(void)result;
return "";
}
#else
const char *USBPD_StateToStr( USBPD_State_e state )
{
switch ( state )
{
case eSTATE_IDLE: return "Idle";
case eSTATE_CABLE_DETECT: return "Cable Detected";
case eSTATE_SOURCE_CAP: return "Got Source Capabilities";
case eSTATE_WAIT_ACCEPT: return "Waiting for Accept";
case eSTATE_WAIT_PS_RDY: return "Waiting for PS_Ready";
case eSTATE_PS_RDY: return "Power Supply Ready";
default: return "Unknown State";
}
};
const char *USBPD_ResultToStr( USBPD_Result_e result )
{
switch ( result )
{
case eUSBPD_OK: return "OK";
case eUSBPD_BUSY: return "Busy";
case eUSBPD_ERROR: return "Error";
case eUSBPD_ERROR_ARGS: return "Error Args";
case eUSBPD_ERROR_NOT_SUPPORTED: return "Error Not Supported";
case eUSBPD_ERROR_TIMEOUT: return "Error Timeout";
default: return "Unknown Result";
}
}
#endif // FUNCONF_USBPD_NO_STR
USBPD_Result_e USBPD_SelectPDO( uint8_t index, uint32_t voltageIn100mV )
{
if ( index >= s_instance.pdoCount )
{
return eUSBPD_ERROR_ARGS;
}
const USBPD_SourcePDO_t *const pdo = &s_instance.caps.Source[index];
*(USBPD_MessageHeader_t *)&s_buffer[0] = ( USBPD_MessageHeader_t ){
.MessageID = s_instance.messageID,
.MessageType = eUSBPD_DATA_MSG_REQUEST,
.NumberOfDataObjects = 1u,
.SpecificationRevision = s_instance.pdVersion,
};
USBPD_RequestDataObject_t *const rdo = (USBPD_RequestDataObject_t *)&s_buffer[sizeof( USBPD_MessageHeader_t )];
if ( USBPD_IsPPS( pdo ) )
{
// Clamp voltage to min/max NOTE: Maybe we should return an error if the voltage is out of range?
const uint32_t minVoltage = pdo->SPR_PPS.MinVoltageIn100mV;
const uint32_t maxVoltage = pdo->SPR_PPS.MaxVoltageIn100mV;
voltageIn100mV = voltageIn100mV > maxVoltage ? maxVoltage : voltageIn100mV;
voltageIn100mV = voltageIn100mV < minVoltage ? minVoltage : voltageIn100mV;
*rdo = ( USBPD_RequestDataObject_t ){
.PPS =
{
.ObjectPosition = index + 1,
.OutputVoltageIn20mV = voltageIn100mV * 5,
.OperatingCurrentIn50mA = pdo->SPR_PPS.MaxCurrentIn50mA,
.NoUSBSuspended = 1u,
.USBComsCapable = 1u, // TODO: Should have these are arguments or define
},
};
}
else
{
*rdo = ( USBPD_RequestDataObject_t ){
.FixedAndVariable =
{
.ObjectPosition = index + 1,
.MaxCurrentIn10mA = pdo->FixedSupply.MaxCurrentIn10mA,
.OperatingCurrentIn10mA = pdo->FixedSupply.MaxCurrentIn10mA,
.USBComsCapable = 1u,
.NoUSBSuspended = 1u,
},
};
}
SendMessage( 6 );
return eUSBPD_OK;
}
/**
* @brief Get the capabilities of the USB PD Source
* @param[out] capabilities: pointer to the capabilities message structure
* @return Number of Power Data Objects (PDOs) in the capabilities message
*/
size_t USBPD_GetCapabilities( USBPD_SPR_CapabilitiesMessage_t **capabilities )
{
if ( s_instance.pdoCount == 0 )
{
return 0;
}
if ( capabilities )
{
*capabilities = &s_instance.caps;
}
return s_instance.pdoCount;
}
bool USBPD_IsPPS( const USBPD_SourcePDO_t *pdo )
{
return ( pdo->Header.PDOType == eUSBPD_PDO_AUGMENTED ) && ( pdo->Header.AugmentedType == eUSBPD_APDO_SPR_PPS );
}
USBPD_SpecificationRevision_e USBPD_GetVersion( void )
{
return s_instance.pdVersion;
}
/**
* @brief Check CC line status
* @param None
* @return USBPD_CC_t
*/
static USBPD_CC_e GetActiveCCLine( void )
{
// Switch to CC1
USBPD->CONFIG &= ~CC_SEL;
Delay_Us( 1 );
// check if CC1 is connected
if ( USBPD->PORT_CC1 & PA_CC_AI )
{
return eUSBPD_CC1;
}
// Switch to CC2
USBPD->CONFIG |= CC_SEL;
Delay_Us( 1 );
if ( USBPD->PORT_CC2 & PA_CC_AI )
{
return eUSBPD_CC2;
}
return eUSBPD_CCNONE;
}
/**
* @brief Switch to RX mode
* @param None
* @return None
*/
static void SwitchRXMode( void )
{
USBPD->BMC_CLK_CNT = UPD_TMR_RX;
USBPD->CONTROL = ( USBPD->CONTROL & ~PD_TX_EN ) | BMC_START;
}
/**
* @brief Begin transmission of PD message
* @param size: size of the message in bytes
* @return None
*/
static void SendMessage( uint8_t size )
{
USBPD->BMC_CLK_CNT = UPD_TMR_TX;
USBPD->TX_SEL = UPD_SOP0;
USBPD->BMC_TX_SZ = size;
USBPD->STATUS = 0;
USBPD->CONTROL |= BMC_START | PD_TX_EN;
}
/**
* @brief Parse the received packet
* @param None
* @return None
*/
static void ParsePacket( void )
{
bool sendGoodCRC = true;
USBPD_MessageHeader_t message = *(USBPD_MessageHeader_t *)s_buffer;
USBPD_State_e nextState = s_instance.state;
if ( message.NumberOfDataObjects == 0u )
{
switch ( (USBPD_ControlMessage_e)message.MessageType )
{
case eUSBPD_CTRL_MSG_GOODCRC:
sendGoodCRC = false;
s_instance.messageID++;
break;
case eUSBPD_CTRL_MSG_ACCEPT: nextState = eSTATE_WAIT_PS_RDY; break;
case eUSBPD_CTRL_MSG_REJECT: nextState = eSTATE_SOURCE_CAP; break;
case eUSBPD_CTRL_MSG_PS_RDY: nextState = eSTATE_PS_RDY; break;
default: break;
}
}
else
{
switch ( (USBPD_DataMessage_e)message.MessageType )
{
case eUSBPD_DATA_MSG_SOURCE_CAP:
nextState = eSTATE_SOURCE_CAP;
s_instance.pdoCount = message.NumberOfDataObjects;
s_instance.pdVersion = message.SpecificationRevision;
memcpy( &s_instance.caps, &s_buffer[2], sizeof( USBPD_SPR_CapabilitiesMessage_t ) );
break;
default: break;
}
}
if ( message.Extended || sendGoodCRC )
{
Delay_Us( 30 );
USBPD_ControlMessage_t reply = ( USBPD_ControlMessage_t ){
.MessageID = message.MessageID,
.MessageType = eUSBPD_CTRL_MSG_GOODCRC,
.SpecificationRevision = s_instance.pdVersion,
};
*(uint16_t *)&s_buffer[0] = reply.data;
SendMessage( sizeof( reply ) );
}
s_instance.state = nextState;
}
void USBPD_IRQHandler( void ) __attribute__( ( interrupt ) );
void USBPD_IRQHandler( void )
{
// Receive complete interrupt
if ( USBPD->STATUS & IF_RX_ACT )
{
// Check if we received a SOP0 packet
if ( ( ( USBPD->STATUS & BMC_AUX_MASK ) == BMC_AUX_SOP0 ) && ( USBPD->BMC_BYTE_CNT >= 6 ) )
{
ParsePacket();
}
USBPD->STATUS |= IF_RX_ACT;
}
// Transmit complete interrupt (GoodCRC only)
if ( USBPD->STATUS & IF_TX_END )
{
SwitchRXMode();
USBPD->STATUS |= IF_TX_END;
}
// Reset interrupt
if ( USBPD->STATUS & IF_RX_RESET )
{
USBPD->STATUS |= IF_RX_RESET;
}
}
#endif

4
hw/.gitignore vendored
View File

@ -39,3 +39,7 @@ fp-info-cache
# Local project settings
*.kicad_prl
.history
# fabrication toolkit output
production

View File

@ -1,29 +1,28 @@
Index,LCSC#,MPN,Manufacturer,Package,Customer #,Description,RoHS,Quantity,MOQ,Multiple,Unit Price(€),Extended Price(€),Product Link
1,C473369,TLV333IDBVR,TI,SOT-23-5,,"2uV Rail-to-Rail Input, Rail-to-Rail Output 70pA 0.16V/us 102dB 17uA 350kHz 1 SOT-23-5 Amplifiers RoHS",yes,5,5,5,0.2047,1.02,https://www.lcsc.com/product-detail/C473369.html
2,C2827931,SS24L,Guangdong Hottech,SOD-123FL,,Diode Independent 40V 2A Surface Mount SOD-123FL,yes,20,20,20,0.0214,0.43,https://www.lcsc.com/product-detail/C2827931.html
1,C473369,TLV333IDBVR,TI,SOT-23-5,,"2uV Rail-to-Rail Input, Rail-to-Rail Output 70pA 0.16V/us 102dB 17uA 350kHz 1 SOT-23-5 Amplifiers RoHS",yes,5,5,5,0.2121,1.06,https://www.lcsc.com/product-detail/C473369.html
2,C2827931,SS24L,Guangdong Hottech,SOD-123FL,,Diode Independent 40V 2A Surface Mount SOD-123FL,yes,20,20,20,0.0204,0.41,https://www.lcsc.com/product-detail/C2827931.html
3,C2931472,U263-163N-4OS1735,XKB Connection,SMD,,USB-C (USB TYPE-C) Receptacle Connector 16 Position Surface Mount,yes,5,5,5,0.2518,1.26,https://www.lcsc.com/product-detail/C2931472.html
4,C2999960,MM5Z3V3,Slkor,SOD-523,,Zener Diode Independent 3.3V 200mW Surface Mount SOD-523,yes,20,20,20,0.0180,0.36,https://www.lcsc.com/product-detail/C2999960.html
5,C52754543,RB521S30T1G-HXY,HXY MOSFET,SOD-523,,1A 1 Independent 30V 350mV@10mA 200mA SOD-523 Single Diodes RoHS,yes,20,20,20,0.0212,0.42,https://www.lcsc.com/product-detail/C52754543.html
5,C52754543,RB521S30T1G-HXY,HXY MOSFET,SOD-523,,1A 1 Independent 30V 350mV@10mA 200mA SOD-523 Single Diodes RoHS,yes,20,20,20,0.0202,0.40,https://www.lcsc.com/product-detail/C52754543.html
6,C42442062,CH32X035F8U6,WCH,QFN-20-EP(3x3),,QFN-20-EP(3x3) Microcontrollers RoHS,yes,5,1,1,0.4460,2.23,https://www.lcsc.com/product-detail/C42442062.html
7,C780769,AP63203WU-7,DIODES,TSOT-23-6,,1.1MHz Buck Fixed 2A 3.3V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,yes,5,1,1,0.3955,1.98,https://www.lcsc.com/product-detail/C780769.html
8,C7466527,AGM403AP,AGMSEMI,PDFN3.3x3.3-8,,N-Channel 40V 65A 69W Surface Mount PDFN3.3x3.3,yes,5,5,5,0.2575,1.29,https://www.lcsc.com/product-detail/C7466527.html
7,C780769,AP63203WU-7,DIODES,TSOT-23-6,,1.1MHz Buck Fixed 2A 3.3V 3.8V~32V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,yes,5,1,1,0.3766,1.88,https://www.lcsc.com/product-detail/C780769.html
8,C7466527,AGM403AP,AGMSEMI,PDFN3.3x3.3-8,,N-Channel 40V 65A 69W Surface Mount PDFN3.3x3.3,yes,5,5,5,0.2447,1.22,https://www.lcsc.com/product-detail/C7466527.html
9,C2906999,FRC0603F1803TS,FOJAN,0603,,180kΩ ±1% 100mW 0603 Thick Film Resistor,yes,100,100,100,0.0010,0.10,https://www.lcsc.com/product-detail/C2906999.html
10,C4169844,RS73F1JTTD2703B,KOA,0603,,200mW 270kΩ Thick Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS,yes,5,5,5,0.0638,0.32,https://www.lcsc.com/product-detail/C4169844.html
11,C2932326,MT3608L,XI'AN Aerosemi Tech,SOT-23-6,,1.2MHz Boost Adjustable 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,yes,10,10,10,0.0373,0.37,https://www.lcsc.com/product-detail/C2932326.html
12,C138714,TPD4E05U06DQAR,TI,USON-10(1x2.5),,14VC Clamp 2.5A@8/20us Ipp TVS DIODE USON-10(1x2.5),yes,5,5,5,0.0629,0.31,https://www.lcsc.com/product-detail/C138714.html
11,C2932326,MT3608L,XI'AN Aerosemi Tech,SOT-23-6,,1.2MHz Boost Adjustable 2.2V~16V 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,yes,10,10,10,0.0373,0.37,https://www.lcsc.com/product-detail/C2932326.html
12,C138714,TPD4E05U06DQAR,TI,USON-10(1x2.5),,14VC Clamp 2.5A@8/20us Ipp TVS DIODE USON-10(1x2.5),yes,5,5,5,0.0679,0.34,https://www.lcsc.com/product-detail/C138714.html
13,C19274408,SC7A20HTR,Hangzhou Silan Microelectronics,LGA-12(2x2),,LGA-12(2x2) Accelerometers RoHS,yes,5,1,1,0.2417,1.21,https://www.lcsc.com/product-detail/C19274408.html
14,C52741377,CPN201610H6R8MT,Magnetsyc,0806,,820mA 6.8uH 1.1A 545mΩ ±20% 0806 Fixed Inductors RoHS,yes,20,20,20,0.0277,0.55,https://www.lcsc.com/product-detail/C52741377.html
15,C18723015,X087-2832TSWIG02-H14,Wisevision,-,,"0.87 128x32 SSD1312 chip I2C LCD, OLED, Graphic RoHS",yes,5,1,1,1.6435,8.22,https://www.lcsc.com/product-detail/C18723015.html
16,C110776,RT0603BRD071KL,YAGEO,0603,,100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS,yes,20,20,20,0.0187,0.37,https://www.lcsc.com/product-detail/C110776.html
17,C162670,NCU18XH103F6SRB,muRata,0603,,NTC Thermistor 10kΩ Surface Mount 0603,yes,10,10,10,0.0533,0.53,https://www.lcsc.com/product-detail/C162670.html
18,C46818248,SIQ-02FVS3,LZG,-,,Encoders - Industrial RoHS,yes,5,1,1,0.9816,4.91,https://www.lcsc.com/product-detail/C46818248.html
19,C41414522,NSG10752,WXNSIC,SOT-23-6,,High Side Gate Driver IC MOSFET IGBT SOT-23-6,yes,5,1,1,0.4842,2.42,https://www.lcsc.com/product-detail/C41414522.html
20,C76799,MLZ1608M4R7WT000,TDK,0603,,350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS,yes,10,10,10,0.0341,0.34,https://www.lcsc.com/product-detail/C76799.html
21,C98192,CL21A475KBQNNNE,Samsung Electro-Mechanics,0805,,4.7uF ±10% 50V Ceramic Capacitor X5R 0805,yes,10,10,10,0.0179,0.18,https://www.lcsc.com/product-detail/C98192.html
22,C29936,CL10B105KA8NNNC,Samsung Electro-Mechanics,0603,,1uF ±10% 25V Ceramic Capacitor X7R 0603,yes,50,50,50,0.0056,0.28,https://www.lcsc.com/product-detail/C29936.html
23,C1590,CL10B104KA8NNNC,Samsung Electro-Mechanics,0603,,100nF ±10% 25V Ceramic Capacitor X7R 0603,yes,100,100,100,0.0032,0.32,https://www.lcsc.com/product-detail/C1590.html
24,C2997487,MPD220M1VD19040R,Ymin,"SMD,7.3x4.3mm",,"35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS",yes,5,1,1,0.7063,3.53,https://www.lcsc.com/product-detail/C2997487.html
25,C5796173,MCASU32MAB7106KPNA01,Taiyo Yuden,1210,,10uF ±10% 50V Ceramic Capacitor X7R 1210,yes,25,5,5,0.0982,2.46,https://www.lcsc.com/product-detail/C5796173.html
26,C5370906,FC-ALX 4030D-2R2MT,FANGCHENG,"SMD,4.2x4.2mm",,"8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS",yes,5,1,1,0.4781,2.39,https://www.lcsc.com/product-detail/C5370906.html
27,C49851,INA226AIDGSR,TI,MSOP-10,,300mV~40V 2.5uV 10nA MSOP-10 Current Regulation/Management RoHS,yes,5,1,1,0.5765,2.88,https://www.lcsc.com/product-detail/C49851.html
28,C49164932,JER1206F1R002,JIERR,1206,,1W 2mΩ ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS,yes,10,10,10,0.0371,0.37,https://www.lcsc.com/product-detail/C49164932.html
15,C110776,RT0603BRD071KL,YAGEO,0603,,100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS,yes,20,20,20,0.0187,0.37,https://www.lcsc.com/product-detail/C110776.html
16,C162670,NCU18XH103F6SRB,muRata,0603,,NTC Thermistor 10kΩ Surface Mount 0603,yes,10,10,10,0.0533,0.53,https://www.lcsc.com/product-detail/C162670.html
17,C46818248,SIQ-02FVS3,LZG,-,,Encoders - Industrial RoHS,yes,5,1,1,0.9816,4.91,https://www.lcsc.com/product-detail/C46818248.html
18,C41414522,NSG10752,WXNSIC,SOT-23-6,,High Side Gate Driver IC MOSFET IGBT SOT-23-6,yes,5,1,1,0.4600,2.30,https://www.lcsc.com/product-detail/C41414522.html
19,C76799,MLZ1608M4R7WT000,TDK,0603,,350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS,yes,10,10,10,0.0341,0.34,https://www.lcsc.com/product-detail/C76799.html
20,C98192,CL21A475KBQNNNE,Samsung Electro-Mechanics,0805,,4.7uF ±10% 50V Ceramic Capacitor X5R 0805,yes,10,10,10,0.0179,0.18,https://www.lcsc.com/product-detail/C98192.html
21,C29936,CL10B105KA8NNNC,Samsung Electro-Mechanics,0603,,1uF ±10% 25V Ceramic Capacitor X7R 0603,yes,50,50,50,0.0056,0.28,https://www.lcsc.com/product-detail/C29936.html
22,C2997487,MPD220M1VD19040R,Ymin,"SMD,7.3x4.3mm",,"35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS",yes,5,1,1,0.7063,3.53,https://www.lcsc.com/product-detail/C2997487.html
23,C5370906,FC-ALX 4030D-2R2MT,FANGCHENG,"SMD,4.2x4.2mm",,"8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS",yes,5,1,1,0.4781,2.39,https://www.lcsc.com/product-detail/C5370906.html
24,C18723014,X069-9616TSWIG02-H14,Wisevision,-,,"0.69 96x16 SSD1312 chip I2C LCD, OLED, Graphic RoHS",yes,2,1,1,1.3337,2.67,https://www.lcsc.com/product-detail/C18723014.html
25,C386166,UMK325AB7106KMHP,Taiyo Yuden,1210,,10uF ±10% 50V Ceramic Capacitor X7R 1210 AEC-Q200,yes,25,5,5,0.0854,2.14,https://www.lcsc.com/product-detail/C386166.html
26,C38582720,TPA191A4-SC6R,3PEAK,SOT-363,,50uV -300mV~+36V 22uA 2.5V/us 120dB 30kHz 80uA 100V/V SOT-363 Amplifiers RoHS,yes,5,5,5,0.5300,2.65,https://www.lcsc.com/product-detail/C38582720.html
27,C5185587,CUM1206-15FR004,FORT,1206,,1W 4mΩ SMD ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS,yes,5,1,1,0.0157,0.08,https://www.lcsc.com/product-detail/C5185587.html

1 Index LCSC# MPN Manufacturer Package Customer # Description RoHS Quantity MOQ Multiple Unit Price(€) Extended Price(€) Product Link
2 1 C473369 TLV333IDBVR TI SOT-23-5 2uV Rail-to-Rail Input, Rail-to-Rail Output 70pA 0.16V/us 102dB 17uA 350kHz 1 SOT-23-5 Amplifiers RoHS yes 5 5 5 0.2047 0.2121 1.02 1.06 https://www.lcsc.com/product-detail/C473369.html
3 2 C2827931 SS24L Guangdong Hottech SOD-123FL Diode Independent 40V 2A Surface Mount SOD-123FL yes 20 20 20 0.0214 0.0204 0.43 0.41 https://www.lcsc.com/product-detail/C2827931.html
4 3 C2931472 U263-163N-4OS1735 XKB Connection SMD USB-C (USB TYPE-C) Receptacle Connector 16 Position Surface Mount yes 5 5 5 0.2518 1.26 https://www.lcsc.com/product-detail/C2931472.html
5 4 C2999960 MM5Z3V3 Slkor SOD-523 Zener Diode Independent 3.3V 200mW Surface Mount SOD-523 yes 20 20 20 0.0180 0.36 https://www.lcsc.com/product-detail/C2999960.html
6 5 C52754543 RB521S30T1G-HXY HXY MOSFET SOD-523 1A 1 Independent 30V 350mV@10mA 200mA SOD-523 Single Diodes RoHS yes 20 20 20 0.0212 0.0202 0.42 0.40 https://www.lcsc.com/product-detail/C52754543.html
7 6 C42442062 CH32X035F8U6 WCH QFN-20-EP(3x3) QFN-20-EP(3x3) Microcontrollers RoHS yes 5 1 1 0.4460 2.23 https://www.lcsc.com/product-detail/C42442062.html
8 7 C780769 AP63203WU-7 DIODES TSOT-23-6 1.1MHz Buck Fixed 2A 3.3V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS 1.1MHz Buck Fixed 2A 3.3V 3.8V~32V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS yes 5 1 1 0.3955 0.3766 1.98 1.88 https://www.lcsc.com/product-detail/C780769.html
9 8 C7466527 AGM403AP AGMSEMI PDFN3.3x3.3-8 N-Channel 40V 65A 69W Surface Mount PDFN3.3x3.3 yes 5 5 5 0.2575 0.2447 1.29 1.22 https://www.lcsc.com/product-detail/C7466527.html
10 9 C2906999 FRC0603F1803TS FOJAN 0603 180kΩ ±1% 100mW 0603 Thick Film Resistor yes 100 100 100 0.0010 0.10 https://www.lcsc.com/product-detail/C2906999.html
11 10 C4169844 RS73F1JTTD2703B KOA 0603 200mW 270kΩ Thick Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS yes 5 5 5 0.0638 0.32 https://www.lcsc.com/product-detail/C4169844.html
12 11 C2932326 MT3608L XI'AN Aerosemi Tech SOT-23-6 1.2MHz Boost Adjustable 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS 1.2MHz Boost Adjustable 2.2V~16V 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS yes 10 10 10 0.0373 0.37 https://www.lcsc.com/product-detail/C2932326.html
13 12 C138714 TPD4E05U06DQAR TI USON-10(1x2.5) 14VC Clamp 2.5A@8/20us Ipp TVS DIODE USON-10(1x2.5) yes 5 5 5 0.0629 0.0679 0.31 0.34 https://www.lcsc.com/product-detail/C138714.html
14 13 C19274408 SC7A20HTR Hangzhou Silan Microelectronics LGA-12(2x2) LGA-12(2x2) Accelerometers RoHS yes 5 1 1 0.2417 1.21 https://www.lcsc.com/product-detail/C19274408.html
15 14 C52741377 CPN201610H6R8MT Magnetsyc 0806 820mA 6.8uH 1.1A 545mΩ ±20% 0806 Fixed Inductors RoHS yes 20 20 20 0.0277 0.55 https://www.lcsc.com/product-detail/C52741377.html
16 15 C18723015 C110776 X087-2832TSWIG02-H14 RT0603BRD071KL Wisevision YAGEO - 0603 0.87 128x32 SSD1312 chip I2C LCD, OLED, Graphic RoHS 100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS yes 5 20 1 20 1 20 1.6435 0.0187 8.22 0.37 https://www.lcsc.com/product-detail/C18723015.html https://www.lcsc.com/product-detail/C110776.html
17 16 C110776 C162670 RT0603BRD071KL NCU18XH103F6SRB YAGEO muRata 0603 100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS NTC Thermistor 10kΩ Surface Mount 0603 yes 20 10 20 10 20 10 0.0187 0.0533 0.37 0.53 https://www.lcsc.com/product-detail/C110776.html https://www.lcsc.com/product-detail/C162670.html
18 17 C162670 C46818248 NCU18XH103F6SRB SIQ-02FVS3 muRata LZG 0603 - NTC Thermistor 10kΩ Surface Mount 0603 Encoders - Industrial RoHS yes 10 5 10 1 10 1 0.0533 0.9816 0.53 4.91 https://www.lcsc.com/product-detail/C162670.html https://www.lcsc.com/product-detail/C46818248.html
19 18 C46818248 C41414522 SIQ-02FVS3 NSG10752 LZG WXNSIC - SOT-23-6 Encoders - Industrial RoHS High Side Gate Driver IC MOSFET IGBT SOT-23-6 yes 5 1 1 0.9816 0.4600 4.91 2.30 https://www.lcsc.com/product-detail/C46818248.html https://www.lcsc.com/product-detail/C41414522.html
20 19 C41414522 C76799 NSG10752 MLZ1608M4R7WT000 WXNSIC TDK SOT-23-6 0603 High Side Gate Driver IC MOSFET IGBT SOT-23-6 350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS yes 5 10 1 10 1 10 0.4842 0.0341 2.42 0.34 https://www.lcsc.com/product-detail/C41414522.html https://www.lcsc.com/product-detail/C76799.html
21 20 C76799 C98192 MLZ1608M4R7WT000 CL21A475KBQNNNE TDK Samsung Electro-Mechanics 0603 0805 350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS 4.7uF ±10% 50V Ceramic Capacitor X5R 0805 yes 10 10 10 0.0341 0.0179 0.34 0.18 https://www.lcsc.com/product-detail/C76799.html https://www.lcsc.com/product-detail/C98192.html
22 21 C98192 C29936 CL21A475KBQNNNE CL10B105KA8NNNC Samsung Electro-Mechanics 0805 0603 4.7uF ±10% 50V Ceramic Capacitor X5R 0805 1uF ±10% 25V Ceramic Capacitor X7R 0603 yes 10 50 10 50 10 50 0.0179 0.0056 0.18 0.28 https://www.lcsc.com/product-detail/C98192.html https://www.lcsc.com/product-detail/C29936.html
23 22 C29936 C2997487 CL10B105KA8NNNC MPD220M1VD19040R Samsung Electro-Mechanics Ymin 0603 SMD,7.3x4.3mm 1uF ±10% 25V Ceramic Capacitor X7R 0603 35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS yes 50 5 50 1 50 1 0.0056 0.7063 0.28 3.53 https://www.lcsc.com/product-detail/C29936.html https://www.lcsc.com/product-detail/C2997487.html
24 23 C1590 C5370906 CL10B104KA8NNNC FC-ALX 4030D-2R2MT Samsung Electro-Mechanics FANGCHENG 0603 SMD,4.2x4.2mm 100nF ±10% 25V Ceramic Capacitor X7R 0603 8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS yes 100 5 100 1 100 1 0.0032 0.4781 0.32 2.39 https://www.lcsc.com/product-detail/C1590.html https://www.lcsc.com/product-detail/C5370906.html
25 24 C2997487 C18723014 MPD220M1VD19040R X069-9616TSWIG02-H14 Ymin Wisevision SMD,7.3x4.3mm - 35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS 0.69 96x16 SSD1312 chip I2C LCD, OLED, Graphic RoHS yes 5 2 1 1 0.7063 1.3337 3.53 2.67 https://www.lcsc.com/product-detail/C2997487.html https://www.lcsc.com/product-detail/C18723014.html
26 25 C5796173 C386166 MCASU32MAB7106KPNA01 UMK325AB7106KMHP Taiyo Yuden 1210 10uF ±10% 50V Ceramic Capacitor X7R 1210 10uF ±10% 50V Ceramic Capacitor X7R 1210 AEC-Q200 yes 25 5 5 0.0982 0.0854 2.46 2.14 https://www.lcsc.com/product-detail/C5796173.html https://www.lcsc.com/product-detail/C386166.html
27 26 C5370906 C38582720 FC-ALX 4030D-2R2MT TPA191A4-SC6R FANGCHENG 3PEAK SMD,4.2x4.2mm SOT-363 8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS 50uV -300mV~+36V 22uA 2.5V/us 120dB 30kHz 80uA 100V/V SOT-363 Amplifiers RoHS yes 5 1 5 1 5 0.4781 0.5300 2.39 2.65 https://www.lcsc.com/product-detail/C5370906.html https://www.lcsc.com/product-detail/C38582720.html
28 27 C49851 C5185587 INA226AIDGSR CUM1206-15FR004 TI FORT MSOP-10 1206 300mV~40V 2.5uV 10nA MSOP-10 Current Regulation/Management RoHS 1W 4mΩ SMD ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS yes 5 1 1 0.5765 0.0157 2.88 0.08 https://www.lcsc.com/product-detail/C49851.html https://www.lcsc.com/product-detail/C5185587.html
28 C49164932 JER1206F1R002 JIERR 1206 1W 2mΩ ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS yes 10 10 10 0.0371 0.37 https://www.lcsc.com/product-detail/C49164932.html

28
hw/bom/order_1.csv Normal file
View File

@ -0,0 +1,28 @@
LCSC Part Number,Manufacture Part Number,Manufacturer,Customer NO.,Package,Description,RoHS,Quantity,Unit Price(€),Ext.Price(€),Estimated lead time (business days),Date Code / Lot No.
C473369,TLV333IDBVR,TI,,SOT-23-5,"2uV Rail-to-Rail Input, Rail-to-Rail Output 70pA 0.16V/us 102dB 17uA 350kHz 1 SOT-23-5 Amplifiers RoHS",YES,5,0.2121,1.06,,
C2827931,SS24L,Guangdong Hottech,,SOD-123FL,Diode Independent 40V 2A Surface Mount SOD-123FL,YES,20,0.0214,0.43,,
C2931472,U263-163N-4OS1735,XKB Connection,,SMD,USB-C (USB TYPE-C) Receptacle Connector 16 Position Surface Mount,YES,5,0.2518,1.26,,
C2999960,MM5Z3V3,Slkor,,SOD-523,Zener Diode Independent 3.3V 200mW Surface Mount SOD-523,YES,20,0.0181,0.36,,
C52754543,RB521S30T1G-HXY,HXY MOSFET,,SOD-523,1A 1 Independent 30V 350mV@10mA 200mA SOD-523 Single Diodes RoHS,YES,20,0.0212,0.42,,
C42442062,CH32X035F8U6,WCH,,QFN-20-EP(3x3),QFN-20-EP(3x3) Microcontrollers RoHS,YES,5,0.446,2.23,,
C780769,AP63203WU-7,DIODES,,TSOT-23-6,1.1MHz Buck Fixed 2A 3.3V 3.8V~32V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,YES,5,0.3766,1.88,,
C7466527,AGM403AP,AGMSEMI,,PDFN3.3x3.3-8,N-Channel 40V 65A 69W Surface Mount PDFN3.3x3.3,YES,5,0.2575,1.29,,
C2906999,FRC0603F1803TS,FOJAN,,0603,180kΩ ±1% 100mW 0603 Thick Film Resistor,YES,100,0.001,0.10,,
C4169844,RS73F1JTTD2703B,KOA,,0603,200mW 270kΩ Thick Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS,YES,5,0.0638,0.32,,
C2932326,MT3608L,XI'AN Aerosemi Tech,,SOT-23-6,1.2MHz Boost Adjustable 2.2V~16V 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS,YES,10,0.0373,0.37,,
C138714,TPD4E05U06DQAR,TI,,USON-10(1x2.5),14VC Clamp 2.5A@8/20us Ipp TVS DIODE USON-10(1x2.5),YES,5,0.0682,0.34,,
C19274408,SC7A20HTR,Hangzhou Silan Microelectronics,,LGA-12(2x2),LGA-12(2x2) Accelerometers RoHS,YES,5,0.2417,1.21,,
C52741377,CPN201610H6R8MT,Magnetsyc,,0806,820mA 6.8uH 1.1A 545mΩ ±20% 0806 Fixed Inductors RoHS,YES,20,0.0277,0.55,,
C110776,RT0603BRD071KL,YAGEO,,0603,100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS,YES,20,0.0187,0.37,,
C162670,NCU18XH103F6SRB,muRata,,0603,NTC Thermistor 10kΩ Surface Mount 0603,YES,10,0.0533,0.53,,
C46818248,SIQ-02FVS3,LZG,,-,Encoders - Industrial RoHS,YES,5,0.9816,4.91,,
C41414522,NSG10752,WXNSIC,,SOT-23-6,High Side Gate Driver IC MOSFET IGBT SOT-23-6,YES,5,0.4842,2.42,,
C76799,MLZ1608M4R7WT000,TDK,,0603,350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS,YES,10,0.0351,0.35,,
C98192,CL21A475KBQNNNE,Samsung Electro-Mechanics,,0805,4.7uF ±10% 50V Ceramic Capacitor X5R 0805,YES,10,0.0179,0.18,,
C29936,CL10B105KA8NNNC,Samsung Electro-Mechanics,,0603,1uF ±10% 25V Ceramic Capacitor X7R 0603,YES,50,0.0056,0.28,,
C2997487,MPD220M1VD19040R,Ymin,,"SMD,7.3x4.3mm","35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS",YES,5,0.7063,3.53,,
C5370906,FC-ALX 4030D-2R2MT,FANGCHENG,,"SMD,4.2x4.2mm","8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS",YES,5,0.4781,2.39,,
C18723014,X069-9616TSWIG02-H14,Wisevision,,-,"0.69 96x16 SSD1312 chip I2C LCD, OLED, Graphic RoHS",YES,2,1.3337,2.67,,
C386166,UMK325AB7106KMHP,Taiyo Yuden,,1210,10uF ±10% 50V Ceramic Capacitor X7R 1210 AEC-Q200,YES,25,0.0854,2.14,,
C38582720,TPA191A4-SC6R,3PEAK,,SOT-363,50uV -300mV~+36V 22uA 2.5V/us 120dB 30kHz 80uA 100V/V SOT-363 Amplifiers RoHS,YES,5,0.53,2.65,,
C5185587,CUM1206-15FR004,FORT,,1206,1W 4mΩ SMD ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS,YES,5,0.0522,0.26,,
1 LCSC Part Number Manufacture Part Number Manufacturer Customer NO. Package Description RoHS Quantity Unit Price(€) Ext.Price(€) Estimated lead time (business days) Date Code / Lot No.
2 C473369 TLV333IDBVR TI SOT-23-5 2uV Rail-to-Rail Input, Rail-to-Rail Output 70pA 0.16V/us 102dB 17uA 350kHz 1 SOT-23-5 Amplifiers RoHS YES 5 0.2121 1.06
3 C2827931 SS24L Guangdong Hottech SOD-123FL Diode Independent 40V 2A Surface Mount SOD-123FL YES 20 0.0214 0.43
4 C2931472 U263-163N-4OS1735 XKB Connection SMD USB-C (USB TYPE-C) Receptacle Connector 16 Position Surface Mount YES 5 0.2518 1.26
5 C2999960 MM5Z3V3 Slkor SOD-523 Zener Diode Independent 3.3V 200mW Surface Mount SOD-523 YES 20 0.0181 0.36
6 C52754543 RB521S30T1G-HXY HXY MOSFET SOD-523 1A 1 Independent 30V 350mV@10mA 200mA SOD-523 Single Diodes RoHS YES 20 0.0212 0.42
7 C42442062 CH32X035F8U6 WCH QFN-20-EP(3x3) QFN-20-EP(3x3) Microcontrollers RoHS YES 5 0.446 2.23
8 C780769 AP63203WU-7 DIODES TSOT-23-6 1.1MHz Buck Fixed 2A 3.3V 3.8V~32V TSOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS YES 5 0.3766 1.88
9 C7466527 AGM403AP AGMSEMI PDFN3.3x3.3-8 N-Channel 40V 65A 69W Surface Mount PDFN3.3x3.3 YES 5 0.2575 1.29
10 C2906999 FRC0603F1803TS FOJAN 0603 180kΩ ±1% 100mW 0603 Thick Film Resistor YES 100 0.001 0.10
11 C4169844 RS73F1JTTD2703B KOA 0603 200mW 270kΩ Thick Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS YES 5 0.0638 0.32
12 C2932326 MT3608L XI'AN Aerosemi Tech SOT-23-6 1.2MHz Boost Adjustable 2.2V~16V 2.5A SOT-23-6 Voltage Regulators - DC DC Switching Regulators RoHS YES 10 0.0373 0.37
13 C138714 TPD4E05U06DQAR TI USON-10(1x2.5) 14VC Clamp 2.5A@8/20us Ipp TVS DIODE USON-10(1x2.5) YES 5 0.0682 0.34
14 C19274408 SC7A20HTR Hangzhou Silan Microelectronics LGA-12(2x2) LGA-12(2x2) Accelerometers RoHS YES 5 0.2417 1.21
15 C52741377 CPN201610H6R8MT Magnetsyc 0806 820mA 6.8uH 1.1A 545mΩ ±20% 0806 Fixed Inductors RoHS YES 20 0.0277 0.55
16 C110776 RT0603BRD071KL YAGEO 0603 100mW 1kΩ 75V Thin Film Resistor ±25ppm/℃ ±0.1% 0603 Chip Resistor - Surface Mount RoHS YES 20 0.0187 0.37
17 C162670 NCU18XH103F6SRB muRata 0603 NTC Thermistor 10kΩ Surface Mount 0603 YES 10 0.0533 0.53
18 C46818248 SIQ-02FVS3 LZG - Encoders - Industrial RoHS YES 5 0.9816 4.91
19 C41414522 NSG10752 WXNSIC SOT-23-6 High Side Gate Driver IC MOSFET IGBT SOT-23-6 YES 5 0.4842 2.42
20 C76799 MLZ1608M4R7WT000 TDK 0603 350mA 4.7uH 120mA 500mΩ Multilayer inductor ±20% 0603 Fixed Inductors RoHS YES 10 0.0351 0.35
21 C98192 CL21A475KBQNNNE Samsung Electro-Mechanics 0805 4.7uF ±10% 50V Ceramic Capacitor X5R 0805 YES 10 0.0179 0.18
22 C29936 CL10B105KA8NNNC Samsung Electro-Mechanics 0603 1uF ±10% 25V Ceramic Capacitor X7R 0603 YES 50 0.0056 0.28
23 C2997487 MPD220M1VD19040R Ymin SMD,7.3x4.3mm 35V 22uF 3.2A@100kHz 40mΩ@100kHz ±20% SMD,7.3x4.3mm Aluminum - Polymer Capacitors RoHS YES 5 0.7063 3.53
24 C5370906 FC-ALX 4030D-2R2MT FANGCHENG SMD,4.2x4.2mm 8.1A 2.2uH 8.1A 10.7mΩ Molded Inductor ±20% SMD,4.2x4.2mm Fixed Inductors RoHS YES 5 0.4781 2.39
25 C18723014 X069-9616TSWIG02-H14 Wisevision - 0.69 96x16 SSD1312 chip I2C LCD, OLED, Graphic RoHS YES 2 1.3337 2.67
26 C386166 UMK325AB7106KMHP Taiyo Yuden 1210 10uF ±10% 50V Ceramic Capacitor X7R 1210 AEC-Q200 YES 25 0.0854 2.14
27 C38582720 TPA191A4-SC6R 3PEAK SOT-363 50uV -300mV~+36V 22uA 2.5V/us 120dB 30kHz 80uA 100V/V SOT-363 Amplifiers RoHS YES 5 0.53 2.65
28 C5185587 CUM1206-15FR004 FORT 1206 1W 4mΩ SMD ±50ppm/℃ Current Sense Resistor ±1% 1206 Current Sense Resistors RoHS YES 5 0.0522 0.26

View File

@ -0,0 +1 @@
{"ARCHIVE_NAME": "", "EXTRA_LAYERS": "", "ALL_ACTIVE_LAYERS": false, "EXTEND_EDGE_CUT": false, "ALTERNATIVE_EDGE_CUT": false, "AUTO TRANSLATE": true, "AUTO FILL": true, "EXCLUDE DNP": false, "OPEN BROWSER": true, "NO_BACKUP_OPT": false}

View File

@ -434,6 +434,12 @@
)
)
)
(pad "A1" smd rect
(at -3.2 -2.4775)
(size 0.5 1.15)
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "ea8dadf2-8afa-4fe2-9e30-22206c244069")
)
(pad "A4" smd rect
(at -2.4 -2.4775)
(size 0.5 1.15)
@ -464,6 +470,12 @@
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "a621d7b8-8475-4012-bb80-22970594526c")
)
(pad "B1" smd rect
(at 3.2185 -2.4775)
(size 0.5 1.15)
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "b6f3c56c-8cda-4c18-83e9-de8afa037a13")
)
(pad "B4" smd rect
(at 2.4 -2.4775)
(size 0.5 1.15)
@ -494,18 +506,6 @@
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "b669d7b8-13ce-4926-b0fa-a776cf6d1e07")
)
(pad "GND" smd rect
(at -3.2 -2.4775)
(size 0.5 1.15)
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "ea8dadf2-8afa-4fe2-9e30-22206c244069")
)
(pad "GND" smd rect
(at 3.2185 -2.4775)
(size 0.5 1.15)
(layers "F.Cu" "F.Mask" "F.Paste")
(uuid "b6f3c56c-8cda-4c18-83e9-de8afa037a13")
)
(pad "S1" thru_hole oval
(at -4.32 -1.8025)
(size 1.2 2.2)

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
@ -48,7 +50,7 @@
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.25
"min_clearance": 0.2
}
},
"diff_pair_dimensions": [
@ -77,6 +79,7 @@
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
@ -94,6 +97,7 @@
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore",
@ -113,9 +117,12 @@
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
@ -123,7 +130,7 @@
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.16,
"min_clearance": 0.15,
"min_connection": 0.16,
"min_copper_edge_clearance": 0.2,
"min_groove_width": 0.0,
@ -131,15 +138,15 @@
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_resolved_spokes": 1,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_through_hole_diameter": 0.2,
"min_track_width": 0.16,
"min_via_annular_width": 0.15,
"min_via_diameter": 0.25,
"solder_mask_to_copper_clearance": 0.0,
"solder_mask_to_copper_clearance": 0.005,
"use_height_for_length_calcs": true
},
"teardrop_options": [
@ -229,17 +236,28 @@
"zones_allow_external_fillets": false
},
"ipc2581": {
"bom_rev": "",
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
"mpn": "",
"sch_revision": ""
},
"layer_pairs": [],
"layer_presets": [],
"viewports": []
},
"boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": {
"equivalence_files": []
},
@ -429,11 +447,14 @@
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"field_name_whitespace": "warning",
"footprint_filter": "ignore",
"footprint_link_issues": "warning",
"four_way_junction": "ignore",
"global_label_dangling": "warning",
"ground_pin_not_ground": "warning",
"hier_label_mismatch": "error",
"isolated_pin_label": "warning",
"label_dangling": "error",
"label_multiple_wires": "warning",
"lib_symbol_issues": "warning",
@ -456,6 +477,7 @@
"similar_power": "warning",
"simulation_model_issue": "ignore",
"single_global_label": "ignore",
"stacked_pin_name": "warning",
"unannotated": "error",
"unconnected_wire_endpoint": "warning",
"undefined_netclass": "error",
@ -476,7 +498,7 @@
"classes": [
{
"bus_width": 12,
"clearance": 0.16,
"clearance": 0.15,
"diff_pair_gap": 0.16,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
@ -488,13 +510,14 @@
"priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.5,
"via_drill": 0.2,
"wire_width": 6
}
],
"meta": {
"version": 4
"version": 5
},
"net_colors": null,
"netclass_assignments": null,
@ -516,6 +539,10 @@
},
"schematic": {
"annotate_start_num": 0,
"annotation": {
"method": 0,
"sort_order": 0
},
"bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [],
"bom_fmt_settings": {
@ -587,6 +614,7 @@
"sort_asc": true,
"sort_field": "Reference"
},
"bus_aliases": {},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
@ -594,6 +622,7 @@
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"hop_over_size_choice": 0,
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
@ -617,6 +646,7 @@
"net_format_name": "",
"page_layout_descr_file": "",
"plot_directory": "",
"reuse_designators": true,
"space_save_all_events": true,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
@ -625,13 +655,28 @@
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
"subpart_id_separator": 0,
"top_level_sheets": [
{
"filename": "usbc_soldering_iron.kicad_sch",
"name": "usbc_soldering_iron",
"uuid": "7095b018-eac3-4b01-b374-28e3216c4fd8"
}
],
"used_designators": "",
"variants": []
},
"sheets": [
[
"7095b018-eac3-4b01-b374-28e3216c4fd8",
"Root"
"usbc_soldering_iron"
]
],
"text_variables": {}
"text_variables": {},
"tuning_profiles": {
"meta": {
"version": 0
},
"tuning_profiles_impedance_geometric": []
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,18 @@
Version 4
SymbolType BLOCK
LINE Normal 64 0 8 0
LINE Normal -8 16 -8 -16
LINE Normal 8 16 8 -16
LINE Normal -8 0 -64 0
WINDOW 3 0 33 Center 2
WINDOW 38 0 -33 Center 2
SYMATTR Value Temperature=25
SYMATTR SpiceModel MMASU32MAB7106_PNA01
SYMATTR Prefix X
SYMATTR ModelFile MMASU32MAB7106_PNA01_LT.cir
PIN -64 0 NONE 8
PINATTR PinName Port1
PINATTR SpiceOrder 1
PIN 64 0 NONE 8
PINATTR PinName Port2
PINATTR SpiceOrder 2

View File

@ -0,0 +1,701 @@
* LTspice Encrypted File
*
* This encrypted file has been supplied by a 3rd
* party vendor that does not wish to publicize
* the technology used to implement this library.
*
* Permission is granted to use this file for
* simulations but not to reverse engineer its
* contents.
*
* MMASU32MAB7106_PNA01 LTspice Model ( Temperature / DC Bias Model )
*--------------------------------------------------------------------------------------------------------
* Model Generated by TAIYO YUDEN Corporation (https://www.yuden.co.jp/en/)
* Version 3.0
* TAIYO YUDEN Control No. 250905
* Copyright(c) 2021 TAIYO YUDEN CO.,LTD. All Rights Reserved.
*--------------------------------------------------------------------------------------------------------
* Product Description (link to TY-COMPAS)
* https://ds.yuden.co.jp/TYCOMPAS/or/detail?pn=MMASU32MAB7106KPNA01&u=M
*--------------------------------------------------------------------------------------------------------
*
* Begin:
1E FD 14 DB 52 AE 58 6A 2E 81 BB EB 90 C3 0B 2A
41 F4 3F AB F8 54 DD 0D 1E 08 9B 9B 3B 9B 47 A7
EC B5 42 B7 92 B1 22 50 FC 89 DD 35 F1 E7 B8 26
F0 C3 6C 8D A8 FB AC FD EA B2 BF 0A 8E 42 06 33
EE F3 B3 AE 40 5F 78 0B 48 12 2D 03 C2 66 80 EE
D0 C4 83 02 D6 2D C0 CD 42 D7 66 53 C4 6B 17 0E
30 FF 6B 2E 99 B6 D5 BF 3E F8 CD 11 4C 08 95 08
75 00 04 36 B3 0D E7 0D D2 01 DA E3 F9 C5 AE A6
35 9E 29 2A AA C6 D2 7B 1D E5 F1 28 60 3B 6F 46
40 EF 64 B4 BF 18 72 32 E2 01 BF F0 7A C5 9C 57
2C A9 FD 41 74 D0 6F FF 04 51 05 E2 8D 82 6C 33
78 00 EB AD BF 95 8E FB 21 36 58 B9 35 3B 96 BF
ED 02 28 86 6A 48 BF FE AD 7B 35 A1 70 06 C5 3F
A7 0A 91 D2 9F 0F 30 D3 37 30 95 7A C9 9F 3A 7F
28 DA 99 AB 2C 9F B9 FA C7 93 DB 2B C4 DB 4A 68
CC 1E 36 94 4E 85 03 8A 48 F9 EB C1 CC 7D CF B9
76 73 49 23 2B EE E8 A1 92 DD 09 03 7C 02 45 4C
FF F9 7C 8E 51 9A 06 FC BF 2F A3 9C 84 25 09 D4
0A 0D 6F B6 82 05 2B 3E 6E 22 30 92 BC 83 2A 69
13 6B 78 1F 44 13 C0 F4 5B 45 87 B6 92 FC 0C E2
7B 0D 4B 2D E5 B0 57 CF 65 A5 78 92 52 3B 80 D3
FD A3 F8 87 53 7A 7C 39 54 C4 EA 63 B1 8C 00 6C
5B 17 87 98 56 93 18 62 86 1A 18 98 9F 28 B8 9D
CB 9E B7 1E 81 74 D4 21 62 18 7F EF C5 3D 4F AB
95 D5 91 E7 34 9A 17 11 B6 FD A2 D8 4A 9C 8B 2D
3C 50 23 4C 2B 55 2D 7F 1C D9 99 F6 B0 13 80 A5
81 F0 D7 45 0F 42 0B AA EB 31 97 22 8B 3A B0 E2
E9 35 6A 14 02 CE FB EF 41 EF 30 A1 5F 7B E9 27
B0 4C FE 8F D5 56 CE 66 51 0F A8 8A 4C 60 99 EB
94 F8 B1 A1 66 4C DC 52 E2 72 F5 05 14 68 51 74
EF 33 5A C1 0B E5 5A 7E 0F 33 00 E8 C2 69 3C CA
FE 4F C2 27 15 15 81 9D 5E 2B 51 04 E7 7E 8B 55
F5 DB 50 52 AC 74 DD 28 DB B4 33 EB 09 E4 35 C1
76 84 36 84 A5 1B E2 B2 CB 64 16 6F E8 45 42 7C
47 FA 21 7E EE 71 C1 68 58 BF 39 D4 8E F7 14 F3
43 E4 34 86 E3 CB 7D 61 9D AD 08 26 2C DF 28 AE
9D 49 32 33 13 03 00 AE C7 40 94 84 9F 70 15 4B
31 14 29 ED BB E9 AF 95 45 0E EF 4F 3F 42 2A A4
E0 43 AA 70 B8 40 90 3B F7 44 52 EF B6 DF C4 1E
8A 4B F9 72 04 13 06 81 6D 04 FD BB EB FE 60 37
A9 03 6D 93 36 9A 71 C4 B7 9F 43 59 EF DF 21 D2
82 49 4E FC 72 79 27 36 EA 27 0F F1 9C 2A 7A 97
D1 C5 B1 D4 AB DD 81 8B CE 1C E4 E1 54 AF 7E 9C
BE 14 0C B0 79 48 AA 83 C6 54 D8 22 B0 A1 9C B7
E8 31 16 80 C8 1C F0 B2 73 14 EE 36 6E 6F F3 46
4C 2C 0D AB B7 7F 5C 70 6B D1 B9 0C E3 83 9D B0
9E 79 D1 7A D2 39 B5 A1 60 48 0E EE F9 1E 4E EE
88 55 53 F9 CE BF 60 60 CA 02 E6 6E 8A CF 73 30
5F 1E 69 1F 3E 67 7C 18 5D 5F 38 C2 63 CB 98 3D
AC 08 BE 7D B8 3B B4 6C 9B B6 DD DF 40 52 E4 A8
0A 68 8A E0 09 E7 EF 81 05 52 05 DF 8C 0C 17 8B
B0 A2 AD 59 42 6A 0F 72 27 CB 14 DA AD EB 94 E8
10 2B BB 92 41 E8 5F 27 69 59 61 BE 30 B0 33 2C
13 33 95 ED AE 73 6D 47 20 80 E3 C3 3A F3 FE 9E
7F B8 FB BF 93 60 A0 9E 47 CD 1E DE 68 93 F0 C4
CD EA E9 88 B0 52 57 79 37 DF 02 93 8A D3 A5 76
03 DB BB 13 81 D7 DF 57 C8 A3 D5 D7 F4 64 8D DC
2D 65 00 87 78 BE 95 B3 C3 5D 20 58 E7 F8 91 2D
A1 3D 03 30 28 F0 81 54 2E DD F0 FE AC A6 88 A4
0A DA BE 9F B4 71 A2 9C 94 7C AA C2 A4 4E 66 9C
1F 58 8A 43 CF 2B 3B 16 DD 0F D7 93 11 E4 0E 28
31 2F 6F 1A 96 C2 08 B0 E5 93 16 11 A2 E4 97 55
D5 F2 D4 9C F4 6E 78 77 98 46 09 03 76 2C 49 2D
77 CE 17 D6 17 27 18 4A 53 FA 4E C7 BA 56 42 93
01 CD A5 B0 7F B7 6C 60 0E FE 84 86 DD 0B F0 D0
10 A6 DF 53 7A 78 31 B4 99 1B 2B E4 FB 36 41 9D
04 C0 12 41 F1 81 E6 B0 33 0B 2D 70 0F 04 17 37
78 79 23 52 DF AB 20 91 D6 2D D1 6C FC 1F 48 CA
E9 23 6C 22 76 9E 0F 78 2C D6 FE 31 58 DC 3E 3D
78 0B 92 91 2E F0 06 CA A4 2D B5 C5 95 46 AB 18
B1 6B BC 7E DB 70 49 39 6F 0A 0A 3C A5 E2 28 B8
8A A2 8D D8 E5 F5 35 CB D3 97 65 3D 4E FC E0 41
44 E3 88 BC 72 F6 A6 76 69 F3 67 DF B1 EC CF 7D
AC E6 2C D4 41 51 B9 CB 15 B5 BB B5 04 81 35 3D
30 7E 61 30 29 1E 4D 41 91 56 B8 35 8F D5 04 2E
1D 18 6B C7 5A 6B D6 C9 28 FF 7D 8B EF 3C 17 98
8D 26 35 DB 1C 9F 7E D6 76 A7 B0 6A 27 B1 1A 07
48 9E 99 56 47 4B 91 32 B5 DB 75 27 65 99 26 B6
F6 BD 98 7E 41 1D 88 B6 D7 DC 1D D0 0C F6 4E A8
8C 50 84 5B 5D 21 26 0D CB A1 E8 25 82 ED 91 BE
8C E2 96 BD B1 25 11 0C 4A 04 8A 6D 3C F6 FE CD
B7 BA 45 6B 66 46 80 57 E8 1F 0A 95 67 3C 67 E3
4E 49 13 40 07 5C CD F0 A3 5F EF FB 07 38 75 0C
D3 A2 FA 31 C7 15 DE 56 96 55 3B 67 1E 89 75 BF
C6 AB D4 51 2B 96 85 70 9C 22 25 62 11 D2 1E FF
C9 04 5A DC 97 47 42 7B 8A 9A 85 FE EC C5 1A 7D
85 AA 05 6C 51 47 AE 61 91 AB 9E 5A CE DB 69 FC
45 35 8B BD 89 EC 5B 62 6D D9 A0 AB 5B 96 FC 40
43 6E 46 8A 7A 94 92 14 4A A5 E6 E9 26 6B B6 58
17 59 A4 3B 8F C0 E9 9A 4A C7 DF 57 57 33 90 52
B4 9E 9E 0D 91 B8 91 DB EA 89 68 78 A5 CC 61 F9
A9 EB 10 94 B0 0F 5B 08 A9 46 BE 55 62 10 2E E2
76 85 CD 09 92 40 42 C0 33 4B 28 48 4F 25 0A C3
B2 3D 53 0B 32 DB 1E AD 79 74 A9 E4 32 9B DD 51
0B 9B 7D FA CC B4 02 C8 1D E7 9F 2C 1C E4 B0 F2
54 28 72 23 F1 74 D6 59 12 6C 1F F8 47 3D 24 4F
8C 05 95 F7 CE EB B1 0F 15 76 74 07 93 6C 24 3A
E0 F8 D4 B6 99 D3 B1 89 13 07 26 63 74 9F 17 B4
E7 5D 46 69 3F F5 45 07 F8 1F 53 87 1A A0 0C A3
10 07 5C 39 5B C0 5D C8 C6 17 C7 48 3E DC 2B 0C
DA 67 7B 56 34 F4 7E 00 92 34 10 2C 5A 83 FB C0
71 F0 91 16 BA D6 BD 9A 8A 70 63 30 30 28 D6 EC
EB E7 56 92 A1 2A 08 20 B2 02 A0 44 05 AA 7D 70
7E DE 8E 49 0D 08 10 87 77 5F C3 7A DD 94 4C D4
13 4D 3E F3 B3 48 CC D0 C9 4C 97 C9 B1 AD 23 B7
B0 92 4C 1F 1F BB C7 CF 1C D5 34 39 25 C8 AC EF
D6 F4 24 7F 3A C9 74 B1 65 5C EC F5 5C 4F 9A 6B
18 98 11 6F 1C 9D 3F D0 0B 2A 0E 84 74 96 3C 47
B6 EF D4 8E D3 27 1F 7E 9F 2D DC 95 9F A9 0D 17
EA E0 0F 99 82 02 E6 66 37 03 69 6B 91 30 41 FB
C6 1B 06 51 39 8B DE EF 36 56 58 9A 5C 00 0D 08
60 1D 7E 7B 38 67 4A B5 4D 0D 98 FE F8 A1 BD 04
E5 4B 92 F8 C6 1E 69 4B 91 7A F2 75 8E 0C AB 7A
30 63 92 B2 B2 2C 72 A2 E5 05 FB B4 4F 81 1C 2F
EA AC D2 2F C6 D9 31 3E BD D2 3E D7 BE 83 31 F6
C0 97 FE 72 D9 8C 6C BC 51 27 06 CA 7A 1E F4 55
34 5F E3 5E BF C8 85 B9 CB E3 0D F9 96 DF C9 76
39 81 26 3A BE 47 80 AD D0 B4 45 75 D8 EC 13 63
1A 28 85 42 F0 66 0A E3 AE 7A 78 F2 5F F4 F3 B4
75 12 49 F7 DB 2B E5 5D 76 14 CE E0 4F 5B C8 EC
63 BD 05 C9 4E 80 79 10 D9 97 AA 85 4A 4E DB 36
F2 B2 24 E9 24 88 8E 64 EF 3D 31 AE AB CE 1B F6
5B 6E 5D 0D CE 96 D2 6E 92 6B F8 7C 28 4B E8 75
1E 6C B1 18 BB 13 86 53 17 14 C1 82 AB A0 40 A2
45 C5 5F B3 35 55 DD 4A 19 27 80 8E 5C C7 FF A4
AB E1 0A F9 91 87 73 38 D4 4F 18 AB 80 8E 4E A3
67 5E B1 FA 5B FB 84 C8 59 24 0F 4E 2E DD DE 9A
B9 30 1B B5 44 56 9E EA 84 BA 82 CE AF 9B 31 D4
D0 5B 0B AB 91 3F 59 D5 01 3A AA 32 02 80 D1 AA
E9 04 E4 4E 81 26 8F 5C 9E 89 5D 5F 7C 48 9F A5
E1 A9 FE A6 4D EB 9A CE DE 73 26 F7 2F 66 83 7E
CC CD CF 35 95 FA 21 32 9D E5 BB D1 13 BB BD A1
4D 2E 98 18 B5 71 50 72 7D 81 93 22 45 06 D1 00
0A B8 84 03 06 3D FD 81 B1 22 01 D8 83 A2 06 D4
BA 29 55 C0 92 E5 92 36 94 AC 9C EA 6E 87 6D A8
D4 33 9D 8F A7 55 08 62 B3 0E EB 78 12 E8 89 37
62 1A 77 F4 07 62 C7 47 AB 05 28 36 2E C1 AF E2
8D 22 F4 13 44 3D 8A 41 1C 3E 9B B6 41 1F BC 5D
3C 22 C5 EC 9D C2 C3 5D D7 E9 FF AB 8C E5 CB C8
1B 8A E8 75 33 5A DD C7 A6 7E 3F 78 B9 CB 63 C9
69 3D D8 FF 6F 72 37 D8 00 96 9D 2C 8E 4B 72 57
E6 BE 3C 04 A2 2E 65 10 77 B4 87 F5 E1 E5 F3 F2
D0 22 8F 51 11 44 BF 4D 40 53 BA 7B 04 43 94 93
7E 17 FB 43 0E 09 E6 18 98 DB FA 2F ED 18 9C FF
6F 62 12 07 21 D3 CB 98 D7 C2 AA C3 A1 6F A7 30
12 47 EC A1 94 A7 06 36 4A 86 4D 5D 2F 14 A8 2E
FF 2B 8A DA C3 33 C2 4F 14 E0 C1 04 F0 DC 7A 1A
58 1C C1 B3 0B 2D E3 1F E2 54 01 BD D2 D0 A7 3C
0C F8 EA D2 B4 0D 43 F0 7C 2C EF E7 94 43 4E E2
FA FB 90 2E FA 76 CA 51 1D E2 F5 C9 85 05 30 59
5F EE D0 6C C9 3D D7 40 9A D9 76 6E 3D 6C B5 81
E4 67 79 0F B5 8F 80 C0 2A 95 AA A6 6D B3 BD D5
73 21 98 1D 86 5F AF 8D 98 9D 74 22 99 03 7B 58
7C 23 63 41 7B DB D2 37 DB F1 B9 C0 44 7E 6A 4B
2A CD 2C DD 99 D4 E2 4A EF 7C 12 51 86 7D B6 E7
23 31 69 11 D4 32 C6 0A 24 DA DB 81 1F 8B 10 3E
FE F5 D1 3C 16 9E 11 B4 14 37 50 1E 30 D5 B4 EE
F2 EC 34 08 F7 20 FF CC 11 D2 DF 37 03 F0 C4 F2
C3 CB A3 60 B7 71 26 36 7A DE 69 97 63 AD B2 ED
E5 9D C2 45 19 31 0E 35 C7 96 D9 65 60 C9 92 99
B7 29 28 28 1A D9 F8 BB 0B 09 B1 E5 2C DD 39 58
B1 AE A8 0C F3 A3 2A 88 FC E2 C2 B5 A2 73 A9 78
3A EC AE D5 6F EC C0 62 33 24 2C 1C F1 27 BD 97
4B 93 9D 21 19 46 4B 0F 92 2F E3 61 93 91 19 91
1D 31 24 19 D5 2C 1D A8 D3 B8 01 0E 36 E9 1A E5
07 3E EC 55 21 5E 7D 41 6E 2B C5 C5 B8 8C 9F E0
FA C7 97 48 89 02 86 5B F9 17 E1 A5 53 4E 62 5B
B0 C6 D8 AE 15 45 E8 DC 1F 98 0C 18 EB B7 16 22
FA 86 FE DC 35 B4 AF C4 ED D0 7B C2 17 68 AC E1
32 D8 9A A2 EF 37 B3 1B E7 0C 35 5A 18 A2 82 CB
57 2D 98 76 FB BC AC B7 1B 3D 16 54 A5 14 11 C0
E6 C1 A4 71 F2 7D 92 52 20 67 D8 03 F3 78 D5 F0
B2 E9 22 63 AF 92 C0 1C 1C 42 38 F9 78 FC 31 F1
6A 5B 79 05 7D 7F FA 59 59 63 65 D7 8B 50 E1 46
B0 EA 93 6B 2B F3 7C 39 2F C4 00 D7 CE 53 6C 50
DB DF E1 73 AC 6E 22 3B 92 D0 5E 5E 9A C0 9E 29
3A 2D F4 FF B8 12 88 36 C0 0F 44 39 80 0E FF 6D
47 BD 0B 78 FD 03 57 F6 F0 22 B4 2E D1 8A 2D 6E
A6 DE F2 DB 99 C2 BB 98 D3 73 87 3D 60 F5 F9 70
D8 49 86 F4 77 9C 18 59 D0 68 CA F7 26 AC 78 90
51 25 DB 18 A1 CC 67 45 18 23 A3 AA 26 21 B9 F7
C9 08 E0 6D 16 E8 4C EC 57 74 F0 63 C4 5F F8 1E
1F 05 83 E6 9E A7 9D 43 41 E4 72 10 45 0E E0 09
63 C2 85 E5 04 7C 07 82 90 D1 B3 95 B6 50 19 2C
76 9B 1F 99 93 7D 61 76 1C E6 E7 B2 A2 2F E0 F6
35 27 82 13 AC 02 C2 D8 20 CA 9E EF FE 32 CB 21
B2 D8 01 A5 52 65 79 A1 EB E0 5B 75 7F FA CC 5E
53 D5 63 CA B8 BD AF 0D C3 A0 C4 A8 F8 0F 0D 86
15 EA 8A 42 BB 12 22 8F 72 DB 4F 4A B5 AA 44 3D
76 8B F4 B8 5B E2 42 CC 74 D9 1F 8F A5 F6 6D 2E
2C 30 C1 3C 1B 87 D8 6D BF B4 82 6D D6 04 C1 DC
7C 45 2F 3C EA 8C 61 A2 AA CB F7 DF 11 76 BA 79
E0 B3 7F FC C1 B5 81 85 86 2F B5 2D BB 94 E3 40
BC 16 FE 56 A6 5B C1 CF 63 37 96 1D 2A A2 0C FD
A0 DA 29 E5 C9 93 83 D2 C7 A1 FB 12 39 B7 A4 FE
17 05 B5 74 78 EE E9 D4 7B EF 58 81 5D 85 42 C7
86 F4 FC 57 1B 3F A5 7A E1 A0 C1 D1 2B 38 C4 74
F2 AA 43 40 2C 28 E1 35 64 15 E0 11 0B 30 3B AB
3C 0F 79 20 39 D6 93 F4 91 6D 77 E8 D9 9E 2B 58
89 43 62 58 89 59 99 D4 D3 B2 AB A7 E0 74 26 DF
68 5B 1B 38 BF B0 87 04 0E 4B 9E B1 83 B7 42 89
A4 04 AB 39 32 32 38 57 1B 31 C1 CA 5F A8 CE EA
36 27 FA 2F EA D8 4E 20 66 68 70 5C 65 32 1D 15
B6 EA 66 87 9A D9 49 73 09 06 AD 7E E5 B5 CA C4
8B ED 4F 65 69 6F 19 75 34 84 3D 8D B3 99 A8 67
EE 09 7B 59 F2 12 D3 F4 8D 22 41 2B 9E A7 CA 43
C7 71 5A 1B 3E 93 92 01 B2 1E BB 1B DA E8 F2 41
49 24 51 C4 04 CE CC CF 47 BB 2A A9 23 A4 57 32
C9 72 3E CB 4D 9D 9F BB C3 BF 5D A7 46 0A 8A C1
54 D9 42 69 5F 26 7C 79 F0 F4 BF 70 7B 4F 67 99
90 73 ED 59 82 55 DE 70 F1 8A 97 FB C9 96 86 CC
6F BD D0 A1 C0 44 4B 63 DF 65 B0 7E CF AC 2A DD
C1 2B 1B 14 7F 6F 06 8F 12 34 43 24 59 DC 08 34
02 A5 22 83 7E AF C1 B1 E2 1E ED C8 49 E9 95 CB
F7 F4 A5 30 5A C9 E7 4B 9E 29 EA B0 8C 7A 1B EE
E2 67 86 71 0C 5C 35 14 CC CC F9 E7 96 FA 6C DE
19 D9 85 A4 B1 1D 9A BE 25 10 16 01 BC 8D C5 A9
B2 54 66 48 67 06 F9 27 9A 90 D1 63 3F 61 AF 1C
C1 62 F7 04 2E F4 08 BC 18 63 53 F5 B5 E5 D5 0B
15 0D 3B 15 C3 6A 23 D9 3A AA 5D D0 63 9D 93 59
C2 03 55 C7 27 92 E1 A1 90 0C F6 00 87 12 E2 A5
70 B8 8C FD D3 8F 53 61 EA 91 06 DD 61 36 3C EA
14 E9 FC F6 C6 82 24 24 71 DA 21 50 9C 25 67 BC
DD 98 6B 65 57 C1 AB B8 A7 F9 A6 16 C5 55 33 C0
75 5E DA 18 A6 67 C9 C1 E6 3F 65 18 55 FE 54 9C
16 CD B8 84 18 2D 6D 28 1A D6 2D 64 5E 03 40 D6
31 3E 6C 29 EB 42 0B D1 56 41 3D 70 D0 C5 93 E1
3B 77 9A 08 E0 28 B2 9B 20 14 A6 2F 07 45 DB C8
EA EB 0D 9B 7E AF 79 5D 1B 88 EF 5F C6 B6 E6 76
84 1B 23 34 39 97 50 73 96 A1 D4 E4 13 DB 8D 3C
6E 48 DB 56 69 7B 03 3A 0A D7 27 5E 90 8A FC FC
09 56 93 E8 32 E6 84 64 A9 E9 1C F0 CF B1 91 E0
AF 4B AD 6C C6 F8 F2 4E 86 66 DC D8 4B F8 44 A3
06 02 3D 60 A3 95 F5 55 DE 33 D3 4C 35 81 78 2E
5A B4 93 F6 4C 87 E5 34 1D 85 2F EB 4B E7 42 56
4F 71 B7 DC D5 EF AD 96 DF E9 46 62 97 5B 09 72
3B 10 C5 95 4A 32 BA 23 91 48 A4 80 AC 9F 45 61
7D 98 A7 D3 7A 9E 9E 1E 28 D3 99 0A AD 07 E2 89
0B 01 56 66 BB 8D DE 04 DD BB CE 4B 8C 33 36 F3
69 78 CD AA 64 D5 04 A7 33 EA 9F 82 73 02 0D 82
09 3F 46 F6 24 C4 FA 5E 1F 15 2A 7F A2 98 7D CF
A0 39 06 85 88 9D D3 94 92 77 06 13 8A E5 15 6D
EE 60 40 76 C7 4F 0F 1F 2B D3 AD A4 1E EC 26 2A
D4 2D EA 4B C4 3F 19 EF 59 21 BB 9F CE 70 D2 9C
21 C1 69 E3 9B E9 9C 61 A2 B1 7B 95 E9 1D 6B 3E
7D 54 9A 29 A0 F5 D5 6C ED 33 69 DB 3D 20 DB 5D
2A 76 91 0D CB E9 11 F9 53 8B 4A D9 70 25 F5 13
F8 41 1E B3 01 77 8F A2 9B 9C 00 AE F2 BC CC B3
AA C8 FB A9 17 92 49 EC F3 91 5B 68 8F 98 CE C2
A9 60 D9 67 CF 1F 07 C8 6C A9 D0 6C 2C 02 F4 1D
9F 05 1D 88 5B 3B F8 93 2B E5 9A 41 25 85 02 73
F3 E1 D4 EA 24 2E 41 FA 69 5D 18 C8 73 DE 17 D0
00 E6 C7 03 CF 0F FE 4B 48 B5 E6 46 EA AB 26 58
92 9A 3C E2 66 2D B6 19 CB 02 5B FC 67 CA 2B A4
EA DB 15 35 43 55 EF E9 B1 97 D2 86 0A 9D 57 23
98 2F 31 B9 95 BF DB 76 07 73 32 88 72 7C 24 EA
29 C3 D0 A5 81 F8 9A B4 88 61 23 BF A0 E2 12 D1
B4 94 0D F3 70 BF C7 D0 02 90 E4 8B CD F0 31 15
5C 10 16 5F 33 50 44 7E 2D 5B B6 99 1E 07 43 0E
93 31 EB CF 9F 3F 6A 10 E1 64 CB 2D E4 08 8D 2C
E8 BD 4C ED 23 EB 74 D1 87 13 FB 09 39 57 62 F7
61 A3 6F EC 2D B4 EF 80 35 00 6D 7B 7B 33 20 ED
48 9D E4 4C A8 E2 5D 2C 02 41 02 F7 6C 1C 37 AB
45 AF 5B 78 8F 05 C1 30 E8 16 6F 5A 61 22 4E 02
37 0C 9A CD C9 79 B3 B7 47 BF 4F 22 9C 8C 23 65
5D 8B 59 91 A0 67 7A 4B B3 03 9D B5 45 72 BA 34
61 73 5D 6E C9 32 83 1E 8F 48 D3 F3 E3 F3 DA C9
4B 1D AC 88 AF 7C 08 77 77 6B 87 7D AC 54 DE BB
74 31 5A 32 88 BB 11 74 42 5E 6B AE AD E5 76 7C
0D 0F B0 DF 47 F4 BE E1 20 E3 99 8A 1F 7A 90 27
C1 9F 2F 03 5B 7C 16 96 89 C1 4B F2 74 35 13 3A
05 7D 65 7C BC ED 05 4C D8 E7 5D 7F FE 6C 43 A8
86 7A E4 25 9C 66 73 87 37 0D 97 22 E3 4B 66 36
41 EE 49 2C E3 71 46 6C 97 17 EC 57 B4 D9 42 56
BA D8 57 D8 96 B3 7B 31 DA BA EE 24 56 F5 B9 F0
15 5E 6B B0 9F 79 AB AD 81 6A 08 C9 68 8A E9 7F
86 59 DD 09 31 CD B8 69 B1 25 04 74 C6 7E 69 9C
6B 1E AB B4 B9 18 95 C0 BC 1F 9A B6 48 5D B2 4C
1F AA 5A 3A 74 38 B4 8F B6 D1 BD 02 E8 0A 3A 5C
0D 0A 5C F9 5D BB 42 83 4A EC 70 3C 4E 36 D8 B1
40 62 91 79 C7 04 F7 05 BE F2 32 E4 EF 06 DD 25
40 B1 56 2C E8 90 25 6D 62 29 11 E2 33 31 4D C9
D8 5A 95 44 D6 E7 B2 D5 F5 61 66 6F 1A 40 DC 4B
45 50 E2 73 01 65 CD BD 5A B6 E5 77 13 05 D2 17
FC 6C 72 5B 8E 46 DA 58 DC E1 DE B0 08 7C AE 67
5D 29 A6 E2 B3 99 B3 30 29 F5 F3 ED B2 46 F4 CA
94 E0 B9 94 14 C6 00 B9 61 44 93 E1 29 B1 6A C1
38 FE 49 5F 9D 45 32 4F 73 40 4C 09 08 C9 D8 D9
C4 65 08 D0 2F C5 48 7A 6B 50 1C AD 88 EF 76 7B
CD 96 C3 6E 71 C3 13 6C 3E 9E A5 8E FA 86 C2 42
42 24 B7 0D FF 0C 1C 85 87 B3 9A 4E 9F 9F C3 86
04 B2 CF DD C0 0F 13 E1 6B A8 EE 00 0A 18 3B CC
3E 40 63 4E C4 5B 44 F9 56 4B FA BE 0A 62 DC BB
17 49 84 36 B1 D9 E6 38 3B 06 78 E1 34 8D 32 42
05 65 13 18 9F 33 9B 5C 67 96 17 3C D8 79 FB 01
7B 49 02 FB 78 8A D1 3E FD D2 0B 24 96 D0 D0 9A
BE 91 8A 8F D4 B1 F1 C3 D2 7C 75 E7 34 78 59 F5
BE 41 6A E7 9E 03 22 30 67 41 DD D8 84 6D F9 47
5F 04 B0 EE F2 A1 CC 69 9D 11 54 E2 01 D3 67 93
98 FB 25 52 47 AF 4F AF 9A 6F 29 85 47 64 87 DA
61 AE 1E B1 64 EA AC A6 D3 CE 62 99 96 73 DF FA
AA FC 0E 7F FA 05 50 84 BC F4 57 DC 0F 01 36 10
33 84 50 C6 4B 54 38 C8 20 28 9B 75 4E 93 B7 2E
FE 8A 14 AC C5 DE E6 36 F6 4A 13 06 E8 EF D2 3D
63 46 9E 5F 46 3A 51 0E 6B 53 08 FC C3 7F E6 90
4C 81 03 BC A8 81 EC 88 79 F2 82 F3 C9 22 84 4A
0B 43 94 BA BF 3D EB 75 50 F0 3A 08 C9 A9 2E 04
C4 0E 1C 3A 07 70 DF E6 64 CC 51 ED D0 FB 5E 37
6D EC 10 88 D7 F1 8F 0C 1D A5 2E 22 BB 86 29 5E
E7 C1 A0 CC E0 48 A6 1C 54 46 A9 26 48 72 C0 0C
2C 7C B1 73 6F 12 3F E1 6F 58 58 C6 DC CD B1 19
EA 82 B2 3A 26 8B C9 87 7F 1C 33 6D 78 0D 11 19
3D AA 14 9D 2A 0C 27 E7 5C DF 66 90 A9 3C 9F 47
15 60 4E CF 51 ED F8 2F AD B1 3E FE 33 73 13 E2
4F D5 AA DF 11 75 C2 D7 68 0D 08 4F 0A 4D C8 B1
B6 B6 6E F7 D3 92 4E 5A 38 7A 73 8A 5B 10 C0 22
07 F2 27 63 1D 41 02 BD 94 37 4F 94 50 F8 EB 93
43 47 44 11 B2 33 8D DE 52 8B 85 C8 7D 68 96 CF
7C 6B F7 0E A4 9D 2D F8 1B 9A 85 CD AE 83 9B 40
A9 EF 66 A5 CB F8 EF BF 2F 3E 60 06 05 4C A3 FD
22 47 FD CF EE A4 8E 55 4A 69 E4 64 50 58 A1 15
8B 88 BD CA 0E F1 ED B0 C2 AC F0 34 87 BD 00 B1
EA 94 14 4C 7B 1A 2E 80 F2 05 52 97 70 66 5D 3B
BA 7E D0 BB 95 2D 01 8C 4B 7D D6 7F 85 AC 98 B9
50 EA AF 0A 3D 4D C9 7E 85 04 6D BD 00 C0 1A 9C
01 6A D4 A3 27 8A 3E A3 AF 27 23 25 E8 15 19 5D
45 1C 9F 84 16 6D E0 26 5B 83 AB 11 D9 F4 79 E1
09 B2 06 D5 B0 83 88 E2 8A 30 B4 5E A3 F4 BF 0E
54 4E 22 77 36 28 95 0A F3 B7 86 2D A7 BC 29 EE
FD D4 03 1F EB B5 21 E0 95 6C BF 14 A0 43 CC 70
C4 85 0F 88 23 44 66 AB 05 DB C6 27 41 B1 18 33
5A CB EF 89 2D 68 70 DC E4 F3 8F 52 E7 75 B1 63
34 6E FE 4B A4 D2 B6 C4 9E 0A 7C 46 58 77 CE 5F
5C BF 10 F7 3E B8 EC DB 4D F6 DE 12 4F 40 7E A0
24 61 01 50 E4 41 C4 DC 79 28 0C 05 29 2C 47 0F
15 09 FD 23 22 2C 28 E0 7E 26 48 D9 44 CE 10 FA
35 92 B3 32 C9 00 F8 0A A6 64 F6 66 96 8D C1 75
9C 1A AA 91 56 85 62 BE 00 25 97 58 0A 0E B0 11
C9 D5 33 37 A8 1C 0A EF 59 A7 D7 10 EB A8 87 20
9A 86 C0 B0 1C F6 61 AF F5 F3 2A 69 3B 89 CE 26
6B BF 09 D5 ED 65 35 A3 83 47 0C 61 CB 57 9D 51
15 D8 0F 2D 7E 1E 7A 9D 31 4A CB FE D0 1D 8B 72
6E 67 1C A9 76 05 84 67 91 3A 33 0A CF 96 59 1B
6A DD D9 8A C4 A3 AF AC 7C 82 25 7F D3 A7 3E C4
92 0B E2 9A EB B4 77 C3 DC 5D C3 D6 F0 17 33 60
B8 C1 57 3B F9 7F 3E EC 2B A2 3F B5 29 56 BA A7
B5 B3 42 57 84 0E 9B 6B A0 01 EF A0 D2 59 98 A3
E0 7A 6D BD 9C 80 1F 50 D6 58 55 E1 34 21 22 94
70 05 A7 DF 9F 68 88 55 7F A3 2E 86 BE 23 A3 5A
EF B0 D1 F0 68 88 01 81 07 82 D6 B8 45 40 D8 23
59 A8 BA 1A C4 6E 78 43 E0 28 14 A2 52 60 C6 A7
64 6A 5B F5 1F C8 EF 65 EE 40 2C 2A 4E D1 AF AD
39 63 32 21 F0 AF 96 74 56 13 A6 6E E3 AE 9F 86
A7 F7 3A 68 D9 CD 21 65 E7 F5 E2 E3 F0 6E 1F 27
D4 E0 E6 BF C1 37 AC E9 3B 54 42 1D 41 12 1B 55
6D DE F6 C5 39 52 21 F6 40 67 03 F3 FA 92 E5 6E
4A C6 00 BA D6 71 82 B9 F1 B8 A5 61 61 2E B5 C7
C8 8B 78 9F D1 4C BA 66 AC C6 35 5B 07 9B 68 84
4C C9 8B 70 7B 81 EA 83 18 CD 78 3E 76 FF E7 D6
2E B9 6C 79 AE 30 01 6B BD 05 7C 97 ED 67 94 C8
3B 93 A8 58 35 32 7E 88 92 D4 D8 17 0B 24 C5 56
82 7A F2 F5 E9 09 C0 44 83 9B 8D 6A 42 56 D5 12
BB EE 3D D8 ED 66 A3 49 0E 4C 61 47 A4 3F DD 15
78 B8 C0 1D 9E B8 06 40 CA 1B B0 8D 27 71 0B 6E
50 25 EA 53 1A 2E 99 41 26 6D 78 91 7C DD EF BB
59 D3 48 62 2B 9D A8 2A 5D FC 60 EF 87 72 B8 FC
7C E4 F1 81 BA D3 F0 F3 37 2E 5B 58 5E DD 0F 84
EE DD 76 54 95 12 EB 2C DF 5F E7 F0 07 76 46 E3
D9 96 EB 30 04 C3 57 20 B3 0E F8 B0 0C 39 5C 9D
AD 4E D9 CC 2C 2C 31 BD 6A E4 92 DA 55 69 F5 43
7F 96 FC 23 89 40 F5 D8 07 13 72 6B 03 38 CC 45
D3 9B D4 61 32 79 25 91 76 AE 93 31 9D 3D BC 9A
07 53 EB 34 A4 39 AC 3F 5E 49 15 CC 19 A5 2A DA
F7 2E 3B 06 79 B7 B3 87 E7 5A 2A 55 7F 8D 4C A2
0D FB 88 AA FB 9D 34 1E 8B 6F 4C 6F 25 1B F8 24
FC 81 56 B6 70 99 41 4C FF 13 EB D9 C5 7F C6 70
97 B9 2F CC F4 42 86 0C 3A 21 56 C3 4C 21 3C F9
A5 3A 50 96 BD E6 7D 6D B1 5B FD E7 0C A5 EC A3
31 53 DB EE 41 25 F8 F8 B6 02 D7 5C FE 49 03 95
D5 EE 7D 85 46 1D 6F 85 5A A9 1A 33 F5 EA 83 D7
BE 48 65 22 F4 0C E2 AE 4B 97 33 03 C0 13 2A 23
C8 2B A2 C0 CD 69 7F AD 50 45 8A 3A 2F 44 38 C8
C1 A4 DF 61 7A 75 BE F6 84 37 B1 26 4F C1 E0 30
EB AD DE 9E 75 B8 2D 71 AA D7 40 D7 64 3A 12 C3
DD E7 30 1F 3B 9B 86 AE F0 DB FD EC 61 64 B6 4E
6D 53 76 D7 0B 32 F4 2A 00 E7 E2 5E 4E 9A 2C 84
4F 48 A5 FB 94 FE B0 59 0B E2 77 3D 71 22 EA F9
5A 73 1B 38 98 80 2A 41 6D 8F 62 E8 13 90 39 EB
38 73 19 D5 EB CE ED 56 2D A9 E6 A2 6A 62 4D 49
A2 BF 29 E0 B9 A6 35 86 F3 D8 71 B5 96 EC 53 CC
53 90 2E D6 4F 2F 4D 51 97 A2 C2 5D C7 EC 88 E8
C2 6A 5F 01 8D 56 0C 4E 5E 8C 96 FC 9E EE D1 FF
89 DD 1E 72 D4 AE AA 7C C6 77 DF 8C 63 DB 11 6B
AB 25 B0 CC 0D C3 F4 28 0A 4D F9 C3 C5 55 10 D3
FE CA 74 07 47 74 3B 60 75 16 22 8B AF C1 C9 30
BE BE 13 B3 A8 94 D5 32 81 A5 65 77 08 B8 65 BD
BF 73 6C 1C C2 F4 27 41 30 8B 2E 2F 3D 0B 44 71
32 AA 6A 4B C3 B5 CE B3 0B 04 AB 4A CB 82 A6 5D
6E FE 07 95 C1 4A 63 49 22 D8 FB 3C 79 CD A6 19
76 F9 F2 4F 26 C1 90 DD E0 8E C5 D0 74 8E 60 3A
3A E2 4F F1 52 CB 0B 53 B7 C6 DE 3D 11 40 E6 F8
35 A6 D4 74 93 F9 E3 BB 18 8B 3C 57 3A 7B 49 B5
1E 76 18 44 5F E5 5F 67 08 DC 58 97 F5 99 A7 6A
A9 D8 F1 BC A6 0B 59 18 0C 3F 52 85 E5 C8 68 18
2C D9 84 80 D0 38 1F E4 4E 1E 0A 4F 85 B2 E0 53
39 CA 1D 58 1F 8E 35 41 B1 5A 38 5C F4 11 6E 7D
2D 75 81 4E 6F 3B 65 2E D7 9E 76 55 8A 69 25 90
BD 4B 7C 74 D1 43 22 5A 42 C6 70 D2 55 0F 02 FF
25 27 59 41 64 3E 7B 90 5C 32 B8 D7 47 08 E7 EB
1E 45 51 E8 FE BF BC DD BB 8B 49 B1 73 D3 91 34
C7 2B AD 49 0E 9C 58 F5 24 AF C8 2B 16 3B AA DF
52 2F A6 BD 06 2E B5 3F 95 9E 36 A8 78 12 DD BA
17 76 19 24 84 2A C2 F0 E8 36 64 47 A6 42 B7 58
AD 4C AC 32 FE 00 52 BC 38 C1 8C BD A2 F4 56 5F
50 35 02 52 0C BB 79 50 E3 FF 3C 65 D1 E9 9C CC
F5 65 CE 6E DF 8D 9A 67 BE BC 8D 45 1B 45 47 98
FB EE 52 0D D2 11 26 C1 03 DF B7 8F 66 AC AC 73
F8 7E 92 53 F5 EE A5 C1 06 FC E2 5C 5E 2B 79 6F
56 F6 C5 A5 64 49 F4 05 66 D8 CD 21 FD 57 8D C9
91 10 43 5A FE C2 9B 26 68 4B 23 22 87 87 20 22
4F 38 7C F7 30 0A B3 0F 46 C7 E5 B3 9D B5 06 13
3F F7 FA 9C 4C 9B 1D CD 61 51 2F 6D D3 D3 B5 9E
A7 3B 9E 5B F6 4A 7E F1 37 B5 88 21 F1 73 D1 0E
B3 7F 60 9C A9 D7 FB 16 FE 0E E3 0D A0 E8 D3 62
8C A1 AC AB AA E2 86 A8 94 03 3F 52 A4 F5 92 C7
27 68 C1 5F 40 25 1E F7 F8 15 E5 9C E9 17 33 E5
89 FC A2 7A AE 01 BB 9D D4 12 A2 0E 35 7A 49 E9
64 18 E3 C7 FA EB D7 45 5B 91 F1 62 D8 3D B6 CC
BC 34 6B 34 4C 6D D3 76 8B 71 2B 66 35 16 78 CB
AD 6D DC 3C 5B B5 30 8B 64 73 69 43 E2 56 A3 A3
5A AD FB 8A 1C 27 53 D3 61 62 64 15 9C F5 7A AC
43 B1 B1 BA B3 E7 50 BE 38 EE 3F 16 D3 04 77 27
21 39 AF CB 32 2A 7F 53 1C 9E 98 5D 1E 5C E5 C6
19 25 05 94 65 48 F4 98 30 92 F2 13 8B 41 99 C4
3E C1 4D 78 79 91 18 06 00 1C AC D4 30 C0 8B 2B
42 14 55 58 DA 1A 5A AE 85 D4 66 9E 3D FE CD F3
AE 08 82 99 D3 46 AA 41 D8 CA 02 47 18 4A C8 52
E9 BD CA E0 43 C4 8D A0 A7 3F 89 26 67 36 98 50
D3 9D BF 7A 68 F4 54 2A 0E FA 81 98 78 A0 F7 9C
F1 DA E6 24 B2 A2 31 78 0F 9C 75 37 E7 DB 4E 28
FF C3 58 67 6D 66 B1 9E F7 C3 8A 8F 08 DF 23 6D
EB 20 CC 1D E3 95 EB BF 3A 1D 2F 7D 59 35 BF A6
9F CE 4A 89 51 E5 3A 39 E9 C1 BC FA FC A9 CA FE
5E 3E 4A B2 BE 55 86 73 7A 3F DE E7 E1 66 31 55
11 5B 35 C4 D6 7E 88 CF AE A6 B6 F9 1B 8E 1F 6B
C8 CB 64 CC D5 E1 2B D5 12 6F 10 38 94 20 A1 72
04 D1 4F CF 01 63 92 7C DA 09 04 23 74 44 A1 2F
0E 83 88 80 DD 71 B3 49 10 49 ED 96 97 4D C3 55
32 59 50 83 D9 1D AC 0A 62 67 BA 35 F2 3E E2 A0
26 7B EC 14 BF 6E F3 53 DF 32 99 78 B1 D2 C1 AE
B3 F3 9C B1 24 45 D3 59 6F 78 D8 99 06 30 E4 44
58 3B EB D0 AD CC 10 40 8D F7 32 1F BF 92 0A BA
56 00 57 96 05 BF 5B 40 7D A1 2D 2F 8E E2 F4 73
8C E5 64 AE 93 64 4A AD 01 16 75 09 77 B2 A6 7B
BB 25 11 DB 66 DC 4D C7 3D 78 CC FE 9D 48 D6 B4
D6 0F 3D 27 C6 D9 FE 50 49 24 1C 41 F1 2C C8 42
F6 29 9A 8F 24 FF 26 16 41 32 C3 C4 8C D2 66 8D
D5 C0 3A 92 E9 05 EA B8 9F 1B 55 E0 3E C1 04 F0
3F 0B 1E 0A 83 7D D0 CF 1F DA 38 DA 70 46 5C A7
4F 53 F8 8A 83 9B B0 B5 C9 3D 84 CE 65 6C ED 7F
C5 B6 69 34 38 F7 B0 D8 B7 94 92 2F 19 53 BD E9
48 58 51 0A FA 7D BF CC 0B 29 6C 69 3A 5A CB 20
F4 E4 48 02 EC 0B E0 C8 42 DE 88 91 71 A8 45 20
A8 73 4C E0 22 D0 B0 56 85 AC CF B8 51 AE F3 90
32 62 E3 07 90 47 47 F2 19 60 60 C5 FA CB 23 EA
EB 10 BD 5E 5F 8E B0 91 33 E2 CD ED D2 FA 51 53
1E A3 68 10 72 91 D6 DF 14 B1 7F C6 78 59 AD 46
63 78 27 9E AA E8 86 00 73 9F 1D 8C C7 69 32 F5
65 09 F9 90 89 3B AA AC 6C 7C E3 B9 C6 74 13 22
01 CF 83 66 64 AA FC 69 2F BF 9C 2C 1E CA 7F 0E
CB D5 28 1E 4E ED CC 2C 62 04 03 F2 A3 F4 E6 A3
3D 5C 7E 64 B6 45 29 48 AE 96 80 C9 82 82 D5 93
B8 38 AF 6D 79 2F F7 C8 A6 E8 23 FA 3E 10 AB 68
C6 17 54 04 8F 33 95 5A 3B 02 5F D6 E0 88 82 0B
E1 86 D8 60 FD 1E 6B D4 30 30 0D 49 15 09 4B 16
73 AC 2E A1 C6 11 59 C0 63 A6 7E 1E 35 64 65 DD
53 39 67 0F 37 D0 F4 31 67 1D 6C 1D DE B0 E4 8D
11 ED B3 02 33 65 52 7F 61 DC 1B 29 09 16 F0 27
C2 E7 D0 A5 07 02 B2 01 83 47 6C 23 77 2B CC EF
CD 74 2C 89 95 F2 49 6B 21 7E F6 E0 49 15 9E 85
A4 A2 D5 FB 78 55 37 0D 30 0F 2B 76 7D 08 8E 7E
20 38 4B 53 A7 6C 90 1E 71 9F F4 76 BD 80 C4 91
75 E8 E2 78 0D 40 24 40 B7 1C BF 3D 15 A2 47 88
25 5F F5 69 14 29 CC DD 0A B4 07 4B 79 1A 46 9F
51 05 E4 BA C4 46 8C 0C 6A FD FC C6 7A 0A 97 8F
02 5D 41 83 C1 E1 58 47 5A C8 DB 28 D7 6D 72 0C
03 DF D0 AB 6C A6 16 06 D7 EA 8A 06 44 51 1B B8
93 6F 5B B3 10 F2 0A 2E C8 F0 2F 48 8B 06 FD C6
A3 B0 E3 66 48 CA 53 DA A0 3C 4F 4B F5 0F 90 1C
9C A8 72 00 C9 11 D7 AD 09 20 21 46 4F 92 80 D1
10 31 62 77 33 68 A5 9F DD 4A DF 39 3C C2 48 31
AE 8E B0 DA C0 10 1F 5F D4 AA F4 21 71 81 85 1D
05 A7 7D E9 08 B3 6B AA 99 8C E4 F3 0D 90 F0 F1
8B 74 59 60 9B 87 4E 75 9E CA B8 57 45 98 70 0B
C3 EF 4C F2 D5 59 B7 13 B1 E4 26 EF 6A F4 E5 B5
71 89 E5 D8 F5 E1 82 2A 0E 15 E4 31 71 78 AA FB
0E D7 40 D7 91 AC D5 27 DD E5 0C 16 6A B1 E7 0F
07 30 8F 9C 38 2A C9 91 D4 35 E5 41 6F 3B C5 FB
05 A2 9F C6 66 98 2E 49 04 4F 4F C3 22 73 61 3E
EA 8D 52 6E 5D 1F B4 87 69 65 C5 FD 98 A8 06 22
26 01 AC F1 38 47 18 C0 6B DC 97 F9 67 66 3C 5D
84 5C E1 72 F3 11 48 60 D3 2D 1C A9 74 31 8B AB
E9 F3 91 9D 01 C1 EF 50 08 BA 50 F4 0E 64 A5 F2
2A A1 55 4E F9 92 EA E4 66 AE 70 3F D8 54 63 54
85 2F D7 C0 9D EE ED 74 5D 4A BE C4 F2 56 D6 BC
3D F9 A9 9C 3E 17 C1 AC 01 AC E9 39 E5 79 4E EA
BA 89 4F 01 C7 B2 45 37 93 EB EC 50 5F DF B0 73
D3 13 87 CB C1 A6 65 20 70 1E E8 2E AF A8 68 64
EC 38 6D 07 28 9B 02 06 4F 79 ED EC 64 3C 4A 26
21 E2 B9 22 B2 21 15 6C 8A 39 FC 87 EF D2 A2 F7
39 3B 8E BD C9 E6 86 71 7E AA 01 0F 40 5D B2 34
1B 91 14 11 E2 0D EC D6 32 D7 4F D3 B6 6B 8B AE
FA 2A AA 2D 3F 29 BE 75 67 1C AA F2 39 43 FF 8B
79 46 2E 81 C3 32 2C 77 A8 31 C9 09 E9 52 D8 4D
14 B5 D3 D4 79 8A 21 14 24 84 5C BD 2A B0 05 11
36 D9 30 BE 67 FA 39 79 FB 6F 80 20 81 F3 12 32
BD B7 63 8F 6E BC F9 70 FB 00 76 F8 8F 7F A3 CF
73 11 77 04 13 9C C4 4B 02 51 5A 28 9F 6F 72 06
A2 C3 AE 2E 3C 4C A3 7F 65 58 B9 6B AC D5 D9 6D
54 24 FD 54 F5 DA AE 77 EF D3 60 F5 07 B5 0C D7
C4 3D 9C 2F 91 23 F0 F0 A8 8A 5B 92 93 AD D3 82
36 6C EF E0 7C 17 91 43 9A 7C 78 8A B0 03 E3 A0
15 FA FD E9 61 E2 6F 3C 24 84 24 CD 23 9E 4C 4E
A6 23 ED 66 76 DF 7C 9E E7 C8 02 F5 1F 1D 0C E4
5F 0D A9 06 FB D8 4A 55 8C BB 46 D6 FF 0B 3C 7E
13 81 91 22 D8 08 58 EC 56 7B 48 27 59 85 E5 28
6C 85 4A 6D 96 3D 83 D6 A2 73 E9 BA 61 60 41 39
F5 EA A1 BC 91 36 E4 FA DF 8E E0 D9 1C 33 37 45
59 68 FF 42 BF 43 CB CD 7E 4B B7 11 34 17 2F 5C
0E 2F 34 A8 57 A7 7C 20 95 BC C3 F8 B5 2E 52 24
51 E5 4B BA 70 7E E0 51 21 49 AF AD B6 EC 5F 42
05 D7 61 5A 02 43 D4 C5 24 0A 15 C7 C7 7D 43 92
A5 FC 1A 97 8D 45 7F 1F 5D 0C 80 1C 13 7E BD 6E
FE 25 FC C6 38 AE 9E 59 82 A2 6F 9F BF 3D 65 C8
A7 B6 0D 46 8A 38 62 CC AD 7A 3C AA D9 8C 31 7E
97 20 F0 5E 96 31 4B 24 CC 4F 97 AF B3 0C 4E 6E
C8 C3 CF 10 78 38 F7 29 BD F6 D7 86 F5 55 1B 86
00 51 D0 4C C9 EF B4 1F A5 60 1A AE 3E 87 E4 F3
30 62 D7 97 6A A0 26 B9 AE 76 CD 1E E7 92 4E 3C
F8 78 3E 9E E5 7A 28 9D 31 6B 2D 25 D6 79 EE F8
BE FF 5B 44 A6 30 EC B0 64 66 02 92 C2 E1 13 B9
0C 67 85 DB 31 CC F7 9F CA 60 DC 39 74 EA 4B EF
F5 9A D8 C3 71 85 72 1D CA C6 43 5F A7 94 3D E0
9D FA 15 54 41 28 D2 C8 15 2B 38 C8 91 B7 B3 C2
EA 6F 71 4E 5D A7 2F 5C 88 1E 69 F2 4B 9F 82 C2
68 0C 41 0D F3 59 E1 15 5D 58 B5 89 2F 4E 26 C9
27 BF AC 92 7A 7E 22 53 31 FC 13 02 50 D5 F6 00
51 05 9A C2 4F FE B7 B5 29 B8 53 A0 5D 1C 0B 33
D9 47 D1 B0 EF 90 90 36 A4 E3 2B 20 31 B6 5A 5E
78 F3 01 B3 AC CE AC 57 B6 47 46 13 FD A9 C2 DB
EC 48 EF 1E 02 14 4F 0C B3 8D B9 05 66 E2 3B D0
EC F4 4B 99 2C B4 02 2A 5E 17 4C 14 BE 3B EF CD
AF 75 C3 7A 2D F9 33 3C D3 78 71 8F B3 BB 97 48
D9 0C 24 17 14 37 40 C8 8A 5B 3D 64 B1 60 A0 83
95 25 18 9C 42 10 6D 94 08 E6 78 CD C7 CB F9 1B
64 8A 7D 37 6E 35 D0 FB A6 12 65 C7 97 16 A8 3B
D2 55 1D 4D 29 D4 D6 05 9B 9C 2E F1 5E 28 41 9F
8A 81 ED 54 0F 9C 6B A1 0B EA D1 2E 44 DF B1 C6
5E FB 8D E9 C5 FF 25 0A F3 A8 63 C4 54 4A E2 8F
54 4F 3F A0 10 3C 07 5B 57 7D AD 00 98 C9 EF F2
D2 6C 4A 8F EA 25 31 EF 52 E5 C5 1F D7 66 7C DC
05 7E 5D 09 95 94 4C EB 52 1E 30 68 5D 03 45 BE
69 E8 47 AE 0D 08 5A 91 32 3F 1B 68 72 81 B3 F1
0E 7E BD 95 21 9E E6 95 52 C9 A0 1A 68 CA EE 6B
5A 33 A2 81 25 D6 79 7A C3 A1 D6 5F 2D DB 3F A1
8E B4 5D 28 A7 A6 BC 70 C8 C4 6E C8 37 D1 48 B5
D4 00 27 FE 38 4B 88 17 C9 BE 2B 45 69 50 56 FA
89 E8 AE A7 E1 6F 20 C5 FA 96 FF 21 AE 57 61 D0
7D 39 C2 FD C4 BF 78 CB 84 C3 AB 7E 7B 4F 5D 30
24 93 B5 95 8A 7C 3D FD 3B 32 09 76 8C 80 4B 3D
55 FF FE 1A 65 EB BA B3 EE 28 7D 30 A9 C2 CF 12
4B 0E 98 7F 9D CB 84 AB 29 1C 8E 9C 7C E8 E4 98
A7 9F 08 E3 CC 92 06 68 C1 15 47 4F 13 7A B5 56
70 37 F5 08 DE 24 B8 0E AA 6C 8E EF 5B 46 52 F2
27 FE 68 D8 7F F2 07 B0 59 9D 1C 1F 9D 9E FE 8E
51 A4 33 56 39 47 CF B1 C0 69 CB F4 26 8B 95 20
7E 44 91 C1 B4 DB 35 E7 91 CF E3 6A 38 D3 F2 07
75 28 BC 9E C4 00 8B 57 10 47 DB 15 36 0D 67 F9
03 4E 75 A3 07 61 8B 4A A9 A8 3B A6 8D 53 E3 8C
F5 7B DE EF 4D 2B 82 2E AC 79 82 0C F3 D6 09 C7
B6 8D EE 90 67 4F E5 99 0C 29 16 35 2F EA AE C2
B7 F6 B8 52 28 A9 06 3D F0 6E BA 72 0B 00 87 2D
DE 3A 5E 72 6F CC C1 F5 7C ED 79 E2 D6 18 68 F6
9F 5B 61 96 02 96 E5 53 E6 B3 84 ED A0 99 7D 58
14 13 74 B8 14 4C AB 4B 69 51 90 BF 4B 80 D0 74
F2 5C 52 5A 05 3A 16 61 23 66 63 E9 1F A4 0A FF
86 A0 F0 C7 8B 78 2C 5B 27 7A 91 CF 75 3C 08 68
53 02 D2 C8 A6 E0 5A 30 19 FA 58 6D 7B F1 EA C3
1B 81 8F 39 0D 5F F4 BB 6C 08 C3 69 D8 E6 35 45
31 3B 5C 29 45 8E D3 B5 68 B7 96 E1 0C 91 B5 C5
00 FA 6E D7 D4 5F CE CC 37 EA 46 C6 A1 DA 37 2F
44 9B 2A F2 63 95 B0 48 2F CE 6A D9 1E AA 5A 3E
97 0E D0 22 09 40 C5 4B B4 3F 86 D4 19 85 5D 25
DE 7B CA 30 A1 00 55 77 BA BB 6A 62 C1 01 0A FA
FE 35 27 80 FF CF 26 D7 0F 23 C9 F4 5F F9 3A C8
1A 41 CE 8F 93 18 16 D0 B1 E1 7F E9 F3 8C B6 4D
EA B3 EA A9 32 0E 12 5D C6 16 CB A2 79 8F C5 15
72 36 2E 1B B0 2C EC F9 60 97 17 CD 0B E6 CC 88
6E 8B 8E 6D D5 05 57 1D 5D 4D 3B 2C F6 D5 FB 0F
A1 85 22 90 FD EE 29 BF 13 19 61 F3 1F 21 FB A9
CE C6 BD 88 95 40 61 B2 00 58 71 30 90 AB D7 1A
56 BE 38 63 F1 E5 02 19 4E 31 4E EB 42 C5 2C 4F
AF 8A 6E F6 62 A5 67 89 8C 89 63 8A 4A 6B F9 25
EB 8C 1A D0 61 92 68 46 DB 09 0E D1 9C BF 1D 56
54 ED BC DD 4F 81 87 F6 4A 28 A7 D1 25 A6 77 99
BB 42 1D AC 3C 0B EA 64 0B FA A5 B3 58 8F 4E E9
29 70 B6 6C 7F 30 DB 6E 23 DE BC 62 82 38 61 9A
69 E8 F9 0B 00 D9 15 A9 36 7A D0 C2 A6 C1 83 F9
53 D5 F9 F2 96 4A E7 E7 FF 9D D5 4D 41 39 8E 4C
2F 23 7E 2C C7 90 F1 64 EF CA 40 4F E1 16 8D 5D
29 A2 AD 1D 60 07 42 37 0D 8A 2F DD 61 78 A6 EC
8D CE 9D 77 5F 34 14 48 6A 68 9E 9A 52 21 5B F8
FF EA B5 E7 18 BA C5 4C 51 DF 21 0C 90 E0 AE DF
25 75 22 CB 8F 76 85 7E 56 07 47 17 7D 47 DB 82
FD 63 1E 29 40 BD 86 99 E7 71 90 A3 77 CC 64 9E
FB 09 F7 64 A1 9E D9 FD 60 DF A5 15 10 46 39 47
4E 39 00 49 62 9B 5D 4D C2 5F 3E 63 6D 5F 94 99
F3 C2 7A 03 7B AA E3 35 A1 1C 11 BA 7D EE 0A B4
66 4A B4 D6 7D 37 AD A9 6B AA 36 D9 FE 45 78 08
E6 08 20 7D E5 7E 20 33 C7 7B 9C B4 51 FA D2 35
7F 66 E4 50 51 D3 82 C0 7D 5F AD 5E EA A3 05 2D
2B 3A D8 35 65 D4 12 C5 B0 D5 7E 98 1D 0D 45 31
D1 85 08 EE 9F B1 D7 0A E3 3F 9C 3A 99 3E EC 8B
71 5E BA 18 F0 91 09 37 BF FE F6 BE F9 A0 C3 57
65 B1 C9 30 FC 6E 7D 2A 40 34 1B DE 86 52 E5 90
61 C9 6A 23 5D ED D5 38 DE AD 17 7E F7 B0 C4 32
43 EE 16 E5 5C 99 68 40 B6 EA 2A DE 12 14 19 4F
2A F1 68 03 4F 01 D9 65 7C C7 C3 79 B6 BF 75 EF
CF 13 FE 07 63 B4 0C FC BA 43 D6 BC B1 D6 EA F5
95 E8 AA 3B 42 AE 7B B7 71 71 32 BD 67 BB 95 98
6D A3 44 E0 60 C8 7D 78 92 9E 9C 71 17 FC 11 EF
C4 72 13 30 55 31 76 81 1B 0E 66 AE 7E E2 DD D6
F0 B1 74 6E E3 42 00 DA 12 0A 2F 3D 08 ED 11 0C
D2 49 6A 43 2A BC 44 E2 D7 87 70 37 80 61 CB 06
72 F7 56 10 47 7B 0D 89 35 07 A8 7C DC 40 52 0A
0B 39 9C 97 81 CB F7 94 5B 55 AA 61 5A 43 7D E7
C7 4D 38 8F 08 32 81 74 75 9F 03 F3 6A DD 86 28
20 AB 2F EA 5C A2 AC 2B EF 29 BA 14 C8 0D 02 BA
39 66 97 9B 8C 78 5C F2 DB 78 27 C2 6A 2A CC 88
1A 4A AC 38 DC 37 91 96 EF 50 6C CD F7 68 AE 61
4C 14 95 66 DE 49 99 71 94 D0 99 5E 92 5D 52 1B
EA 17 EE D6 47 1D C8 7E B3 87 60 B0 87 2F FB E3
15 DD B5 4F 39 A6 ED 0B 8B 27 7F 1E 0E 21 86 6F
CF 60 B8 95 D0 49 AD 5E FD 5D F0 1D C1 DF E7 52
4D 2B 52 FC C9 C3 F7 EB 83 B4 D2 97 7D FC AF 11
53 70 F8 90 0D D2 0F 88 66 9A 4F 7B 55 2A 7B E8
EA 79 11 4E 29 91 2F A3 D3 2D 32 CF 60 41 A2 C4
C5 34 27 F2 E7 B0 3C 84 2C 9B 29 1C C5 FA 4F 24
24 30 F4 9B 35 AE 66 17 67 70 EF 32 1A 8F 3F 1E
92 5E 15 15 40 54 41 71 8D 6E 9D C1 4C E3 7E 4D
C3 33 9C 70 7A F2 5D F4 26 3A D2 B3 9B E3 25 00
ED CC AA 6E 0D 44 91 DA 6E CE 86 5F 45 75 E3 90
0D 70 77 0A B7 EC 87 70 0D 49 BA 6F 76 7C 64 C8
3C 5B 4B D7 B7 39 AE 92 62 A3 3D 47 44 83 94 63
34 AE 1B EB 51 29 C8 17 D9 4C E9 40 77 42 81 A6
18 0C 49 30 28 8F 28 0D 76 B3 0A 4F CA 12 E8 84
95 0F D7 27 49 24 2E 3D EF 7F 5B 8E 48 D3 AE 17
6E 87 C7 09 A6 51 7C E1 AD FC 28 CE FB 0C CA 1C
06 F6 BC 10 1F 71 30 B5 CD A9 BD C2 21 58 09 32
63 45 CA 59 5E F4 3B 25 44 8E 1B B3 7E 73 E7 BD
49 65 18 17 A2 FF 65 B5 0B FF 69 5E EB 7A 96 19
4F 44 FB 18 FF 23 D9 78 15 8F 47 4D 4C 9E C1 34
E9 24 E9 DD 8C CF 1D 0C CE 8C CB 46 3F 4F 63 C2
61 AB 61 F7 94 1D A9 E4 A0 C0 19 D5 8F 45 E7 37
A9 3D C7 47 94 CF 84 B3 83 77 20 0D 16 59 BE A7
95 8D AA D3 15 31 4D 0B CC 73 77 03 7C F3 D9 09
A1 7C CA EA F2 A2 30 87 03 9B E6 29 6D 3A E9 AE
8F 72 00 F9 CE 74 C5 55 2C 1C 4C 28 3C C4 FA 7D
B8 43 88 0E 3E 98 5C B5 81 9C 2F AD E0 CB DD D4
DB 45 28 A6 90 E8 13 9D 5C DA F1 4C BB 67 15 EF
9C 9B EA 7E 01 48 AE F2 84 00 00 6C C4 13 67 61
A6 C2 20 2A 61 14 41 38 57 3A D1 94 DD 7B B8 54
84 77 04 06 BF 88 D7 C1 D3 CA 9F 03 E8 91 C3 02
F3 F9 73 E9 E7 79 31 BD 25 3A 1E DD 32 82 64 36
02 EA A2 69 2C 9A A4 2F 43 13 08 9A B1 24 91 86
15 2D D4 5A 69 65 B5 23 AF AF FB 9D DB 44 C3 E7
83 44 08 B1 93 9C 7D 0D 75 8F 45 FD 06 99 79 60
61 0F 9A A1 E4 60 77 D4 2F 76 66 FA 8B A6 81 8E
* End 138167944 2957739639

View File

@ -30,57 +30,60 @@ WIRE -544 -432 -544 -560
WIRE -384 -432 -544 -432
WIRE -16 -432 -16 -560
WIRE -16 -432 -320 -432
WIRE -1600 -400 -1600 -496
WIRE -1600 -320 -1600 -496
WIRE -880 -320 -880 -336
WIRE -800 -320 -800 -368
WIRE -1600 -288 -1600 -320
WIRE -1648 -256 -1840 -256
WIRE -1840 -240 -1840 -256
WIRE -1600 -208 -1600 -240
WIRE 752 -208 752 -560
WIRE -1600 -176 -1600 -208
WIRE 240 -144 208 -144
WIRE 512 -144 304 -144
WIRE 704 -128 592 -128
WIRE -1600 -112 -1600 -208
WIRE 208 -80 208 -144
WIRE 208 -80 96 -80
WIRE 352 -80 208 -80
WIRE 512 -80 512 -144
WIRE 512 -80 480 -80
WIRE 656 -80 512 -80
WIRE -1600 -64 -1600 -112
WIRE -1600 -64 -1728 -64
WIRE -1600 -64 -1600 -96
WIRE 656 -64 656 -80
WIRE -1600 -48 -1600 -64
WIRE -1728 -16 -1728 -64
WIRE 352 -16 320 -16
WIRE 592 -16 592 -128
WIRE 592 -16 480 -16
WIRE 320 0 320 -16
WIRE -1600 48 -1600 32
WIRE 352 48 96 48
WIRE 656 48 656 0
WIRE 656 48 480 48
WIRE 752 48 752 -112
WIRE 752 48 656 48
WIRE 976 48 752 48
WIRE -1600 80 -1600 16
WIRE -1600 80 -1728 80
WIRE -1600 96 -1600 80
WIRE 752 96 752 48
WIRE -1728 128 -1728 48
WIRE -1728 128 -1728 80
WIRE 976 128 976 48
WIRE 96 144 96 48
WIRE -1600 192 -1600 176
WIRE 752 208 752 176
WIRE 848 208 752 208
WIRE 752 240 752 208
WIRE 848 256 848 208
WIRE -1728 272 -1728 192
WIRE 752 384 752 320
WIRE 848 384 848 320
WIRE 976 384 976 192
FLAG 752 384 0
FLAG -1600 128 0
FLAG -1600 272 0
FLAG 96 224 0
FLAG -1600 -560 vbus
FLAG -992 -560 vmid
FLAG 848 384 0
FLAG -1680 -416 0
FLAG -1600 -112 vdrv
FLAG -1728 128 0
FLAG -1600 -208 vdrv
FLAG -1728 272 0
FLAG 320 0 0
FLAG 96 -80 cp
FLAG 96 0 0
@ -91,17 +94,19 @@ FLAG 976 384 0
FLAG -800 -320 0
FLAG 400 -320 0
FLAG -880 -320 0
FLAG -1648 -304 0
FLAG -1840 -160 0
SYMBOL nmos 704 -208 R0
SYMATTR InstName M1
SYMATTR Value AON7140
SYMBOL res 736 224 R0
SYMATTR InstName R1
SYMATTR Value {rtip}
SYMBOL voltage -1600 32 R0
SYMBOL voltage -1600 176 R0
WINDOW 123 0 0 Left 0
WINDOW 39 24 44 Left 2
SYMATTR InstName V1
SYMATTR Value PWL(0 0 1m 0 1.1m {vbus} 10m {vbus} 10.1m 0)
SYMATTR Value {vbus}
SYMBOL voltage 96 128 R0
WINDOW 123 0 0 Left 0
WINDOW 39 0 0 Left 0
@ -118,20 +123,20 @@ SYMATTR Value 5m
SYMBOL cap 832 256 R0
SYMATTR InstName C4
SYMATTR Value 10p
SYMBOL ind -1616 -416 R0
SYMBOL ind -1616 -192 R0
SYMATTR InstName L2
SYMATTR Value 500n
SYMATTR SpiceLine Rser=1m
SYMBOL res -1616 -304 R0
SYMBOL res -1616 -80 R0
SYMATTR InstName R8
SYMATTR Value 120m
SYMBOL cap -1696 -480 R0
SYMATTR InstName C5
SYMATTR Value 1µ
SYMBOL res -1616 -64 R0
SYMBOL res -1616 80 R0
SYMATTR InstName R9
SYMATTR Value 20m
SYMBOL cap -1744 -16 R0
SYMBOL cap -1744 128 R0
SYMATTR InstName C6
SYMATTR Value 200µ
SYMBOL IRS10752L 416 -48 R0
@ -149,15 +154,6 @@ SYMBOL ind 736 80 R0
SYMATTR InstName L3
SYMATTR Value 10n
SYMATTR SpiceLine Rser=1m
SYMBOL MCASU32MAB7106_PNA01 80 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U4
SYMBOL MCASU32MAB7106_PNA01 192 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U5
SYMBOL MCASU32MAB7106_PNA01 288 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U6
SYMBOL ind -416 -544 R270
WINDOW 0 32 56 VTop 2
WINDOW 3 5 56 VBottom 2
@ -185,19 +181,36 @@ SYMATTR InstName D1
SYMATTR Value RB068M-60
SYMBOL Contrib\\CHEMI-CON\\Capacitors\\Alcap-PolymerHybrid-SMD\\HHXC350ARA220ME61G -816 -432 R0
SYMATTR InstName C2
SYMBOL MCASU32MAB7106_PNA01 400 -384 R90
SYMBOL sw -1600 -336 R0
SYMATTR InstName S1
SYMATTR Value SW1
SYMBOL voltage -1840 -256 R0
SYMATTR InstName V4
SYMATTR Value PWL(0 0 1m 0 1.1m 1 6m 1 6.1m 0)
SYMBOL MMASU32MAB7106_PNA01 -880 -400 R90
SYMATTR Value Temperature=40
SYMATTR InstName U3
SYMBOL MMASU32MAB7106_PNA01 80 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U1
SYMBOL MCASU32MAB7106_PNA01 -880 -400 R90
SYMBOL MMASU32MAB7106_PNA01 192 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U8
SYMATTR InstName U4
SYMBOL MMASU32MAB7106_PNA01 288 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U5
SYMBOL MMASU32MAB7106_PNA01 400 -384 R90
SYMATTR Value Temperature=40
SYMATTR InstName U6
TEXT -1656 -1016 Left 2 !.tran 12m
TEXT -1648 -808 Left 2 !.param fsw=100k
TEXT -1648 -776 Left 2 !.param d={pout/(vbus*vbus/rtip)}
TEXT -1648 -904 Left 2 !.param vbus=28
TEXT -1648 -840 Left 2 !.param pout=130
TEXT -1648 -872 Left 2 !.param rtip=2.5
TEXT -576 -40 Left 2 !.param rtip=2.5
TEXT 352 112 Left 2 !.lib IRS10752L.lib
TEXT -1648 -936 Left 2 !.param vcc=3.3
TEXT -1656 -992 Left 2 !.options abstol=10n vntol=10n reltol=0.005 gmin=10p method=gear
TEXT -480 -632 Left 2 !.param L=2.2u Is=7
TEXT -584 -64 Left 2 !*.step param rtip list 2.5 3 3.5 4.5 5 100k
TEXT -1496 -16 Left 2 !.model SW1 SW(Ron=1n Roff=10Meg Vt=0.5 Vh=0.1)