these register definitions are common to all cortex mcus. some of the registers might not be implemented everywhere (especially the floating point registers), but defining them does no harm. this modification does not result in any changes in the example binaries.
275 lines
6.8 KiB
C
275 lines
6.8 KiB
C
/*
|
|
* This file is part of the libopencm3 project.
|
|
*
|
|
* Copyright (C) 2010 Gareth McMullin <gareth@blacksphere.co.nz>
|
|
*
|
|
* This library is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This library 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 Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* along with this library. 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/usb/usbd.h>
|
|
#include <libopencm3/usb/hid.h>
|
|
|
|
/* Define this to include the DFU APP interface. */
|
|
#define INCLUDE_DFU_INTERFACE
|
|
|
|
#ifdef INCLUDE_DFU_INTERFACE
|
|
#include <libopencm3/cm3/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 = 0x20,
|
|
};
|
|
|
|
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();
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
rcc_clock_setup_in_hsi_out_48mhz();
|
|
|
|
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_IOPAEN);
|
|
rcc_peripheral_enable_clock(&RCC_APB2ENR, RCC_APB2ENR_AFIOEN);
|
|
|
|
AFIO_MAPR |= AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON;
|
|
gpio_set_mode(GPIOA, GPIO_MODE_INPUT, 0, GPIO15);
|
|
|
|
usbd_init(&stm32f103_usb_driver, &dev, &config, usb_strings);
|
|
usbd_register_set_config_callback(hid_set_config);
|
|
|
|
gpio_set(GPIOA, GPIO15);
|
|
gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_2_MHZ,
|
|
GPIO_CNF_OUTPUT_PUSHPULL, GPIO15);
|
|
|
|
while (1)
|
|
usbd_poll();
|
|
}
|
|
|
|
void sys_tick_handler(void)
|
|
{
|
|
static int x = 0;
|
|
static int dir = 1;
|
|
u8 buf[4] = {0, 0, 0, 0};
|
|
|
|
buf[1] = dir;
|
|
x += dir;
|
|
if (x > 30)
|
|
dir = -dir;
|
|
if (x < -30)
|
|
dir = -dir;
|
|
|
|
usbd_ep_write_packet(0x81, buf, 4);
|
|
}
|