Add initial CAN FD CDC composite firmware
- Custom board definition for STM32G0B1KBU6 (ews_board) - Zephyr-based firmware with modular architecture - USB composite device: gs_usb CAN FD + CDC ACM interfaces - PFET control via CDC text commands (PA8, PB2) - Status LED on PB4, CAN FD on PB0/PB1 - No external crystal - uses HSI with USB clock recovery - Ready for build testing with: west build -b ews_board
This commit is contained in:
parent
69b8cb0b79
commit
3d328fb7a2
|
|
@ -0,0 +1,11 @@
|
||||||
|
cmake_minimum_required(VERSION 3.20.0)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
# 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_board
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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
|
||||||
|
|
@ -0,0 +1,10 @@
|
||||||
|
identifier: ews_board
|
||||||
|
name: EWS Board
|
||||||
|
type: mcu
|
||||||
|
arch: arm
|
||||||
|
family: stm32
|
||||||
|
series: stm32g0x
|
||||||
|
socs:
|
||||||
|
- name: stm32g0b1xx
|
||||||
|
testing:
|
||||||
|
default: true
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
# 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_board
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
/dts-v1/;
|
||||||
|
#include <st/g0/stm32g0b1Xb.dtsi>
|
||||||
|
#include <st/g0/stm32g0b1k(b-c-e)ux-pinctrl.dtsi>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
model = "EWS Board STM32G0B1KBU6";
|
||||||
|
compatible = "ews,ews-board";
|
||||||
|
|
||||||
|
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>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
# EWS Board Configuration
|
||||||
|
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
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
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,78 @@
|
||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* 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 */
|
||||||
Loading…
Reference in New Issue