aboutsummaryrefslogtreecommitdiff
path: root/examples/stm32/f1/lisa-m-1
diff options
context:
space:
mode:
Diffstat (limited to 'examples/stm32/f1/lisa-m-1')
-rw-r--r--examples/stm32/f1/lisa-m-1/can/Makefile25
-rw-r--r--examples/stm32/f1/lisa-m-1/can/can.c232
-rw-r--r--examples/stm32/f1/lisa-m-1/fancyblink/Makefile25
-rw-r--r--examples/stm32/f1/lisa-m-1/fancyblink/fancyblink.c68
-rw-r--r--examples/stm32/f1/lisa-m-1/lisa-m.ld32
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_cdcacm/Makefile25
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_cdcacm/README7
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c258
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm_test.py56
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_dfu/Makefile25
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_dfu/README7
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c259
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_hid/Makefile25
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_hid/README7
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_hid/adxl345.h38
-rw-r--r--examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c361
16 files changed, 1450 insertions, 0 deletions
diff --git a/examples/stm32/f1/lisa-m-1/can/Makefile b/examples/stm32/f1/lisa-m-1/can/Makefile
new file mode 100644
index 0000000..bf5aeb2
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/can/Makefile
@@ -0,0 +1,25 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BINARY = can
+
+LDSCRIPT = ../lisa-m.ld
+
+include ../../Makefile.include
+
diff --git a/examples/stm32/f1/lisa-m-1/can/can.c b/examples/stm32/f1/lisa-m-1/can/can.c
new file mode 100644
index 0000000..256e6f2
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/can/can.c
@@ -0,0 +1,232 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Thomas Otto <tommi@viadmin.org>
+ * Copyright (C) 2010 Piotr Esden-Tempski <piotr@esden.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/f1/rcc.h>
+#include <libopencm3/stm32/f1/flash.h>
+#include <libopencm3/stm32/f1/gpio.h>
+#include <libopencm3/stm32/nvic.h>
+#include <libopencm3/stm32/systick.h>
+#include <libopencm3/stm32/can.h>
+
+struct can_tx_msg {
+ u32 std_id;
+ u32 ext_id;
+ u8 ide;
+ u8 rtr;
+ u8 dlc;
+ u8 data[8];
+};
+
+struct can_rx_msg {
+ u32 std_id;
+ u32 ext_id;
+ u8 ide;
+ u8 rtr;
+ u8 dlc;
+ u8 data[8];
+ u8 fmi;
+};
+
+struct can_tx_msg can_tx_msg;
+struct can_rx_msg can_rx_msg;
+
+void gpio_setup(void)
+{
+ /* Enable Alternate Function clock. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
+
+ /* Enable GPIOA clock. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
+
+ /* Enable GPIOB clock. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
+
+ /* Enable GPIOC clock. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+
+ /* Preconfigure LEDs. */
+ gpio_set(GPIOA, GPIO8); /* LED0 off */
+ gpio_set(GPIOB, GPIO4); /* LED1 off */
+ gpio_set(GPIOC, GPIO15); /* LED2 off */
+ gpio_set(GPIOC, GPIO2); /* LED3 off */
+ gpio_set(GPIOC, GPIO5); /* LED4 off */
+
+ /* Configure LED GPIOOs. */
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO8);
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO4);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO5);
+
+ /* Configure PB4 as GPIO. */
+ AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST;
+
+}
+
+void systick_setup(void)
+{
+ /* 72MHz / 8 => 9000000 counts per second */
+ systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
+
+ /* 9000000/9000 = 1000 overflows per second - every 1ms one interrupt */
+ systick_set_reload(9000);
+
+ systick_interrupt_enable();
+
+ /* Start counting. */
+ systick_counter_enable();
+}
+
+void can_setup(void)
+{
+ /* Enable peripheral clocks. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_CANEN);
+
+ AFIO_MAPR = AFIO_MAPR_CAN1_REMAP_PORTB;
+
+ /* Configure CAN pin: RX (input pull-up). */
+ gpio_set_mode(GPIOB, GPIO_MODE_INPUT,
+ GPIO_CNF_INPUT_PULL_UPDOWN, GPIO_CAN1_PB_RX);
+ gpio_set(GPIOB, GPIO_CAN1_PB_RX);
+
+ /* Configure CAN pin: TX. */
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_CAN1_PB_TX);
+
+ /* NVIC setup. */
+ nvic_enable_irq(NVIC_USB_LP_CAN_RX0_IRQ);
+ nvic_set_priority(NVIC_USB_LP_CAN_RX0_IRQ, 1);
+
+ /* Reset CAN. */
+ can_reset(CAN1);
+
+ /* CAN cell init. */
+ if (can_init(CAN1,
+ false, /* TTCM: Time triggered comm mode? */
+ true, /* ABOM: Automatic bus-off management? */
+ false, /* AWUM: Automatic wakeup mode? */
+ false, /* NART: No automatic retransmission? */
+ false, /* RFLM: Receive FIFO locked mode? */
+ false, /* TXFP: Transmit FIFO priority? */
+ CAN_BTR_SJW_1TQ,
+ CAN_BTR_TS1_3TQ,
+ CAN_BTR_TS2_4TQ,
+ 12)) /* BRP+1: Baud rate prescaler */
+ {
+ gpio_set(GPIOA, GPIO8); /* LED0 off */
+ gpio_set(GPIOB, GPIO4); /* LED1 off */
+ gpio_set(GPIOC, GPIO15); /* LED2 off */
+ gpio_clear(GPIOC, GPIO2); /* LED3 on */
+ gpio_set(GPIOC, GPIO5); /* LED4 off */
+
+ /* Die because we failed to initialize. */
+ while (1)
+ __asm__("nop");
+ }
+
+ /* CAN filter 0 init. */
+ can_filter_id_mask_32bit_init(CAN1,
+ 0, /* Filter ID */
+ 0, /* CAN ID */
+ 0, /* CAN ID mask */
+ 0, /* FIFO assignment (here: FIFO0) */
+ true); /* Enable the filter. */
+
+ /* Enable CAN RX interrupt. */
+ can_enable_irq(CAN1, CAN_IER_FMPIE0);
+}
+
+void sys_tick_handler(void)
+{
+ static int temp32 = 0;
+ static u8 data[8] = {0, 1, 2, 0, 0, 0, 0, 0};
+
+ /* We call this handler every 1ms so 1000ms = 1s on/off. */
+ if (++temp32 != 1000)
+ return;
+
+ temp32 = 0;
+
+ /* Transmit CAN frame. */
+ data[0]++;
+ if (can_transmit(CAN1,
+ 0, /* (EX/ST)ID: CAN ID */
+ false, /* IDE: CAN ID extended? */
+ false, /* RTR: Request transmit? */
+ 8, /* DLC: Data length */
+ data) == -1)
+ {
+ gpio_set(GPIOA, GPIO8); /* LED0 off */
+ gpio_set(GPIOB, GPIO4); /* LED1 off */
+ gpio_set(GPIOC, GPIO15); /* LED2 off */
+ gpio_set(GPIOC, GPIO2); /* LED3 off */
+ gpio_clear(GPIOC, GPIO5); /* LED4 on */
+ }
+}
+
+void usb_lp_can_rx0_isr(void)
+{
+ u32 id, fmi;
+ bool ext, rtr;
+ u8 length, data[8];
+
+ can_receive(CAN1, 0, false, &id, &ext, &rtr, &fmi, &length, data);
+
+ if (data[0] & 1)
+ gpio_clear(GPIOA, GPIO8);
+ else
+ gpio_set(GPIOA, GPIO8);
+
+ if (data[0] & 2)
+ gpio_clear(GPIOB, GPIO4);
+ else
+ gpio_set(GPIOB, GPIO4);
+
+ if (data[0] & 4)
+ gpio_clear(GPIOC, GPIO15);
+ else
+ gpio_set(GPIOC, GPIO15);
+
+ if (data[0] & 8)
+ gpio_clear(GPIOC, GPIO2);
+ else
+ gpio_set(GPIOC, GPIO2);
+
+ can_fifo_release(CAN1, 0);
+}
+
+int main(void)
+{
+ rcc_clock_setup_in_hse_12mhz_out_72mhz();
+ gpio_setup();
+ can_setup();
+ systick_setup();
+
+ while (1); /* Halt. */
+
+ return 0;
+}
diff --git a/examples/stm32/f1/lisa-m-1/fancyblink/Makefile b/examples/stm32/f1/lisa-m-1/fancyblink/Makefile
new file mode 100644
index 0000000..52f5d95
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/fancyblink/Makefile
@@ -0,0 +1,25 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BINARY = fancyblink
+
+LDSCRIPT = ../lisa-m.ld
+
+include ../../Makefile.include
+
diff --git a/examples/stm32/f1/lisa-m-1/fancyblink/fancyblink.c b/examples/stm32/f1/lisa-m-1/fancyblink/fancyblink.c
new file mode 100644
index 0000000..9f4f7dc
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/fancyblink/fancyblink.c
@@ -0,0 +1,68 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ * Copyright (C) 2011 Piotr Esden-Tempski <piotr@esden.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <libopencm3/stm32/f1/rcc.h>
+#include <libopencm3/stm32/f1/gpio.h>
+
+/* Set STM32 to 72 MHz. */
+void clock_setup(void)
+{
+ rcc_clock_setup_in_hse_12mhz_out_72mhz();
+
+ /* Enable GPIOB, GPIOC, and AFIO clocks. */
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
+}
+
+void gpio_setup(void)
+{
+ /* Set GPIO13 (in GPIO port C) to 'output push-pull'. */
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO13);
+
+ /* Set GPIO4 (in GPIO port B) to 'output push-pull'. */
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO4);
+
+ AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_FULL_SWJ_NO_JNTRST;
+
+ /* Preconfigure the LEDs. */
+ gpio_set(GPIOB, GPIO4); /* Switch off LED. */
+ gpio_clear(GPIOC, GPIO13); /* Switch on LED. */
+}
+
+int main(void)
+{
+ int i;
+
+ clock_setup();
+ gpio_setup();
+
+ /* Blink the LEDs (PC13 and PB4) on the board. */
+ while (1) {
+ gpio_toggle(GPIOC, GPIO13); /* LED on/off */
+ gpio_toggle(GPIOB, GPIO4); /* LED on/off */
+ for (i = 0; i < 800000; i++) /* Wait a bit. */
+ __asm__("nop");
+ }
+
+ return 0;
+}
diff --git a/examples/stm32/f1/lisa-m-1/lisa-m.ld b/examples/stm32/f1/lisa-m-1/lisa-m.ld
new file mode 100644
index 0000000..726d34a
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/lisa-m.ld
@@ -0,0 +1,32 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* Linker script for Lisa-M (STM32F103RBT6, 128K flash, 20K RAM). */
+/* TODO: Chip name and sizes correct? */
+
+/* Define memory regions. */
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
+}
+
+/* Include the common ld script. */
+INCLUDE libopencm3_stm32f1.ld
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_cdcacm/Makefile b/examples/stm32/f1/lisa-m-1/usb_cdcacm/Makefile
new file mode 100644
index 0000000..a913f73
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_cdcacm/Makefile
@@ -0,0 +1,25 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BINARY = cdcacm
+
+LDSCRIPT = ../lisa-m.ld
+
+include ../../Makefile.include
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_cdcacm/README b/examples/stm32/f1/lisa-m-1/usb_cdcacm/README
new file mode 100644
index 0000000..2f1ee4b
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_cdcacm/README
@@ -0,0 +1,7 @@
+------------------------------------------------------------------------------
+README
+------------------------------------------------------------------------------
+
+This example implements a USB CDC-ACM device (aka Virtual Serial Port)
+to demonstrate the use of the USB device stack.
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c
new file mode 100644
index 0000000..d3dad52
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm.c
@@ -0,0 +1,258 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <libopencm3/stm32/f1/rcc.h>
+#include <libopencm3/stm32/f1/gpio.h>
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/cdc.h>
+
+static const struct usb_device_descriptor dev = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = USB_CLASS_CDC,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = 64,
+ .idVendor = 0x0483,
+ .idProduct = 0x5740,
+ .bcdDevice = 0x0200,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 3,
+ .bNumConfigurations = 1,
+};
+
+/*
+ * This notification endpoint isn't implemented. According to CDC spec it's
+ * optional, but its absence causes a NULL pointer dereference in the
+ * Linux cdc_acm driver.
+ */
+static const struct usb_endpoint_descriptor comm_endp[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x83,
+ .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
+ .wMaxPacketSize = 16,
+ .bInterval = 255,
+}};
+
+static const struct usb_endpoint_descriptor data_endp[] = {{
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x01,
+ .bmAttributes = USB_ENDPOINT_ATTR_BULK,
+ .wMaxPacketSize = 64,
+ .bInterval = 1,
+}, {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x82,
+ .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)) 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 = 1,
+ },
+ .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 = 0,
+ .bSubordinateInterface0 = 1,
+ }
+};
+
+static const struct usb_interface_descriptor comm_iface[] = {{
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_CDC,
+ .bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
+ .bInterfaceProtocol = USB_CDC_PROTOCOL_AT,
+ .iInterface = 0,
+
+ .endpoint = comm_endp,
+
+ .extra = &cdcacm_functional_descriptors,
+ .extralen = sizeof(cdcacm_functional_descriptors)
+}};
+
+static const struct usb_interface_descriptor data_iface[] = {{
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 2,
+ .bInterfaceClass = USB_CLASS_DATA,
+ .bInterfaceSubClass = 0,
+ .bInterfaceProtocol = 0,
+ .iInterface = 0,
+
+ .endpoint = data_endp,
+}};
+
+static const struct usb_interface ifaces[] = {{
+ .num_altsetting = 1,
+ .altsetting = comm_iface,
+}, {
+ .num_altsetting = 1,
+ .altsetting = data_iface,
+}};
+
+static const struct usb_config_descriptor config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE,
+ .bDescriptorType = USB_DT_CONFIGURATION,
+ .wTotalLength = 0,
+ .bNumInterfaces = 2,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = 0x80,
+ .bMaxPower = 0x32,
+
+ .interface = ifaces,
+};
+
+static const char *usb_strings[] = {
+ "x",
+ "Black Sphere Technologies",
+ "CDC-ACM Demo",
+ "DEMO",
+};
+
+static int cdcacm_control_request(struct usb_setup_data *req, u8 **buf,
+ u16 *len, void (**complete)(struct usb_setup_data *req))
+{
+ (void)complete;
+ (void)buf;
+
+ switch (req->bRequest) {
+ case USB_CDC_REQ_SET_CONTROL_LINE_STATE: {
+ /*
+ * This Linux cdc_acm driver requires this to be implemented
+ * even though it's optional in the CDC spec, and we don't
+ * advertise it in the ACM functional descriptor.
+ */
+ char buf[10];
+ struct usb_cdc_notification *notif = (void*)buf;
+
+ /* We echo signals back to host as notification. */
+ notif->bmRequestType = 0xA1;
+ notif->bNotification = USB_CDC_NOTIFY_SERIAL_STATE;
+ notif->wValue = 0;
+ notif->wIndex = 0;
+ notif->wLength = 2;
+ buf[8] = req->wValue & 3;
+ buf[9] = 0;
+ // usbd_ep_write_packet(0x83, buf, 10);
+ return 1;
+ }
+ case USB_CDC_REQ_SET_LINE_CODING:
+ if (*len < sizeof(struct usb_cdc_line_coding))
+ return 0;
+
+ return 1;
+ }
+ return 0;
+}
+
+static void cdcacm_data_rx_cb(u8 ep)
+{
+ (void)ep;
+
+ char buf[64];
+ int len = usbd_ep_read_packet(0x01, buf, 64);
+
+ if (len) {
+ while (usbd_ep_write_packet(0x82, buf, len) == 0)
+ ;
+ buf[len] = 0;
+ }
+
+ gpio_toggle(GPIOC, GPIO5);
+}
+
+static void cdcacm_set_config(u16 wValue)
+{
+ (void)wValue;
+
+ usbd_ep_setup(0x01, USB_ENDPOINT_ATTR_BULK, 64, cdcacm_data_rx_cb);
+ usbd_ep_setup(0x82, USB_ENDPOINT_ATTR_BULK, 64, NULL);
+ usbd_ep_setup(0x83, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
+
+ usbd_register_control_callback(
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ cdcacm_control_request);
+}
+
+int main(void)
+{
+ int i;
+
+ rcc_clock_setup_in_hsi_out_48mhz();
+
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+ rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN);
+
+ gpio_set(GPIOC, GPIO2);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2);
+ gpio_set(GPIOC, GPIO5);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO5);
+
+ usbd_init(&stm32f107_usb_driver, &dev, &config, usb_strings);
+ usbd_register_set_config_callback(cdcacm_set_config);
+
+ for (i = 0; i < 0x800000; i++)
+ __asm__("nop");
+ gpio_clear(GPIOC, GPIO2);
+
+ while (1)
+ usbd_poll();
+}
diff --git a/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm_test.py b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm_test.py
new file mode 100644
index 0000000..4694639
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_cdcacm/cdcacm_test.py
@@ -0,0 +1,56 @@
+#! /usr/bin/env python
+#
+# This file is part of the libopencm3 project.
+#
+# Copyright (C) 2011 Piotr Esden-Tempski <piotr@esden.net>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import serial
+import signal
+import sys
+import time
+
+def signal_handler(signal, frame):
+ print 'You pressed Ctrl+C!'
+ ser.close();
+ sys.exit(0)
+
+signal.signal(signal.SIGINT, signal_handler);
+
+ser = serial.Serial('/dev/cu.usbmodemDEM1', 115200, timeout=0.05);
+
+error = 0
+
+tim = time.time();
+
+cycles = 0
+
+while 1==1:
+
+ ser.write("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}");
+
+ buf = ser.read(1024);
+
+ cycles += 1
+
+ if buf != "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890!@#$%^&*(){}" :
+ error+=1
+
+ print "received " + buf + " errors: " + str(error) + " cycles: " + str(cycles) + " runtime: " + str(time.time() - tim)
+
+ #time.sleep(0.1);
+
+ser.close();
diff --git a/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile b/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile
new file mode 100644
index 0000000..88ca7e5
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_dfu/Makefile
@@ -0,0 +1,25 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BINARY = usbdfu
+
+LDSCRIPT = ../lisa-m.ld
+
+include ../../Makefile.include
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_dfu/README b/examples/stm32/f1/lisa-m-1/usb_dfu/README
new file mode 100644
index 0000000..9c0169a
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_dfu/README
@@ -0,0 +1,7 @@
+------------------------------------------------------------------------------
+README
+------------------------------------------------------------------------------
+
+This example implements a USB Device Firmware Upgrade (DFU) bootloader
+to demonstrate the use of the USB device stack.
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c b/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c
new file mode 100644
index 0000000..30e8b7e
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_dfu/usbdfu.c
@@ -0,0 +1,259 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <string.h>
+#include <libopencm3/stm32/f1/rcc.h>
+#include <libopencm3/stm32/f1/gpio.h>
+#include <libopencm3/stm32/f1/flash.h>
+#include <libopencm3/stm32/f1/scb.h>
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/dfu.h>
+
+#define APP_ADDRESS 0x08002000
+
+/* Commands sent with wBlockNum == 0 as per ST implementation. */
+#define CMD_SETADDR 0x21
+#define CMD_ERASE 0x41
+
+/* We need a special large control buffer for this device: */
+u8 usbd_control_buffer[1024];
+
+static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
+
+static struct {
+ u8 buf[sizeof(usbd_control_buffer)];
+ u16 len;
+ u32 addr;
+ u16 blocknum;
+} prog;
+
+const struct usb_device_descriptor dev = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = 64,
+ .idVendor = 0x0483,
+ .idProduct = 0xDF11,
+ .bcdDevice = 0x0200,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 3,
+ .bNumConfigurations = 1,
+};
+
+const struct usb_dfu_descriptor dfu_function = {
+ .bLength = sizeof(struct usb_dfu_descriptor),
+ .bDescriptorType = DFU_FUNCTIONAL,
+ .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
+ .wDetachTimeout = 255,
+ .wTransferSize = 1024,
+ .bcdDFUVersion = 0x011A,
+};
+
+const struct usb_interface_descriptor iface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = 0xFE, /* Device Firmware Upgrade */
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 2,
+
+ /* The ST Microelectronics DfuSe application needs this string.
+ * The format isn't documented... */
+ .iInterface = 4,
+
+ .extra = &dfu_function,
+ .extralen = sizeof(dfu_function),
+};
+
+const struct usb_interface ifaces[] = {{
+ .num_altsetting = 1,
+ .altsetting = &iface,
+}};
+
+const struct usb_config_descriptor config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE,
+ .bDescriptorType = USB_DT_CONFIGURATION,
+ .wTotalLength = 0,
+ .bNumInterfaces = 1,
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = 0xC0,
+ .bMaxPower = 0x32,
+
+ .interface = ifaces,
+};
+
+static const char *usb_strings[] = {
+ "x",
+ "Black Sphere Technologies",
+ "DFU Demo",
+ "DEMO",
+ /* This string is used by ST Microelectronics' DfuSe utility. */
+ "@Internal Flash /0x08000000/8*001Ka,56*001Kg",
+};
+
+static u8 usbdfu_getstatus(u32 *bwPollTimeout)
+{
+ switch (usbdfu_state) {
+ case STATE_DFU_DNLOAD_SYNC:
+ usbdfu_state = STATE_DFU_DNBUSY;
+ *bwPollTimeout = 100;
+ return DFU_STATUS_OK;
+ case STATE_DFU_MANIFEST_SYNC:
+ /* Device will reset when read is complete. */
+ usbdfu_state = STATE_DFU_MANIFEST;
+ return DFU_STATUS_OK;
+ default:
+ return DFU_STATUS_OK;
+ }
+}
+
+static void usbdfu_getstatus_complete(struct usb_setup_data *req)
+{
+ int i;
+ (void)req;
+
+ switch (usbdfu_state) {
+ case STATE_DFU_DNBUSY:
+ flash_unlock();
+ if (prog.blocknum == 0) {
+ switch (prog.buf[0]) {
+ case CMD_ERASE:
+ flash_erase_page(*(u32 *)(prog.buf + 1));
+ case CMD_SETADDR:
+ prog.addr = *(u32 *)(prog.buf + 1);
+ }
+ } else {
+ u32 baseaddr = prog.addr + ((prog.blocknum - 2) *
+ dfu_function.wTransferSize);
+ for (i = 0; i < prog.len; i += 2)
+ flash_program_half_word(baseaddr + i,
+ *(u16 *)(prog.buf + i));
+ }
+ flash_lock();
+
+ /* Jump straight to dfuDNLOAD-IDLE, skipping dfuDNLOAD-SYNC. */
+ usbdfu_state = STATE_DFU_DNLOAD_IDLE;
+ return;
+ case STATE_DFU_MANIFEST:
+ /* USB device must detach, we just reset... */
+ scb_reset_system();
+ return; /* Will never return. */
+ default:
+ return;
+ }
+}
+
+static int usbdfu_control_request(struct usb_setup_data *req, u8 **buf,
+ u16 *len, void (**complete)(struct usb_setup_data *req))
+{
+ if ((req->bmRequestType & 0x7F) != 0x21)
+ return 0; /* Only accept class request. */
+
+ switch (req->bRequest) {
+ case DFU_DNLOAD:
+ if ((len == NULL) || (*len == 0)) {
+ usbdfu_state = STATE_DFU_MANIFEST_SYNC;
+ return 1;
+ } else {
+ /* Copy download data for use on GET_STATUS. */
+ prog.blocknum = req->wValue;
+ prog.len = *len;
+ memcpy(prog.buf, *buf, *len);
+ usbdfu_state = STATE_DFU_DNLOAD_SYNC;
+ return 1;
+ }
+ case DFU_CLRSTATUS:
+ /* Clear error and return to dfuIDLE. */
+ if (usbdfu_state == STATE_DFU_ERROR)
+ usbdfu_state = STATE_DFU_IDLE;
+ return 1;
+ case DFU_ABORT:
+ /* Abort returns to dfuIDLE state. */
+ usbdfu_state = STATE_DFU_IDLE;
+ return 1;
+ case DFU_UPLOAD:
+ /* Upload not supported for now. */
+ return 0;
+ case DFU_GETSTATUS: {
+ u32 bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
+ (*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
+ (*buf)[1] = bwPollTimeout & 0xFF;
+ (*buf)[2] = (bwPollTimeout >> 8) & 0xFF;
+ (*buf)[3] = (bwPollTimeout >> 16) & 0xFF;
+ (*buf)[4] = usbdfu_state;
+ (*buf)[5] = 0; /* iString not used here */
+ *len = 6;
+ *complete = usbdfu_getstatus_complete;
+ return 1;
+ }
+ case DFU_GETSTATE:
+ /* Return state with no state transision. */
+ *buf[0] = usbdfu_state;
+ *len = 1;
+ return 1;
+ }
+
+ return 0;
+}
+
+int main(void)
+{
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
+
+ if (!gpio_get(GPIOA, GPIO10)) {
+ /* Boot the application if it's valid. */
+ if ((*(volatile u32 *)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
+ /* Set vector table base address. */
+ SCB_VTOR = APP_ADDRESS & 0xFFFF;
+ /* Initialise master stack pointer. */
+ asm volatile("msr msp, %0"::"g"
+ (*(volatile u32 *)APP_ADDRESS));
+ /* Jump to application. */
+ (*(void (**)())(APP_ADDRESS + 4))();
+ }
+ }
+
+ rcc_clock_setup_in_hsi_out_48mhz();
+
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+ rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN);
+
+ gpio_set(GPIOC, GPIO2);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_50_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2);
+
+ usbd_init(&stm32f107_usb_driver, &dev, &config, usb_strings);
+ usbd_set_control_buffer_size(sizeof(usbd_control_buffer));
+ usbd_register_control_callback(
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ usbdfu_control_request);
+
+ gpio_clear(GPIOC, GPIO2);
+
+ while (1)
+ usbd_poll();
+}
diff --git a/examples/stm32/f1/lisa-m-1/usb_hid/Makefile b/examples/stm32/f1/lisa-m-1/usb_hid/Makefile
new file mode 100644
index 0000000..15d3391
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_hid/Makefile
@@ -0,0 +1,25 @@
+##
+## This file is part of the libopencm3 project.
+##
+## Copyright (C) 2009 Uwe Hermann <uwe@hermann-uwe.de>
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program. If not, see <http://www.gnu.org/licenses/>.
+##
+
+BINARY = usbhid
+
+LDSCRIPT = ../lisa-m.ld
+
+include ../../Makefile.include
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_hid/README b/examples/stm32/f1/lisa-m-1/usb_hid/README
new file mode 100644
index 0000000..92645c9
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_hid/README
@@ -0,0 +1,7 @@
+------------------------------------------------------------------------------
+README
+------------------------------------------------------------------------------
+
+This example implements a USB Human Interface Device (HID)
+to demonstrate the use of the USB device stack.
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_hid/adxl345.h b/examples/stm32/f1/lisa-m-1/usb_hid/adxl345.h
new file mode 100644
index 0000000..a9720c4
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_hid/adxl345.h
@@ -0,0 +1,38 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ADXL345_H
+#define __ADXL345_H
+
+/* Register addresses */
+#define ADXL345_DEVID 0x00
+#define ADXL345_POWER_CTL 0x2D
+#define ADXL345_DATA_FORMAT 0x31
+#define ADXL345_DATAX0 0x32
+#define ADXL345_DATAX1 0x33
+#define ADXL345_DATAY0 0x34
+#define ADXL345_DATAY1 0x35
+#define ADXL345_DATAZ0 0x36
+#define ADXL345_DATAZ1 0x37
+
+#define ADXL345_POWER_CTL_MEASURE (1 << 3)
+#define ADXL345_DATA_FORMAT_LALIGN (1 << 2)
+
+#endif
+
diff --git a/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c b/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c
new file mode 100644
index 0000000..54c1538
--- /dev/null
+++ b/examples/stm32/f1/lisa-m-1/usb_hid/usbhid.c
@@ -0,0 +1,361 @@
+/*
+ * This file is part of the libopencm3 project.
+ *
+ * Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
+ * Copyright (C) 2011 Piotr Esden-Tempski <piotr@esden.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <libopencm3/stm32/f1/rcc.h>
+#include <libopencm3/stm32/f1/gpio.h>
+#include <libopencm3/stm32/systick.h>
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/otg_fs.h>
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/hid.h>
+#include "adxl345.h"
+
+/* Define this to include the DFU APP interface. */
+#define INCLUDE_DFU_INTERFACE
+
+#ifdef INCLUDE_DFU_INTERFACE
+#include <libopencm3/stm32/f1/scb.h>
+#include <libopencm3/usb/dfu.h>
+#endif
+
+const struct usb_device_descriptor dev = {
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = 64,
+ .idVendor = 0x0483,
+ .idProduct = 0x5710,
+ .bcdDevice = 0x0200,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 3,
+ .bNumConfigurations = 1,
+};
+
+/* I have no idea what this means. I haven't read the HID spec. */
+static const u8 hid_report_descriptor[] = {
+ 0x05, 0x01, 0x09, 0x02, 0xA1, 0x01, 0x09, 0x01,
+ 0xA1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+ 0x15, 0x00, 0x25, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x81, 0x02, 0x95, 0x01, 0x75, 0x05, 0x81, 0x01,
+ 0x05, 0x01, 0x09, 0x30, 0x09, 0x31, 0x09, 0x38,
+ 0x15, 0x81, 0x25, 0x7F, 0x75, 0x08, 0x95, 0x03,
+ 0x81, 0x06, 0xC0, 0x09, 0x3c, 0x05, 0xff, 0x09,
+ 0x01, 0x15, 0x00, 0x25, 0x01, 0x75, 0x01, 0x95,
+ 0x02, 0xb1, 0x22, 0x75, 0x06, 0x95, 0x01, 0xb1,
+ 0x01, 0xc0,
+};
+
+static const struct {
+ struct usb_hid_descriptor hid_descriptor;
+ struct {
+ u8 bReportDescriptorType;
+ u16 wDescriptorLength;
+ } __attribute__((packed)) hid_report;
+} __attribute__((packed)) hid_function = {
+ .hid_descriptor = {
+ .bLength = sizeof(hid_function),
+ .bDescriptorType = USB_DT_HID,
+ .bcdHID = 0x0100,
+ .bCountryCode = 0,
+ .bNumDescriptors = 1,
+ },
+ .hid_report = {
+ .bReportDescriptorType = USB_DT_REPORT,
+ .wDescriptorLength = sizeof(hid_report_descriptor),
+ }
+};
+
+const struct usb_endpoint_descriptor hid_endpoint = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 0x81,
+ .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
+ .wMaxPacketSize = 4,
+ .bInterval = 0x02,
+};
+
+const struct usb_interface_descriptor hid_iface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_HID,
+ .bInterfaceSubClass = 1, /* boot */
+ .bInterfaceProtocol = 2, /* mouse */
+ .iInterface = 0,
+
+ .endpoint = &hid_endpoint,
+
+ .extra = &hid_function,
+ .extralen = sizeof(hid_function),
+};
+
+#ifdef INCLUDE_DFU_INTERFACE
+const struct usb_dfu_descriptor dfu_function = {
+ .bLength = sizeof(struct usb_dfu_descriptor),
+ .bDescriptorType = DFU_FUNCTIONAL,
+ .bmAttributes = USB_DFU_CAN_DOWNLOAD | USB_DFU_WILL_DETACH,
+ .wDetachTimeout = 255,
+ .wTransferSize = 1024,
+ .bcdDFUVersion = 0x011A,
+};
+
+const struct usb_interface_descriptor dfu_iface = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 1,
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = 0xFE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = 0,
+
+ .extra = &dfu_function,
+ .extralen = sizeof(dfu_function),
+};
+#endif
+
+const struct usb_interface ifaces[] = {{
+ .num_altsetting = 1,
+ .altsetting = &hid_iface,
+#ifdef INCLUDE_DFU_INTERFACE
+}, {
+ .num_altsetting = 1,
+ .altsetting = &dfu_iface,
+#endif
+}};
+
+const struct usb_config_descriptor config = {
+ .bLength = USB_DT_CONFIGURATION_SIZE,
+ .bDescriptorType = USB_DT_CONFIGURATION,
+ .wTotalLength = 0,
+#ifdef INCLUDE_DFU_INTERFACE
+ .bNumInterfaces = 2,
+#else
+ .bNumInterfaces = 1,
+#endif
+ .bConfigurationValue = 1,
+ .iConfiguration = 0,
+ .bmAttributes = 0xC0,
+ .bMaxPower = 0x32,
+
+ .interface = ifaces,
+};
+
+static const char *usb_strings[] = {
+ "x",
+ "Black Sphere Technologies",
+ "HID Demo",
+ "DEMO",
+};
+
+static int hid_control_request(struct usb_setup_data *req, u8 **buf, u16 *len,
+ void (**complete)(struct usb_setup_data *req))
+{
+ (void)complete;
+
+ if((req->bmRequestType != 0x81) ||
+ (req->bRequest != USB_REQ_GET_DESCRIPTOR) ||
+ (req->wValue != 0x2200))
+ return 0;
+
+ /* Handle the HID report descriptor. */
+ *buf = (u8 *)hid_report_descriptor;
+ *len = sizeof(hid_report_descriptor);
+
+ return 1;
+}
+
+#ifdef INCLUDE_DFU_INTERFACE
+static void dfu_detach_complete(struct usb_setup_data *req)
+{
+ (void)req;
+
+ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15);
+ gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO10);
+ gpio_set(GPIOA, GPIO10);
+ scb_reset_core();
+}
+
+static int dfu_control_request(struct usb_setup_data *req, u8 **buf, u16 *len,
+ void (**complete)(struct usb_setup_data *req))
+{
+ (void)buf;
+ (void)len;
+
+ if ((req->bmRequestType != 0x21) || (req->bRequest != DFU_DETACH))
+ return 0; /* Only accept class request. */
+
+ *complete = dfu_detach_complete;
+
+ return 1;
+}
+#endif
+
+static void hid_set_config(u16 wValue)
+{
+ (void)wValue;
+
+ usbd_ep_setup(0x81, USB_ENDPOINT_ATTR_INTERRUPT, 4, NULL);
+
+ usbd_register_control_callback(
+ USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ hid_control_request);
+#ifdef INCLUDE_DFU_INTERFACE
+ usbd_register_control_callback(
+ USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
+ USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
+ dfu_control_request);
+#endif
+
+ systick_set_clocksource(STK_CTRL_CLKSOURCE_AHB_DIV8);
+ systick_set_reload(100000);
+ systick_interrupt_enable();
+ systick_counter_enable();
+}
+
+static u8 spi_readwrite(u32 spi, u8 data)
+{
+ while (SPI_SR(spi) & SPI_SR_BSY)
+ ;
+ SPI_DR(spi) = data;
+ while (!(SPI_SR(spi) & SPI_SR_RXNE))
+ ;
+ return SPI_DR(spi);
+}
+
+static u8 accel_read(u8 addr)
+{
+ u8 ret;
+ gpio_clear(GPIOB, GPIO12);
+ spi_readwrite(SPI2, addr | 0x80);
+ ret = spi_readwrite(SPI2, 0);
+ gpio_set(GPIOB, GPIO12);
+ return ret;
+}
+
+static void accel_write(u8 addr, u8 data)
+{
+ gpio_clear(GPIOB, GPIO12);
+ spi_readwrite(SPI2, addr);
+ spi_readwrite(SPI2, data);
+ gpio_set(GPIOB, GPIO12);
+}
+
+static void accel_get(s16 *x, s16 *y, s16 *z)
+{
+ if (x)
+ *x = accel_read(ADXL345_DATAX0) |
+ (accel_read(ADXL345_DATAX1) << 8);
+ if (y)
+ *y = accel_read(ADXL345_DATAY0) |
+ (accel_read(ADXL345_DATAY1) << 8);
+ if (z)
+ *z = accel_read(ADXL345_DATAZ0) |
+ (accel_read(ADXL345_DATAZ1) << 8);
+}
+
+int main(void)
+{
+ int i;
+
+ rcc_clock_setup_in_hse_12mhz_out_72mhz();
+
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPBEN);
+ rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPCEN);
+ rcc_peripheral_enable_clock(&RCC_APB1ENR, RCC_APB1ENR_SPI2EN);
+ rcc_peripheral_enable_clock(&RCC_AHBENR, RCC_AHBENR_OTGFSEN);
+
+ /* Configure SPI2: PB13(SCK), PB14(MISO), PB15(MOSI). */
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL,
+ GPIO_SPI2_SCK | GPIO_SPI2_MOSI);
+ gpio_set_mode(GPIOB, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT,
+ GPIO_SPI2_MISO);
+ /* Enable CS pin on PB12. */
+ gpio_set(GPIOB, GPIO12);
+ gpio_set_mode(GPIOB, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
+
+ /* Force to SPI mode. This should be default after reset! */
+ SPI2_I2SCFGR = 0;
+ spi_init_master(SPI2,
+ SPI_CR1_BAUDRATE_FPCLK_DIV_256,
+ SPI_CR1_CPOL_CLK_TO_1_WHEN_IDLE,
+ SPI_CR1_CPHA_CLK_TRANSITION_2,
+ SPI_CR1_DFF_8BIT,
+ SPI_CR1_MSBFIRST);
+ /* Ignore the stupid NSS pin. */
+ spi_enable_software_slave_management(SPI2);
+ spi_set_nss_high(SPI2);
+ spi_enable(SPI2);
+
+ (void)accel_read(ADXL345_DEVID);
+ accel_write(ADXL345_POWER_CTL, ADXL345_POWER_CTL_MEASURE);
+ accel_write(ADXL345_DATA_FORMAT, ADXL345_DATA_FORMAT_LALIGN);
+
+ /* USB_DETECT as input. */
+ gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO8);
+
+ /* Green LED off, as output. */
+ gpio_set(GPIOC, GPIO2);
+ gpio_set_mode(GPIOC, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO2);
+
+ usbd_init(&stm32f107_usb_driver, &dev, &config, usb_strings);
+ usbd_register_set_config_callback(hid_set_config);
+
+ /* Delay some seconds to show that pull-up switch works. */
+ for (i = 0; i < 0x800000; i++)
+ __asm__("nop");
+
+ /* Wait for USB Vbus. */
+ while (gpio_get(GPIOA, GPIO8) == 0)
+ __asm__("nop");
+
+ /* Green LED on, connect USB. */
+ gpio_clear(GPIOC, GPIO2);
+ // OTG_FS_GCCFG &= ~OTG_FS_GCCFG_VBUSBSEN;
+
+ while (1)
+ usbd_poll();
+}
+
+void sys_tick_handler(void)
+{
+ s16 x, y;
+ u8 buf[4] = {0, 0, 0, 0};
+
+ accel_get(&x, &y, NULL);
+ buf[1] = x >> 9;
+ buf[2] = y >> 9;
+
+ usbd_ep_write_packet(0x81, buf, 4);
+}