mirror of
https://github.com/andreili/katapult.git
synced 2025-08-23 19:34:06 +02:00
stm32: Add support for flashing over USB and serial
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
799fe5313b
commit
ad566230c9
46
src/Kconfig
46
src/Kconfig
@ -2,19 +2,47 @@
|
|||||||
|
|
||||||
mainmenu "CanBoot Configuration"
|
mainmenu "CanBoot Configuration"
|
||||||
|
|
||||||
|
config LOW_LEVEL_OPTIONS
|
||||||
|
bool
|
||||||
|
default y
|
||||||
|
|
||||||
config MACH_STM32
|
config MACH_STM32
|
||||||
bool
|
bool
|
||||||
default y
|
default y
|
||||||
|
|
||||||
source "src/stm32/Kconfig"
|
source "src/stm32/Kconfig"
|
||||||
|
|
||||||
config CANSERIAL
|
# Generic configuration options for serial ports
|
||||||
bool
|
config SERIAL_BAUD
|
||||||
default y
|
depends on SERIAL
|
||||||
|
int "Baud rate for serial port" if LOW_LEVEL_OPTIONS
|
||||||
|
default 250000
|
||||||
|
help
|
||||||
|
Specify the baud rate of the serial port. This should be set
|
||||||
|
to 250000. Read the FAQ before changing this value.
|
||||||
|
|
||||||
config CANBUS_FREQUENCY
|
# Generic configuration options for USB
|
||||||
int "CAN bus speed"
|
config USB_VENDOR_ID
|
||||||
default 500000
|
default 0x1d50
|
||||||
|
config USB_DEVICE_ID
|
||||||
|
default 0x614e
|
||||||
|
config USB_SERIAL_NUMBER_CHIPID
|
||||||
|
depends on HAVE_CHIPID
|
||||||
|
default y
|
||||||
|
config USB_SERIAL_NUMBER
|
||||||
|
default "12345"
|
||||||
|
|
||||||
|
menu "USB ids"
|
||||||
|
depends on USBSERIAL && LOW_LEVEL_OPTIONS
|
||||||
|
config USB_VENDOR_ID
|
||||||
|
hex "USB vendor ID"
|
||||||
|
config USB_DEVICE_ID
|
||||||
|
hex "USB device ID"
|
||||||
|
config USB_SERIAL_NUMBER_CHIPID
|
||||||
|
bool "USB serial number from CHIPID" if HAVE_CHIPID
|
||||||
|
config USB_SERIAL_NUMBER
|
||||||
|
string "USB serial number" if !USB_SERIAL_NUMBER_CHIPID
|
||||||
|
endmenu
|
||||||
|
|
||||||
config ENABLE_DOUBLE_RESET
|
config ENABLE_DOUBLE_RESET
|
||||||
bool "Support bootloader entry on rapid double click of reset button"
|
bool "Support bootloader entry on rapid double click of reset button"
|
||||||
@ -35,3 +63,9 @@ config ENABLE_LED
|
|||||||
config STATUS_LED_PIN
|
config STATUS_LED_PIN
|
||||||
string "Status LED GPIO Pin"
|
string "Status LED GPIO Pin"
|
||||||
depends on ENABLE_LED
|
depends on ENABLE_LED
|
||||||
|
|
||||||
|
# The HAVE_x options allow boards to disable support for some commands
|
||||||
|
# if the hardware does not support the feature.
|
||||||
|
config HAVE_CHIPID
|
||||||
|
bool
|
||||||
|
default n
|
||||||
|
@ -82,8 +82,11 @@ command_dispatch(uint8_t *buf, uint_fast8_t msglen)
|
|||||||
command_complete(data);
|
command_complete(data);
|
||||||
break;
|
break;
|
||||||
case CMD_GET_CANBUS_ID:
|
case CMD_GET_CANBUS_ID:
|
||||||
command_get_canbus_id(data);
|
if (CONFIG_CANSERIAL) {
|
||||||
break;
|
command_get_canbus_id(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// NO BREAK
|
||||||
default:
|
default:
|
||||||
// Unknown command or gabage data, NACK it
|
// Unknown command or gabage data, NACK it
|
||||||
command_respond_command_error();
|
command_respond_command_error();
|
||||||
|
122
src/generic/serial_irq.c
Normal file
122
src/generic/serial_irq.c
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// Generic interrupt based serial uart helper code
|
||||||
|
//
|
||||||
|
// Copyright (C) 2016-2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include <string.h> // memmove
|
||||||
|
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
||||||
|
#include "board/io.h" // readb
|
||||||
|
#include "board/irq.h" // irq_save
|
||||||
|
#include "board/misc.h" // console_sendf
|
||||||
|
#include "board/pgm.h" // READP
|
||||||
|
#include "command.h" // DECL_CONSTANT
|
||||||
|
#include "sched.h" // sched_wake_tasks
|
||||||
|
#include "serial_irq.h" // serial_enable_tx_irq
|
||||||
|
|
||||||
|
#define RX_BUFFER_SIZE 192
|
||||||
|
|
||||||
|
static uint8_t receive_buf[RX_BUFFER_SIZE], receive_pos;
|
||||||
|
static uint8_t transmit_buf[96], transmit_pos, transmit_max;
|
||||||
|
|
||||||
|
DECL_CONSTANT("SERIAL_BAUD", CONFIG_SERIAL_BAUD);
|
||||||
|
DECL_CONSTANT("RECEIVE_WINDOW", RX_BUFFER_SIZE);
|
||||||
|
|
||||||
|
// Rx interrupt - store read data
|
||||||
|
void
|
||||||
|
serial_rx_byte(uint_fast8_t data)
|
||||||
|
{
|
||||||
|
if (data == MESSAGE_SYNC)
|
||||||
|
sched_wake_tasks();
|
||||||
|
if (receive_pos >= sizeof(receive_buf))
|
||||||
|
// Serial overflow - ignore it as crc error will force retransmit
|
||||||
|
return;
|
||||||
|
receive_buf[receive_pos++] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tx interrupt - get next byte to transmit
|
||||||
|
int
|
||||||
|
serial_get_tx_byte(uint8_t *pdata)
|
||||||
|
{
|
||||||
|
if (transmit_pos >= transmit_max)
|
||||||
|
return -1;
|
||||||
|
*pdata = transmit_buf[transmit_pos++];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from the receive buffer the given number of bytes
|
||||||
|
static void
|
||||||
|
console_pop_input(uint_fast8_t len)
|
||||||
|
{
|
||||||
|
uint_fast8_t copied = 0;
|
||||||
|
for (;;) {
|
||||||
|
uint_fast8_t rpos = readb(&receive_pos);
|
||||||
|
uint_fast8_t needcopy = rpos - len;
|
||||||
|
if (needcopy) {
|
||||||
|
memmove(&receive_buf[copied], &receive_buf[copied + len]
|
||||||
|
, needcopy - copied);
|
||||||
|
copied = needcopy;
|
||||||
|
sched_wake_tasks();
|
||||||
|
}
|
||||||
|
irqstatus_t flag = irq_save();
|
||||||
|
if (rpos != readb(&receive_pos)) {
|
||||||
|
// Raced with irq handler - retry
|
||||||
|
irq_restore(flag);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
receive_pos = needcopy;
|
||||||
|
irq_restore(flag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process any incoming commands
|
||||||
|
void
|
||||||
|
console_task(void)
|
||||||
|
{
|
||||||
|
uint_fast8_t rpos = readb(&receive_pos), pop_count;
|
||||||
|
int_fast8_t ret = command_find_block(receive_buf, rpos, &pop_count);
|
||||||
|
if (ret > 0)
|
||||||
|
command_dispatch(receive_buf, pop_count);
|
||||||
|
if (ret) {
|
||||||
|
console_pop_input(pop_count);
|
||||||
|
if (ret > 0)
|
||||||
|
command_send_ack();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DECL_TASK(console_task);
|
||||||
|
|
||||||
|
// Encode and transmit a "response" message
|
||||||
|
void
|
||||||
|
console_sendf(const struct command_encoder *ce, va_list args)
|
||||||
|
{
|
||||||
|
// Verify space for message
|
||||||
|
uint_fast8_t tpos = readb(&transmit_pos), tmax = readb(&transmit_max);
|
||||||
|
if (tpos >= tmax) {
|
||||||
|
tpos = tmax = 0;
|
||||||
|
writeb(&transmit_max, 0);
|
||||||
|
writeb(&transmit_pos, 0);
|
||||||
|
}
|
||||||
|
uint_fast8_t max_size = READP(ce->max_size);
|
||||||
|
if (tmax + max_size > sizeof(transmit_buf)) {
|
||||||
|
if (tmax + max_size - tpos > sizeof(transmit_buf))
|
||||||
|
// Not enough space for message
|
||||||
|
return;
|
||||||
|
// Disable TX irq and move buffer
|
||||||
|
writeb(&transmit_max, 0);
|
||||||
|
tpos = readb(&transmit_pos);
|
||||||
|
tmax -= tpos;
|
||||||
|
memmove(&transmit_buf[0], &transmit_buf[tpos], tmax);
|
||||||
|
writeb(&transmit_pos, 0);
|
||||||
|
writeb(&transmit_max, tmax);
|
||||||
|
serial_enable_tx_irq();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate message
|
||||||
|
uint8_t *buf = &transmit_buf[tmax];
|
||||||
|
uint_fast8_t msglen = command_encode_and_frame(buf, ce, args);
|
||||||
|
|
||||||
|
// Start message transmit
|
||||||
|
writeb(&transmit_max, tmax + msglen);
|
||||||
|
serial_enable_tx_irq();
|
||||||
|
}
|
13
src/generic/serial_irq.h
Normal file
13
src/generic/serial_irq.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#ifndef __GENERIC_SERIAL_IRQ_H
|
||||||
|
#define __GENERIC_SERIAL_IRQ_H
|
||||||
|
|
||||||
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
|
// callback provided by board specific code
|
||||||
|
void serial_enable_tx_irq(void);
|
||||||
|
|
||||||
|
// serial_irq.c
|
||||||
|
void serial_rx_byte(uint_fast8_t data);
|
||||||
|
int serial_get_tx_byte(uint8_t *pdata);
|
||||||
|
|
||||||
|
#endif // serial_irq.h
|
531
src/generic/usb_cdc.c
Normal file
531
src/generic/usb_cdc.c
Normal file
@ -0,0 +1,531 @@
|
|||||||
|
// Support for standard serial port over USB emulation
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include <string.h> // memmove
|
||||||
|
#include "autoconf.h" // CONFIG_USB_VENDOR_ID
|
||||||
|
#include "board/pgm.h" // PROGMEM
|
||||||
|
#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
|
||||||
|
#include "byteorder.h" // cpu_to_le16
|
||||||
|
#include "command.h" // output
|
||||||
|
#include "generic/usbstd.h" // struct usb_device_descriptor
|
||||||
|
#include "generic/usbstd_cdc.h" // struct usb_cdc_header_descriptor
|
||||||
|
#include "sched.h" // sched_wake_task
|
||||||
|
#include "usb_cdc.h" // usb_notify_ep0
|
||||||
|
|
||||||
|
// To debug a USB connection over UART, uncomment the two macros
|
||||||
|
// below, alter the board KConfig to "select USBSERIAL" on a serial
|
||||||
|
// UART build (so both USB and UART are enabled in a single build),
|
||||||
|
// compile the code using serial UART, add output() calls to the USB
|
||||||
|
// code as needed, deploy the new binary, and then connect via
|
||||||
|
// console.py using UART to see those output() messages.
|
||||||
|
//#define console_sendf(ce,va) console_sendf_usb(ce,va)
|
||||||
|
//#define command_find_and_dispatch(rb, rp, pc) ({*(pc) = rp; 1;})
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Message block sending
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
static struct task_wake usb_bulk_in_wake;
|
||||||
|
static uint8_t transmit_buf[192], transmit_pos;
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_notify_bulk_in(void)
|
||||||
|
{
|
||||||
|
sched_wake_task(&usb_bulk_in_wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_bulk_in_task(void)
|
||||||
|
{
|
||||||
|
if (!sched_check_wake(&usb_bulk_in_wake))
|
||||||
|
return;
|
||||||
|
uint_fast8_t tpos = transmit_pos;
|
||||||
|
if (!tpos)
|
||||||
|
return;
|
||||||
|
uint_fast8_t max_tpos = (tpos > USB_CDC_EP_BULK_IN_SIZE
|
||||||
|
? USB_CDC_EP_BULK_IN_SIZE : tpos);
|
||||||
|
int_fast8_t ret = usb_send_bulk_in(transmit_buf, max_tpos);
|
||||||
|
if (ret <= 0)
|
||||||
|
return;
|
||||||
|
uint_fast8_t needcopy = tpos - ret;
|
||||||
|
if (needcopy) {
|
||||||
|
memmove(transmit_buf, &transmit_buf[ret], needcopy);
|
||||||
|
usb_notify_bulk_in();
|
||||||
|
}
|
||||||
|
transmit_pos = needcopy;
|
||||||
|
}
|
||||||
|
DECL_TASK(usb_bulk_in_task);
|
||||||
|
|
||||||
|
// Encode and transmit a "response" message
|
||||||
|
void
|
||||||
|
console_sendf(const struct command_encoder *ce, va_list args)
|
||||||
|
{
|
||||||
|
// Verify space for message
|
||||||
|
uint_fast8_t tpos = transmit_pos, max_size = READP(ce->max_size);
|
||||||
|
if (tpos + max_size > sizeof(transmit_buf))
|
||||||
|
// Not enough space for message
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Generate message
|
||||||
|
uint8_t *buf = &transmit_buf[tpos];
|
||||||
|
uint_fast8_t msglen = command_encode_and_frame(buf, ce, args);
|
||||||
|
|
||||||
|
// Start message transmit
|
||||||
|
transmit_pos = tpos + msglen;
|
||||||
|
usb_notify_bulk_in();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Message block reading
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
static struct task_wake usb_bulk_out_wake;
|
||||||
|
static uint8_t receive_buf[128], receive_pos;
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_notify_bulk_out(void)
|
||||||
|
{
|
||||||
|
sched_wake_task(&usb_bulk_out_wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_bulk_out_task(void)
|
||||||
|
{
|
||||||
|
if (!sched_check_wake(&usb_bulk_out_wake))
|
||||||
|
return;
|
||||||
|
// Read data
|
||||||
|
uint_fast8_t rpos = receive_pos, pop_count;
|
||||||
|
if (rpos + USB_CDC_EP_BULK_OUT_SIZE <= sizeof(receive_buf)) {
|
||||||
|
int_fast8_t ret = usb_read_bulk_out(
|
||||||
|
&receive_buf[rpos], USB_CDC_EP_BULK_OUT_SIZE);
|
||||||
|
if (ret > 0) {
|
||||||
|
rpos += ret;
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
}
|
||||||
|
// Process a message block
|
||||||
|
int_fast8_t ret = command_find_and_dispatch(receive_buf, rpos, &pop_count);
|
||||||
|
if (ret) {
|
||||||
|
// Move buffer
|
||||||
|
uint_fast8_t needcopy = rpos - pop_count;
|
||||||
|
if (needcopy) {
|
||||||
|
memmove(receive_buf, &receive_buf[pop_count], needcopy);
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
}
|
||||||
|
rpos = needcopy;
|
||||||
|
}
|
||||||
|
receive_pos = rpos;
|
||||||
|
}
|
||||||
|
DECL_TASK(usb_bulk_out_task);
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* USB descriptors
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
#define CONCAT1(a, b) a ## b
|
||||||
|
#define CONCAT(a, b) CONCAT1(a, b)
|
||||||
|
#define USB_STR_MANUFACTURER u"CanBoot"
|
||||||
|
#define USB_STR_PRODUCT CONCAT(u,CONFIG_MCU)
|
||||||
|
#define USB_STR_SERIAL CONCAT(u,CONFIG_USB_SERIAL_NUMBER)
|
||||||
|
|
||||||
|
// String descriptors
|
||||||
|
enum {
|
||||||
|
USB_STR_ID_MANUFACTURER = 1, USB_STR_ID_PRODUCT, USB_STR_ID_SERIAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZE_cdc_string_langids (sizeof(cdc_string_langids) + 2)
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor cdc_string_langids PROGMEM = {
|
||||||
|
.bLength = SIZE_cdc_string_langids,
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.data = { cpu_to_le16(USB_LANGID_ENGLISH_US) },
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZE_cdc_string_manufacturer \
|
||||||
|
(sizeof(cdc_string_manufacturer) + sizeof(USB_STR_MANUFACTURER) - 2)
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor cdc_string_manufacturer PROGMEM = {
|
||||||
|
.bLength = SIZE_cdc_string_manufacturer,
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.data = USB_STR_MANUFACTURER,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZE_cdc_string_product \
|
||||||
|
(sizeof(cdc_string_product) + sizeof(USB_STR_PRODUCT) - 2)
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor cdc_string_product PROGMEM = {
|
||||||
|
.bLength = SIZE_cdc_string_product,
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.data = USB_STR_PRODUCT,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZE_cdc_string_serial \
|
||||||
|
(sizeof(cdc_string_serial) + sizeof(USB_STR_SERIAL) - 2)
|
||||||
|
|
||||||
|
static const struct usb_string_descriptor cdc_string_serial PROGMEM = {
|
||||||
|
.bLength = SIZE_cdc_string_serial,
|
||||||
|
.bDescriptorType = USB_DT_STRING,
|
||||||
|
.data = USB_STR_SERIAL,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Device descriptor
|
||||||
|
static const struct usb_device_descriptor cdc_device_descriptor PROGMEM = {
|
||||||
|
.bLength = sizeof(cdc_device_descriptor),
|
||||||
|
.bDescriptorType = USB_DT_DEVICE,
|
||||||
|
.bcdUSB = cpu_to_le16(0x0200),
|
||||||
|
.bDeviceClass = USB_CLASS_COMM,
|
||||||
|
.bMaxPacketSize0 = USB_CDC_EP0_SIZE,
|
||||||
|
.idVendor = cpu_to_le16(CONFIG_USB_VENDOR_ID),
|
||||||
|
.idProduct = cpu_to_le16(CONFIG_USB_DEVICE_ID),
|
||||||
|
.bcdDevice = cpu_to_le16(0x0100),
|
||||||
|
.iManufacturer = USB_STR_ID_MANUFACTURER,
|
||||||
|
.iProduct = USB_STR_ID_PRODUCT,
|
||||||
|
.iSerialNumber = USB_STR_ID_SERIAL,
|
||||||
|
.bNumConfigurations = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Config descriptor
|
||||||
|
static const struct config_s {
|
||||||
|
struct usb_config_descriptor config;
|
||||||
|
struct usb_interface_descriptor iface0;
|
||||||
|
struct usb_cdc_header_descriptor cdc_hdr;
|
||||||
|
struct usb_cdc_acm_descriptor cdc_acm;
|
||||||
|
struct usb_cdc_union_descriptor cdc_union;
|
||||||
|
struct usb_endpoint_descriptor ep1;
|
||||||
|
struct usb_interface_descriptor iface1;
|
||||||
|
struct usb_endpoint_descriptor ep2;
|
||||||
|
struct usb_endpoint_descriptor ep3;
|
||||||
|
} PACKED cdc_config_descriptor PROGMEM = {
|
||||||
|
.config = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.config),
|
||||||
|
.bDescriptorType = USB_DT_CONFIG,
|
||||||
|
.wTotalLength = cpu_to_le16(sizeof(cdc_config_descriptor)),
|
||||||
|
.bNumInterfaces = 2,
|
||||||
|
.bConfigurationValue = 1,
|
||||||
|
.bmAttributes = 0xC0,
|
||||||
|
.bMaxPower = 50,
|
||||||
|
},
|
||||||
|
.iface0 = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.iface0),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 0,
|
||||||
|
.bNumEndpoints = 1,
|
||||||
|
.bInterfaceClass = USB_CLASS_COMM,
|
||||||
|
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
||||||
|
.bInterfaceProtocol = USB_CDC_ACM_PROTO_AT_V25TER,
|
||||||
|
},
|
||||||
|
.cdc_hdr = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.cdc_hdr),
|
||||||
|
.bDescriptorType = USB_CDC_CS_INTERFACE,
|
||||||
|
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
|
||||||
|
.bcdCDC = 0x0110,
|
||||||
|
},
|
||||||
|
.cdc_acm = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.cdc_acm),
|
||||||
|
.bDescriptorType = USB_CDC_CS_INTERFACE,
|
||||||
|
.bDescriptorSubType = USB_CDC_ACM_TYPE,
|
||||||
|
.bmCapabilities = 0x06,
|
||||||
|
},
|
||||||
|
.cdc_union = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.cdc_union),
|
||||||
|
.bDescriptorType = USB_CDC_CS_INTERFACE,
|
||||||
|
.bDescriptorSubType = USB_CDC_UNION_TYPE,
|
||||||
|
.bMasterInterface0 = 0,
|
||||||
|
.bSlaveInterface0 = 1,
|
||||||
|
},
|
||||||
|
.ep1 = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.ep1),
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = USB_CDC_EP_ACM | USB_DIR_IN,
|
||||||
|
.bmAttributes = USB_ENDPOINT_XFER_INT,
|
||||||
|
.wMaxPacketSize = cpu_to_le16(USB_CDC_EP_ACM_SIZE),
|
||||||
|
.bInterval = 255,
|
||||||
|
},
|
||||||
|
.iface1 = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.iface1),
|
||||||
|
.bDescriptorType = USB_DT_INTERFACE,
|
||||||
|
.bInterfaceNumber = 1,
|
||||||
|
.bNumEndpoints = 2,
|
||||||
|
.bInterfaceClass = 0x0A,
|
||||||
|
},
|
||||||
|
.ep2 = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.ep2),
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = USB_CDC_EP_BULK_OUT,
|
||||||
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||||
|
.wMaxPacketSize = cpu_to_le16(USB_CDC_EP_BULK_OUT_SIZE),
|
||||||
|
},
|
||||||
|
.ep3 = {
|
||||||
|
.bLength = sizeof(cdc_config_descriptor.ep3),
|
||||||
|
.bDescriptorType = USB_DT_ENDPOINT,
|
||||||
|
.bEndpointAddress = USB_CDC_EP_BULK_IN | USB_DIR_IN,
|
||||||
|
.bmAttributes = USB_ENDPOINT_XFER_BULK,
|
||||||
|
.wMaxPacketSize = cpu_to_le16(USB_CDC_EP_BULK_IN_SIZE),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
// List of available descriptors
|
||||||
|
static const struct descriptor_s {
|
||||||
|
uint_fast16_t wValue;
|
||||||
|
uint_fast16_t wIndex;
|
||||||
|
const void *desc;
|
||||||
|
uint_fast8_t size;
|
||||||
|
} cdc_descriptors[] PROGMEM = {
|
||||||
|
{ USB_DT_DEVICE<<8, 0x0000,
|
||||||
|
&cdc_device_descriptor, sizeof(cdc_device_descriptor) },
|
||||||
|
{ USB_DT_CONFIG<<8, 0x0000,
|
||||||
|
&cdc_config_descriptor, sizeof(cdc_config_descriptor) },
|
||||||
|
{ USB_DT_STRING<<8, 0x0000,
|
||||||
|
&cdc_string_langids, SIZE_cdc_string_langids },
|
||||||
|
{ (USB_DT_STRING<<8) | USB_STR_ID_MANUFACTURER, USB_LANGID_ENGLISH_US,
|
||||||
|
&cdc_string_manufacturer, SIZE_cdc_string_manufacturer },
|
||||||
|
{ (USB_DT_STRING<<8) | USB_STR_ID_PRODUCT, USB_LANGID_ENGLISH_US,
|
||||||
|
&cdc_string_product, SIZE_cdc_string_product },
|
||||||
|
#if !CONFIG_USB_SERIAL_NUMBER_CHIPID
|
||||||
|
{ (USB_DT_STRING<<8) | USB_STR_ID_SERIAL, USB_LANGID_ENGLISH_US,
|
||||||
|
&cdc_string_serial, SIZE_cdc_string_serial },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// Fill in a USB serial string descriptor from a chip id
|
||||||
|
void
|
||||||
|
usb_fill_serial(struct usb_string_descriptor *desc, int strlen, void *id)
|
||||||
|
{
|
||||||
|
desc->bLength = sizeof(*desc) + strlen * sizeof(desc->data[0]);
|
||||||
|
desc->bDescriptorType = USB_DT_STRING;
|
||||||
|
|
||||||
|
uint8_t *src = id;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < strlen; i++) {
|
||||||
|
uint8_t c = i & 1 ? src[i/2] & 0x0f : src[i/2] >> 4;
|
||||||
|
desc->data[i] = c < 10 ? c + '0' : c - 10 + 'A';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* USB endpoint 0 control message handling
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
// State tracking
|
||||||
|
enum {
|
||||||
|
UX_READ = 1<<0, UX_SEND = 1<<1, UX_SEND_PROGMEM = 1<<2, UX_SEND_ZLP = 1<<3
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *usb_xfer_data;
|
||||||
|
static uint8_t usb_xfer_size, usb_xfer_flags;
|
||||||
|
|
||||||
|
// Set the USB "stall" condition
|
||||||
|
static void
|
||||||
|
usb_do_stall(void)
|
||||||
|
{
|
||||||
|
usb_stall_ep0();
|
||||||
|
usb_xfer_flags = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transfer data on the usb endpoint 0
|
||||||
|
static void
|
||||||
|
usb_do_xfer(void *data, uint_fast8_t size, uint_fast8_t flags)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
uint_fast8_t xs = size;
|
||||||
|
if (xs > USB_CDC_EP0_SIZE)
|
||||||
|
xs = USB_CDC_EP0_SIZE;
|
||||||
|
int_fast8_t ret;
|
||||||
|
if (flags & UX_READ)
|
||||||
|
ret = usb_read_ep0(data, xs);
|
||||||
|
else if (NEED_PROGMEM && flags & UX_SEND_PROGMEM)
|
||||||
|
ret = usb_send_ep0_progmem(data, xs);
|
||||||
|
else
|
||||||
|
ret = usb_send_ep0(data, xs);
|
||||||
|
if (ret == xs) {
|
||||||
|
// Success
|
||||||
|
data += xs;
|
||||||
|
size -= xs;
|
||||||
|
if (!size) {
|
||||||
|
// Entire transfer completed successfully
|
||||||
|
if (flags & UX_READ) {
|
||||||
|
// Send status packet at end of read
|
||||||
|
flags = UX_SEND;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (xs == USB_CDC_EP0_SIZE && flags & UX_SEND_ZLP)
|
||||||
|
// Must send zero-length-packet
|
||||||
|
continue;
|
||||||
|
usb_xfer_flags = 0;
|
||||||
|
usb_notify_ep0();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ret == -1) {
|
||||||
|
// Interface busy - retry later
|
||||||
|
usb_xfer_data = data;
|
||||||
|
usb_xfer_size = size;
|
||||||
|
usb_xfer_flags = flags;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Error
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_get_descriptor(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType != USB_DIR_IN)
|
||||||
|
goto fail;
|
||||||
|
void *desc = NULL;
|
||||||
|
uint_fast8_t flags, size, i;
|
||||||
|
for (i=0; i<ARRAY_SIZE(cdc_descriptors); i++) {
|
||||||
|
const struct descriptor_s *d = &cdc_descriptors[i];
|
||||||
|
if (READP(d->wValue) == req->wValue
|
||||||
|
&& READP(d->wIndex) == req->wIndex) {
|
||||||
|
flags = NEED_PROGMEM ? UX_SEND_PROGMEM : UX_SEND;
|
||||||
|
size = READP(d->size);
|
||||||
|
desc = (void*)READP(d->desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (CONFIG_USB_SERIAL_NUMBER_CHIPID
|
||||||
|
&& req->wValue == ((USB_DT_STRING<<8) | USB_STR_ID_SERIAL)
|
||||||
|
&& req->wIndex == USB_LANGID_ENGLISH_US) {
|
||||||
|
struct usb_string_descriptor *usbserial_serialid;
|
||||||
|
usbserial_serialid = usbserial_get_serialid();
|
||||||
|
flags = UX_SEND;
|
||||||
|
size = usbserial_serialid->bLength;
|
||||||
|
desc = (void*)usbserial_serialid;
|
||||||
|
}
|
||||||
|
if (desc) {
|
||||||
|
if (size > req->wLength)
|
||||||
|
size = req->wLength;
|
||||||
|
else if (size < req->wLength)
|
||||||
|
flags |= UX_SEND_ZLP;
|
||||||
|
usb_do_xfer(desc, size, flags);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fail:
|
||||||
|
usb_do_stall();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_set_address(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType || req->wIndex || req->wLength) {
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usb_set_address(req->wValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_set_configuration(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType || req->wValue != 1 || req->wIndex || req->wLength) {
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usb_set_configure();
|
||||||
|
usb_notify_bulk_in();
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
usb_do_xfer(NULL, 0, UX_SEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct usb_cdc_line_coding line_coding;
|
||||||
|
static uint8_t line_control_state;
|
||||||
|
|
||||||
|
static void
|
||||||
|
check_reboot(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_set_line_coding(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType != 0x21 || req->wValue || req->wIndex
|
||||||
|
|| req->wLength != sizeof(line_coding)) {
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usb_do_xfer(&line_coding, sizeof(line_coding), UX_READ);
|
||||||
|
check_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_get_line_coding(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType != 0xa1 || req->wValue || req->wIndex
|
||||||
|
|| req->wLength < sizeof(line_coding)) {
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
usb_do_xfer(&line_coding, sizeof(line_coding), UX_SEND);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_req_set_line(struct usb_ctrlrequest *req)
|
||||||
|
{
|
||||||
|
if (req->bRequestType != 0x21 || req->wIndex || req->wLength) {
|
||||||
|
usb_do_stall();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
line_control_state = req->wValue;
|
||||||
|
usb_do_xfer(NULL, 0, UX_SEND);
|
||||||
|
check_reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usb_state_ready(void)
|
||||||
|
{
|
||||||
|
struct usb_ctrlrequest req;
|
||||||
|
int_fast8_t ret = usb_read_ep0_setup(&req, sizeof(req));
|
||||||
|
if (ret != sizeof(req))
|
||||||
|
return;
|
||||||
|
switch (req.bRequest) {
|
||||||
|
case USB_REQ_GET_DESCRIPTOR: usb_req_get_descriptor(&req); break;
|
||||||
|
case USB_REQ_SET_ADDRESS: usb_req_set_address(&req); break;
|
||||||
|
case USB_REQ_SET_CONFIGURATION: usb_req_set_configuration(&req); break;
|
||||||
|
case USB_CDC_REQ_SET_LINE_CODING: usb_req_set_line_coding(&req); break;
|
||||||
|
case USB_CDC_REQ_GET_LINE_CODING: usb_req_get_line_coding(&req); break;
|
||||||
|
case USB_CDC_REQ_SET_CONTROL_LINE_STATE: usb_req_set_line(&req); break;
|
||||||
|
default: usb_do_stall(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// State tracking dispatch
|
||||||
|
static struct task_wake usb_ep0_wake;
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_notify_ep0(void)
|
||||||
|
{
|
||||||
|
sched_wake_task(&usb_ep0_wake);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_ep0_task(void)
|
||||||
|
{
|
||||||
|
if (!sched_check_wake(&usb_ep0_wake))
|
||||||
|
return;
|
||||||
|
if (usb_xfer_flags)
|
||||||
|
usb_do_xfer(usb_xfer_data, usb_xfer_size, usb_xfer_flags);
|
||||||
|
else
|
||||||
|
usb_state_ready();
|
||||||
|
}
|
||||||
|
DECL_TASK(usb_ep0_task);
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_shutdown(void)
|
||||||
|
{
|
||||||
|
usb_notify_bulk_in();
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
usb_notify_ep0();
|
||||||
|
}
|
||||||
|
DECL_SHUTDOWN(usb_shutdown);
|
33
src/generic/usb_cdc.h
Normal file
33
src/generic/usb_cdc.h
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
#ifndef __GENERIC_USB_CDC_H
|
||||||
|
#define __GENERIC_USB_CDC_H
|
||||||
|
|
||||||
|
#include <stdint.h> // uint_fast8_t
|
||||||
|
|
||||||
|
// endpoint sizes
|
||||||
|
enum {
|
||||||
|
USB_CDC_EP0_SIZE = 16,
|
||||||
|
USB_CDC_EP_ACM_SIZE = 8,
|
||||||
|
USB_CDC_EP_BULK_OUT_SIZE = 64,
|
||||||
|
USB_CDC_EP_BULK_IN_SIZE = 64,
|
||||||
|
};
|
||||||
|
|
||||||
|
// callbacks provided by board specific code
|
||||||
|
int_fast8_t usb_read_bulk_out(void *data, uint_fast8_t max_len);
|
||||||
|
int_fast8_t usb_send_bulk_in(void *data, uint_fast8_t len);
|
||||||
|
int_fast8_t usb_read_ep0(void *data, uint_fast8_t max_len);
|
||||||
|
int_fast8_t usb_read_ep0_setup(void *data, uint_fast8_t max_len);
|
||||||
|
int_fast8_t usb_send_ep0(const void *data, uint_fast8_t len);
|
||||||
|
int_fast8_t usb_send_ep0_progmem(const void *data, uint_fast8_t len);
|
||||||
|
void usb_stall_ep0(void);
|
||||||
|
void usb_set_address(uint_fast8_t addr);
|
||||||
|
void usb_set_configure(void);
|
||||||
|
void usb_request_bootloader(void);
|
||||||
|
struct usb_string_descriptor *usbserial_get_serialid(void);
|
||||||
|
|
||||||
|
// usb_cdc.c
|
||||||
|
void usb_fill_serial(struct usb_string_descriptor *desc, int strlen, void *id);
|
||||||
|
void usb_notify_bulk_in(void);
|
||||||
|
void usb_notify_bulk_out(void);
|
||||||
|
void usb_notify_ep0(void);
|
||||||
|
|
||||||
|
#endif // usb_cdc.h
|
11
src/generic/usb_cdc_ep.h
Normal file
11
src/generic/usb_cdc_ep.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef __GENERIC_USB_CDC_EP_H
|
||||||
|
#define __GENERIC_USB_CDC_EP_H
|
||||||
|
|
||||||
|
// Default USB endpoint ids
|
||||||
|
enum {
|
||||||
|
USB_CDC_EP_ACM = 1,
|
||||||
|
USB_CDC_EP_BULK_OUT = 2,
|
||||||
|
USB_CDC_EP_BULK_IN = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // usb_cdc_ep.h
|
122
src/generic/usbstd.h
Normal file
122
src/generic/usbstd.h
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// Standard definitions for USB commands and data structures
|
||||||
|
#ifndef __GENERIC_USBSTD_H
|
||||||
|
#define __GENERIC_USBSTD_H
|
||||||
|
|
||||||
|
#include <stdint.h> // uint8_t
|
||||||
|
#include "compiler.h" // PACKED
|
||||||
|
|
||||||
|
#define USB_DIR_OUT 0 /* to device */
|
||||||
|
#define USB_DIR_IN 0x80 /* to host */
|
||||||
|
|
||||||
|
#define USB_REQ_GET_STATUS 0x00
|
||||||
|
#define USB_REQ_CLEAR_FEATURE 0x01
|
||||||
|
#define USB_REQ_SET_FEATURE 0x03
|
||||||
|
#define USB_REQ_SET_ADDRESS 0x05
|
||||||
|
#define USB_REQ_GET_DESCRIPTOR 0x06
|
||||||
|
#define USB_REQ_SET_DESCRIPTOR 0x07
|
||||||
|
#define USB_REQ_GET_CONFIGURATION 0x08
|
||||||
|
#define USB_REQ_SET_CONFIGURATION 0x09
|
||||||
|
#define USB_REQ_GET_INTERFACE 0x0A
|
||||||
|
#define USB_REQ_SET_INTERFACE 0x0B
|
||||||
|
#define USB_REQ_SYNCH_FRAME 0x0C
|
||||||
|
|
||||||
|
struct usb_ctrlrequest {
|
||||||
|
uint8_t bRequestType;
|
||||||
|
uint8_t bRequest;
|
||||||
|
uint16_t wValue;
|
||||||
|
uint16_t wIndex;
|
||||||
|
uint16_t wLength;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_DT_DEVICE 0x01
|
||||||
|
#define USB_DT_CONFIG 0x02
|
||||||
|
#define USB_DT_STRING 0x03
|
||||||
|
#define USB_DT_INTERFACE 0x04
|
||||||
|
#define USB_DT_ENDPOINT 0x05
|
||||||
|
#define USB_DT_DEVICE_QUALIFIER 0x06
|
||||||
|
#define USB_DT_OTHER_SPEED_CONFIG 0x07
|
||||||
|
#define USB_DT_ENDPOINT_COMPANION 0x30
|
||||||
|
|
||||||
|
struct usb_device_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
|
||||||
|
uint16_t bcdUSB;
|
||||||
|
uint8_t bDeviceClass;
|
||||||
|
uint8_t bDeviceSubClass;
|
||||||
|
uint8_t bDeviceProtocol;
|
||||||
|
uint8_t bMaxPacketSize0;
|
||||||
|
uint16_t idVendor;
|
||||||
|
uint16_t idProduct;
|
||||||
|
uint16_t bcdDevice;
|
||||||
|
uint8_t iManufacturer;
|
||||||
|
uint8_t iProduct;
|
||||||
|
uint8_t iSerialNumber;
|
||||||
|
uint8_t bNumConfigurations;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_CLASS_PER_INTERFACE 0 /* for DeviceClass */
|
||||||
|
#define USB_CLASS_AUDIO 1
|
||||||
|
#define USB_CLASS_COMM 2
|
||||||
|
#define USB_CLASS_HID 3
|
||||||
|
#define USB_CLASS_PHYSICAL 5
|
||||||
|
#define USB_CLASS_STILL_IMAGE 6
|
||||||
|
#define USB_CLASS_PRINTER 7
|
||||||
|
#define USB_CLASS_MASS_STORAGE 8
|
||||||
|
#define USB_CLASS_HUB 9
|
||||||
|
|
||||||
|
struct usb_config_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
|
||||||
|
uint16_t wTotalLength;
|
||||||
|
uint8_t bNumInterfaces;
|
||||||
|
uint8_t bConfigurationValue;
|
||||||
|
uint8_t iConfiguration;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint8_t bMaxPower;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct usb_interface_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
|
||||||
|
uint8_t bInterfaceNumber;
|
||||||
|
uint8_t bAlternateSetting;
|
||||||
|
uint8_t bNumEndpoints;
|
||||||
|
uint8_t bInterfaceClass;
|
||||||
|
uint8_t bInterfaceSubClass;
|
||||||
|
uint8_t bInterfaceProtocol;
|
||||||
|
uint8_t iInterface;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct usb_endpoint_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
|
||||||
|
uint8_t bEndpointAddress;
|
||||||
|
uint8_t bmAttributes;
|
||||||
|
uint16_t wMaxPacketSize;
|
||||||
|
uint8_t bInterval;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_ENDPOINT_NUMBER_MASK 0x0f /* in bEndpointAddress */
|
||||||
|
#define USB_ENDPOINT_DIR_MASK 0x80
|
||||||
|
|
||||||
|
#define USB_ENDPOINT_XFERTYPE_MASK 0x03 /* in bmAttributes */
|
||||||
|
#define USB_ENDPOINT_XFER_CONTROL 0
|
||||||
|
#define USB_ENDPOINT_XFER_ISOC 1
|
||||||
|
#define USB_ENDPOINT_XFER_BULK 2
|
||||||
|
#define USB_ENDPOINT_XFER_INT 3
|
||||||
|
#define USB_ENDPOINT_MAX_ADJUSTABLE 0x80
|
||||||
|
|
||||||
|
struct usb_string_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
//uint16_t data[];
|
||||||
|
typeof(*u"") data[];
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_LANGID_ENGLISH_US 0x0409
|
||||||
|
|
||||||
|
#endif // usbstd.h
|
49
src/generic/usbstd_cdc.h
Normal file
49
src/generic/usbstd_cdc.h
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
// Standard definitions for USB CDC devices
|
||||||
|
#ifndef __GENERIC_USBSTD_CDC_H
|
||||||
|
#define __GENERIC_USBSTD_CDC_H
|
||||||
|
|
||||||
|
#define USB_CDC_SUBCLASS_ACM 0x02
|
||||||
|
|
||||||
|
#define USB_CDC_ACM_PROTO_AT_V25TER 1
|
||||||
|
|
||||||
|
struct usb_cdc_header_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bDescriptorSubType;
|
||||||
|
uint16_t bcdCDC;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_CDC_HEADER_TYPE 0x00
|
||||||
|
#define USB_CDC_ACM_TYPE 0x02
|
||||||
|
#define USB_CDC_UNION_TYPE 0x06
|
||||||
|
|
||||||
|
#define USB_CDC_CS_INTERFACE 0x24
|
||||||
|
#define USB_CDC_CS_ENDPOINT 0x25
|
||||||
|
|
||||||
|
struct usb_cdc_acm_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bDescriptorSubType;
|
||||||
|
uint8_t bmCapabilities;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct usb_cdc_union_descriptor {
|
||||||
|
uint8_t bLength;
|
||||||
|
uint8_t bDescriptorType;
|
||||||
|
uint8_t bDescriptorSubType;
|
||||||
|
uint8_t bMasterInterface0;
|
||||||
|
uint8_t bSlaveInterface0;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
||||||
|
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||||
|
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||||
|
|
||||||
|
struct usb_cdc_line_coding {
|
||||||
|
uint32_t dwDTERate;
|
||||||
|
uint8_t bCharFormat;
|
||||||
|
uint8_t bParityType;
|
||||||
|
uint8_t bDataBits;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
#endif // usbstd_cdc.h
|
@ -9,6 +9,12 @@
|
|||||||
#include "bootentry.h" // bootentry_check
|
#include "bootentry.h" // bootentry_check
|
||||||
#include "sched.h" // sched_check_periodic
|
#include "sched.h" // sched_check_periodic
|
||||||
|
|
||||||
|
// Wrapper for Klipper compatibility
|
||||||
|
void
|
||||||
|
sched_wake_tasks(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// Note that a task is ready to run
|
// Note that a task is ready to run
|
||||||
void
|
void
|
||||||
sched_wake_task(struct task_wake *w)
|
sched_wake_task(struct task_wake *w)
|
||||||
|
@ -17,6 +17,7 @@ struct task_wake {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// sched.c
|
// sched.c
|
||||||
|
void sched_wake_tasks(void);
|
||||||
void sched_wake_task(struct task_wake *w);
|
void sched_wake_task(struct task_wake *w);
|
||||||
uint8_t sched_check_wake(struct task_wake *w);
|
uint8_t sched_check_wake(struct task_wake *w);
|
||||||
void sched_main(void);
|
void sched_main(void);
|
||||||
|
@ -2,44 +2,77 @@
|
|||||||
|
|
||||||
if MACH_STM32
|
if MACH_STM32
|
||||||
|
|
||||||
config ENABLE_STM32F4
|
config STM32_SELECT
|
||||||
bool
|
bool
|
||||||
|
default y
|
||||||
|
select HAVE_GPIO
|
||||||
|
select HAVE_GPIO_ADC
|
||||||
|
select HAVE_GPIO_I2C if !(MACH_STM32F031 || MACH_STM32H7)
|
||||||
|
select HAVE_GPIO_SPI if !MACH_STM32F031
|
||||||
|
select HAVE_GPIO_HARD_PWM if MACH_STM32F1 || MACH_STM32F4 || MACH_STM32H7
|
||||||
|
select HAVE_GPIO_BITBANGING if !MACH_STM32F031
|
||||||
|
select HAVE_STRICT_TIMING
|
||||||
|
select HAVE_CHIPID
|
||||||
|
select HAVE_STEPPER_BOTH_EDGE
|
||||||
|
|
||||||
config BOARD_DIRECTORY
|
config BOARD_DIRECTORY
|
||||||
string
|
string
|
||||||
default "stm32"
|
default "stm32"
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Chip selection
|
||||||
|
######################################################################
|
||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "Processor model"
|
prompt "Processor model"
|
||||||
config MACH_STM32F042
|
|
||||||
bool "STM32F042"
|
|
||||||
select MACH_STM32F0
|
|
||||||
select MACH_STM32F0x2
|
|
||||||
config MACH_STM32F072
|
|
||||||
bool "STM32F072"
|
|
||||||
select MACH_STM32F0
|
|
||||||
select MACH_STM32F0x2
|
|
||||||
config MACH_STM32F103
|
config MACH_STM32F103
|
||||||
bool "STM32F103"
|
bool "STM32F103"
|
||||||
select MACH_STM32F1
|
select MACH_STM32F1
|
||||||
config MACH_STM32F207
|
config MACH_STM32F207
|
||||||
bool "STM32F207" if ENABLE_STM32F4
|
bool "STM32F207" if 0
|
||||||
select MACH_STM32F2
|
select MACH_STM32F2
|
||||||
|
config MACH_STM32F401
|
||||||
|
bool "STM32F401" if 0
|
||||||
|
select MACH_STM32F4
|
||||||
config MACH_STM32F405
|
config MACH_STM32F405
|
||||||
bool "STM32F405" if ENABLE_STM32F4
|
bool "STM32F405" if 0
|
||||||
select MACH_STM32F4
|
select MACH_STM32F4
|
||||||
select MACH_STM32F4x5
|
select MACH_STM32F4x5
|
||||||
config MACH_STM32F407
|
config MACH_STM32F407
|
||||||
bool "STM32F407" if ENABLE_STM32F4
|
bool "STM32F407" if 0
|
||||||
select MACH_STM32F4
|
select MACH_STM32F4
|
||||||
select MACH_STM32F4x5
|
select MACH_STM32F4x5
|
||||||
config MACH_STM32F429
|
config MACH_STM32F429
|
||||||
bool "STM32F429" if ENABLE_STM32F4
|
bool "STM32F429" if 0
|
||||||
select MACH_STM32F4
|
select MACH_STM32F4
|
||||||
select MACH_STM32F4x5
|
select MACH_STM32F4x5
|
||||||
config MACH_STM32F446
|
config MACH_STM32F446
|
||||||
bool "STM32F446" if ENABLE_STM32F4
|
bool "STM32F446" if 0
|
||||||
select MACH_STM32F4
|
select MACH_STM32F4
|
||||||
|
config MACH_STM32F031
|
||||||
|
bool "STM32F031" if 0
|
||||||
|
select MACH_STM32F0
|
||||||
|
config MACH_STM32F042
|
||||||
|
bool "STM32F042"
|
||||||
|
select MACH_STM32F0
|
||||||
|
select MACH_STM32F0x2
|
||||||
|
config MACH_STM32F070
|
||||||
|
bool "STM32F070" if 0
|
||||||
|
select MACH_STM32F0
|
||||||
|
config MACH_STM32F072
|
||||||
|
bool "STM32F072"
|
||||||
|
select MACH_STM32F0
|
||||||
|
select MACH_STM32F0x2
|
||||||
|
config MACH_STM32G0B1
|
||||||
|
bool "STM32G0B1" if 0
|
||||||
|
select MACH_STM32G0
|
||||||
|
config MACH_STM32H743
|
||||||
|
bool "STM32H743" if 0
|
||||||
|
select MACH_STM32H7
|
||||||
|
config MACH_STM32H750
|
||||||
|
bool "STM32H750" if 0
|
||||||
|
select MACH_STM32H7
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
config MACH_STM32F0
|
config MACH_STM32F0
|
||||||
@ -50,17 +83,40 @@ config MACH_STM32F2
|
|||||||
bool
|
bool
|
||||||
config MACH_STM32F4
|
config MACH_STM32F4
|
||||||
bool
|
bool
|
||||||
|
config MACH_STM32G0
|
||||||
|
bool
|
||||||
|
config MACH_STM32H7
|
||||||
|
bool
|
||||||
|
config MACH_STM32F0x2 # F042, F072 series
|
||||||
|
bool
|
||||||
|
config MACH_STM32F4x5 # F405, F407, F429 series
|
||||||
|
bool
|
||||||
|
config HAVE_STM32_USBFS
|
||||||
|
bool
|
||||||
|
default y if MACH_STM32F103 || MACH_STM32F0x2 || MACH_STM32F070 || MACH_STM32G0
|
||||||
|
config HAVE_STM32_USBOTG
|
||||||
|
bool
|
||||||
|
default y if MACH_STM32F2 || MACH_STM32F4 || MACH_STM32H7
|
||||||
|
config HAVE_STM32_CANBUS
|
||||||
|
bool
|
||||||
|
default y if MACH_STM32F1 || MACH_STM32F2 || MACH_STM32F4x5 || MACH_STM32F446 || MACH_STM32F0x2
|
||||||
|
|
||||||
config MCU
|
config MCU
|
||||||
string
|
string
|
||||||
|
default "stm32f031x6" if MACH_STM32F031
|
||||||
default "stm32f042x6" if MACH_STM32F042
|
default "stm32f042x6" if MACH_STM32F042
|
||||||
|
default "stm32f070xb" if MACH_STM32F070
|
||||||
default "stm32f072xb" if MACH_STM32F072
|
default "stm32f072xb" if MACH_STM32F072
|
||||||
default "stm32f103xe" if MACH_STM32F103
|
default "stm32f103xe" if MACH_STM32F103
|
||||||
default "stm32f207xx" if MACH_STM32F207
|
default "stm32f207xx" if MACH_STM32F207
|
||||||
|
default "stm32f401xc" if MACH_STM32F401
|
||||||
default "stm32f405xx" if MACH_STM32F405
|
default "stm32f405xx" if MACH_STM32F405
|
||||||
default "stm32f407xx" if MACH_STM32F407
|
default "stm32f407xx" if MACH_STM32F407
|
||||||
default "stm32f429xx" if MACH_STM32F429
|
default "stm32f429xx" if MACH_STM32F429
|
||||||
default "stm32f446xx" if MACH_STM32F446
|
default "stm32f446xx" if MACH_STM32F446
|
||||||
|
default "stm32g0b1xx" if MACH_STM32G0B1
|
||||||
|
default "stm32h743xx" if MACH_STM32H743
|
||||||
|
default "stm32h750xx" if MACH_STM32H750
|
||||||
|
|
||||||
config CLOCK_FREQ
|
config CLOCK_FREQ
|
||||||
int
|
int
|
||||||
@ -68,50 +124,49 @@ config CLOCK_FREQ
|
|||||||
default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL
|
default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL
|
||||||
default 72000000 if MACH_STM32F103
|
default 72000000 if MACH_STM32F103
|
||||||
default 120000000 if MACH_STM32F207
|
default 120000000 if MACH_STM32F207
|
||||||
|
default 84000000 if MACH_STM32F401
|
||||||
default 168000000 if MACH_STM32F4x5
|
default 168000000 if MACH_STM32F4x5
|
||||||
default 180000000 if MACH_STM32F446
|
default 180000000 if MACH_STM32F446
|
||||||
|
default 64000000 if MACH_STM32G0
|
||||||
|
default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports
|
||||||
|
|
||||||
config FLASH_SIZE
|
config FLASH_SIZE
|
||||||
hex
|
hex
|
||||||
|
default 0x4000 if MACH_STM32F031
|
||||||
default 0x8000 if MACH_STM32F042
|
default 0x8000 if MACH_STM32F042
|
||||||
default 0x20000 if MACH_STM32F072
|
default 0x20000 if MACH_STM32F070 || MACH_STM32F072
|
||||||
default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB)
|
default 0x10000 if MACH_STM32F103 # Flash size of stm32f103x8 (64KiB)
|
||||||
default 0x40000 if MACH_STM32F2
|
default 0x40000 if MACH_STM32F2 || MACH_STM32F401
|
||||||
default 0x80000 if MACH_STM32F4
|
default 0x80000 if MACH_STM32F4x5 || MACH_STM32F446
|
||||||
|
default 0x20000 if MACH_STM32G0B1
|
||||||
|
default 0x20000 if MACH_STM32H750
|
||||||
|
default 0x200000 if MACH_STM32H743
|
||||||
|
|
||||||
config RAM_START
|
config RAM_START
|
||||||
hex
|
hex
|
||||||
|
default 0x24000000 if MACH_STM32H743
|
||||||
default 0x20000000
|
default 0x20000000
|
||||||
|
|
||||||
config RAM_SIZE
|
config RAM_SIZE
|
||||||
hex
|
hex
|
||||||
|
default 0x1000 if MACH_STM32F031
|
||||||
default 0x1800 if MACH_STM32F042
|
default 0x1800 if MACH_STM32F042
|
||||||
default 0x4000 if MACH_STM32F072
|
default 0x4000 if MACH_STM32F070 || MACH_STM32F072
|
||||||
default 0x5000 if MACH_STM32F103 # Ram size of stm32f103x8 (20KiB)
|
default 0x5000 if MACH_STM32F103 # Ram size of stm32f103x8 (20KiB)
|
||||||
default 0x20000 if MACH_STM32F207
|
default 0x20000 if MACH_STM32F207
|
||||||
default 0x20000 if MACH_STM32F4
|
default 0x10000 if MACH_STM32F401
|
||||||
|
default 0x20000 if MACH_STM32F4x5 || MACH_STM32F446
|
||||||
|
default 0x24000 if MACH_STM32G0B1
|
||||||
|
default 0x20000 if MACH_STM32H750
|
||||||
|
default 0x80000 if MACH_STM32H743
|
||||||
|
|
||||||
config STACK_SIZE
|
config STACK_SIZE
|
||||||
int
|
int
|
||||||
default 512
|
default 512
|
||||||
|
|
||||||
config FLASH_START
|
|
||||||
hex
|
|
||||||
default 0x8000000
|
|
||||||
|
|
||||||
config APPLICATION_START
|
|
||||||
hex
|
|
||||||
default 0x8002000 if MACH_STM32F103
|
|
||||||
default 0x8002000
|
|
||||||
|
|
||||||
config ARMCM_RAM_VECTORTABLE
|
|
||||||
bool
|
|
||||||
default y if MACH_STM32F0 && FLASH_START != 0x8000000
|
|
||||||
default n
|
|
||||||
|
|
||||||
config STM32F103GD_DISABLE_SWD
|
config STM32F103GD_DISABLE_SWD
|
||||||
bool "Disable SWD at startup (for GigaDevice stm32f103 clones)"
|
bool "Disable SWD at startup (for GigaDevice stm32f103 clones)"
|
||||||
depends on MACH_STM32F103
|
depends on MACH_STM32F103 && LOW_LEVEL_OPTIONS
|
||||||
default n
|
default n
|
||||||
help
|
help
|
||||||
The GigaDevice clone of the STM32F103 may not be able to
|
The GigaDevice clone of the STM32F103 may not be able to
|
||||||
@ -119,8 +174,56 @@ config STM32F103GD_DISABLE_SWD
|
|||||||
and PA14 pins from being available. Selecting this option
|
and PA14 pins from being available. Selecting this option
|
||||||
disables SWD at startup and thus makes these pins available.
|
disables SWD at startup and thus makes these pins available.
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Bootloader
|
||||||
|
######################################################################
|
||||||
|
|
||||||
choice
|
choice
|
||||||
prompt "Clock Reference"
|
prompt "Bootloader offset" if 0
|
||||||
|
config STM32_FLASH_START_2000
|
||||||
|
bool "8KiB bootloader" if MACH_STM32F103 || MACH_STM32F070 || MACH_STM32G0 || MACH_STM32F0x2
|
||||||
|
config STM32_FLASH_START_5000
|
||||||
|
bool "20KiB bootloader" if MACH_STM32F103
|
||||||
|
config STM32_FLASH_START_7000
|
||||||
|
bool "28KiB bootloader" if MACH_STM32F103
|
||||||
|
config STM32_FLASH_START_8000
|
||||||
|
bool "32KiB bootloader" if MACH_STM32F1 || MACH_STM32F2 || MACH_STM32F4
|
||||||
|
config STM32_FLASH_START_8800
|
||||||
|
bool "34KiB bootloader (Chitu v6 Bootloader)" if MACH_STM32F103
|
||||||
|
config STM32_FLASH_START_20200
|
||||||
|
bool "128KiB bootloader with 512 byte offset (Prusa Buddy)" if MACH_STM32F4x5
|
||||||
|
config STM32_FLASH_START_C000
|
||||||
|
bool "48KiB bootloader (MKS Robin Nano V3)" if MACH_STM32F4x5
|
||||||
|
config STM32_FLASH_START_10000
|
||||||
|
bool "64KiB bootloader" if MACH_STM32F103 || MACH_STM32F446 || MACH_STM32F401
|
||||||
|
|
||||||
|
config STM32_FLASH_START_800
|
||||||
|
bool "2KiB bootloader (HID Bootloader)" if MACH_STM32F103
|
||||||
|
config STM32_FLASH_START_4000
|
||||||
|
bool "16KiB bootloader (HID Bootloader)" if MACH_STM32F207 || MACH_STM32F401 || MACH_STM32F4x5 || MACH_STM32F103 || MACH_STM32F072
|
||||||
|
config STM32_FLASH_START_20000
|
||||||
|
bool "128KiB bootloader (SKR SE BX v2.0)" if MACH_STM32H743
|
||||||
|
|
||||||
|
config STM32_FLASH_START_0000
|
||||||
|
bool "No bootloader"
|
||||||
|
endchoice
|
||||||
|
config FLASH_START
|
||||||
|
hex
|
||||||
|
default 0x8000000
|
||||||
|
|
||||||
|
config ARMCM_RAM_VECTORTABLE
|
||||||
|
bool
|
||||||
|
default y if MACH_STM32F0 && FLASH_START != 0x8000000
|
||||||
|
default n
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Clock
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
choice
|
||||||
|
prompt "Clock Reference" if LOW_LEVEL_OPTIONS
|
||||||
config STM32_CLOCK_REF_8M
|
config STM32_CLOCK_REF_8M
|
||||||
bool "8 MHz crystal"
|
bool "8 MHz crystal"
|
||||||
config STM32_CLOCK_REF_12M
|
config STM32_CLOCK_REF_12M
|
||||||
@ -140,26 +243,8 @@ config CLOCK_REF_FREQ
|
|||||||
default 1 if STM32_CLOCK_REF_INTERNAL
|
default 1 if STM32_CLOCK_REF_INTERNAL
|
||||||
default 8000000
|
default 8000000
|
||||||
|
|
||||||
choice
|
|
||||||
prompt "CAN pins"
|
|
||||||
config STM32_CANBUS_PA11_PA12
|
|
||||||
bool "Pins PA11(rx) and PA12(tx)"
|
|
||||||
config STM32_CANBUS_PA11_PA12_REMAP
|
|
||||||
bool "Pins on PA9(rx) and PA10(tx)" if MACH_STM32F042
|
|
||||||
config STM32_CANBUS_PB8_PB9
|
|
||||||
bool "Pins PB8(rx) and PB9(tx)"
|
|
||||||
config STM32_CANBUS_PI9_PH13
|
|
||||||
bool "Pins PI9(rx) and PH13(tx)" if MACH_STM32F4
|
|
||||||
config STM32_CANBUS_PB5_PB6
|
|
||||||
bool "Pins PB5(rx) and PB6(tx)" if MACH_STM32F4
|
|
||||||
config STM32_CANBUS_PB12_PB13
|
|
||||||
bool "Pins PB12(rx) and PB13(tx)" if MACH_STM32F4
|
|
||||||
config STM32_CANBUS_PD0_PD1
|
|
||||||
bool "Pins PD0(rx) and PD1(tx)"
|
|
||||||
endchoice
|
|
||||||
|
|
||||||
config STM32F0_TRIM
|
config STM32F0_TRIM
|
||||||
int "Internal clock trim override" if MACH_STM32F0 && STM32_CLOCK_REF_INTERNAL
|
int "Internal clock trim override" if LOW_LEVEL_OPTIONS && MACH_STM32F0 && STM32_CLOCK_REF_INTERNAL && !USBSERIAL
|
||||||
default 16
|
default 16
|
||||||
help
|
help
|
||||||
Specify the internal clock trim value. Setting this can be
|
Specify the internal clock trim value. Setting this can be
|
||||||
@ -167,6 +252,100 @@ config STM32F0_TRIM
|
|||||||
Default is 16 (use factory default). Each increment increases
|
Default is 16 (use factory default). Each increment increases
|
||||||
the clock rate by ~240KHz.
|
the clock rate by ~240KHz.
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Communication inteface
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
config USBSERIAL
|
||||||
|
bool
|
||||||
|
config SERIAL
|
||||||
|
bool
|
||||||
|
config CANSERIAL
|
||||||
|
bool
|
||||||
|
choice
|
||||||
|
prompt "Communication interface"
|
||||||
|
config STM32_USB_PA11_PA12
|
||||||
|
bool "USB (on PA11/PA12)" if HAVE_STM32_USBFS || HAVE_STM32_USBOTG
|
||||||
|
select USBSERIAL
|
||||||
|
config STM32_USB_PA11_PA12_REMAP
|
||||||
|
bool "USB (on PA9/PA10)" if LOW_LEVEL_OPTIONS && MACH_STM32F042
|
||||||
|
select USBSERIAL
|
||||||
|
config STM32_USB_PB14_PB15
|
||||||
|
bool "USB (on PB14/PB15)"
|
||||||
|
depends on MACH_STM32H7
|
||||||
|
select USBSERIAL
|
||||||
|
config STM32_SERIAL_USART1
|
||||||
|
bool "Serial (on USART1 PA10/PA9)"
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART1_ALT_PB7_PB6
|
||||||
|
bool "Serial (on USART1 PB7/PB6)" if LOW_LEVEL_OPTIONS
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART2
|
||||||
|
bool "Serial (on USART2 PA3/PA2)" if LOW_LEVEL_OPTIONS
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART2_ALT_PA15_PA14
|
||||||
|
bool "Serial (on USART2 PA15/PA14)" if LOW_LEVEL_OPTIONS && MACH_STM32F0
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART2_ALT_PD6_PD5
|
||||||
|
bool "Serial (on USART2 PD6/PD5)" if LOW_LEVEL_OPTIONS && !MACH_STM32F0
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART3
|
||||||
|
bool "Serial (on USART3 PB11/PB10)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on !MACH_STM32F0 && !MACH_STM32F401
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_USART3_ALT_PD9_PD8
|
||||||
|
bool "Serial (on USART3 PD9/PD8)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on !MACH_STM32F0 && !MACH_STM32F401
|
||||||
|
select SERIAL
|
||||||
|
config STM32_SERIAL_UART4
|
||||||
|
bool "Serial (on UART4 PA0/PA1)"
|
||||||
|
depends on MACH_STM32H7
|
||||||
|
select SERIAL
|
||||||
|
config STM32_CANBUS_PA11_PA12
|
||||||
|
bool "CAN bus (on PA11/PA12)"
|
||||||
|
depends on HAVE_STM32_CANBUS
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PA11_PA12_REMAP
|
||||||
|
bool "CAN bus (on PA9/PA10)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS && MACH_STM32F042
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PB8_PB9
|
||||||
|
bool "CAN bus (on PB8/PB9)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PI9_PH13
|
||||||
|
bool "CAN bus (on PI9/PH13)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS && MACH_STM32F4
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PB5_PB6
|
||||||
|
bool "CAN bus (on PB5/PB6)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS && MACH_STM32F4
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PB12_PB13
|
||||||
|
bool "CAN bus (on PB12/PB13)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS && MACH_STM32F4
|
||||||
|
select CANSERIAL
|
||||||
|
config STM32_CANBUS_PD0_PD1
|
||||||
|
bool "CAN bus (on PD0/PD1)" if LOW_LEVEL_OPTIONS
|
||||||
|
depends on HAVE_STM32_CANBUS
|
||||||
|
select CANSERIAL
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config CANBUS_FREQUENCY
|
||||||
|
int "CAN bus speed" if LOW_LEVEL_OPTIONS && CANSERIAL
|
||||||
|
default 500000
|
||||||
|
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Flash settings
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
config APPLICATION_START
|
||||||
|
hex
|
||||||
|
default 0x8002000 if MACH_STM32F103
|
||||||
|
default 0x8002000
|
||||||
|
|
||||||
config MAX_FLASH_PAGE_SIZE
|
config MAX_FLASH_PAGE_SIZE
|
||||||
hex
|
hex
|
||||||
default 0x400 if MACH_STM32F042
|
default 0x400 if MACH_STM32F042
|
||||||
|
@ -41,8 +41,17 @@ src-$(CONFIG_MACH_STM32F4) += ../lib/stm32f4/system_stm32f4xx.c
|
|||||||
src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c
|
src-$(CONFIG_MACH_STM32F4) += stm32/stm32f4.c generic/armcm_timer.c
|
||||||
src-$(CONFIG_MACH_STM32F4) += stm32/gpioperiph.c
|
src-$(CONFIG_MACH_STM32F4) += stm32/gpioperiph.c
|
||||||
|
|
||||||
can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
|
usb-src-$(CONFIG_HAVE_STM32_USBFS) := stm32/usbfs.c
|
||||||
src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c
|
usb-src-$(CONFIG_HAVE_STM32_USBOTG) := stm32/usbotg.c
|
||||||
|
src-$(CONFIG_USBSERIAL) += $(usb-src-y) stm32/chipid.c generic/usb_cdc.c
|
||||||
|
serial-src-y := stm32/serial.c
|
||||||
|
serial-src-$(CONFIG_MACH_STM32F0) := stm32/stm32f0_serial.c
|
||||||
|
serial-src-$(CONFIG_MACH_STM32G0) := stm32/stm32f0_serial.c
|
||||||
|
serial-src-$(CONFIG_MACH_STM32H7) := stm32/stm32h7_serial.c
|
||||||
|
src-$(CONFIG_SERIAL) += $(serial-src-y) generic/serial_irq.c
|
||||||
|
src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
|
||||||
|
src-$(CONFIG_CANSERIAL) += generic/canbus.c
|
||||||
|
|
||||||
dirs-$(CONFIG_CANSERIAL) += lib/fast-hash
|
dirs-$(CONFIG_CANSERIAL) += lib/fast-hash
|
||||||
|
|
||||||
# Binary output file rules
|
# Binary output file rules
|
||||||
|
33
src/stm32/chipid.c
Normal file
33
src/stm32/chipid.c
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
// Support for extracting the hardware chip id on stm32
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include "generic/usb_cdc.h" // usb_fill_serial
|
||||||
|
#include "generic/usbstd.h" // usb_string_descriptor
|
||||||
|
#include "internal.h" // UID_BASE
|
||||||
|
#include "sched.h" // DECL_INIT
|
||||||
|
|
||||||
|
#define CHIP_UID_LEN 12
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
struct usb_string_descriptor desc;
|
||||||
|
uint16_t data[CHIP_UID_LEN * 2];
|
||||||
|
} cdc_chipid;
|
||||||
|
|
||||||
|
struct usb_string_descriptor *
|
||||||
|
usbserial_get_serialid(void)
|
||||||
|
{
|
||||||
|
return &cdc_chipid.desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
chipid_init(void)
|
||||||
|
{
|
||||||
|
if (!CONFIG_USB_SERIAL_NUMBER_CHIPID)
|
||||||
|
return;
|
||||||
|
usb_fill_serial(&cdc_chipid.desc, ARRAY_SIZE(cdc_chipid.data)
|
||||||
|
, (void*)UID_BASE);
|
||||||
|
}
|
||||||
|
DECL_INIT(chipid_init);
|
93
src/stm32/serial.c
Normal file
93
src/stm32/serial.c
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
// STM32 serial
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
||||||
|
#include "board/armcm_boot.h" // armcm_enable_irq
|
||||||
|
#include "board/serial_irq.h" // serial_rx_byte
|
||||||
|
#include "command.h" // DECL_CONSTANT_STR
|
||||||
|
#include "internal.h" // enable_pclock
|
||||||
|
#include "sched.h" // DECL_INIT
|
||||||
|
|
||||||
|
// Select the configured serial port
|
||||||
|
#if CONFIG_STM32_SERIAL_USART1
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA10,PA9");
|
||||||
|
#define GPIO_Rx GPIO('A', 10)
|
||||||
|
#define GPIO_Tx GPIO('A', 9)
|
||||||
|
#define USARTx USART1
|
||||||
|
#define USARTx_IRQn USART1_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART1_ALT_PB7_PB6
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PB7,PB6");
|
||||||
|
#define GPIO_Rx GPIO('B', 7)
|
||||||
|
#define GPIO_Tx GPIO('B', 6)
|
||||||
|
#define USARTx USART1
|
||||||
|
#define USARTx_IRQn USART1_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART2
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA3,PA2");
|
||||||
|
#define GPIO_Rx GPIO('A', 3)
|
||||||
|
#define GPIO_Tx GPIO('A', 2)
|
||||||
|
#define USARTx USART2
|
||||||
|
#define USARTx_IRQn USART2_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART2_ALT_PD6_PD5
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PD6,PD5");
|
||||||
|
#define GPIO_Rx GPIO('D', 6)
|
||||||
|
#define GPIO_Tx GPIO('D', 5)
|
||||||
|
#define USARTx USART2
|
||||||
|
#define USARTx_IRQn USART2_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART3
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PB11,PB10");
|
||||||
|
#define GPIO_Rx GPIO('B', 11)
|
||||||
|
#define GPIO_Tx GPIO('B', 10)
|
||||||
|
#define USARTx USART3
|
||||||
|
#define USARTx_IRQn USART3_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART3_ALT_PD9_PD8
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PD9,PD8");
|
||||||
|
#define GPIO_Rx GPIO('D', 9)
|
||||||
|
#define GPIO_Tx GPIO('D', 8)
|
||||||
|
#define USARTx USART3
|
||||||
|
#define USARTx_IRQn USART3_IRQn
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CR1_FLAGS (USART_CR1_UE | USART_CR1_RE | USART_CR1_TE \
|
||||||
|
| USART_CR1_RXNEIE)
|
||||||
|
|
||||||
|
void
|
||||||
|
USARTx_IRQHandler(void)
|
||||||
|
{
|
||||||
|
uint32_t sr = USARTx->SR;
|
||||||
|
if (sr & (USART_SR_RXNE | USART_SR_ORE))
|
||||||
|
serial_rx_byte(USARTx->DR);
|
||||||
|
if (sr & USART_SR_TXE && USARTx->CR1 & USART_CR1_TXEIE) {
|
||||||
|
uint8_t data;
|
||||||
|
int ret = serial_get_tx_byte(&data);
|
||||||
|
if (ret)
|
||||||
|
USARTx->CR1 = CR1_FLAGS;
|
||||||
|
else
|
||||||
|
USARTx->DR = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serial_enable_tx_irq(void)
|
||||||
|
{
|
||||||
|
USARTx->CR1 = CR1_FLAGS | USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serial_init(void)
|
||||||
|
{
|
||||||
|
enable_pclock((uint32_t)USARTx);
|
||||||
|
|
||||||
|
uint32_t pclk = get_pclock_frequency((uint32_t)USARTx);
|
||||||
|
uint32_t div = DIV_ROUND_CLOSEST(pclk, CONFIG_SERIAL_BAUD);
|
||||||
|
USARTx->BRR = (((div / 16) << USART_BRR_DIV_Mantissa_Pos)
|
||||||
|
| ((div % 16) << USART_BRR_DIV_Fraction_Pos));
|
||||||
|
USARTx->CR1 = CR1_FLAGS;
|
||||||
|
armcm_enable_irq(USARTx_IRQHandler, USARTx_IRQn, 0);
|
||||||
|
|
||||||
|
gpio_peripheral(GPIO_Rx, GPIO_FUNCTION(7), 1);
|
||||||
|
gpio_peripheral(GPIO_Tx, GPIO_FUNCTION(7), 0);
|
||||||
|
}
|
||||||
|
DECL_INIT(serial_init);
|
@ -8,9 +8,15 @@
|
|||||||
#include "board/armcm_boot.h" // armcm_main
|
#include "board/armcm_boot.h" // armcm_main
|
||||||
#include "board/irq.h" // irq_disable
|
#include "board/irq.h" // irq_disable
|
||||||
#include "board/misc.h" // timer_init
|
#include "board/misc.h" // timer_init
|
||||||
|
#include "command.h" // DECL_CONSTANT_STR
|
||||||
#include "internal.h" // enable_pclock
|
#include "internal.h" // enable_pclock
|
||||||
#include "sched.h" // sched_main
|
#include "sched.h" // sched_main
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Clock setup
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
#define FREQ_PERIPH 48000000
|
#define FREQ_PERIPH 48000000
|
||||||
|
|
||||||
// Map a peripheral address to its enable bits
|
// Map a peripheral address to its enable bits
|
||||||
@ -45,6 +51,10 @@ gpio_clock_enable(GPIO_TypeDef *regs)
|
|||||||
RCC->AHBENR;
|
RCC->AHBENR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !CONFIG_STM32_CLOCK_REF_INTERNAL
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_crystal", "PF0,PF1");
|
||||||
|
#endif
|
||||||
|
|
||||||
// Configure and enable the PLL as clock source
|
// Configure and enable the PLL as clock source
|
||||||
static void
|
static void
|
||||||
pll_setup(void)
|
pll_setup(void)
|
||||||
@ -75,10 +85,39 @@ pll_setup(void)
|
|||||||
|
|
||||||
// Setup CFGR3 register
|
// Setup CFGR3 register
|
||||||
uint32_t cfgr3 = RCC_CFGR3_I2C1SW;
|
uint32_t cfgr3 = RCC_CFGR3_I2C1SW;
|
||||||
|
#if CONFIG_USBSERIAL
|
||||||
|
// Select PLL as source for USB clock
|
||||||
|
cfgr3 |= RCC_CFGR3_USBSW;
|
||||||
|
#endif
|
||||||
RCC->CFGR3 = cfgr3;
|
RCC->CFGR3 = cfgr3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure and enable internal 48Mhz clock on the stm32f042
|
||||||
|
static void
|
||||||
|
hsi48_setup(void)
|
||||||
|
{
|
||||||
|
#if CONFIG_MACH_STM32F0x2
|
||||||
|
// Enable HSI48
|
||||||
|
RCC->CR2 |= RCC_CR2_HSI48ON;
|
||||||
|
while (!(RCC->CR2 & RCC_CR2_HSI48RDY))
|
||||||
|
;
|
||||||
|
|
||||||
|
// Switch system clock to HSI48
|
||||||
|
RCC->CFGR = RCC_CFGR_SW_HSI48;
|
||||||
|
while ((RCC->CFGR & RCC_CFGR_SWS_Msk) != RCC_CFGR_SWS_HSI48)
|
||||||
|
;
|
||||||
|
|
||||||
|
// Enable USB clock recovery
|
||||||
|
if (CONFIG_USBSERIAL) {
|
||||||
|
enable_pclock(CRS_BASE);
|
||||||
|
CRS->CR |= CRS_CR_AUTOTRIMEN | CRS_CR_CEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup I2C1 clock
|
||||||
|
RCC->CFGR3 = RCC_CFGR3_I2C1SW;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Enable high speed internal 14Mhz clock for ADC
|
// Enable high speed internal 14Mhz clock for ADC
|
||||||
static void
|
static void
|
||||||
hsi14_setup(void)
|
hsi14_setup(void)
|
||||||
@ -89,27 +128,35 @@ hsi14_setup(void)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Startup
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
// Main entry point - called from armcm_boot.c:ResetHandler()
|
// Main entry point - called from armcm_boot.c:ResetHandler()
|
||||||
void
|
void
|
||||||
armcm_main(void)
|
armcm_main(void)
|
||||||
{
|
{
|
||||||
SystemInit();
|
SystemInit();
|
||||||
|
|
||||||
|
enable_pclock(SYSCFG_BASE);
|
||||||
|
|
||||||
// Set flash latency
|
// Set flash latency
|
||||||
FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE;
|
FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE;
|
||||||
|
|
||||||
// Configure main clock
|
// Configure main clock
|
||||||
pll_setup();
|
if (CONFIG_MACH_STM32F0x2 && CONFIG_STM32_CLOCK_REF_INTERNAL
|
||||||
|
&& CONFIG_USBSERIAL)
|
||||||
|
hsi48_setup();
|
||||||
|
else
|
||||||
|
pll_setup();
|
||||||
|
|
||||||
// Turn on hsi14 oscillator for ADC
|
// Turn on hsi14 oscillator for ADC
|
||||||
hsi14_setup();
|
hsi14_setup();
|
||||||
|
|
||||||
// Support pin remapping USB/CAN pins on low pinout stm32f042
|
// Support pin remapping USB/CAN pins on low pinout stm32f042
|
||||||
#ifdef SYSCFG_CFGR1_PA11_PA12_RMP
|
#ifdef SYSCFG_CFGR1_PA11_PA12_RMP
|
||||||
if (CONFIG_STM32_CANBUS_PA11_PA12_REMAP) {
|
if (CONFIG_STM32_USB_PA11_PA12_REMAP || CONFIG_STM32_CANBUS_PA11_PA12_REMAP)
|
||||||
enable_pclock(SYSCFG_BASE);
|
|
||||||
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
|
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
timer_init();
|
timer_init();
|
||||||
|
102
src/stm32/stm32f0_serial.c
Normal file
102
src/stm32/stm32f0_serial.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// STM32F0 serial
|
||||||
|
//
|
||||||
|
// Copyright (C) 2019 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include "autoconf.h" // CONFIG_SERIAL_BAUD
|
||||||
|
#include "board/armcm_boot.h" // armcm_enable_irq
|
||||||
|
#include "board/serial_irq.h" // serial_rx_byte
|
||||||
|
#include "command.h" // DECL_CONSTANT_STR
|
||||||
|
#include "internal.h" // enable_pclock
|
||||||
|
#include "sched.h" // DECL_INIT
|
||||||
|
|
||||||
|
// Select the configured serial port
|
||||||
|
#if CONFIG_STM32_SERIAL_USART1
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA10,PA9");
|
||||||
|
#define GPIO_Rx GPIO('A', 10)
|
||||||
|
#define GPIO_Tx GPIO('A', 9)
|
||||||
|
#define USARTx_FUNCTION GPIO_FUNCTION(1)
|
||||||
|
#define USARTx USART1
|
||||||
|
#define USARTx_IRQn USART1_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART1_ALT_PB7_PB6
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PB7,PB6");
|
||||||
|
#define GPIO_Rx GPIO('B', 7)
|
||||||
|
#define GPIO_Tx GPIO('B', 6)
|
||||||
|
#define USARTx_FUNCTION GPIO_FUNCTION(0)
|
||||||
|
#define USARTx USART1
|
||||||
|
#define USARTx_IRQn USART1_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART2
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA3,PA2");
|
||||||
|
#define GPIO_Rx GPIO('A', 3)
|
||||||
|
#define GPIO_Tx GPIO('A', 2)
|
||||||
|
#define USARTx_FUNCTION GPIO_FUNCTION(1)
|
||||||
|
#define USARTx USART2
|
||||||
|
#define USARTx_IRQn USART2_IRQn
|
||||||
|
#elif CONFIG_STM32_SERIAL_USART2_ALT_PA15_PA14
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA15,PA14");
|
||||||
|
#define GPIO_Rx GPIO('A', 15)
|
||||||
|
#define GPIO_Tx GPIO('A', 14)
|
||||||
|
#define USARTx_FUNCTION GPIO_FUNCTION(1)
|
||||||
|
#define USARTx USART2
|
||||||
|
#define USARTx_IRQn USART2_IRQn
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MACH_STM32F031
|
||||||
|
// The stm32f031 has same pins for USART2, but everything is routed to USART1
|
||||||
|
#define USART2 USART1
|
||||||
|
#define USART2_IRQn USART1_IRQn
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CONFIG_MACH_STM32G0
|
||||||
|
// The stm32g0 has slightly different register names
|
||||||
|
#define USART2_IRQn USART2_LPUART2_IRQn
|
||||||
|
#define USART_CR1_RXNEIE USART_CR1_RXNEIE_RXFNEIE
|
||||||
|
#define USART_CR1_TXEIE USART_CR1_TXEIE_TXFNFIE
|
||||||
|
#define USART_ISR_RXNE USART_ISR_RXNE_RXFNE
|
||||||
|
#define USART_ISR_TXE USART_ISR_TXE_TXFNF
|
||||||
|
#define USART_BRR_DIV_MANTISSA_Pos 4
|
||||||
|
#define USART_BRR_DIV_FRACTION_Pos 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CR1_FLAGS (USART_CR1_UE | USART_CR1_RE | USART_CR1_TE \
|
||||||
|
| USART_CR1_RXNEIE)
|
||||||
|
|
||||||
|
void
|
||||||
|
USARTx_IRQHandler(void)
|
||||||
|
{
|
||||||
|
uint32_t sr = USARTx->ISR;
|
||||||
|
if (sr & (USART_ISR_RXNE | USART_ISR_ORE))
|
||||||
|
serial_rx_byte(USARTx->RDR);
|
||||||
|
if (sr & USART_ISR_TXE && USARTx->CR1 & USART_CR1_TXEIE) {
|
||||||
|
uint8_t data;
|
||||||
|
int ret = serial_get_tx_byte(&data);
|
||||||
|
if (ret)
|
||||||
|
USARTx->CR1 = CR1_FLAGS;
|
||||||
|
else
|
||||||
|
USARTx->TDR = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serial_enable_tx_irq(void)
|
||||||
|
{
|
||||||
|
USARTx->CR1 = CR1_FLAGS | USART_CR1_TXEIE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
serial_init(void)
|
||||||
|
{
|
||||||
|
enable_pclock((uint32_t)USARTx);
|
||||||
|
|
||||||
|
uint32_t pclk = get_pclock_frequency((uint32_t)USARTx);
|
||||||
|
uint32_t div = DIV_ROUND_CLOSEST(pclk, CONFIG_SERIAL_BAUD);
|
||||||
|
USARTx->BRR = (((div / 16) << USART_BRR_DIV_MANTISSA_Pos)
|
||||||
|
| ((div % 16) << USART_BRR_DIV_FRACTION_Pos));
|
||||||
|
USARTx->CR1 = CR1_FLAGS;
|
||||||
|
armcm_enable_irq(USARTx_IRQHandler, USARTx_IRQn, 0);
|
||||||
|
|
||||||
|
gpio_peripheral(GPIO_Rx, USARTx_FUNCTION, 1);
|
||||||
|
gpio_peripheral(GPIO_Tx, USARTx_FUNCTION, 0);
|
||||||
|
}
|
||||||
|
DECL_INIT(serial_init);
|
@ -7,9 +7,15 @@
|
|||||||
#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ
|
#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ
|
||||||
#include "board/armcm_boot.h" // VectorTable
|
#include "board/armcm_boot.h" // VectorTable
|
||||||
#include "board/irq.h" // irq_disable
|
#include "board/irq.h" // irq_disable
|
||||||
|
#include "board/usb_cdc.h" // usb_request_bootloader
|
||||||
#include "internal.h" // enable_pclock
|
#include "internal.h" // enable_pclock
|
||||||
#include "sched.h" // sched_main
|
#include "sched.h" // sched_main
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Clock setup
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2)
|
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2)
|
||||||
|
|
||||||
// Map a peripheral address to its enable bits
|
// Map a peripheral address to its enable bits
|
||||||
@ -204,6 +210,7 @@ gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************
|
/****************************************************************
|
||||||
* Startup
|
* Startup
|
||||||
****************************************************************/
|
****************************************************************/
|
||||||
|
360
src/stm32/usbfs.c
Normal file
360
src/stm32/usbfs.c
Normal file
@ -0,0 +1,360 @@
|
|||||||
|
// Hardware interface to "fullspeed USB controller"
|
||||||
|
//
|
||||||
|
// Copyright (C) 2018-2021 Kevin O'Connor <kevin@koconnor.net>
|
||||||
|
//
|
||||||
|
// This file may be distributed under the terms of the GNU GPLv3 license.
|
||||||
|
|
||||||
|
#include <string.h> // NULL
|
||||||
|
#include "board/armcm_boot.h" // armcm_enable_irq
|
||||||
|
#include "board/armcm_timer.h" // udelay
|
||||||
|
#include "board/gpio.h" // gpio_out_setup
|
||||||
|
#include "board/io.h" // writeb
|
||||||
|
#include "board/usb_cdc.h" // usb_notify_ep0
|
||||||
|
#include "board/usb_cdc_ep.h" // USB_CDC_EP_BULK_IN
|
||||||
|
#include "command.h" // DECL_CONSTANT_STR
|
||||||
|
#include "internal.h" // GPIO
|
||||||
|
#include "sched.h" // DECL_INIT
|
||||||
|
|
||||||
|
#if CONFIG_MACH_STM32F103
|
||||||
|
// Transfer memory is accessed with 32bits, but contains only 16bits of data
|
||||||
|
typedef volatile uint32_t epmword_t;
|
||||||
|
#define WSIZE 2
|
||||||
|
#define USBx_IRQn USB_LP_IRQn
|
||||||
|
#elif CONFIG_MACH_STM32F0
|
||||||
|
// Transfer memory is accessed with 16bits and contains 16bits of data
|
||||||
|
typedef volatile uint16_t epmword_t;
|
||||||
|
#define WSIZE 2
|
||||||
|
#define USBx_IRQn USB_IRQn
|
||||||
|
#elif CONFIG_MACH_STM32G0
|
||||||
|
// Transfer memory is accessed with 32bits and contains 32bits of data
|
||||||
|
typedef volatile uint32_t epmword_t;
|
||||||
|
#define WSIZE 4
|
||||||
|
#define USBx_IRQn USB_UCPD1_2_IRQn
|
||||||
|
|
||||||
|
// The stm32g0 has slightly different register names
|
||||||
|
#define USB USB_DRD_FS
|
||||||
|
#define USB_PMAADDR USB_DRD_PMAADDR
|
||||||
|
#define USB_EPADDR_FIELD USB_CHEP_ADDR
|
||||||
|
#define USB_EP_CTR_RX USB_EP_VTRX
|
||||||
|
#define USB_EP_CTR_TX USB_EP_VTTX
|
||||||
|
#define USB_EPRX_STAT USB_EP_RX_STRX
|
||||||
|
#define USB_EPTX_STAT USB_EP_TX_STTX
|
||||||
|
#define USB_ISTR_EP_ID USB_ISTR_IDN
|
||||||
|
#define USB_CNTR_FRES USB_CNTR_USBRST
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* USB transfer memory
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
// Layout of the USB transfer memory
|
||||||
|
#define EPM ((epmword_t*)USB_PMAADDR)
|
||||||
|
#define EPM_EP_DESC(ep) (&EPM[(ep) * (8 / WSIZE)])
|
||||||
|
#define EPM_BUF_OFFSET 0x10
|
||||||
|
#define EPM_EP_BUF_SIZE (64 / WSIZE + 1)
|
||||||
|
#define EPM_EP_TX_BUF(ep) (&EPM[EPM_BUF_OFFSET + (ep)*2*EPM_EP_BUF_SIZE])
|
||||||
|
#define EPM_EP_RX_BUF(ep) (&EPM[EPM_BUF_OFFSET + (1+(ep)*2)*EPM_EP_BUF_SIZE])
|
||||||
|
|
||||||
|
// Configure the usb descriptor for an endpoint
|
||||||
|
static void
|
||||||
|
epm_ep_desc_setup(int ep, int rx_size)
|
||||||
|
{
|
||||||
|
uint32_t addr_tx = (EPM_EP_TX_BUF(ep) - EPM) * WSIZE, count_tx = 0;
|
||||||
|
uint32_t addr_rx = (EPM_EP_RX_BUF(ep) - EPM) * WSIZE;
|
||||||
|
uint32_t count_rx = (rx_size <= 30 ? DIV_ROUND_UP(rx_size, 2) << 10
|
||||||
|
: ((DIV_ROUND_UP(rx_size, 32) - 1) << 10) | 0x8000);
|
||||||
|
epmword_t *desc = EPM_EP_DESC(ep);
|
||||||
|
if (WSIZE == 2) {
|
||||||
|
desc[0] = addr_tx;
|
||||||
|
desc[1] = count_tx;
|
||||||
|
desc[2] = addr_rx;
|
||||||
|
desc[3] = count_rx;
|
||||||
|
} else {
|
||||||
|
desc[0] = addr_tx | (count_tx << 16);
|
||||||
|
desc[1] = addr_rx | (count_rx << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return number of read bytes on an rx endpoint
|
||||||
|
static uint32_t
|
||||||
|
epm_get_ep_count_rx(int ep)
|
||||||
|
{
|
||||||
|
epmword_t *desc = EPM_EP_DESC(ep);
|
||||||
|
if (WSIZE == 2)
|
||||||
|
return desc[3] & 0x3ff;
|
||||||
|
return (desc[1] >> 16) & 0x3ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set number of bytes ready to be transmitted on a tx endpoint
|
||||||
|
static void
|
||||||
|
epm_set_ep_count_tx(int ep, uint32_t count)
|
||||||
|
{
|
||||||
|
epmword_t *desc = EPM_EP_DESC(ep);
|
||||||
|
if (WSIZE == 2) {
|
||||||
|
desc[1] = count;
|
||||||
|
} else {
|
||||||
|
uint32_t addr_tx = (EPM_EP_TX_BUF(ep) - EPM) * WSIZE;
|
||||||
|
desc[0] = addr_tx | (count << 16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the transfer descriptors in dedicated usb memory
|
||||||
|
static void
|
||||||
|
btable_configure(void)
|
||||||
|
{
|
||||||
|
epm_ep_desc_setup(0, USB_CDC_EP0_SIZE);
|
||||||
|
epm_ep_desc_setup(USB_CDC_EP_ACM, 0);
|
||||||
|
epm_ep_desc_setup(USB_CDC_EP_BULK_OUT, USB_CDC_EP_BULK_OUT_SIZE);
|
||||||
|
epm_ep_desc_setup(USB_CDC_EP_BULK_IN, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a packet stored in dedicated usb memory
|
||||||
|
static uint32_t
|
||||||
|
btable_read_packet(int ep, uint8_t *dest, int max_len)
|
||||||
|
{
|
||||||
|
epmword_t *src = EPM_EP_RX_BUF(ep);
|
||||||
|
uint32_t count = epm_get_ep_count_rx(ep);
|
||||||
|
if (count > max_len)
|
||||||
|
count = max_len;
|
||||||
|
int i;
|
||||||
|
for (i=0; i<count/WSIZE; i++) {
|
||||||
|
uint32_t d = *src++;
|
||||||
|
*dest++ = d;
|
||||||
|
*dest++ = d >> 8;
|
||||||
|
if (WSIZE == 4) {
|
||||||
|
*dest++ = d >> 16;
|
||||||
|
*dest++ = d >> 24;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count & (WSIZE-1)) {
|
||||||
|
uint32_t d = *src;
|
||||||
|
*dest++ = d;
|
||||||
|
if ((count & (WSIZE-1)) > 1)
|
||||||
|
*dest++ = d >> 8;
|
||||||
|
if ((count & (WSIZE-1)) > 2)
|
||||||
|
*dest++ = d >> 16;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write a packet to dedicated usb memory
|
||||||
|
static void
|
||||||
|
btable_write_packet(int ep, const uint8_t *src, int count)
|
||||||
|
{
|
||||||
|
epmword_t *dest = EPM_EP_TX_BUF(ep);
|
||||||
|
int i;
|
||||||
|
for (i=0; i<count/WSIZE; i++) {
|
||||||
|
uint8_t b1 = *src++, b2 = *src++, b3 = 0, b4 = 0;
|
||||||
|
if (WSIZE == 4) {
|
||||||
|
b3 = *src++;
|
||||||
|
b4 = *src++;
|
||||||
|
}
|
||||||
|
*dest++ = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
|
||||||
|
}
|
||||||
|
if (count & (WSIZE-1)) {
|
||||||
|
uint32_t d = *src++;
|
||||||
|
if ((count & (WSIZE-1)) > 1)
|
||||||
|
d |= *src++ << 8;
|
||||||
|
if ((count & (WSIZE-1)) > 2)
|
||||||
|
d |= *src++ << 16;
|
||||||
|
*dest = d;
|
||||||
|
}
|
||||||
|
epm_set_ep_count_tx(ep, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* USB endpoint register
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
#define USB_EPR ((volatile uint32_t *)USB_BASE)
|
||||||
|
|
||||||
|
#define EPR_RWBITS (USB_EPADDR_FIELD | USB_EP_KIND | USB_EP_TYPE_MASK)
|
||||||
|
#define EPR_RWCBITS (USB_EP_CTR_RX | USB_EP_CTR_TX)
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
set_stat_rx_bits(uint32_t epr, uint32_t bits)
|
||||||
|
{
|
||||||
|
return ((epr & (EPR_RWBITS | USB_EPRX_STAT)) ^ bits) | EPR_RWCBITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
set_stat_tx_bits(uint32_t epr, uint32_t bits)
|
||||||
|
{
|
||||||
|
return ((epr & (EPR_RWBITS | USB_EPTX_STAT)) ^ bits) | EPR_RWCBITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
set_stat_rxtx_bits(uint32_t epr, uint32_t bits)
|
||||||
|
{
|
||||||
|
uint32_t mask = EPR_RWBITS | USB_EPRX_STAT | USB_EPTX_STAT;
|
||||||
|
return ((epr & mask) ^ bits) | EPR_RWCBITS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* USB interface
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
int_fast8_t
|
||||||
|
usb_read_bulk_out(void *data, uint_fast8_t max_len)
|
||||||
|
{
|
||||||
|
uint32_t epr = USB_EPR[USB_CDC_EP_BULK_OUT];
|
||||||
|
if ((epr & USB_EPRX_STAT) == USB_EP_RX_VALID)
|
||||||
|
// No data ready
|
||||||
|
return -1;
|
||||||
|
uint32_t count = btable_read_packet(USB_CDC_EP_BULK_OUT, data, max_len);
|
||||||
|
USB_EPR[USB_CDC_EP_BULK_OUT] = set_stat_rx_bits(epr, USB_EP_RX_VALID);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_fast8_t
|
||||||
|
usb_send_bulk_in(void *data, uint_fast8_t len)
|
||||||
|
{
|
||||||
|
uint32_t epr = USB_EPR[USB_CDC_EP_BULK_IN];
|
||||||
|
if ((epr & USB_EPTX_STAT) != USB_EP_TX_NAK)
|
||||||
|
// No buffer space available
|
||||||
|
return -1;
|
||||||
|
btable_write_packet(USB_CDC_EP_BULK_IN, data, len);
|
||||||
|
USB_EPR[USB_CDC_EP_BULK_IN] = set_stat_tx_bits(epr, USB_EP_TX_VALID);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_fast8_t
|
||||||
|
usb_read_ep0(void *data, uint_fast8_t max_len)
|
||||||
|
{
|
||||||
|
uint32_t epr = USB_EPR[0];
|
||||||
|
if ((epr & USB_EPRX_STAT) != USB_EP_RX_NAK)
|
||||||
|
// No data ready
|
||||||
|
return -1;
|
||||||
|
uint32_t count = btable_read_packet(0, data, max_len);
|
||||||
|
USB_EPR[0] = set_stat_rxtx_bits(epr, USB_EP_RX_VALID | USB_EP_TX_NAK);
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
int_fast8_t
|
||||||
|
usb_read_ep0_setup(void *data, uint_fast8_t max_len)
|
||||||
|
{
|
||||||
|
return usb_read_ep0(data, max_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int_fast8_t
|
||||||
|
usb_send_ep0(const void *data, uint_fast8_t len)
|
||||||
|
{
|
||||||
|
uint32_t epr = USB_EPR[0];
|
||||||
|
if ((epr & USB_EPRX_STAT) != USB_EP_RX_VALID)
|
||||||
|
// Transfer interrupted
|
||||||
|
return -2;
|
||||||
|
if ((epr & USB_EPTX_STAT) != USB_EP_TX_NAK)
|
||||||
|
// No buffer space available
|
||||||
|
return -1;
|
||||||
|
btable_write_packet(0, data, len);
|
||||||
|
USB_EPR[0] = set_stat_tx_bits(epr, USB_EP_TX_VALID);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_stall_ep0(void)
|
||||||
|
{
|
||||||
|
USB_EPR[0] = set_stat_rxtx_bits(USB_EPR[0]
|
||||||
|
, USB_EP_RX_STALL | USB_EP_TX_STALL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t set_address;
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_set_address(uint_fast8_t addr)
|
||||||
|
{
|
||||||
|
writeb(&set_address, addr | USB_DADDR_EF);
|
||||||
|
usb_send_ep0(NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usb_set_configure(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/****************************************************************
|
||||||
|
* Setup and interrupts
|
||||||
|
****************************************************************/
|
||||||
|
|
||||||
|
// Configure interface after a USB reset event
|
||||||
|
static void
|
||||||
|
usb_reset(void)
|
||||||
|
{
|
||||||
|
USB_EPR[0] = 0 | USB_EP_CONTROL | USB_EP_RX_VALID | USB_EP_TX_NAK;
|
||||||
|
USB_EPR[USB_CDC_EP_ACM] = (USB_CDC_EP_ACM | USB_EP_INTERRUPT
|
||||||
|
| USB_EP_RX_NAK | USB_EP_TX_NAK);
|
||||||
|
USB_EPR[USB_CDC_EP_BULK_OUT] = (USB_CDC_EP_BULK_OUT | USB_EP_BULK
|
||||||
|
| USB_EP_RX_VALID | USB_EP_TX_NAK);
|
||||||
|
USB_EPR[USB_CDC_EP_BULK_IN] = (USB_CDC_EP_BULK_IN | USB_EP_BULK
|
||||||
|
| USB_EP_RX_NAK | USB_EP_TX_NAK);
|
||||||
|
|
||||||
|
USB->CNTR = USB_CNTR_CTRM | USB_CNTR_RESETM;
|
||||||
|
USB->DADDR = USB_DADDR_EF;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main irq handler
|
||||||
|
void
|
||||||
|
USB_IRQHandler(void)
|
||||||
|
{
|
||||||
|
uint32_t istr = USB->ISTR;
|
||||||
|
if (istr & USB_ISTR_CTR) {
|
||||||
|
// Endpoint activity
|
||||||
|
uint32_t ep = istr & USB_ISTR_EP_ID;
|
||||||
|
uint32_t epr = USB_EPR[ep];
|
||||||
|
USB_EPR[ep] = epr & EPR_RWBITS;
|
||||||
|
if (ep == 0) {
|
||||||
|
usb_notify_ep0();
|
||||||
|
if (epr & USB_EP_CTR_TX && set_address) {
|
||||||
|
// Apply address after last "in" message transmitted
|
||||||
|
USB->DADDR = set_address;
|
||||||
|
set_address = 0;
|
||||||
|
}
|
||||||
|
} else if (ep == USB_CDC_EP_BULK_OUT) {
|
||||||
|
usb_notify_bulk_out();
|
||||||
|
} else if (ep == USB_CDC_EP_BULK_IN) {
|
||||||
|
usb_notify_bulk_in();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (istr & USB_ISTR_RESET) {
|
||||||
|
// USB Reset
|
||||||
|
USB->ISTR = (uint16_t)~USB_ISTR_RESET;
|
||||||
|
usb_reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DECL_CONSTANT_STR("RESERVE_PINS_USB", "PA11,PA12");
|
||||||
|
|
||||||
|
// Initialize the usb controller
|
||||||
|
void
|
||||||
|
usb_init(void)
|
||||||
|
{
|
||||||
|
if (CONFIG_MACH_STM32F1) {
|
||||||
|
// Pull the D+ pin low briefly to signal a new connection
|
||||||
|
gpio_out_setup(GPIO('A', 12), 0);
|
||||||
|
udelay(5000);
|
||||||
|
gpio_in_setup(GPIO('A', 12), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable USB clock
|
||||||
|
enable_pclock(USB_BASE);
|
||||||
|
|
||||||
|
// Setup USB packet memory
|
||||||
|
btable_configure();
|
||||||
|
|
||||||
|
// Enable USB pullup
|
||||||
|
#ifdef USB_BCDR_DPPU
|
||||||
|
USB->BCDR = USB_BCDR_DPPU;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Reset usb controller and enable interrupts
|
||||||
|
USB->CNTR = USB_CNTR_FRES;
|
||||||
|
USB->DADDR = 0;
|
||||||
|
USB->CNTR = USB_CNTR_RESETM;
|
||||||
|
USB->ISTR = 0;
|
||||||
|
armcm_enable_irq(USB_IRQHandler, USBx_IRQn, 1);
|
||||||
|
}
|
||||||
|
DECL_INIT(usb_init);
|
Loading…
x
Reference in New Issue
Block a user