aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGareth McMullin2011-02-12 22:06:53 +1300
committerGareth McMullin2011-02-12 22:06:53 +1300
commitdf5c3d06d591c8408e31d7068c9e7c600f3c7e9e (patch)
treea251203a0eb3f8b926ef93e90003580add5e8d0b
parentf293cc4bc19409ac77287f0e7298801d55e42b11 (diff)
Added extra ACM interface for serial emulation using USART1.
-rw-r--r--src/stm32/cdcacm.c204
-rw-r--r--src/stm32/gdb_if.c2
-rw-r--r--src/stm32/platform.c44
-rw-r--r--src/stm32/platform.h2
4 files changed, 227 insertions, 25 deletions
diff --git a/src/stm32/cdcacm.c b/src/stm32/cdcacm.c
index b2fe1d1..82dd39c 100644
--- a/src/stm32/cdcacm.c
+++ b/src/stm32/cdcacm.c
@@ -32,6 +32,7 @@
#include <libopencm3/usb/cdc.h>
#include <libopencm3/stm32/scb.h>
#include <libopencm3/usb/dfu.h>
+#include <libopencm3/stm32/usart.h>
#include <stdlib.h>
#include "platform.h"
@@ -60,16 +61,16 @@ static const struct usb_device_descriptor dev = {
/* This notification endpoint isn't implemented. According to CDC spec its
* optional, but its absence causes a NULL pointer dereference in Linux cdc_acm
* driver. */
-static const struct usb_endpoint_descriptor comm_endp[] = {{
+static const struct usb_endpoint_descriptor gdb_comm_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x83,
+ .bEndpointAddress = 0x82,
.bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
.wMaxPacketSize = 16,
.bInterval = 255,
}};
-static const struct usb_endpoint_descriptor data_endp[] = {{
+static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = 0x01,
@@ -79,7 +80,7 @@ static const struct usb_endpoint_descriptor data_endp[] = {{
}, {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
+ .bEndpointAddress = 0x81,
.bmAttributes = USB_ENDPOINT_ATTR_BULK,
.wMaxPacketSize = 64,
.bInterval = 1,
@@ -90,7 +91,7 @@ static const struct {
struct usb_cdc_call_management_descriptor call_mgmt;
struct usb_cdc_acm_descriptor acm;
struct usb_cdc_union_descriptor cdc_union;
-} __attribute__((packed)) cdcacm_functional_descriptors = {
+} __attribute__((packed)) gdb_cdcacm_functional_descriptors = {
.header = {
.bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
.bDescriptorType = CS_INTERFACE,
@@ -120,7 +121,7 @@ static const struct {
}
};
-static const struct usb_interface_descriptor comm_iface[] = {{
+static const struct usb_interface_descriptor gdb_comm_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 0,
@@ -131,13 +132,13 @@ static const struct usb_interface_descriptor comm_iface[] = {{
.bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
.iInterface = 0,
- .endpoint = comm_endp,
+ .endpoint = gdb_comm_endp,
- .extra = &cdcacm_functional_descriptors,
- .extralen = sizeof(cdcacm_functional_descriptors)
+ .extra = &gdb_cdcacm_functional_descriptors,
+ .extralen = sizeof(gdb_cdcacm_functional_descriptors)
}};
-static const struct usb_interface_descriptor data_iface[] = {{
+static const struct usb_interface_descriptor gdb_data_iface[] = {{
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bInterfaceNumber = 1,
@@ -148,9 +149,103 @@ static const struct usb_interface_descriptor data_iface[] = {{
.bInterfaceProtocol = 0,
.iInterface = 0,
- .endpoint = data_endp,
+ .endpoint = gdb_data_endp,
+}};
+
+#ifdef INCLUDE_UART_INTERFACE
+/* Serial ACM interface */
+static const struct usb_endpoint_descriptor uart_comm_endp[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x84,
+ .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
+ .wMaxPacketSize = 16,
+ .bInterval = 255,
+}};
+
+static const struct usb_endpoint_descriptor uart_data_endp[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x03,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = 64,
+ .bInterval = 1,
+}, {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x83,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = 64,
+ .bInterval = 1,
}};
+static const struct {
+ struct usb_cdc_header_descriptor header;
+ struct usb_cdc_call_management_descriptor call_mgmt;
+ struct usb_cdc_acm_descriptor acm;
+ struct usb_cdc_union_descriptor cdc_union;
+} __attribute__((packed)) uart_cdcacm_functional_descriptors = {
+ .header = {
+ .bFunctionLength = sizeof(struct usb_cdc_header_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_HEADER,
+ .bcdCDC = 0x0110,
+ },
+ .call_mgmt = {
+ .bFunctionLength =
+ sizeof(struct usb_cdc_call_management_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_CALL_MANAGEMENT,
+ .bmCapabilities = 0,
+ .bDataInterface = 3,
+ },
+ .acm = {
+ .bFunctionLength = sizeof(struct usb_cdc_acm_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_ACM,
+ .bmCapabilities = 0,
+ },
+ .cdc_union = {
+ .bFunctionLength = sizeof(struct usb_cdc_union_descriptor),
+ .bDescriptorType = CS_INTERFACE,
+ .bDescriptorSubtype = USB_CDC_TYPE_UNION,
+ .bControlInterface = 2,
+ .bSubordinateInterface0 = 3,
+ }
+};
+
+static const struct usb_interface_descriptor uart_comm_iface[] = {{
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 2,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_CDC,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+ .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
+ .iInterface = 0,
+
+ .endpoint = uart_comm_endp,
+
+ .extra = &uart_cdcacm_functional_descriptors,
+ .extralen = sizeof(uart_cdcacm_functional_descriptors)
+}};
+
+static const struct usb_interface_descriptor uart_data_iface[] = {{
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 3,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = 0,
+
+ .endpoint = uart_data_endp,
+}};
+#endif
+
const struct usb_dfu_descriptor dfu_function = {
.bLength = sizeof(struct usb_dfu_descriptor),
.bDescriptorType = DFU_FUNCTIONAL,
@@ -163,7 +258,7 @@ const struct usb_dfu_descriptor dfu_function = {
const struct usb_interface_descriptor dfu_iface = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 2,
+ .bInterfaceNumber = 4,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = 0xFE,
@@ -177,11 +272,19 @@ const struct usb_interface_descriptor dfu_iface = {
static const struct usb_interface ifaces[] = {{
.num_altsetting = 1,
- .altsetting = comm_iface,
+ .altsetting = gdb_comm_iface,
+}, {
+ .num_altsetting = 1,
+ .altsetting = gdb_data_iface,
+}, {
+#ifdef INCLUDE_UART_INTERFACE
+ .num_altsetting = 1,
+ .altsetting = uart_comm_iface,
}, {
.num_altsetting = 1,
- .altsetting = data_iface,
+ .altsetting = uart_data_iface,
}, {
+#endif
.num_altsetting = 1,
.altsetting = &dfu_iface,
}};
@@ -190,7 +293,11 @@ static const struct usb_config_descriptor config = {
.bLength = USB_DT_CONFIGURATION_SIZE,
.bDescriptorType = USB_DT_CONFIGURATION,
.wTotalLength = 0,
+#ifdef INCLUDE_UART_INTERFACE
+ .bNumInterfaces = 5,
+#else
.bNumInterfaces = 3,
+#endif
.bConfigurationValue = 1,
.iConfiguration = 0,
.bmAttributes = 0x80,
@@ -228,8 +335,6 @@ static int cdcacm_control_request(struct usb_setup_data *req, uint8_t **buf,
uint16_t *len, void (**complete)(struct usb_setup_data *req))
{
(void)complete;
- (void)buf;
- (void)len;
switch(req->bRequest) {
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
@@ -237,8 +342,45 @@ static int cdcacm_control_request(struct usb_setup_data *req, uint8_t **buf,
* even though it's optional in the CDC spec, and we don't
* advertise it in the ACM functional descriptor. */
return 1;
+#ifdef INLCUDE_UART_INTERFACE
+ case USB_CDC_REQ_SET_LINE_CODING: {
+ if(*len < sizeof(struct usb_cdc_line_coding))
+ return 0;
+
+ if(req->wIndex != 2)
+ return 0;
+
+ struct usb_cdc_line_coding *coding = *buf;
+ usart_set_baudrate(USART1, coding->dwDTERate);
+ usart_set_databits(USART1, coding->bDataBits);
+ switch(coding->bCharFormat) {
+ case 0:
+ usart_set_stopbits(USART1, USART_STOPBITS_1);
+ break;
+ case 1:
+ usart_set_stopbits(USART1, USART_STOPBITS_1_5);
+ break;
+ case 2:
+ usart_set_stopbits(USART1, USART_STOPBITS_2);
+ break;
+ }
+ switch(coding->bParityType) {
+ case 0:
+ usart_set_parity(USART1, USART_PARITY_NONE);
+ break;
+ case 1:
+ usart_set_parity(USART1, USART_PARITY_ODD);
+ break;
+ case 2:
+ usart_set_parity(USART1, USART_PARITY_EVEN);
+ break;
+ }
+
+ return 1;
+ }
+#endif
case DFU_DETACH:
- if(req->wIndex == 2) {
+ if(req->wIndex == 4) {
*complete = dfu_detach_complete;
return 1;
}
@@ -252,13 +394,33 @@ int cdcacm_get_config(void)
return configured;
}
+#ifdef INCLUDE_UART_INTERFACE
+static void cdcacm_data_rx_cb(u8 ep)
+{
+ (void)ep;
+
+ char buf[64];
+ int len = usbd_ep_read_packet(0x03, buf, 64);
+ for(int i = 0; i < len; i++)
+ usart_send_blocking(USART1, buf[i]);
+}
+#endif
+
static void cdcacm_set_config(u16 wValue)
{
configured = wValue;
+ /* GDB interface */
usbd_ep_setup(0x01, USB_ENDPOINT_ATTR_BULK, 64, NULL);
- usbd_ep_setup(0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
- usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
+ usbd_ep_setup(0x81, USB_ENDPOINT_ATTR_BULK, 64, NULL);
+ usbd_ep_setup(0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
+
+#ifdef INCLUDE_UART_INTERFACE
+ /* Serial interface */
+ usbd_ep_setup(0x03, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
+ usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_BULK, 64, NULL);
+ usbd_ep_setup(0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
+#endif
usbd_register_control_callback(
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
@@ -266,11 +428,15 @@ static void cdcacm_set_config(u16 wValue)
cdcacm_control_request);
}
+/* We need a special large control buffer for this device: */
+uint8_t usbd_control_buffer[256];
+
void cdcacm_init(void)
{
get_dev_unique_id(serial_no);
usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings);
+ usbd_set_control_buffer_size(sizeof(usbd_control_buffer));
usbd_register_set_config_callback(cdcacm_set_config);
nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
diff --git a/src/stm32/gdb_if.c b/src/stm32/gdb_if.c
index 852b43f..c825707 100644
--- a/src/stm32/gdb_if.c
+++ b/src/stm32/gdb_if.c
@@ -39,7 +39,7 @@ void gdb_if_putchar(unsigned char c, int flush)
{
buffer_in[count_in++] = c;
if(flush || (count_in == VIRTUAL_COM_PORT_DATA_SIZE)) {
- while(usbd_ep_write_packet(2, buffer_in, count_in) <= 0);
+ while(usbd_ep_write_packet(1, buffer_in, count_in) <= 0);
count_in = 0;
}
}
diff --git a/src/stm32/platform.c b/src/stm32/platform.c
index 1760595..246daa9 100644
--- a/src/stm32/platform.c
+++ b/src/stm32/platform.c
@@ -27,8 +27,10 @@
#include <libopencm3/stm32/systick.h>
#include <libopencm3/stm32/scb.h>
#include <libopencm3/stm32/nvic.h>
+#include <libopencm3/stm32/usart.h>
#include "platform.h"
+#include "jtag_scan.h"
#include <ctype.h>
@@ -39,9 +41,9 @@ jmp_buf fatal_error_jmpbuf;
void morse(const char *msg, char repeat);
static void morse_update(void);
+static void uart_init(void);
-int
-platform_init(void)
+int platform_init(void)
{
#ifndef LIGHT
rcc_clock_setup_in_hse_8mhz_out_72mhz();
@@ -79,12 +81,12 @@ platform_init(void)
systick_interrupt_enable();
systick_counter_enable();
+#ifdef INCLUDE_UART_INTERFACE
+ uart_init();
+#endif
#ifndef LIGHT
SCB_VTOR = 0x2000; // Relocate interrupt vector table here
#endif
- /* Enable IRQs */
- nvic_enable_irq(NVIC_TIM2_IRQ);
-
cdcacm_init();
jtag_scan();
@@ -181,3 +183,35 @@ static void morse_update(void)
code >>= 1; bits--;
}
+#ifdef INCLUDE_UART_INTERFACE
+void uart_init(void)
+{
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_USART1EN);
+
+ /* UART1 TX to 'alternate function output push-pull' */
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO9);
+
+ /* Setup UART parameters. */
+ usart_set_baudrate(USART1, 38400);
+ usart_set_databits(USART1, 8);
+ usart_set_stopbits(USART1, USART_STOPBITS_1);
+ usart_set_mode(USART1, USART_MODE_TX_RX);
+ usart_set_parity(USART1, USART_PARITY_NONE);
+ usart_set_flow_control(USART1, USART_FLOWCONTROL_NONE);
+
+ /* Finally enable the USART. */
+ usart_enable(USART1);
+
+ /* Enable interrupts */
+ USART1_CR1 |= USART_CR1_RXNEIE;
+ nvic_enable_irq(NVIC_USART1_IRQ);
+}
+
+void usart1_isr(void)
+{
+ char c = usart_recv(USART1);
+
+ usbd_ep_write_packet(0x83, &c, 1);
+}
+#endif
diff --git a/src/stm32/platform.h b/src/stm32/platform.h
index 5249bdf..923e478 100644
--- a/src/stm32/platform.h
+++ b/src/stm32/platform.h
@@ -30,6 +30,8 @@
#include "gdb_packet.h"
+//#define INCLUDE_UART_INTERFACE
+
/* Important pin mappings for STM32 implementation:
*
* LED0 = PB2 (Yellow LED : Running)