stm32: Add support for flashing over USB and serial

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
Kevin O'Connor 2022-05-11 19:40:28 -04:00 committed by Eric Callahan
parent 799fe5313b
commit ad566230c9
19 changed files with 1824 additions and 69 deletions

View File

@ -2,19 +2,47 @@
mainmenu "CanBoot Configuration"
config LOW_LEVEL_OPTIONS
bool
default y
config MACH_STM32
bool
default y
source "src/stm32/Kconfig"
config CANSERIAL
bool
default y
# Generic configuration options for serial ports
config SERIAL_BAUD
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
int "CAN bus speed"
default 500000
# Generic configuration options for USB
config USB_VENDOR_ID
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
bool "Support bootloader entry on rapid double click of reset button"
@ -35,3 +63,9 @@ config ENABLE_LED
config STATUS_LED_PIN
string "Status LED GPIO Pin"
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

View File

@ -82,8 +82,11 @@ command_dispatch(uint8_t *buf, uint_fast8_t msglen)
command_complete(data);
break;
case CMD_GET_CANBUS_ID:
command_get_canbus_id(data);
break;
if (CONFIG_CANSERIAL) {
command_get_canbus_id(data);
break;
}
// NO BREAK
default:
// Unknown command or gabage data, NACK it
command_respond_command_error();

122
src/generic/serial_irq.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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

View File

@ -9,6 +9,12 @@
#include "bootentry.h" // bootentry_check
#include "sched.h" // sched_check_periodic
// Wrapper for Klipper compatibility
void
sched_wake_tasks(void)
{
}
// Note that a task is ready to run
void
sched_wake_task(struct task_wake *w)

View File

@ -17,6 +17,7 @@ struct task_wake {
};
// sched.c
void sched_wake_tasks(void);
void sched_wake_task(struct task_wake *w);
uint8_t sched_check_wake(struct task_wake *w);
void sched_main(void);

View File

@ -2,44 +2,77 @@
if MACH_STM32
config ENABLE_STM32F4
config STM32_SELECT
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
string
default "stm32"
######################################################################
# Chip selection
######################################################################
choice
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
bool "STM32F103"
select MACH_STM32F1
config MACH_STM32F207
bool "STM32F207" if ENABLE_STM32F4
bool "STM32F207" if 0
select MACH_STM32F2
config MACH_STM32F401
bool "STM32F401" if 0
select MACH_STM32F4
config MACH_STM32F405
bool "STM32F405" if ENABLE_STM32F4
bool "STM32F405" if 0
select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F407
bool "STM32F407" if ENABLE_STM32F4
bool "STM32F407" if 0
select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F429
bool "STM32F429" if ENABLE_STM32F4
bool "STM32F429" if 0
select MACH_STM32F4
select MACH_STM32F4x5
config MACH_STM32F446
bool "STM32F446" if ENABLE_STM32F4
bool "STM32F446" if 0
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
config MACH_STM32F0
@ -50,17 +83,40 @@ config MACH_STM32F2
bool
config MACH_STM32F4
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
string
default "stm32f031x6" if MACH_STM32F031
default "stm32f042x6" if MACH_STM32F042
default "stm32f070xb" if MACH_STM32F070
default "stm32f072xb" if MACH_STM32F072
default "stm32f103xe" if MACH_STM32F103
default "stm32f207xx" if MACH_STM32F207
default "stm32f401xc" if MACH_STM32F401
default "stm32f405xx" if MACH_STM32F405
default "stm32f407xx" if MACH_STM32F407
default "stm32f429xx" if MACH_STM32F429
default "stm32f446xx" if MACH_STM32F446
default "stm32g0b1xx" if MACH_STM32G0B1
default "stm32h743xx" if MACH_STM32H743
default "stm32h750xx" if MACH_STM32H750
config CLOCK_FREQ
int
@ -68,50 +124,49 @@ config CLOCK_FREQ
default 64000000 if MACH_STM32F103 && STM32_CLOCK_REF_INTERNAL
default 72000000 if MACH_STM32F103
default 120000000 if MACH_STM32F207
default 84000000 if MACH_STM32F401
default 168000000 if MACH_STM32F4x5
default 180000000 if MACH_STM32F446
default 64000000 if MACH_STM32G0
default 400000000 if MACH_STM32H7 # 400Mhz is max Klipper currently supports
config FLASH_SIZE
hex
default 0x4000 if MACH_STM32F031
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 0x40000 if MACH_STM32F2
default 0x80000 if MACH_STM32F4
default 0x40000 if MACH_STM32F2 || MACH_STM32F401
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
hex
default 0x24000000 if MACH_STM32H743
default 0x20000000
config RAM_SIZE
hex
default 0x1000 if MACH_STM32F031
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 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
int
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
bool "Disable SWD at startup (for GigaDevice stm32f103 clones)"
depends on MACH_STM32F103
depends on MACH_STM32F103 && LOW_LEVEL_OPTIONS
default n
help
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
disables SWD at startup and thus makes these pins available.
######################################################################
# Bootloader
######################################################################
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
bool "8 MHz crystal"
config STM32_CLOCK_REF_12M
@ -140,26 +243,8 @@ config CLOCK_REF_FREQ
default 1 if STM32_CLOCK_REF_INTERNAL
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
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
help
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
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
hex
default 0x400 if MACH_STM32F042

View File

@ -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/gpioperiph.c
can-src-$(CONFIG_CANSERIAL) += stm32/can.c ../lib/fast-hash/fasthash.c
src-$(CONFIG_CANSERIAL) += $(can-src-y) generic/canbus.c
usb-src-$(CONFIG_HAVE_STM32_USBFS) := stm32/usbfs.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
# Binary output file rules

33
src/stm32/chipid.c Normal file
View 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
View 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);

View File

@ -8,9 +8,15 @@
#include "board/armcm_boot.h" // armcm_main
#include "board/irq.h" // irq_disable
#include "board/misc.h" // timer_init
#include "command.h" // DECL_CONSTANT_STR
#include "internal.h" // enable_pclock
#include "sched.h" // sched_main
/****************************************************************
* Clock setup
****************************************************************/
#define FREQ_PERIPH 48000000
// Map a peripheral address to its enable bits
@ -45,6 +51,10 @@ gpio_clock_enable(GPIO_TypeDef *regs)
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
static void
pll_setup(void)
@ -75,10 +85,39 @@ pll_setup(void)
// Setup CFGR3 register
uint32_t cfgr3 = RCC_CFGR3_I2C1SW;
#if CONFIG_USBSERIAL
// Select PLL as source for USB clock
cfgr3 |= RCC_CFGR3_USBSW;
#endif
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
static void
hsi14_setup(void)
@ -89,27 +128,35 @@ hsi14_setup(void)
;
}
/****************************************************************
* Startup
****************************************************************/
// Main entry point - called from armcm_boot.c:ResetHandler()
void
armcm_main(void)
{
SystemInit();
enable_pclock(SYSCFG_BASE);
// Set flash latency
FLASH->ACR = (1 << FLASH_ACR_LATENCY_Pos) | FLASH_ACR_PRFTBE;
// 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
hsi14_setup();
// Support pin remapping USB/CAN pins on low pinout stm32f042
#ifdef SYSCFG_CFGR1_PA11_PA12_RMP
if (CONFIG_STM32_CANBUS_PA11_PA12_REMAP) {
enable_pclock(SYSCFG_BASE);
if (CONFIG_STM32_USB_PA11_PA12_REMAP || CONFIG_STM32_CANBUS_PA11_PA12_REMAP)
SYSCFG->CFGR1 |= SYSCFG_CFGR1_PA11_PA12_RMP;
}
#endif
timer_init();

102
src/stm32/stm32f0_serial.c Normal file
View 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);

View File

@ -7,9 +7,15 @@
#include "autoconf.h" // CONFIG_CLOCK_REF_FREQ
#include "board/armcm_boot.h" // VectorTable
#include "board/irq.h" // irq_disable
#include "board/usb_cdc.h" // usb_request_bootloader
#include "internal.h" // enable_pclock
#include "sched.h" // sched_main
/****************************************************************
* Clock setup
****************************************************************/
#define FREQ_PERIPH (CONFIG_CLOCK_FREQ / 2)
// Map a peripheral address to its enable bits
@ -204,6 +210,7 @@ gpio_peripheral(uint32_t gpio, uint32_t mode, int pullup)
}
}
/****************************************************************
* Startup
****************************************************************/

360
src/stm32/usbfs.c Normal file
View 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);