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:
87
firmware/canfd_cdc_composite/src/cdc_handler.c
Normal file
87
firmware/canfd_cdc_composite/src/cdc_handler.c
Normal file
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
20
firmware/canfd_cdc_composite/src/cdc_handler.h
Normal file
20
firmware/canfd_cdc_composite/src/cdc_handler.h
Normal file
@@ -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 */
|
||||
62
firmware/canfd_cdc_composite/src/gs_usb_can.c
Normal file
62
firmware/canfd_cdc_composite/src/gs_usb_can.c
Normal file
@@ -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
|
||||
*/
|
||||
23
firmware/canfd_cdc_composite/src/gs_usb_can.h
Normal file
23
firmware/canfd_cdc_composite/src/gs_usb_can.h
Normal file
@@ -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 */
|
||||
82
firmware/canfd_cdc_composite/src/main.c
Normal file
82
firmware/canfd_cdc_composite/src/main.c
Normal file
@@ -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;
|
||||
}
|
||||
78
firmware/canfd_cdc_composite/src/pfet_control.c
Normal file
78
firmware/canfd_cdc_composite/src/pfet_control.c
Normal file
@@ -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;
|
||||
}
|
||||
31
firmware/canfd_cdc_composite/src/pfet_control.h
Normal file
31
firmware/canfd_cdc_composite/src/pfet_control.h
Normal file
@@ -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 */
|
||||
Reference in New Issue
Block a user