Compare commits

..

63 Commits

Author SHA1 Message Date
3c50fcd695 fix FR_math impl 2026-05-10 12:58:25 +02:00
c1cee6a15a Merge branch 'external-handle' of https://git.alemauri.eu/alema/usbc_soldering_iron into external-handle 2026-05-10 12:09:00 +02:00
204e750b74 use FR_math for fixed point arithmetic 2026-05-10 12:08:56 +02:00
64326d0dea fix delta calc to signed 2026-05-10 11:07:28 +02:00
f0d961a65d TODOs for usbpd EPR impl 2026-05-09 01:06:31 +02:00
0200e47327 start work on PID controller 2026-05-09 01:05:49 +02:00
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
53 changed files with 469605 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

@ -3,3 +3,13 @@
Repo for a cool usb-c soldering iron that uses C245 cartridges and power up to 130W. 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.

55
fw/Makefile Normal file
View File

@ -0,0 +1,55 @@
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)))
# include fr_math
FRMATH_DIR:=fr_math
FRMATH_SRC:=$(wildcard $(FRMATH_DIR)/*.c)
EXTRA_CFLAGS += -I$(U8G2_DIR) -I$(FRMATH_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 fr_math
FRMATH_OBJS := $(addprefix $(BUILD_DIR)/, $(notdir $(FRMATH_SRC:.c=.o)))
$(BUILD_DIR)/%.o : $(FRMATH_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) $(FRMATH_OBJS) $(TARGET_OBJS) ch32fun.o
$(PREFIX)-gcc -o $@ $(U8G2_OBJS) $(TARGET_OBJS) $(FRMATH_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

256
fw/display.c Normal file
View File

@ -0,0 +1,256 @@
#include <u8g2.h>
#include <ch32fun.h>
#include <stdio.h>
#include "display.h"
#include "lib_i2c.h"
static u8g2_t u8g2;
static const char digits_lut[] =
"0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859"
"6061626364656667686970717273747576777879"
"8081828384858687888990919293949596979899";
// GPIO and delay callback for u8g2/u8x8 display driver
static 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;
}
static 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);
u8g2_SetBitmapMode(&u8g2, 1);
u8g2_SetFontMode(&u8g2, 1);
return &u8g2;
}
const char* u16toa(uint16_t value)
{
// Max uint16_t is 65535 (5 digits) + null terminator
static char buf[6];
char *p = &buf[5];
*p = '\0';
// Process two digits at a time using the LUT
while (value >= 100) {
const unsigned int idx = (value % 100) * 2;
value /= 100;
*--p = digits_lut[idx + 1];
*--p = digits_lut[idx];
}
// Handle the remaining value (< 100)
if (value < 10) {
*--p = (char)('0' + value);
} else {
const unsigned int idx = value * 2;
*--p = digits_lut[idx + 1];
*--p = digits_lut[idx];
}
return p;
}
const char* i16toa(int16_t value)
{
static char buf[7];
uint16_t uval;
bool negative = false;
if (value < 0) {
negative = true;
uval = (uint16_t)-value;
} else {
uval = (uint16_t)value;
}
char *p = &buf[6];
*p = '\0';
// Same LUT logic as unsigned
while (uval >= 100) {
const unsigned int idx = (uval % 100) * 2;
uval /= 100;
*--p = digits_lut[idx + 1];
*--p = digits_lut[idx];
}
if (uval < 10) {
*--p = (char)('0' + uval);
} else {
const unsigned int idx = uval * 2;
*--p = digits_lut[idx + 1];
*--p = digits_lut[idx];
}
if (negative) {
*--p = '-';
}
return p;
}
static char str_buf[32];
uint8_t str_len;
int buf_putc(char c) { str_buf[str_len++] = c; return 0; }
const char* buf_get(void) { str_buf[str_len] = '\0'; str_len = 0; return str_buf; }

17
fw/display.h Normal file
View File

@ -0,0 +1,17 @@
#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);
const char* i16toa(int16_t value);
const char* u16toa(uint16_t value);
int buf_putc(char c);
const char* buf_get(void);
#endif // _DISPLAY_H

26
fw/filter.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef _FILTER_H
#define _FILTER_H
#include <stdint.h>
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
static_assert(-4 >> 1 == -2, ">> doesn't do sign extension");
// Fixed-Point Exponential Moving Average
// alpha = 1/2^k
// x: output value
// s: current sample
#define U16_FP_EMA_K2(x, s) (uint16_t)((((uint32_t)(x)<<2) - (x) + (s)) >> 2)
#define U16_FP_EMA_K4(x, s) (uint16_t)((((uint32_t)(x)<<4) - (x) + (s)) >> 4)
#define U16_FP_EMA_K8(x, s) (uint16_t)((((uint32_t)(x)<<8) - (x) + (s)) >> 8)
#define U16_FP_EMA_K16(x, s) (uint16_t)((((uint32_t)(x)<<16) - (x) + (s)) >> 16)
#define I16_FP_EMA_K2(x, s) (int16_t)((((int32_t)(x)<<2) - (x) + (s)) >> 2)
#define I16_FP_EMA_K4(x, s) (int16_t)((((int32_t)(x)<<4) - (x) + (s)) >> 4)
#define I16_FP_EMA_K8(x, s) (int16_t)((((int32_t)(x)<<8) - (x) + (s)) >> 8)
#define I16_FP_EMA_K16(x, s) (int16_t)((((int32_t)(x)<<16) - (x) + (s)) >> 16)
#endif // _FILTER_H

120
fw/fr_math/FR_defs.h Normal file
View File

@ -0,0 +1,120 @@
/**
* @file FR_Defs.h - type definitions used in Fixed-Radix math lib
*
* @copy Copyright (C) <2001-2026> <M. A. Chatterjee>
* @author M A Chatterjee <deftio [at] deftio [dot] com>
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
*/
#ifndef __FR_Platform_Defs_H__
#define __FR_Platform_Defs_H__
/*
* Fixed-width integer typedefs.
*
* Prefer C99 <stdint.h> when available (gcc, clang, MSVC, IAR, Keil, sdcc,
* MSP430-gcc, AVR-gcc, RISC-V, ARM toolchains). For bare-metal toolchains
* or pre-C99 compilers that lack <stdint.h>, define FR_NO_STDINT before
* including this header and the types are provided via sizeof()-based
* fallback definitions that cover the common 8/16/32/64-bit layouts.
*/
#ifndef FR_NO_STDINT
#include <stdint.h>
#else
/* ---- fallback: no <stdint.h> ------------------------------------ */
/* Works on any toolchain where char=8, short=16, int/long=32 bits,
* which covers virtually all embedded targets (AVR, MSP430, ARM,
* 68HC11, 68k, PPC, RISC-V, Xtensa, x86). Adjust if your platform
* differs.
*/
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
#if defined(__AVR__) || defined(__MSP430__) || defined(__m68hc1x__)
/* On these targets int is 16-bit; use long for 32-bit */
typedef unsigned long uint32_t;
typedef signed long int32_t;
#else
typedef unsigned int uint32_t;
typedef signed int int32_t;
#endif
/* 64-bit: available on most 32-bit+ GCC targets via long long */
typedef unsigned long long uint64_t;
typedef signed long long int64_t;
#endif /* FR_NO_STDINT */
/*
* Arduino's USBAPI.h typedefs u8 and u16 as unsigned char / unsigned short.
* On AVR, uint8_t/uint16_t resolve to unsigned int types, which are the same
* width but different C++ types causing a redefinition error. Skip those
* two typedefs when building in an Arduino environment; the Arduino-provided
* types are the same width and work identically.
*
* The guard checks __cplusplus too because Arduino.h (which pulls in
* USBAPI.h) is only auto-included in .ino/.cpp translation units.
* Plain-C files (.c) compiled by the Arduino build system need our
* typedefs even though the ARDUINO macro is defined for them.
*/
#if defined(ARDUINO) && defined(__cplusplus)
/* Arduino C++ TU — USBAPI.h already provides u8 and u16 */
#else
typedef uint8_t u8;
typedef uint16_t u16;
#endif
typedef int8_t s8;
typedef int16_t s16;
typedef uint32_t u32;
typedef int32_t s32;
typedef uint64_t u64;
typedef int64_t s64;
typedef short FR_bool;
#define FR_SWAP_BYTES(x) (((x >> 8) & 0xff) | ((x << 8) & 0xff00))
/*=======================================================
* Sentinel values for math errors.
*
* Functions that can hit a domain error (sqrt of negative, log of <=0, etc.)
* return one of these sentinels rather than raising an error code. Callers
* that care can check `result == FR_DOMAIN_ERROR` before using the value.
*
* FR_OVERFLOW_POS and FR_OVERFLOW_NEG are the saturating-overflow values
* returned by FR_FixMulSat / FR_FixAddSat etc. They are deliberately the
* extremes of s32 so that they compare correctly under signed comparison.
*
* Note: FR_DOMAIN_ERROR equals INT32_MIN (the same value as FR_OVERFLOW_NEG
* would naturally be), so a single check `result <= FR_OVERFLOW_NEG` cannot
* distinguish "saturating-negative-overflow" from "domain error". In
* practice the two never occur in the same call: saturating ops never go
* to a domain-error state, and domain-error ops never saturate. The names
* exist to make caller intent self-documenting.
*/
#define FR_DOMAIN_ERROR ((s32)0x80000000) /* INT32_MIN: e.g. sqrt(<0) */
#define FR_OVERFLOW_POS ((s32)0x7fffffff) /* INT32_MAX: e.g. FR_FixMulSat + */
#define FR_OVERFLOW_NEG ((s32)0x80000000) /* INT32_MIN: e.g. FR_FixMulSat - */
#define FR_FALSE (0)
#define FR_TRUE (!FR_FALSE)
#endif /* __FR_Platform_Defs_H__ */

1837
fw/fr_math/FR_math.c Normal file

File diff suppressed because it is too large Load Diff

653
fw/fr_math/FR_math.h Normal file
View File

@ -0,0 +1,653 @@
/**
* @FR_math.h - header definition file for fixed radix math routines
*
* @copy Copyright (C) <2001-2026> <M. A. Chatterjee>
* @author M A Chatterjee <deftio [at] deftio [dot] com>
*
* This file contains integer math settable fixed point radix math routines for
* use on systems in which floating point is not desired or unavailable.
*
* @license:
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source
* distribution.
*
*/
#ifndef __FR_Math_h__
#define __FR_Math_h__
#define FR_MATH_VERSION "2.0.8"
#define FR_MATH_VERSION_HEX 0x020008 /* major << 16 | minor << 8 | patch */
#ifdef FR_CORE_ONLY
#define FR_NO_PRINT
#define FR_NO_WAVES
#endif
#ifdef FR_LEAN
#define FR_NO_WAVES
#endif
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef __FR_Platform_Defs_H__
#include "FR_defs.h"
#endif
/* Quick note on macro parameter wrapping:
* Arguments are parenthesized in expansions, e.g.
* #define MACRO_X_SQUARED(x) ((x)*(x)) // inner parens around each x
* Macros substitute text as-is. If a parameter is an expression like 3+4*5
* and the body mixes operators without extra parentheses, precedence errors
* follow. Parenthesize parameters (and fragile subexpressions) in the macro body.
* Example: MACRO_X_SQUARED_BAD(x) (x*x) -> 3+4*5*3+4*5 == 83 (wrong).
* MACRO_X_SQUARED(x) ((x)*(x)) -> (3+4*5)*(3+4*5) == 529 (right).
*/
/*absolute value for integer and fixed radix types*/
#define FR_ABS(x) (((x) < 0) ? (-(x)) : (x))
/*sign of x. Not as good as The Sign of Four, but I digress */
#define FR_SGN(x) ((x) >> ((((signed)sizeof(x)) << 3) - 1))
/*===============================================
* Simple Fixed Point Math Conversions
* r is radix precision in bits, converts to/from integer w truncation */
#define I2FR(x, r) ((x) << (r))
#define FR2I(x, r) ((x) >> (r))
/*===============================================
* Make a fixed radix number from integer + base-10 fractional parts.
* r = output radix (fractional bits)
* i = integer part (signed)
* f = decimal-fraction digits as written, e.g. for "12.34" pass f=34
* d = number of decimal digits in f, e.g. for "12.34" pass d=2
*
* FR_NUM(12, 34, 2, 10) 12.34 in s.10 = (12<<10) + (34<<10)/100 = 12636
* FR_NUM(-3, 5, 1, 16) -3.5 in s.16 = (-3<<16) - (5<<16)/10
*
* The fraction is rounded toward zero. For round-to-nearest, add half an LSB
* before scaling at the call site. Sign of the fractional part follows the
* sign of i (for i==0 the result is positive, matching "+0.5" intuition).
*/
#define FR_NUM_POW10(d) ( \
((d) == 0) ? 1L : \
((d) == 1) ? 10L : \
((d) == 2) ? 100L : \
((d) == 3) ? 1000L : \
((d) == 4) ? 10000L : \
((d) == 5) ? 100000L : \
((d) == 6) ? 1000000L : \
((d) == 7) ? 10000000L : \
((d) == 8) ? 100000000L : 1000000000L)
#define FR_NUM(i, f, d, r) ( \
((s32)(i) << (r)) + \
(((i) < 0) \
? -((s32)(((s32)(f) << (r)) / FR_NUM_POW10(d))) \
: ((s32)(((s32)(f) << (r)) / FR_NUM_POW10(d)))))
/*
FR_INT(x,r) convert a fixed radix variable x of radix r to an integer
*/
#define FR_INT(x, r) (((x) < 0) ? -((-(x)) >> (r)) : ((x) >> (r)))
/* Change Radix (x,current_radix, new_radix)
* change number from its current fixed radix (can be 0 or integer) to a new fixed radix
* Useful when dealing with numbers with mixed radixes. This is a MACRO so
* this code expands in place and x is modified.
*/
#define FR_CHRDX(x, r_cur, r_new) (((r_cur) - (r_new)) >= 0 ? ((x) >> ((r_cur) - (r_new))) : ((x) << ((r_new) - (r_cur))))
/* return only the fractional part of x */
#define FR_FRAC(x, r) ((FR_ABS(x)) & (((1 << (r)) - 1)))
/* return the fractional part of number x with radix xr scaled to radix nr bits */
#define FR_FRACS(x, xr, nr) (FR_CHRDX(FR_FRAC((x), (xr)), (xr), (nr)))
/******************************************************
Add (sub) to fixed point numbers by converting the second number to the
same radix as the first. If yr < xr then possibility of overflow is increased.
Note: for two vars, i, j, of prec ir, jr, it is not necessarily true that
FR_ADD(i,ir,j,jr) == FR_ADD(j,jr,i,ir)
*/
#define FR_ADD(x, xr, y, yr) ((x) += FR_CHRDX(y, yr, xr))
#define FR_SUB(x, xr, y, yr) ((x) -= FR_CHRDX(y, yr, xr))
/* Fixed-radix division with round-to-nearest: x (at radix xr) / y (at radix yr),
* result at radix xr. Uses a 64-bit intermediate so the full Q16.16 range works
* correctly. Adds half the divisor before truncation to achieve 0.5 LSB error. */
static inline s32 FR_div_rnd(s64 num, s32 den) {
if ((num ^ den) >= 0) /* same sign: positive quotient */
return (s32)((num + den / 2) / den);
else /* negative quotient */
return (s32)((num - den / 2) / den);
}
#define FR_DIV(x, xr, y, yr) FR_div_rnd((s64)(x) << (yr), (s32)(y))
/* FR_DIV_TRUNC: truncating division (old FR_DIV behavior). Useful when the
* caller knows the quotient is exact or truncation is acceptable. */
#define FR_DIV_TRUNC(x, xr, y, yr) ((s32)(((s64)(x) << (yr)) / (s32)(y)))
/* FR_DIV32: 32-bit-only division. Requires |x| < 2^(31-yr) to avoid
* overflow in the intermediate (x << yr). Use FR_DIV for full-range
* division with 64-bit intermediate. */
#define FR_DIV32(x, xr, y, yr) (((s32)(x) << (yr)) / (s32)(y))
/* Remainder: both operands should be at the same radix. */
#define FR_MOD(x, y) ((x) % (y))
/* min, max, clamp */
#define FR_MIN(a, b) (((a) < (b)) ? (a) : (b))
#define FR_MAX(a, b) (((a) > (b)) ? (a) : (b))
#define FR_CLAMP(x, lo, hi) (FR_MIN(FR_MAX((x), (lo)), (hi)))
/* Check if x is a power of 2. */
#define FR_ISPOW2(x) (!((x) & ((x) - 1)))
/* floor and ceiling in current radix, leaving current radix intact
* this means the lower radix number of bits are set to 0
*/
#define FR_FLOOR(x, r) ((x) & (~((1 << r) - 1)))
#define FR_CEIL(x, r) (FR_FLOOR(x, r) + ((FR_FRAC(x, r) ? (1 << r) : 0)))
/*******************************************************
Interpolate between 2 fixed point values (x0,x1) of any radix,
with a fractional delta, of a supplied precision.
If delta is outside 0<= delta<=1 then extrapolation
does work but programmer should watch for possible overflow.
x0,x1 need not have same radix as delta
*/
#define FR_INTERP(x0, x1, delta, prec) ((x0) + ((((x1) - (x0)) * (delta)) >> (prec)))
/******************************************************
FR_INTERPI is the same as FR_INTERP except that insures the
range is btw [0<= delta < 1] --> ((0 ... (1<<prec)-1)
Note: delta should be >= 0
*/
#define FR_INTERPI(x0, x1, delta, prec) ((x0) + ((((x1) - (x0)) * ((delta) & ((1 << (prec)) - 1))) >> (prec)))
/******************************************************
Convert to double, this is for debug only and WILL NOT compile under many embedded systems.
Fixed Radix to Floating Point Double Conversion
since this is a MACRO it will not be compiled or instantiated unless it is actually called in code.
*/
#define FR2D(x, r) ((double)(((double)(x)) / ((double)(1 << (r)))))
#define D2FR(d, r) ((s32)(d * (1 << r)))
/******************************************************
Useful Constants
FR_kXXXX "k" denotes constant to help when reading macros used in source code
FR_krXXX "r" == reciprocal e.g. 1/XXX
As these are MACROS, they take only compiled code space if actually used.
Consts here calculated by multiply the natural base10 value by (1<<FR_kPREC)
*/
#define FR_kPREC (16) /* bits of precision in constants listed below */
#define FR_kE (178145) /* 2.718281828459 */
#define FR_krE (24109) /* 0.367879441171 */
#define FR_kPI (205887) /* 3.141592653589 */
#define FR_krPI (20861) /* 0.318309886183 */
#define FR_kDEG2RAD (1144) /* 0.017453292519 */
#define FR_kRAD2DEG (3754936) /*57.295779513082 */
#define FR_kQ2RAD (102944) /* 1.570796326794 */
#define FR_kRAD2Q (41722) /* 0.636619772367 */
/*log2 to ln conversions (see MACROS) */
#define FR_kLOG2E (94548) /* 1.442695040890 */
#define FR_krLOG2E (45426) /* 0.693147180560 */
/*log2 to log10 conversions (see MACROS) */
#define FR_kLOG2_10 (217706) /* 3.32192809489 */
#define FR_krLOG2_10 (19728) /* 0.30102999566 */
/* High-precision scaling constants at radix 28.
* Used by FR_EXP, FR_ln, FR_log10 for base conversion.
* At radix 28 these have ~9 decimal digits of precision, far exceeding
* the ~4.8 digits of Q16.16.
*/
#define FR_kLOG2E_28 (387270501) /* log2(e) = 1.4426950408889634 */
#define FR_krLOG2E_28 (186065279) /* ln(2) = 0.6931471805599453 */
#define FR_kLOG2_10_28 (891723283) /* log2(10) = 3.3219280948873622 */
#define FR_krLOG2_10_28 (80807124) /* log10(2) = 0.3010299956639812 */
/* Multiply fixed-point value x (any radix) by a radix-28 constant k.
* Result stays at x's radix. Uses 64-bit intermediate.
* Rounds to nearest (adds 0.5 LSB before shift).
*/
#define FR_MULK28(x, k) ((s32)((((int64_t)(x) * (int64_t)(k)) + (1 << 27)) >> 28))
// common sqrts
#define FR_kSQRT2 (92682) /* 1.414213562373 */
#define FR_krSQRT2 (46341) /* 0.707106781186 */
#define FR_kSQRT3 (113512) /* 1.732050807568 */
#define FR_krSQRT3 (37837) /* 0.577350269189 */
#define FR_kSQRT5 (146543) /* 2.236067977599 */
#define FR_krSQRT5 (29309) /* 0.447213595499 */
#define FR_kSQRT10 (207243) /* 3.162277660168 */
#define FR_krSQRT10 (20724) /* 0.316227766016 */
/*===============================================
* Arithmetic operations
*/
s32 FR_FixMuls(s32 x, s32 y); // mul signed, round-to-nearest, NOT saturated
s32 FR_FixMulSat(s32 x, s32 y); // mul signed, round-to-nearest, saturated
s32 FR_FixAddSat(s32 x, s32 y); // add signed, saturated
/*================================================
* Constants used in Trig tables, definitions
*
* FR_TRIG_PREC internal table precision (u0.15, sine table)
* FR_TRIG_OUT_PREC output precision of sin/cos/tan (s15.16 since v2.0.1)
* FR_TRIG_ONE exact 1.0 in output format (1 << 16 = 65536)
*
* sin/cos return s32 at radix 16 (s15.16). This matches libfixmath Q16.16
* precision and allows exact representation of 1.0 at the poles.
* tan returns s32 at radix 16 (s15.16). Saturates at ±FR_TRIG_MAXVAL.
*/
#define FR_TRIG_PREC (15)
#define FR_TRIG_OUT_PREC (16)
#define FR_TRIG_MASK ((1 << (FR_TRIG_PREC)) - 1)
#define FR_TRIG_ONE (1L << FR_TRIG_OUT_PREC) /* 65536 = 1.0 */
#define FR_TRIG_MAXVAL ((s32)0x7fffffff) /* tan saturation max */
#define FR_TRIG_MINVAL (-FR_TRIG_MAXVAL) /* tan saturation min */
/* Bit Shift Scaling macros. Useful on some platforms with poor MUL performance.
* Also can be useful if you need to scale numbers with
* large portions of bits_in_use and a larger register size is not available.
* For example, suppose you need to scale a large 32bit number say z=0xa4239323
* from degrees to radians. Ideally this number would be multiplied by 0.017
* but using a (z*FR_kDEG2RAD) >> FR_kPREC type operation is likely to overflow
* due the MUL result being large. The FR_RAD2DEG MACRO below doesn't require
* accumulator headroom bits and so has no chance for loss of precision.
* Another benefit is some low end micros (8051, 68xx, MSP430(low end),
* PIC-8 family) have no multiplier. So these allow the programmer an option
* to see if performance or precision are better expressed as shifts rather than
* scaled multiplies. As always, mileage may vary depending on architecture,
* compiler and other considerations.
*/
/* scale by 10s */
#define FR_SMUL10(x) (((x) << 3) + (((x) << 1)))
#define FR_SDIV10(x) (((x) >> 3) - ((x) >> 5) + ((x) >> 7) - ((x) >> 9) + ((x) >> 11))
/* scale by 1/log2(e) 0.693147180560 used for converting log2() to ln() */
#define FR_SrLOG2E(x) (((x) >> 1) + ((x) >> 2) - ((x) >> 3) + ((x) >> 4) + ((x) >> 7) - ((x) >> 9) - ((x) >> 12) + ((x) >> 15))
/* scale by log2(e) 1.442695040889 used for converting pow2() to exp() */
#define FR_SLOG2E(x) ((x) + ((x) >> 1) - ((x) >> 4) + ((x) >> 8) + ((x) >> 10) + ((x) >> 12) + ((x) >> 14))
/* scale by 1/log2(10) 0.30102999566 used for converting log2() to log10 */
#define FR_SrLOG2_10(x) (((x) >> 2) + ((x) >> 4) - ((x) >> 6) + ((x) >> 7) - ((x) >> 8) + ((x) >> 12))
/* scale by log2(10) 3.32192809489 used for converting pow2() to pow10 */
#define FR_SLOG2_10(x) (((x) << 1) + (x) + ((x) >> 2) + ((x) >> 4) + ((x) >> 7) + ((x) >> 10) + ((x) >> 11) + ((x) >> 13))
/* Shift-only angular conversion macros
*
* All are pure constant multipliers expressed as shifts no multiply, no
* divide, no 64-bit intermediates, no accumulators. Work at any radix: if
* your input is degrees at radix 8, the output is the target unit at radix 8.
* The caller shifts as needed.
*
* Angular units:
* degrees = 360 per revolution
* radians = 2*pi per revolution
* BAM = 65536 per revolution (Binary Angular Measure, u16)
* quadrants = 4 per revolution (= BAM >> 14)
*
* Side-effect note: x is referenced multiple times in each macro do not
* pass expressions with side effects.
*/
/* FR_DEG2RAD(x): multiply by pi/180 ≈ 0.017453 (5 terms, ~17 bits) */
#define FR_DEG2RAD(x) (((x) >> 6) + ((x) >> 9) - ((x) >> 13) - ((x) >> 19) - ((x) >> 20))
/* FR_RAD2DEG(x): multiply by 180/pi ≈ 57.29578 (7 terms, ~19 bits) */
#define FR_RAD2DEG(x) (((x) << 6) - ((x) << 3) + (x) + ((x) >> 2) + (((x) >> 4) - ((x) >> 6)) - ((x) >> 10))
/* FR_DEG2BAM(x): multiply by 65536/360 ≈ 182.0449 (7 terms, ~18 bits).
* Intermediate terms overflow s32 when |x| > ~256 deg at s15.16 (x<<7 term),
* but the overflow is harmless when the result is truncated to u16 BAM
* (two's complement wrapping preserves modular correctness).
* For full-precision s32 BAM (sub-BAM interpolation), use fr_deg_to_bam(). */
#define FR_DEG2BAM(x) (((x)<<7)+((x)<<6)-((x)<<3)-((x)<<1)+((x)>>5)+((x)>>6)-((x)>>9))
/* FR_BAM2DEG(x): multiply by 360/65536 = 0.00549316 (4 terms, exact) */
#define FR_BAM2DEG(x) (((x)>>8)+((x)>>9)-((x)>>12)-((x)>>13))
/* FR_RAD2BAM(x): multiply by 65536/(2*pi) ≈ 10430.378 (7 terms, ~21 bits).
* CAUTION: overflows s32 when |x| > ~4 rad at s15.16 (x<<13 term).
* For safe conversion at any radix, use fr_rad_to_bam() instead.
* #define FR_RAD2BAM(x) (((x)<<13)+((x)<<11)+((x)<<7)+((x)<<6)-((x)<<1)+((x)>>1)-((x)>>3)) */
#define FR_RAD2BAM(x) (((x)<<13)+((x)<<11)+((x)<<7)+((x)<<6)-((x)<<1)+((x)>>1)-((x)>>3)+((x)>>8)-((x)>>11)-((x)>>14))
/* ── Overflow-safe rad/deg to BAM conversion functions ─────────────
*
* These replace the FR_RAD2BAM / FR_DEG2BAM macros for callers that
* need the full ±2*pi or ±360° range at any radix.
*
* Strategy: normalize input to radix 16, conditionally reduce into
* a safe zone, apply the full-precision shift-only multiply, then
* extract the u16 BAM. No precision loss from halving/quartering.
*
* fr_rad_to_bam: reduce to [-pi, pi], reordered terms. ±2*pi safe.
* fr_deg_to_bam: reduce to [-90, 90) + quadrant offset. ±360° safe.
*/
/* Pi constants at any radix: FR_PI(r) = round(pi * 2^r), etc.
* Compiler evaluates at compile time when r is a constant.
* Max safe radix: FR_PI r<=29, FR_TWO_PI r<=28, FR_HALF_PI r<=30. */
#define FR_PI(r) ((s32)(3.14159265358979323846 * (1LL << (r)) + 0.5))
#define FR_TWO_PI(r) ((s32)(6.28318530717958647692 * (1LL << (r)) + 0.5))
#define FR_HALF_PI(r) ((s32)(1.57079632679489661923 * (1LL << (r)) + 0.5))
#define FR_THREE_HALF_PI(r) ((s32)(4.71238898038468985769 * (1LL << (r)) + 0.5))
/* Convenience aliases at radix 16 */
#define FR_PI_R16 FR_PI(16)
#define FR_TWO_PI_R16 FR_TWO_PI(16)
/* Degree constants at radix 16 (exact — no truncation) */
#define FR_D90_R16 ((s32)90 << 16)
#define FR_D180_R16 ((s32)180 << 16)
#define FR_D360_R16 ((s32)360 << 16)
u16 fr_rad_to_bam(s32 rad, u16 radix);
#ifndef FR_LEAN
u16 fr_deg_to_bam(s32 deg, u16 radix);
#endif
/* FR_BAM2RAD(x): multiply by 2*pi/65536 ≈ 0.0000959 (5 terms, ~18 bits) */
#define FR_BAM2RAD(x) (((x)>>13)-((x)>>15)+((x)>>18)+((x)>>21)+((x)>>25))
/* Legacy quadrant macros (quadrants = BAM >> 14) */
#define FR_RAD2Q(x) (((x) >> 1) + ((x) >> 3) + ((x) >> 7) + ((x) >> 8) - ((x) >> 14))
#define FR_Q2RAD(x) ((x) + ((x) >> 1) + ((x) >> 4) + ((x) >> 7) + ((x) >> 11))
#define FR_DEG2Q(x) (((x) >> 6) - ((x) >> 8) - ((x) >> 11) - ((x) >> 13))
#define FR_Q2DEG(x) (((x) << 6) + ((x) << 4) + ((x) << 3) + ((x) << 1))
/*===============================================
* BAM (Binary Angular Measure) internal angle representation
*
* One full circle = 2^16 BAM units. So:
* 0 = 0 deg = 0 rad
* 16384 = 90 deg = pi/2 rad (FR_BAM_QUADRANT)
* 32768 = 180 deg = pi rad
* 49152 = 270 deg = 3pi/2 rad
* 65536 wraps to 0 (because BAM is u16)
*
* BAM is the natural representation for fixed-point trig because:
* - The top 2 bits select the quadrant (no `% 360` modulo needed).
* - The next 7 bits index the 128-entry quadrant table directly.
* - The bottom 7 bits give linear-interpolation precision.
*/
#define FR_BAM_BITS (16)
#define FR_BAM_FULL (1L << FR_BAM_BITS) /* 65536 */
#define FR_BAM_QUADRANT (FR_BAM_FULL >> 2) /* 16384 */
#define FR_BAM_HALF (FR_BAM_FULL >> 1) /* 32768 */
/*===============================================
* Radian-native and BAM-native trig (recommended)
*
* All sin/cos functions return s32 at radix 16 (s15.16).
* 1.0 is represented exactly as FR_TRIG_ONE (65536).
* Poles (0, 90, 180, 270 deg) produce exact ±FR_TRIG_ONE or 0.
*
* fr_cos_bam(bam) cos of a BAM angle, s15.16 result
* fr_sin_bam(bam) sin of a BAM angle, s15.16 result
* fr_cos(rad, radix) cos of radians at radix, s15.16 result
* fr_sin(rad, radix) sin of radians at radix, s15.16 result
* fr_tan(rad, radix) tan of radians at radix, s15.16 result
* fr_cos_deg(deg, radix) cos of fixed-radix degrees, s15.16 result
* fr_sin_deg(deg, radix) sin of fixed-radix degrees, s15.16 result
* fr_tan_deg(deg, radix) tan of fixed-radix degrees, s15.16 result
*
* All go through the same 129-entry quadrant table with linear interpolation.
* Worst-case error: ~2 LSB in s15.16 (~3e-5 absolute), except at the four
* cardinal angles where the result is exact.
*
* The radian and degree wrappers (fr_sin, fr_cos, fr_tan, etc.) range-reduce
* their input, convert to u16 BAM, and call the BAM-native functions. Small-
* angle bypasses at the zero crossings (sin0, cos0, tan0) use the linear
* approximation sin(δ)δ to avoid BAM quantization error where it matters most.
*/
s32 fr_cos_bam(u16 bam);
s32 fr_sin_bam(u16 bam);
#ifndef FR_LEAN
s32 fr_tan_bam(u16 bam);
#endif
s32 fr_cos(s32 rad, u16 radix);
s32 fr_sin(s32 rad, u16 radix);
s32 fr_tan(s32 rad, u16 radix);
/* Integer degrees -> BAM using division (exact at all multiples of 45 deg). */
#define FR_DEG2BAM_I(deg) ((u16)((((s32)(deg) << 16) + ((deg) >= 0 ? 180 : -180)) / 360))
/* Legacy single-arg integer-degree macros — use FR_CosI / FR_SinI instead */
/* #define fr_cos_deg(deg) fr_cos_bam(FR_DEG2BAM_I(deg)) — removed, name reused for 2-arg function */
/* #define fr_sin_deg(deg) fr_sin_bam(FR_DEG2BAM_I(deg)) — removed, name reused for 2-arg function */
#ifndef FR_LEAN
/*===============================================
* Degree-input trig API
*
* FR_CosI(deg) cos of integer degrees, s15.16 result
* FR_SinI(deg) sin of integer degrees, s15.16 result
* FR_TanI(deg) tan of integer degrees, s15.16 result
* fr_cos_deg(deg, radix) cos of fixed-radix degrees, s15.16 result
* fr_sin_deg(deg, radix) sin of fixed-radix degrees, s15.16 result
* fr_tan_deg(deg, radix) tan of fixed-radix degrees, s15.16 result
*/
#define FR_CosI(deg) fr_cos_bam(FR_DEG2BAM_I(deg))
#define FR_SinI(deg) fr_sin_bam(FR_DEG2BAM_I(deg))
s32 fr_cos_deg(s32 deg, u16 radix);
s32 fr_sin_deg(s32 deg, u16 radix);
s32 FR_TanI(s32 deg);
s32 fr_tan_deg(s32 deg, u16 radix);
/* Legacy macros — use fr_sin_deg/fr_cos_deg/fr_tan_deg in new code */
#define FR_Sin fr_sin_deg
#define FR_Cos fr_cos_deg
#define FR_Tan fr_tan_deg
#endif /* FR_LEAN */
/* Inverse trig — output in radians at caller-specified radix (s32).
* FR_atan2 returns radians at radix 16 (s15.16).
* Range: acos [0, pi], asin [-pi/2, pi/2],
* atan [-pi/2, pi/2], atan2 [-pi, pi].
*/
s32 FR_acos(s32 input, u16 radix, u16 out_radix);
s32 FR_asin(s32 input, u16 radix, u16 out_radix);
s32 FR_atan(s32 input, u16 radix, u16 out_radix);
s32 FR_atan2(s32 y, s32 x, u16 out_radix);
/* Logarithms */
#define FR_LOG2MIN (-(32767 << 16)) /* returned instead of "negative infinity" */
s32 FR_log2(s32 input, u16 radix, u16 output_radix);
s32 FR_ln(s32 input, u16 radix, u16 output_radix);
#ifndef FR_LEAN
s32 FR_log10(s32 input, u16 radix, u16 output_radix);
#endif
/* Power */
s32 FR_pow2(s32 input, u16 radix);
#define FR_EXP(input, radix) (FR_pow2(FR_MULK28((input), FR_kLOG2E_28), (radix)))
#define FR_POW10(input, radix) (FR_pow2(FR_MULK28((input), FR_kLOG2_10_28), (radix)))
/* Shift-only (multiply-free) base-conversion variants.
* Lower accuracy (~5-10 LSB at Q16.16) but no multiply instruction.
* Use these on targets where 32x32->64 multiply is expensive.
*/
#define FR_EXP_FAST(input, radix) (FR_pow2(FR_SLOG2E(input), radix))
#define FR_POW10_FAST(input, radix) (FR_pow2(FR_SLOG2_10(input), radix))
/*===============================================
* Formatted output and string parsing
*
* Define FR_NO_PRINT before including this header to exclude all
* print/format functions from compilation. This saves ~1.7 KB of ROM
* on targets that don't need human-readable output (e.g. headless
* sensor nodes, DSP-only firmware).
*
* #define FR_NO_PRINT
* #include "FR_math.h"
*/
#ifndef FR_NO_PRINT
/* printing family of functions */
int FR_printNumF(int (*f)(char), s32 n, int radix, int pad, int prec); /* print fixed radix num as floating point e.g. -12.34" */
int FR_printNumD(int (*f)(char), int n, int pad); /* print decimal number with optional padding e.g. " 12" */
int FR_printNumH(int (*f)(char), int n, int showPrefix); /* print num as a hexidecimal e.g. "0x12ab" */
/* string-to-fixed-point parser (inverse of FR_printNumF) */
s32 FR_numstr(const char *s, u16 radix);
#endif /* FR_NO_PRINT */
/*===============================================
* Square root and hypot
*
* Both take fixed-radix inputs and return a result at the same radix.
* Algorithm: digit-by-digit isqrt on a 64-bit accumulator (no division,
* at most 32 iterations). Rounds to nearest.
*
* Domain error sentinel: input < 0 (sqrt) returns FR_DOMAIN_ERROR. Caller
* can check `result == FR_DOMAIN_ERROR` to detect domain errors.
*/
s32 FR_sqrt(s32 input, u16 radix);
#ifndef FR_LEAN
s32 FR_hypot(s32 x, s32 y, u16 radix);
#endif
/* Fast approximate magnitude — shift-only, no multiply, no 64-bit.
* Based on piecewise-linear approximation of sqrt(x*x + y*y).
* See US Patent 6,567,777 B1 (Chatterjee, expired).
*
* FR_hypot_fast8(x, y) 8-segment, ~0.10% peak error
*
* Inputs are raw signed integers (or fixed-point at any radix the
* result is at the same radix as the inputs, just like FR_hypot).
* No radix parameter needed because the algorithm is scale-invariant.
*/
s32 FR_hypot_fast8(s32 x, s32 y);
/*===============================================
* Wave generators and ADSR envelope
*
* Define FR_NO_WAVES before including this header to exclude all
* waveform generators (square, pulse, triangle, saw, noise) and the
* ADSR envelope from compilation. This saves ~400 B of ROM on targets
* that only need math/trig and don't do audio synthesis.
*
* #define FR_NO_WAVES
* #include "FR_math.h"
*/
#ifndef FR_NO_WAVES
/*===============================================
* Wave generators synth-style fixed-shape waveforms.
*
* All take a u16 BAM phase in [0, 65535] (a full cycle) and return s16
* in s0.15 in [-32767, +32767]. Use FR_HZ2BAM_INC below to compute a
* phase increment for a target frequency.
*
* fr_wave_sqr(phase) 50% square
* fr_wave_pwm(phase, duty) variable-duty pulse
* fr_wave_tri(phase) symmetric triangle
* fr_wave_saw(phase) rising sawtooth
* fr_wave_tri_morph(phase, brk) variable-symmetry triangle (morphs to saw)
* fr_wave_noise(state*) LFSR pseudorandom noise
*
* fr_wave_tri_morph returns [0, 32767] (unipolar) caller can re-bias
* if a bipolar form is desired. The other waves are bipolar [-32767, +32767].
*/
s16 fr_wave_sqr(u16 phase);
s16 fr_wave_pwm(u16 phase, u16 duty);
s16 fr_wave_tri(u16 phase);
s16 fr_wave_saw(u16 phase);
s16 fr_wave_tri_morph(u16 phase, u16 break_point);
s16 fr_wave_noise(u32 *state);
/* FR_HZ2BAM_INC(hz, sample_rate)
* Compute the per-sample BAM phase increment for a target frequency in Hz
* given a sample rate in Hz. Result is a u16 to add to the running phase
* each sample (the running phase wraps mod 2^16 naturally because it's u16).
*
* u16 phase = 0;
* u16 inc = FR_HZ2BAM_INC(440, 48000);
* for (...) { sample = fr_sin_bam(phase); phase += inc; }
*
* Range: hz must be < sample_rate / 2 (Nyquist) for a meaningful tone;
* higher hz aliases. The macro does not enforce this.
*
* Side-effect note: hz and sample_rate are evaluated once each.
*/
#define FR_HZ2BAM_INC(hz, sample_rate) ((u16)(((u32)(hz) * 65536UL) / (u32)(sample_rate)))
/*===============================================
* ADSR envelope generator
*
* Linear-segment Attack-Decay-Sustain-Release envelope. Caller-allocated
* struct, no malloc, no global state. Internal level is held in s1.30 so
* very long envelopes (e.g. 48000-sample attack at 48 kHz) still get a
* non-zero per-sample increment. Output is s0.15 in [0, 32767].
*
* Lifecycle:
* fr_adsr_t env;
* fr_adsr_init(&env, atk_samples, dec_samples, sustain_s015, rel_samples);
* fr_adsr_trigger(&env); // note-on
* for (...) sample = fr_adsr_step(&env); // per-audio-sample
* fr_adsr_release(&env); // note-off
* for (...) sample = fr_adsr_step(&env); // until env.state == FR_ADSR_IDLE
*/
#define FR_ADSR_IDLE (0)
#define FR_ADSR_ATTACK (1)
#define FR_ADSR_DECAY (2)
#define FR_ADSR_SUSTAIN (3)
#define FR_ADSR_RELEASE (4)
typedef struct fr_adsr_s {
u8 state; /* FR_ADSR_* */
s32 level; /* current envelope value, s1.30 */
s32 sustain; /* sustain target, s1.30 */
s32 attack_inc; /* per-sample increment during attack */
s32 decay_dec; /* per-sample decrement during decay */
s32 release_dec; /* per-sample decrement during release */
} fr_adsr_t;
void fr_adsr_init(fr_adsr_t *env,
u32 attack_samples,
u32 decay_samples,
s16 sustain_level_s015,
u32 release_samples);
void fr_adsr_trigger(fr_adsr_t *env);
void fr_adsr_release(fr_adsr_t *env);
s16 fr_adsr_step(fr_adsr_t *env);
#endif /* FR_NO_WAVES */
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* __FR_Math_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

634
fw/main.c Normal file
View File

@ -0,0 +1,634 @@
#include "fr_math/FR_math.h"
#include <ch32fun.h>
#include <stdint.h>
#include <stdio.h>
#include <fsusb.h>
#define FR_LEAN
// #define FR_CORE_ONLY
#include <FR_math.h>
#include "funconfig.h"
#include "lib_i2c.h"
#include "display.h"
#include "filter.h"
#include "sc7a20.h"
#include "pd.h"
// Radix for fixed point operations
#define R 16
// 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.
if (funDigitalRead(PIN_BTN) == 0) return;
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;
}
__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_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_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_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_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;
static s32 e;
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;
}
int16_t delta = (int16_t)pd_profile.set_temp - tip_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, u16toa(tip_temp_c));
// Display bus voltage
u8g2_DrawStr(u8g2, x_off+45, y_off+7, "V:");
u8g2_DrawStr(u8g2, x_off+55, y_off+7, u16toa(vbus_mv/1000));
// 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));
FR_printNumF(buf_putc, e, R, 0, 3);
u8g2_DrawStr(u8g2, x_off+0, y_off+15, buf_get());
// Display current
u8g2_DrawStr(u8g2, x_off+45, y_off+15, "A:");
u8g2_DrawStr(u8g2, x_off+55, y_off+15, u16toa(current_ma));
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;
static s32 err_p, err_i, err_d, prev_err;
uint16_t duty;
// absolute temperature error
s32 err = I2FR(delta, R);
err_p = err;
err_i = FR_CLAMP(FR_FixAddSat(err_i, err), I2FR(-1000, R), I2FR(1000, R));
err_d = FR_SUB(err, R, prev_err, R);
prev_err = err;
const s32 kp = FR_numstr("0.00700", R);
const s32 ki = FR_numstr("0.00001", R);
const s32 kd = FR_numstr("0.00000", R);
e = FR_FixAddSat(e, FR_FixMulSat(err_p, kp));
e = FR_FixAddSat(e, FR_FixMulSat(err_i, ki));
e = FR_FixAddSat(e, FR_FixMulSat(err_d, kd));
e = FR_CLAMP(e, I2FR(0, R), I2FR(100, R));
duty = FR2I(FR_FixMulSat(FR_DIV(e, R, I2FR(100, R), R), I2FR(pd_profile.max_duty, R)), R);
if (duty <= 100) {
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 {
e = 0;
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

979
fw/usbpd.h Normal file
View File

@ -0,0 +1,979 @@
/* 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 enum PACKED
{
eUSBPD_EXTENDED_MSG_SOURCE_CAP_EXT = 0b00001,
eUSBPD_EXTENDED_MSG_STATUS = 0b00010,
eUSBPD_EXTENDED_MSG_GET_BATTERY_CAP = 0b00011,
eUSBPD_EXTENDED_MSG_GET_BATTERY_STATUS = 0b00100,
eUSBPD_EXTENDED_MSG_BATTERY_CAP = 0b00101,
eUSBPD_EXTENDED_MSG_GET_MANUFACTURER_INFO = 0b00110,
eUSBPD_EXTENDED_MSG_MANUFACTURER_INFO = 0b00111,
eUSBPD_EXTENDED_MSG_SECURITY_REQUEST = 0b01000,
eUSBPD_EXTENDED_MSG_SECURITY_RESPONSE = 0b01001,
eUSBPD_EXTENDED_MSG_FIRMWARE_UPDATE_REQUEST = 0b01010,
eUSBPD_EXTENDED_MSG_FIRMWARE_UPDATE_RESPONSE = 0b01011,
eUSBPD_EXTENDED_MSG_PPS_STATUS = 0b01100,
eUSBPD_EXTENDED_MSG_COUNTRY_INFO = 0b01101,
eUSBPD_EXTENDED_MSG_COUNTRY_CODES = 0b01110,
eUSBPD_EXTENDED_MSG_SINK_CAP_EXTENDED = 0b01111,
eUSBPD_EXTENDED_MSG_EXTENDED_CONTROL = 0b10000,
eUSBPD_EXTENDED_MSG_EPR_SOURCE_CAP = 0b10001,
eUSBPD_EXTENDED_MSG_EPR_SINK_CAP = 0b10010,
eUSBPD_EXTENDED_MSG_VENDOR_DEFINED_EXTENDED = 0b11110
} USBPD_ExtendedMessage_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 union
{
uint16_t data;
struct
{
uint16_t DataSize : 9u;
uint16_t Reserved : 1u;
uint16_t RequestChunk : 1u;
uint16_t ChunkNumber : 4u;
uint16_t Chunked : 1u;
};
} USBPD_ExtendedHeader_t;
static_assert( sizeof( USBPD_ExtendedHeader_t ) == sizeof( uint16_t ), "USBPD_ExtendedHeader_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" );
// TODO: as per 6.15.8 EPR Source Capabilities Message, when the extended bit is
// set a extended header is present and the capabilities become from 7 to 11 PDOs
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;
}
}
// TODO: this ignores the extended part of the protocol, so we never parse
// the extended capabilities region
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 # Local project settings
*.kicad_prl *.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 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 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.0214,0.43,https://www.lcsc.com/product-detail/C2827931.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 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 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 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 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.2575,1.29,https://www.lcsc.com/product-detail/C7466527.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 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 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 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.0629,0.31,https://www.lcsc.com/product-detail/C138714.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 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 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 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,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,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,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,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 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,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,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,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,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 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,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 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,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 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,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 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,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 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
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

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 (pad "A4" smd rect
(at -2.4 -2.4775) (at -2.4 -2.4775)
(size 0.5 1.15) (size 0.5 1.15)
@ -464,6 +470,12 @@
(layers "F.Cu" "F.Mask" "F.Paste") (layers "F.Cu" "F.Mask" "F.Paste")
(uuid "a621d7b8-8475-4012-bb80-22970594526c") (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 (pad "B4" smd rect
(at 2.4 -2.4775) (at 2.4 -2.4775)
(size 0.5 1.15) (size 0.5 1.15)
@ -494,18 +506,6 @@
(layers "F.Cu" "F.Mask" "F.Paste") (layers "F.Cu" "F.Mask" "F.Paste")
(uuid "b669d7b8-13ce-4926-b0fa-a776cf6d1e07") (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 (pad "S1" thru_hole oval
(at -4.32 -1.8025) (at -4.32 -1.8025)
(size 1.2 2.2) (size 1.2 2.2)

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
"3dviewports": [], "3dviewports": [],
"design_settings": { "design_settings": {
"defaults": { "defaults": {
"apply_defaults_to_fp_barcodes": false,
"apply_defaults_to_fp_dimensions": false,
"apply_defaults_to_fp_fields": false, "apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false, "apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false, "apply_defaults_to_fp_text": false,
@ -48,7 +50,7 @@
"silk_text_thickness": 0.1, "silk_text_thickness": 0.1,
"silk_text_upright": false, "silk_text_upright": false,
"zones": { "zones": {
"min_clearance": 0.25 "min_clearance": 0.2
} }
}, },
"diff_pair_dimensions": [ "diff_pair_dimensions": [
@ -77,6 +79,7 @@
"extra_footprint": "warning", "extra_footprint": "warning",
"footprint": "error", "footprint": "error",
"footprint_filters_mismatch": "ignore", "footprint_filters_mismatch": "ignore",
"footprint_symbol_field_mismatch": "warning",
"footprint_symbol_mismatch": "warning", "footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore", "footprint_type_mismatch": "ignore",
"hole_clearance": "error", "hole_clearance": "error",
@ -94,6 +97,7 @@
"mirrored_text_on_front_layer": "warning", "mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore", "missing_courtyard": "ignore",
"missing_footprint": "warning", "missing_footprint": "warning",
"missing_tuning_profile": "warning",
"net_conflict": "warning", "net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning", "nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore", "npth_inside_courtyard": "ignore",
@ -113,9 +117,12 @@
"too_many_vias": "error", "too_many_vias": "error",
"track_angle": "error", "track_angle": "error",
"track_dangling": "warning", "track_dangling": "warning",
"track_not_centered_on_via": "ignore",
"track_on_post_machined_layer": "error",
"track_segment_length": "error", "track_segment_length": "error",
"track_width": "error", "track_width": "error",
"tracks_crossing": "error", "tracks_crossing": "error",
"tuning_profile_track_geometries": "ignore",
"unconnected_items": "error", "unconnected_items": "error",
"unresolved_variable": "error", "unresolved_variable": "error",
"via_dangling": "warning", "via_dangling": "warning",
@ -123,7 +130,7 @@
}, },
"rules": { "rules": {
"max_error": 0.005, "max_error": 0.005,
"min_clearance": 0.16, "min_clearance": 0.15,
"min_connection": 0.16, "min_connection": 0.16,
"min_copper_edge_clearance": 0.2, "min_copper_edge_clearance": 0.2,
"min_groove_width": 0.0, "min_groove_width": 0.0,
@ -131,15 +138,15 @@
"min_hole_to_hole": 0.25, "min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2, "min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1, "min_microvia_drill": 0.1,
"min_resolved_spokes": 2, "min_resolved_spokes": 1,
"min_silk_clearance": 0.0, "min_silk_clearance": 0.0,
"min_text_height": 0.8, "min_text_height": 0.8,
"min_text_thickness": 0.08, "min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3, "min_through_hole_diameter": 0.2,
"min_track_width": 0.16, "min_track_width": 0.16,
"min_via_annular_width": 0.15, "min_via_annular_width": 0.15,
"min_via_diameter": 0.25, "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 "use_height_for_length_calcs": true
}, },
"teardrop_options": [ "teardrop_options": [
@ -229,17 +236,28 @@
"zones_allow_external_fillets": false "zones_allow_external_fillets": false
}, },
"ipc2581": { "ipc2581": {
"bom_rev": "",
"dist": "", "dist": "",
"distpn": "", "distpn": "",
"internal_id": "", "internal_id": "",
"mfg": "", "mfg": "",
"mpn": "" "mpn": "",
"sch_revision": ""
}, },
"layer_pairs": [], "layer_pairs": [],
"layer_presets": [], "layer_presets": [],
"viewports": [] "viewports": []
}, },
"boards": [], "boards": [],
"component_class_settings": {
"assignments": [],
"meta": {
"version": 0
},
"sheet_component_classes": {
"enabled": false
}
},
"cvpcb": { "cvpcb": {
"equivalence_files": [] "equivalence_files": []
}, },
@ -429,11 +447,14 @@
"duplicate_sheet_names": "error", "duplicate_sheet_names": "error",
"endpoint_off_grid": "warning", "endpoint_off_grid": "warning",
"extra_units": "error", "extra_units": "error",
"field_name_whitespace": "warning",
"footprint_filter": "ignore", "footprint_filter": "ignore",
"footprint_link_issues": "warning", "footprint_link_issues": "warning",
"four_way_junction": "ignore", "four_way_junction": "ignore",
"global_label_dangling": "warning", "global_label_dangling": "warning",
"ground_pin_not_ground": "warning",
"hier_label_mismatch": "error", "hier_label_mismatch": "error",
"isolated_pin_label": "warning",
"label_dangling": "error", "label_dangling": "error",
"label_multiple_wires": "warning", "label_multiple_wires": "warning",
"lib_symbol_issues": "warning", "lib_symbol_issues": "warning",
@ -456,6 +477,7 @@
"similar_power": "warning", "similar_power": "warning",
"simulation_model_issue": "ignore", "simulation_model_issue": "ignore",
"single_global_label": "ignore", "single_global_label": "ignore",
"stacked_pin_name": "warning",
"unannotated": "error", "unannotated": "error",
"unconnected_wire_endpoint": "warning", "unconnected_wire_endpoint": "warning",
"undefined_netclass": "error", "undefined_netclass": "error",
@ -476,7 +498,7 @@
"classes": [ "classes": [
{ {
"bus_width": 12, "bus_width": 12,
"clearance": 0.16, "clearance": 0.15,
"diff_pair_gap": 0.16, "diff_pair_gap": 0.16,
"diff_pair_via_gap": 0.25, "diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2, "diff_pair_width": 0.2,
@ -488,13 +510,14 @@
"priority": 2147483647, "priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)", "schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2, "track_width": 0.2,
"tuning_profile": "",
"via_diameter": 0.5, "via_diameter": 0.5,
"via_drill": 0.2, "via_drill": 0.2,
"wire_width": 6 "wire_width": 6
} }
], ],
"meta": { "meta": {
"version": 4 "version": 5
}, },
"net_colors": null, "net_colors": null,
"netclass_assignments": null, "netclass_assignments": null,
@ -516,6 +539,10 @@
}, },
"schematic": { "schematic": {
"annotate_start_num": 0, "annotate_start_num": 0,
"annotation": {
"method": 0,
"sort_order": 0
},
"bom_export_filename": "${PROJECTNAME}.csv", "bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [], "bom_fmt_presets": [],
"bom_fmt_settings": { "bom_fmt_settings": {
@ -587,6 +614,7 @@
"sort_asc": true, "sort_asc": true,
"sort_field": "Reference" "sort_field": "Reference"
}, },
"bus_aliases": {},
"connection_grid_size": 50.0, "connection_grid_size": 50.0,
"drawing": { "drawing": {
"dashed_lines_dash_length_ratio": 12.0, "dashed_lines_dash_length_ratio": 12.0,
@ -594,6 +622,7 @@
"default_line_thickness": 6.0, "default_line_thickness": 6.0,
"default_text_size": 50.0, "default_text_size": 50.0,
"field_names": [], "field_names": [],
"hop_over_size_choice": 0,
"intersheets_ref_own_page": false, "intersheets_ref_own_page": false,
"intersheets_ref_prefix": "", "intersheets_ref_prefix": "",
"intersheets_ref_short": false, "intersheets_ref_short": false,
@ -617,6 +646,7 @@
"net_format_name": "", "net_format_name": "",
"page_layout_descr_file": "", "page_layout_descr_file": "",
"plot_directory": "", "plot_directory": "",
"reuse_designators": true,
"space_save_all_events": true, "space_save_all_events": true,
"spice_current_sheet_as_root": false, "spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"", "spice_external_command": "spice \"%I\"",
@ -625,13 +655,28 @@
"spice_save_all_dissipations": false, "spice_save_all_dissipations": false,
"spice_save_all_voltages": false, "spice_save_all_voltages": false,
"subpart_first_id": 65, "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": [ "sheets": [
[ [
"7095b018-eac3-4b01-b374-28e3216c4fd8", "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 -384 -432 -544 -432
WIRE -16 -432 -16 -560 WIRE -16 -432 -16 -560
WIRE -16 -432 -320 -432 WIRE -16 -432 -320 -432
WIRE -1600 -400 -1600 -496 WIRE -1600 -320 -1600 -496
WIRE -880 -320 -880 -336 WIRE -880 -320 -880 -336
WIRE -800 -320 -800 -368 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 752 -208 752 -560
WIRE -1600 -176 -1600 -208
WIRE 240 -144 208 -144 WIRE 240 -144 208 -144
WIRE 512 -144 304 -144 WIRE 512 -144 304 -144
WIRE 704 -128 592 -128 WIRE 704 -128 592 -128
WIRE -1600 -112 -1600 -208
WIRE 208 -80 208 -144 WIRE 208 -80 208 -144
WIRE 208 -80 96 -80 WIRE 208 -80 96 -80
WIRE 352 -80 208 -80 WIRE 352 -80 208 -80
WIRE 512 -80 512 -144 WIRE 512 -80 512 -144
WIRE 512 -80 480 -80 WIRE 512 -80 480 -80
WIRE 656 -80 512 -80 WIRE 656 -80 512 -80
WIRE -1600 -64 -1600 -112 WIRE -1600 -64 -1600 -96
WIRE -1600 -64 -1728 -64
WIRE 656 -64 656 -80 WIRE 656 -64 656 -80
WIRE -1600 -48 -1600 -64
WIRE -1728 -16 -1728 -64
WIRE 352 -16 320 -16 WIRE 352 -16 320 -16
WIRE 592 -16 592 -128 WIRE 592 -16 592 -128
WIRE 592 -16 480 -16 WIRE 592 -16 480 -16
WIRE 320 0 320 -16 WIRE 320 0 320 -16
WIRE -1600 48 -1600 32
WIRE 352 48 96 48 WIRE 352 48 96 48
WIRE 656 48 656 0 WIRE 656 48 656 0
WIRE 656 48 480 48 WIRE 656 48 480 48
WIRE 752 48 752 -112 WIRE 752 48 752 -112
WIRE 752 48 656 48 WIRE 752 48 656 48
WIRE 976 48 752 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 752 96 752 48
WIRE -1728 128 -1728 48 WIRE -1728 128 -1728 80
WIRE 976 128 976 48 WIRE 976 128 976 48
WIRE 96 144 96 48 WIRE 96 144 96 48
WIRE -1600 192 -1600 176
WIRE 752 208 752 176 WIRE 752 208 752 176
WIRE 848 208 752 208 WIRE 848 208 752 208
WIRE 752 240 752 208 WIRE 752 240 752 208
WIRE 848 256 848 208 WIRE 848 256 848 208
WIRE -1728 272 -1728 192
WIRE 752 384 752 320 WIRE 752 384 752 320
WIRE 848 384 848 320 WIRE 848 384 848 320
WIRE 976 384 976 192 WIRE 976 384 976 192
FLAG 752 384 0 FLAG 752 384 0
FLAG -1600 128 0 FLAG -1600 272 0
FLAG 96 224 0 FLAG 96 224 0
FLAG -1600 -560 vbus FLAG -1600 -560 vbus
FLAG -992 -560 vmid FLAG -992 -560 vmid
FLAG 848 384 0 FLAG 848 384 0
FLAG -1680 -416 0 FLAG -1680 -416 0
FLAG -1600 -112 vdrv FLAG -1600 -208 vdrv
FLAG -1728 128 0 FLAG -1728 272 0
FLAG 320 0 0 FLAG 320 0 0
FLAG 96 -80 cp FLAG 96 -80 cp
FLAG 96 0 0 FLAG 96 0 0
@ -91,17 +94,19 @@ FLAG 976 384 0
FLAG -800 -320 0 FLAG -800 -320 0
FLAG 400 -320 0 FLAG 400 -320 0
FLAG -880 -320 0 FLAG -880 -320 0
FLAG -1648 -304 0
FLAG -1840 -160 0
SYMBOL nmos 704 -208 R0 SYMBOL nmos 704 -208 R0
SYMATTR InstName M1 SYMATTR InstName M1
SYMATTR Value AON7140 SYMATTR Value AON7140
SYMBOL res 736 224 R0 SYMBOL res 736 224 R0
SYMATTR InstName R1 SYMATTR InstName R1
SYMATTR Value {rtip} SYMATTR Value {rtip}
SYMBOL voltage -1600 32 R0 SYMBOL voltage -1600 176 R0
WINDOW 123 0 0 Left 0 WINDOW 123 0 0 Left 0
WINDOW 39 24 44 Left 2 WINDOW 39 24 44 Left 2
SYMATTR InstName V1 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 SYMBOL voltage 96 128 R0
WINDOW 123 0 0 Left 0 WINDOW 123 0 0 Left 0
WINDOW 39 0 0 Left 0 WINDOW 39 0 0 Left 0
@ -118,20 +123,20 @@ SYMATTR Value 5m
SYMBOL cap 832 256 R0 SYMBOL cap 832 256 R0
SYMATTR InstName C4 SYMATTR InstName C4
SYMATTR Value 10p SYMATTR Value 10p
SYMBOL ind -1616 -416 R0 SYMBOL ind -1616 -192 R0
SYMATTR InstName L2 SYMATTR InstName L2
SYMATTR Value 500n SYMATTR Value 500n
SYMATTR SpiceLine Rser=1m SYMATTR SpiceLine Rser=1m
SYMBOL res -1616 -304 R0 SYMBOL res -1616 -80 R0
SYMATTR InstName R8 SYMATTR InstName R8
SYMATTR Value 120m SYMATTR Value 120m
SYMBOL cap -1696 -480 R0 SYMBOL cap -1696 -480 R0
SYMATTR InstName C5 SYMATTR InstName C5
SYMATTR Value 1µ SYMATTR Value 1µ
SYMBOL res -1616 -64 R0 SYMBOL res -1616 80 R0
SYMATTR InstName R9 SYMATTR InstName R9
SYMATTR Value 20m SYMATTR Value 20m
SYMBOL cap -1744 -16 R0 SYMBOL cap -1744 128 R0
SYMATTR InstName C6 SYMATTR InstName C6
SYMATTR Value 200µ SYMATTR Value 200µ
SYMBOL IRS10752L 416 -48 R0 SYMBOL IRS10752L 416 -48 R0
@ -149,15 +154,6 @@ SYMBOL ind 736 80 R0
SYMATTR InstName L3 SYMATTR InstName L3
SYMATTR Value 10n SYMATTR Value 10n
SYMATTR SpiceLine Rser=1m 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 SYMBOL ind -416 -544 R270
WINDOW 0 32 56 VTop 2 WINDOW 0 32 56 VTop 2
WINDOW 3 5 56 VBottom 2 WINDOW 3 5 56 VBottom 2
@ -185,19 +181,36 @@ SYMATTR InstName D1
SYMATTR Value RB068M-60 SYMATTR Value RB068M-60
SYMBOL Contrib\\CHEMI-CON\\Capacitors\\Alcap-PolymerHybrid-SMD\\HHXC350ARA220ME61G -816 -432 R0 SYMBOL Contrib\\CHEMI-CON\\Capacitors\\Alcap-PolymerHybrid-SMD\\HHXC350ARA220ME61G -816 -432 R0
SYMATTR InstName C2 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 Value Temperature=40
SYMATTR InstName U1 SYMATTR InstName U1
SYMBOL MCASU32MAB7106_PNA01 -880 -400 R90 SYMBOL MMASU32MAB7106_PNA01 192 -384 R90
SYMATTR Value Temperature=40 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 -1656 -1016 Left 2 !.tran 12m
TEXT -1648 -808 Left 2 !.param fsw=100k TEXT -1648 -808 Left 2 !.param fsw=100k
TEXT -1648 -776 Left 2 !.param d={pout/(vbus*vbus/rtip)} TEXT -1648 -776 Left 2 !.param d={pout/(vbus*vbus/rtip)}
TEXT -1648 -904 Left 2 !.param vbus=28 TEXT -1648 -904 Left 2 !.param vbus=28
TEXT -1648 -840 Left 2 !.param pout=130 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 352 112 Left 2 !.lib IRS10752L.lib
TEXT -1648 -936 Left 2 !.param vcc=3.3 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 -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 -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)