Compare commits

2 Commits

Author SHA1 Message Date
ccf4d66c7b Rev. 0.3: Add 10µF capacitor C304 to CAN transceiver and QR code placeholder
- Added 10µF capacitor C304 for improved CAN communication stability
- Added QR code placeholder for serial number on PCB
- Enhanced signal integrity with additional filtering at CAN transceiver
- Improved traceability with unique identification capability
- Updated changelogs and documentation for Rev. 0.3
2025-12-09 09:31:55 +01:00
401d8f5c1b Rev 0.2: Major hardware improvements and production readiness
Hardware Improvements (Thanks to shx for schematic cleanup):
- Clean up schematic organization and structure
- Set CAN transceiver Silent pin to GND for stability
- Add status LEDs (yellow: 24V/5V/3.3V, green: MCU PB4)
- Replace jumpers with solder jumpers on bottom side
- Add jumpers to output PFETs for permanent-on without firmware
- Add robust test points for 5V/GND load testing
- Add optional heatsink for DC/DC converter on bottom
- Add 10µF capacitor for MCU on 3.3V rail

Component Optimizations:
- Replace 30kΩ with 33kΩ basic part for simplified BOM
- Change DC/DC feedback: 15.5kΩ15kΩ (new output: 5.1V)
- Upgrade CAN ESD protection: NUP2105LPESD1CAN
- Increase CAN termination resistor footprint: 04020603
- Switch USB hub supply from 5V to 3.3V per datasheet

Production Ready:
- Add all LCSC part numbers and rotations
- Generate complete production data package
- Improve PCB layout and button placement
- Create comprehensive changelog documentation
2025-12-08 11:11:39 +01:00
27 changed files with 1890 additions and 2105 deletions

View File

@@ -7,6 +7,16 @@ Alle wichtigen Änderungen an diesem Projekt werden in dieser Datei dokumentiert
Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/de/1.0.0/),
und dieses Projekt folgt [Semantic Versioning](https://semver.org/lang/de/).
## [Rev. 0.3] - 2025-12-09
### Hinzugefügt
- **CAN-Transceiver:** 10µF Kondensator C304 für verbesserte Stabilität der CAN-Kommunikation
- **PCB Layout:** QR Code Platzhalter für Seriennummer auf der Platine
### Technische Details
- **Verbesserte Signal-Integrität:** Zusätzliche Filterung am CAN-Transceiver für stabilere Datenübertragung
- **Rückverfolgbarkeit:** QR Code ermöglicht eindeutige Identifikation und Dokumentation
## [Rev. 0.2] - 2025-12-08
### Verbesserungen

View File

@@ -7,6 +7,16 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/).
## [Rev. 0.3] - 2025-12-09
### Added
- **CAN Transceiver:** 10µF capacitor C304 for improved CAN communication stability
- **PCB Layout:** QR code placeholder for serial number on the PCB
### Technical Details
- **Enhanced Signal Integrity:** Additional filtering at CAN transceiver for more stable data transmission
- **Traceability:** QR code enables unique identification and documentation
## [Rev. 0.2] - 2025-12-08
### Improvements

File diff suppressed because it is too large Load Diff

View File

@@ -804,6 +804,6 @@
]
],
"text_variables": {
"PROJEKT_REV": "0.2"
"PROJEKT_REV": "0.3"
}
}

BIN
EWS.pdf

Binary file not shown.

View File

@@ -1,14 +0,0 @@
cmake_minimum_required(VERSION 3.20.0)
# Set board root to find our custom board
set(BOARD_ROOT ${CMAKE_CURRENT_SOURCE_DIR})
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(ews_canfd_cdc_composite)
target_sources(app PRIVATE
src/main.c
src/cdc_handler.c
src/pfet_control.c
src/gs_usb_can.c
)

View File

@@ -1,47 +0,0 @@
# CAN FD CDC Composite Firmware
A Zephyr-based firmware for the EWS board that provides:
- CAN FD to gs_usb interface (similar to candlelight)
- USB CDC interface for PFET control
- USB composite device functionality
## Features
- **CAN FD Support**: Full CAN FD protocol support via gs_usb interface
- **USB Composite**: Single USB device with multiple interfaces:
- gs_usb interface for CAN communication
- CDC ACM interface for PFET control and status
- **PFET Control**: Control both output PFETs via CDC commands
- **Status LEDs**: Control status LEDs for visual feedback
- **Compatible**: Works with standard CAN utilities (can-utils, etc.)
## Hardware Target
- **MCU**: STM32G0B1KBU6 (on EWS board)
- **CAN**: CAN FD via FDCAN1 (PB0/PB1) with SN65HVD230 transceiver
- **USB**: USB 2.0 Full Speed (PA11/PA12)
- **GPIOs**:
- PFET1 control: PA8
- PFET2 control: PB2
- Status LED: PB4
## Build Requirements
- Zephyr RTOS (v3.5+)
- West build tool
- ARM GCC toolchain
## Building
```bash
west build -b ews
```
## CDC Protocol
The CDC interface uses simple text commands:
- `PFET1_ON\n` - Turn on PFET1
- `PFET1_OFF\n` - Turn off PFET1
- `PFET2_ON\n` - Turn on PFET2
- `PFET2_OFF\n` - Turn off PFET2
- `STATUS\n` - Get current PFET status

View File

@@ -1,10 +0,0 @@
# SPDX-License-Identifier: Apache-2.0
if(CONFIG_BOARD_EWS)
board_runner_args(jlink "--device=STM32G0B1KB" "--speed=4000")
board_runner_args(pyocd "--target=stm32g0b1kbux")
include(${ZEPHYR_BASE}/boards/common/pyocd.board.cmake)
include(${ZEPHYR_BASE}/boards/common/jlink.board.cmake)
include(${ZEPHYR_BASE}/boards/common/openocd.board.cmake)
endif()

View File

@@ -1,5 +0,0 @@
board:
name: ews
vendor: ews
socs:
- name: stm32g0b1xx

View File

@@ -1,47 +0,0 @@
# EWS Board
## Overview
The EWS Board is based on the STM32G0B1KBU6 microcontroller in UFQFPN32 package.
## Hardware Features
- STM32G0B1KBU6 MCU (Arm Cortex-M0+ core, 128 KB Flash, 36 KB RAM)
- Internal HSI oscillator with USB clock recovery
- USB 2.0 Full Speed interface
- CAN FD interface
- Status LED on PB4
- Two PFET control outputs (PA8, PB2)
## Pin Configuration
| Function | Pin | Notes |
|----------|-----|-------|
| Status LED | PB4 | Active high |
| PFET1 Control | PA8 | Active high |
| PFET2 Control | PB2 | Active high |
| CAN RX | PB0 | FDCAN1_RX |
| CAN TX | PB1 | FDCAN1_TX |
| USB D- | PA11 | USB_DM |
| USB D+ | PA12 | USB_DP |
## Clock Configuration
The board uses the internal HSI oscillator (16 MHz) with PLL to generate:
- System clock: 64 MHz
- USB clock: 48 MHz (from PLL Q output)
- CAN clock: 64 MHz
No external crystal is used; USB clock recovery ensures accurate timing for USB communication.
## Programming and Debugging
The board supports programming via:
- USB DFU (built-in STM32 bootloader)
- SWD interface (if exposed)
## Building Firmware
```bash
west build -b ews
```

View File

@@ -1,104 +0,0 @@
/dts-v1/;
#include <st/g0/stm32g0b1Xb.dtsi>
#include <st/g0/stm32g0b1k(b-c-e)ux-pinctrl.dtsi>
/ {
model = "EWS Board STM32G0B1KBU6";
compatible = "ews,ews";
chosen {
zephyr,console = &cdc_acm_uart0;
zephyr,shell-uart = &cdc_acm_uart0;
zephyr,sram = &sram0;
zephyr,flash = &flash0;
zephyr,canbus = &fdcan1;
};
leds {
compatible = "gpio-leds";
status_led: led_0 {
gpios = <&gpiob 4 GPIO_ACTIVE_HIGH>;
label = "Status LED";
};
};
pfets {
compatible = "gpio-leds";
pfet1: pfet_1 {
gpios = <&gpioa 8 GPIO_ACTIVE_HIGH>;
label = "PFET1 Control";
};
pfet2: pfet_2 {
gpios = <&gpiob 2 GPIO_ACTIVE_HIGH>;
label = "PFET2 Control";
};
};
aliases {
led0 = &status_led;
pfet0 = &pfet1;
pfet1 = &pfet2;
};
};
&clk_hsi {
status = "okay";
};
&pll {
div-m = <1>;
mul-n = <8>;
div-q = <2>;
div-r = <2>;
clocks = <&clk_hsi>;
status = "okay";
};
&rcc {
clocks = <&pll>;
clock-frequency = <DT_FREQ_M(64)>;
ahb-prescaler = <1>;
apb1-prescaler = <1>;
};
&fdcan1 {
pinctrl-0 = <&fdcan1_rx_pb0 &fdcan1_tx_pb1>;
pinctrl-names = "default";
bus-speed = <500000>;
bus-speed-data = <2000000>;
status = "okay";
};
&usb {
pinctrl-0 = <&usb_dm_pa11 &usb_dp_pa12>;
pinctrl-names = "default";
status = "okay";
cdc_acm_uart0: cdc_acm_uart0 {
compatible = "zephyr,cdc-acm-uart";
};
};
&gpioa {
status = "okay";
};
&gpiob {
status = "okay";
};
&flash0 {
partitions {
compatible = "fixed-partitions";
#address-cells = <1>;
#size-cells = <1>;
boot_partition: partition@0 {
label = "mcuboot";
reg = <0x00000000 0x00002000>;
};
slot0_partition: partition@2000 {
label = "image-0";
reg = <0x00002000 0x0001E000>;
};
};
};

View File

@@ -1,23 +0,0 @@
# EWS Board Configuration
CONFIG_BOARD_EWS=y
CONFIG_SOC_SERIES_STM32G0X=y
CONFIG_SOC_STM32G0B1XX=y
# Clock configuration - USB clock sync, no external crystal
CONFIG_CLOCK_CONTROL=y
CONFIG_CLOCK_STM32_HSI=y
CONFIG_CLOCK_STM32_PLL_SRC_HSI=y
CONFIG_CLOCK_STM32_PLL_M_DIVISOR=1
CONFIG_CLOCK_STM32_PLL_N_MULTIPLIER=8
CONFIG_CLOCK_STM32_PLL_Q_DIVISOR=2
CONFIG_CLOCK_STM32_PLL_R_DIVISOR=2
# USB 48MHz from PLL
CONFIG_CLOCK_STM32_PLL_Q_DIVISOR=2
# Enable GPIO
CONFIG_GPIO=y
# Enable CAN
CONFIG_CAN=y

View File

@@ -1,28 +0,0 @@
CONFIG_USB_DEVICE_STACK=y
CONFIG_USB_DEVICE_COMPOSITE=y
# USB CDC ACM
CONFIG_USB_CDC_ACM=y
CONFIG_SERIAL=y
CONFIG_UART_CONSOLE=n
CONFIG_USB_UART_CONSOLE=y
# CAN configuration
CONFIG_CAN=y
CONFIG_CAN_FD_MODE=y
# Networking for gs_usb
CONFIG_NETWORKING=y
CONFIG_NET_SOCKETS=y
CONFIG_NET_SOCKETS_CAN=y
# GPIO for PFET control
CONFIG_GPIO=y
# Logging
CONFIG_LOG=y
CONFIG_USB_DEVICE_LOG_LEVEL_DBG=y
# System
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=2048

View File

@@ -1,87 +0,0 @@
/*
* CDC Handler Module
* Handles USB CDC ACM commands for PFET control
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/uart.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include <string.h>
#include "cdc_handler.h"
#include "pfet_control.h"
LOG_MODULE_REGISTER(cdc_handler, LOG_LEVEL_DBG);
#define CDC_DEVICE_NAME "CDC_ACM_0"
#define RX_BUF_SIZE 64
static const struct device *cdc_dev;
static char rx_buf[RX_BUF_SIZE];
static int rx_pos = 0;
static void process_command(char *cmd)
{
char response[128];
if (strncmp(cmd, "PFET1_ON", 8) == 0) {
pfet_set_state(1, true);
strcpy(response, "PFET1 ON\r\n");
} else if (strncmp(cmd, "PFET1_OFF", 9) == 0) {
pfet_set_state(1, false);
strcpy(response, "PFET1 OFF\r\n");
} else if (strncmp(cmd, "PFET2_ON", 8) == 0) {
pfet_set_state(2, true);
strcpy(response, "PFET2 ON\r\n");
} else if (strncmp(cmd, "PFET2_OFF", 9) == 0) {
pfet_set_state(2, false);
strcpy(response, "PFET2 OFF\r\n");
} else if (strncmp(cmd, "STATUS", 6) == 0) {
snprintf(response, sizeof(response),
"PFET1: %s, PFET2: %s\r\n",
pfet_get_state(1) ? "ON" : "OFF",
pfet_get_state(2) ? "ON" : "OFF");
} else {
strcpy(response, "ERROR: Unknown command\r\n");
}
/* Send response */
uart_poll_out_string(cdc_dev, response);
}
int cdc_handler_init(void)
{
cdc_dev = device_get_binding(CDC_DEVICE_NAME);
if (!cdc_dev) {
LOG_ERR("CDC ACM device not found");
return -ENODEV;
}
LOG_INF("CDC handler initialized");
return 0;
}
void cdc_handler_process(void)
{
char c;
/* Check for incoming characters */
while (uart_poll_in(cdc_dev, (unsigned char *)&c) == 0) {
if (c == '\n' || c == '\r') {
/* End of command */
if (rx_pos > 0) {
rx_buf[rx_pos] = '\0';
process_command(rx_buf);
rx_pos = 0;
}
} else if (rx_pos < (RX_BUF_SIZE - 1)) {
/* Add character to buffer */
rx_buf[rx_pos++] = c;
} else {
/* Buffer full, reset */
rx_pos = 0;
}
}
}

View File

@@ -1,20 +0,0 @@
/*
* CDC Handler Header
*/
#ifndef CDC_HANDLER_H
#define CDC_HANDLER_H
/**
* Initialize CDC handler
* @return 0 on success, negative error code on failure
*/
int cdc_handler_init(void);
/**
* Process incoming CDC commands
* Should be called regularly from main loop
*/
void cdc_handler_process(void);
#endif /* CDC_HANDLER_H */

View File

@@ -1,62 +0,0 @@
/*
* gs_usb CAN Interface
* Implements gs_usb protocol for CAN FD communication
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/can.h>
#include <zephyr/logging/log.h>
#include "gs_usb_can.h"
LOG_MODULE_REGISTER(gs_usb_can, LOG_LEVEL_DBG);
/* CAN device */
static const struct device *can_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_canbus));
int gs_usb_can_init(void)
{
int ret;
if (!device_is_ready(can_dev)) {
LOG_ERR("CAN device not ready");
return -ENODEV;
}
/* Configure CAN timing for 500kbps (adjust as needed) */
struct can_timing timing = {
.sjw = 1,
.prop_seg = 6,
.phase_seg1 = 7,
.phase_seg2 = 2,
.prescaler = 6
};
ret = can_set_timing(can_dev, &timing);
if (ret < 0) {
LOG_ERR("Failed to set CAN timing: %d", ret);
return ret;
}
/* Start CAN controller */
ret = can_start(can_dev);
if (ret < 0) {
LOG_ERR("Failed to start CAN: %d", ret);
return ret;
}
LOG_INF("gs_usb CAN interface initialized");
return 0;
}
int gs_usb_can_send_frame(const struct can_frame *frame)
{
return can_send(can_dev, frame, K_FOREVER, NULL, NULL);
}
/* TODO: Implement full gs_usb protocol */
/* This would require implementing the USB bulk endpoints and
gs_usb command/response protocol as defined in:
https://github.com/candle-usb/candleLight_fw
*/

View File

@@ -1,23 +0,0 @@
/*
* gs_usb CAN Interface Header
*/
#ifndef GS_USB_CAN_H
#define GS_USB_CAN_H
#include <zephyr/drivers/can.h>
/**
* Initialize gs_usb CAN interface
* @return 0 on success, negative error code on failure
*/
int gs_usb_can_init(void);
/**
* Send a CAN frame
* @param frame CAN frame to send
* @return 0 on success, negative error code on failure
*/
int gs_usb_can_send_frame(const struct can_frame *frame);
#endif /* GS_USB_CAN_H */

View File

@@ -1,82 +0,0 @@
/*
* EWS CAN FD CDC Composite Firmware
* Main application entry point
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/usb/usb_device.h>
#include <zephyr/logging/log.h>
#include "cdc_handler.h"
#include "pfet_control.h"
#include "gs_usb_can.h"
LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);
/* LED definitions - adjust to actual EWS board pins */
#define LED_STATUS_NODE DT_ALIAS(led0)
static const struct gpio_dt_spec led_status = GPIO_DT_SPEC_GET(LED_STATUS_NODE, gpios);
int main(void)
{
int ret;
LOG_INF("EWS CAN FD CDC Composite Firmware starting...");
/* Initialize status LED */
if (!gpio_is_ready_dt(&led_status)) {
LOG_ERR("Status LED device not ready");
return -ENODEV;
}
ret = gpio_pin_configure_dt(&led_status, GPIO_OUTPUT_ACTIVE);
if (ret < 0) {
LOG_ERR("Error configuring status LED: %d", ret);
return ret;
}
/* Initialize PFET control */
ret = pfet_control_init();
if (ret < 0) {
LOG_ERR("Failed to initialize PFET control: %d", ret);
return ret;
}
/* Initialize USB composite device */
ret = usb_enable(NULL);
if (ret != 0) {
LOG_ERR("Failed to enable USB: %d", ret);
return ret;
}
/* Initialize CDC handler */
ret = cdc_handler_init();
if (ret < 0) {
LOG_ERR("Failed to initialize CDC handler: %d", ret);
return ret;
}
/* Initialize gs_usb CAN interface */
ret = gs_usb_can_init();
if (ret < 0) {
LOG_ERR("Failed to initialize gs_usb CAN: %d", ret);
return ret;
}
LOG_INF("EWS firmware initialized successfully");
/* Main loop */
while (1) {
/* Toggle status LED to show activity */
gpio_pin_toggle_dt(&led_status);
/* Handle CDC commands */
cdc_handler_process();
k_msleep(500);
}
return 0;
}

View File

@@ -1,78 +0,0 @@
/*
* PFET Control Module
* Controls the two output PFETs on the EWS board
*/
#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/drivers/gpio.h>
#include <zephyr/logging/log.h>
#include "pfet_control.h"
LOG_MODULE_REGISTER(pfet_control, LOG_LEVEL_DBG);
/* PFET control pin definitions */
static const struct gpio_dt_spec pfet1 = GPIO_DT_SPEC_GET(DT_ALIAS(pfet0), gpios);
static const struct gpio_dt_spec pfet2 = GPIO_DT_SPEC_GET(DT_ALIAS(pfet1), gpios);
static bool pfet1_state = false;
static bool pfet2_state = false;
int pfet_control_init(void)
{
int ret;
if (!gpio_is_ready_dt(&pfet1) || !gpio_is_ready_dt(&pfet2)) {
LOG_ERR("PFET GPIO devices not ready");
return -ENODEV;
}
/* Configure PFET pins as output, initially off */
ret = gpio_pin_configure_dt(&pfet1, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure PFET1 pin: %d", ret);
return ret;
}
ret = gpio_pin_configure_dt(&pfet2, GPIO_OUTPUT_INACTIVE);
if (ret < 0) {
LOG_ERR("Failed to configure PFET2 pin: %d", ret);
return ret;
}
LOG_INF("PFET control initialized");
return 0;
}
int pfet_set_state(int pfet_num, bool state)
{
int ret;
if (pfet_num == 1) {
ret = gpio_pin_set_dt(&pfet1, state ? 1 : 0);
if (ret == 0) {
pfet1_state = state;
LOG_INF("PFET1 %s", state ? "ON" : "OFF");
}
} else if (pfet_num == 2) {
ret = gpio_pin_set_dt(&pfet2, state ? 1 : 0);
if (ret == 0) {
pfet2_state = state;
LOG_INF("PFET2 %s", state ? "ON" : "OFF");
}
} else {
return -EINVAL;
}
return ret;
}
bool pfet_get_state(int pfet_num)
{
if (pfet_num == 1) {
return pfet1_state;
} else if (pfet_num == 2) {
return pfet2_state;
}
return false;
}

View File

@@ -1,31 +0,0 @@
/*
* PFET Control Header
*/
#ifndef PFET_CONTROL_H
#define PFET_CONTROL_H
#include <stdbool.h>
/**
* Initialize PFET control
* @return 0 on success, negative error code on failure
*/
int pfet_control_init(void);
/**
* Set PFET state
* @param pfet_num PFET number (1 or 2)
* @param state true for ON, false for OFF
* @return 0 on success, negative error code on failure
*/
int pfet_set_state(int pfet_num, bool state);
/**
* Get current PFET state
* @param pfet_num PFET number (1 or 2)
* @return current state (true=ON, false=OFF)
*/
bool pfet_get_state(int pfet_num);
#endif /* PFET_CONTROL_H */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 890 KiB

After

Width:  |  Height:  |  Size: 832 KiB

File diff suppressed because it is too large Load Diff

View File

@@ -2,12 +2,12 @@
"C201, C403",CP_Elec_6.3x7.7,2,100u,C3151829
"C202, C204, C205, C206",1206,4,10u,C13585
"C203, C207, C211",0402,3,1u,C52923
"C208, C210, C301, C302, C304, C401, C404",0402,7,100n,C307331
"C208, C210, C301, C302, C305, C401, C404",0402,7,100n,C307331
C209,0402,1,4u7,C23733
C212,0603,1,220p,C1603
C213,0402,1,1n,C1523
"C214, C215, C216, C217, C305, C306, C405, C406",1206,8,22u,C12891
"C303, C402",0603,2,10u,C96446
"C214, C215, C216, C217, C306, C307, C405, C406",1206,8,22u,C12891
"C303, C304, C402",0603,3,10u,C96446
"D201, D202, D203",0805,3,YELLOW,C2296
D301,0805,1,GREEN,C2297
D302,SOT-23,1,PESD1CAN,C907838
1 Designator Footprint Quantity Value LCSC Part #
2 C201, C403 CP_Elec_6.3x7.7 2 100u C3151829
3 C202, C204, C205, C206 1206 4 10u C13585
4 C203, C207, C211 0402 3 1u C52923
5 C208, C210, C301, C302, C304, C401, C404 C208, C210, C301, C302, C305, C401, C404 0402 7 100n C307331
6 C209 0402 1 4u7 C23733
7 C212 0603 1 220p C1603
8 C213 0402 1 1n C1523
9 C214, C215, C216, C217, C305, C306, C405, C406 C214, C215, C216, C217, C306, C307, C405, C406 1206 8 22u C12891
10 C303, C402 C303, C304, C402 0603 2 3 10u C96446
11 D201, D202, D203 0805 3 YELLOW C2296
12 D301 0805 1 GREEN C2297
13 D302 SOT-23 1 PESD1CAN C907838

View File

@@ -21,6 +21,7 @@ C303:1
C304:1
C305:1
C306:1
C307:1
C401:1
C402:1
C403:1
1 C201:1
21 C304:1
22 C305:1
23 C306:1
24 C307:1
25 C401:1
26 C402:1
27 C403:1

File diff suppressed because it is too large Load Diff

View File

@@ -19,9 +19,10 @@ C217,177.25,-116.9,270.0,top
C301,173.25,-83.52,270.0,top
C302,173.1,-86.45,90.0,top
C303,174.3,-86.675,270.0,top
C304,157.3875,-78.5475,90.0,top
C305,142.875,-77.6,180.0,top
C306,142.875,-75.2,180.0,top
C304,157.65,-76.1,90.0,top
C305,157.3875,-78.5475,90.0,top
C306,142.875,-77.6,180.0,top
C307,142.875,-75.2,180.0,top
C401,180.78,-78.7,0.0,top
C402,178.125,-77.2,180.0,top
C403,175.4,-104.9,270.0,top
1 Designator Mid X Mid Y Rotation Layer
19 C301 173.25 -83.52 270.0 top
20 C302 173.1 -86.45 90.0 top
21 C303 174.3 -86.675 270.0 top
22 C304 157.3875 157.65 -78.5475 -76.1 90.0 top
23 C305 142.875 157.3875 -77.6 -78.5475 180.0 90.0 top
24 C306 142.875 -75.2 -77.6 180.0 top
25 C307 142.875 -75.2 180.0 top
26 C401 180.78 -78.7 0.0 top
27 C402 178.125 -77.2 180.0 top
28 C403 175.4 -104.9 270.0 top