aboutsummaryrefslogtreecommitdiff
path: root/src/platforms/stm32
diff options
context:
space:
mode:
Diffstat (limited to 'src/platforms/stm32')
-rw-r--r--src/platforms/stm32/cdcacm.c575
-rw-r--r--src/platforms/stm32/dfu_f1.c25
-rw-r--r--src/platforms/stm32/dfu_f4.c39
-rw-r--r--src/platforms/stm32/dfucore.c121
-rw-r--r--src/platforms/stm32/gdb_if.c79
-rw-r--r--src/platforms/stm32/gpio.h71
-rw-r--r--src/platforms/stm32/jtagtap.c27
-rw-r--r--src/platforms/stm32/serialno.c45
-rw-r--r--src/platforms/stm32/swdptap.c8
-rw-r--r--src/platforms/stm32/timing.c66
-rw-r--r--src/platforms/stm32/timing.h27
-rw-r--r--src/platforms/stm32/traceswo.c6
-rw-r--r--src/platforms/stm32/usbdfu.h16
-rw-r--r--src/platforms/stm32/usbuart.c147
14 files changed, 514 insertions, 738 deletions
diff --git a/src/platforms/stm32/cdcacm.c b/src/platforms/stm32/cdcacm.c
deleted file mode 100644
index 93b0f33..0000000
--- a/src/platforms/stm32/cdcacm.c
+++ /dev/null
@@ -1,575 +0,0 @@
-/*
- * This file is part of the Black Magic Debug project.
- *
- * Copyright (C) 2011 Black Sphere Technologies Ltd.
- * Written by 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/>.
- */
-
-/* This file implements a the USB Communications Device Class - Abstract
- * Control Model (CDC-ACM) as defined in CDC PSTN subclass 1.2.
- * A Device Firmware Upgrade (DFU 1.1) class interface is provided for
- * field firmware upgrade.
- *
- * The device's unique id is used as the USB serial number string.
- */
-
-#include <libopencm3/cm3/nvic.h>
-#include <libopencm3/usb/usbd.h>
-#include <libopencm3/usb/cdc.h>
-#include <libopencm3/cm3/scb.h>
-#include <libopencm3/usb/dfu.h>
-#include <stdlib.h>
-
-#include "platform.h"
-#include "gdb_if.h"
-#if defined(PLATFORM_HAS_TRACESWO)
-#include <traceswo.h>
-#endif
-#include <usbuart.h>
-
-#define DFU_IF_NO 4
-
-usbd_device * usbdev;
-
-static char *get_dev_unique_id(char *serial_no);
-
-static int configured;
-static int cdcacm_gdb_dtr = 1;
-
-
-static const struct usb_device_descriptor dev = {
- .bLength = USB_DT_DEVICE_SIZE,
- .bDescriptorType = USB_DT_DEVICE,
- .bcdUSB = 0x0200,
- .bDeviceClass = 0xEF, /* Miscellaneous Device */
- .bDeviceSubClass = 2, /* Common Class */
- .bDeviceProtocol = 1, /* Interface Association */
- .bMaxPacketSize0 = 64,
- .idVendor = 0x1D50,
- .idProduct = 0x6018,
- .bcdDevice = 0x0100,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 3,
- .bNumConfigurations = 1,
-};
-
-/* 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 gdb_comm_endp[] = {{
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x82,
- .bmAttributes = USB_ENDPOINT_ATTR_INTERRUPT,
- .wMaxPacketSize = 16,
- .bInterval = 255,
-}};
-
-static const struct usb_endpoint_descriptor gdb_data_endp[] = {{
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x01,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CDCACM_PACKET_SIZE,
- .bInterval = 1,
-}, {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x81,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CDCACM_PACKET_SIZE,
- .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)) gdb_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 = 2, /* SET_LINE_CODING supported */
- },
- .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 gdb_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 = 4,
-
- .endpoint = gdb_comm_endp,
-
- .extra = &gdb_cdcacm_functional_descriptors,
- .extralen = sizeof(gdb_cdcacm_functional_descriptors)
-}};
-
-static const struct usb_interface_descriptor gdb_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 = gdb_data_endp,
-}};
-
-static const struct usb_iface_assoc_descriptor gdb_assoc = {
- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
- .bFirstInterface = 0,
- .bInterfaceCount = 2,
- .bFunctionClass = USB_CLASS_CDC,
- .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
- .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
- .iFunction = 0,
-};
-
-/* 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 = CDCACM_PACKET_SIZE,
- .bInterval = 1,
-}, {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x83,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = CDCACM_PACKET_SIZE,
- .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 = 2, /* SET_LINE_CODING supported*/
- },
- .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 = 5,
-
- .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,
-}};
-
-static const struct usb_iface_assoc_descriptor uart_assoc = {
- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
- .bFirstInterface = 2,
- .bInterfaceCount = 2,
- .bFunctionClass = USB_CLASS_CDC,
- .bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
- .bFunctionProtocol = USB_CDC_PROTOCOL_AT,
- .iFunction = 0,
-};
-
-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 = DFU_IF_NO,
- .bAlternateSetting = 0,
- .bNumEndpoints = 0,
- .bInterfaceClass = 0xFE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
- .iInterface = 6,
-
- .extra = &dfu_function,
- .extralen = sizeof(dfu_function),
-};
-
-static const struct usb_iface_assoc_descriptor dfu_assoc = {
- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
- .bFirstInterface = 4,
- .bInterfaceCount = 1,
- .bFunctionClass = 0xFE,
- .bFunctionSubClass = 1,
- .bFunctionProtocol = 1,
- .iFunction = 6,
-};
-
-#if defined(PLATFORM_HAS_TRACESWO)
-static const struct usb_endpoint_descriptor trace_endp[] = {{
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 0x85,
- .bmAttributes = USB_ENDPOINT_ATTR_BULK,
- .wMaxPacketSize = 64,
- .bInterval = 0,
-}};
-
-const struct usb_interface_descriptor trace_iface = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 5,
- .bAlternateSetting = 0,
- .bNumEndpoints = 1,
- .bInterfaceClass = 0xFF,
- .bInterfaceSubClass = 0xFF,
- .bInterfaceProtocol = 0xFF,
- .iInterface = 7,
-
- .endpoint = trace_endp,
-};
-
-static const struct usb_iface_assoc_descriptor trace_assoc = {
- .bLength = USB_DT_INTERFACE_ASSOCIATION_SIZE,
- .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
- .bFirstInterface = 5,
- .bInterfaceCount = 1,
- .bFunctionClass = 0xFF,
- .bFunctionSubClass = 0xFF,
- .bFunctionProtocol = 0xFF,
- .iFunction = 7,
-};
-#endif
-
-static const struct usb_interface ifaces[] = {{
- .num_altsetting = 1,
- .iface_assoc = &gdb_assoc,
- .altsetting = gdb_comm_iface,
-}, {
- .num_altsetting = 1,
- .altsetting = gdb_data_iface,
-}, {
- .num_altsetting = 1,
- .iface_assoc = &uart_assoc,
- .altsetting = uart_comm_iface,
-}, {
- .num_altsetting = 1,
- .altsetting = uart_data_iface,
-}, {
- .num_altsetting = 1,
- .iface_assoc = &dfu_assoc,
- .altsetting = &dfu_iface,
-#if defined(PLATFORM_HAS_TRACESWO)
-}, {
- .num_altsetting = 1,
- .iface_assoc = &trace_assoc,
- .altsetting = &trace_iface,
-#endif
-}};
-
-static const struct usb_config_descriptor config = {
- .bLength = USB_DT_CONFIGURATION_SIZE,
- .bDescriptorType = USB_DT_CONFIGURATION,
- .wTotalLength = 0,
-#if defined(PLATFORM_HAS_TRACESWO)
- .bNumInterfaces = 6,
-#else
- .bNumInterfaces = 5,
-#endif
- .bConfigurationValue = 1,
- .iConfiguration = 0,
- .bmAttributes = 0x80,
- .bMaxPower = 0x32,
-
- .interface = ifaces,
-};
-
-char serial_no[9];
-
-static const char *usb_strings[] = {
- "Black Sphere Technologies",
- BOARD_IDENT,
- serial_no,
- "Black Magic GDB Server",
- "Black Magic UART Port",
- DFU_IDENT,
-#if defined(PLATFORM_HAS_TRACESWO)
- "Black Magic Trace Capture",
-#endif
-};
-
-static void dfu_detach_complete(usbd_device *dev, struct usb_setup_data *req)
-{
- (void)dev;
- (void)req;
-
- /* Disconnect USB cable */
- disconnect_usb();
-
- /* Assert boot-request pin */
- assert_boot_pin();
-
- /* Reset core to enter bootloader */
- scb_reset_core();
-}
-
-static int cdcacm_control_request(usbd_device *dev,
- struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
- void (**complete)(usbd_device *dev, struct usb_setup_data *req))
-{
- (void)dev;
- (void)complete;
- (void)buf;
- (void)len;
-
- switch(req->bRequest) {
- case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
- /* Ignore if not for GDB interface */
- if(req->wIndex != 0)
- return 1;
-
- cdcacm_gdb_dtr = req->wValue & 1;
-
- return 1;
- case USB_CDC_REQ_SET_LINE_CODING:
- if(*len < sizeof(struct usb_cdc_line_coding))
- return 0;
-
- switch(req->wIndex) {
- case 2:
- usbuart_set_line_coding((struct usb_cdc_line_coding*)*buf);
- case 0:
- return 1; /* Ignore on GDB Port */
- default:
- return 0;
- }
- case DFU_GETSTATUS:
- if(req->wIndex == DFU_IF_NO) {
- (*buf)[0] = DFU_STATUS_OK;
- (*buf)[1] = 0;
- (*buf)[2] = 0;
- (*buf)[3] = 0;
- (*buf)[4] = STATE_APP_IDLE;
- (*buf)[5] = 0; /* iString not used here */
- *len = 6;
-
- return 1;
- }
- case DFU_DETACH:
- if(req->wIndex == DFU_IF_NO) {
- *complete = dfu_detach_complete;
- return 1;
- }
- return 0;
- }
- return 0;
-}
-
-int cdcacm_get_config(void)
-{
- return configured;
-}
-
-int cdcacm_get_dtr(void)
-{
- return cdcacm_gdb_dtr;
-}
-
-static void cdcacm_set_config(usbd_device *dev, u16 wValue)
-{
- configured = wValue;
-
- /* GDB interface */
- usbd_ep_setup(dev, 0x01, USB_ENDPOINT_ATTR_BULK,
- CDCACM_PACKET_SIZE, gdb_usb_out_cb);
- usbd_ep_setup(dev, 0x81, USB_ENDPOINT_ATTR_BULK,
- CDCACM_PACKET_SIZE, NULL);
- usbd_ep_setup(dev, 0x82, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
-
- /* Serial interface */
- usbd_ep_setup(dev, 0x03, USB_ENDPOINT_ATTR_BULK,
- CDCACM_PACKET_SIZE, usbuart_usb_out_cb);
- usbd_ep_setup(dev, 0x83, USB_ENDPOINT_ATTR_BULK,
- CDCACM_PACKET_SIZE, usbuart_usb_in_cb);
- usbd_ep_setup(dev, 0x84, USB_ENDPOINT_ATTR_INTERRUPT, 16, NULL);
-
-#if defined(PLATFORM_HAS_TRACESWO)
- /* Trace interface */
- usbd_ep_setup(dev, 0x85, USB_ENDPOINT_ATTR_BULK,
- 64, trace_buf_drain);
-#endif
-
- usbd_register_control_callback(dev,
- USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
- USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
- cdcacm_control_request);
-
- /* Notify the host that DCD is asserted.
- * Allows the use of /dev/tty* devices on *BSD/MacOS
- */
- 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] = 3; /* DCD | DSR */
- buf[9] = 0;
- usbd_ep_write_packet(dev, 0x82, buf, 10);
- notif->wIndex = 2;
- usbd_ep_write_packet(dev, 0x84, buf, 10);
-}
-
-/* We need a special large control buffer for this device: */
-uint8_t usbd_control_buffer[256];
-
-void cdcacm_init(void)
-{
- void exti15_10_isr(void);
-
- get_dev_unique_id(serial_no);
-
- usbdev = usbd_init(&USB_DRIVER, &dev, &config, usb_strings, sizeof(usb_strings)/sizeof(char *));
- usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer));
- usbd_register_set_config_callback(usbdev, cdcacm_set_config);
-
- nvic_set_priority(USB_IRQ, IRQ_PRI_USB);
- nvic_enable_irq(USB_IRQ);
- setup_vbus_irq();
-}
-
-void USB_ISR(void)
-{
- usbd_poll(usbdev);
-}
-
-static char *get_dev_unique_id(char *s)
-{
-#if defined(STM32F4)
- volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFF7A10;
-#else
- volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8;
-#endif
- uint32_t unique_id = *unique_id_p +
- *(unique_id_p + 1) +
- *(unique_id_p + 2);
- int i;
-
- /* Fetch serial number from chip's unique ID */
- for(i = 0; i < 8; i++) {
- s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
- }
- for(i = 0; i < 8; i++)
- if(s[i] > '9')
- s[i] += 'A' - '9' - 1;
- s[8] = 0;
-
- return s;
-}
diff --git a/src/platforms/stm32/dfu_f1.c b/src/platforms/stm32/dfu_f1.c
index 9d82bec..abbdbe6 100644
--- a/src/platforms/stm32/dfu_f1.c
+++ b/src/platforms/stm32/dfu_f1.c
@@ -16,11 +16,11 @@
* 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 "general.h"
+#include "usbdfu.h"
#include <libopencm3/stm32/f1/flash.h>
#include <libopencm3/cm3/scb.h>
-#include "usbdfu.h"
#define FLASH_OBP_RDP 0x1FFFF800
#define FLASH_OBP_WRP10 0x1FFFF808
@@ -48,7 +48,7 @@ void dfu_flash_program_buffer(uint32_t baseaddr, void *buf, int len)
{
for(int i = 0; i < len; i += 2)
flash_program_half_word(baseaddr + i,
- *(u16*)(buf+i));
+ *(uint16_t*)(buf+i));
}
uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum)
@@ -59,8 +59,10 @@ uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum)
return 100;
}
-void dfu_protect_enable(void)
+void dfu_protect(dfu_mode_t mode)
{
+ if (mode == DFU_MODE) {
+#ifdef DFU_SELF_PROTECT
if ((FLASH_WRPR & 0x03) != 0x00) {
flash_unlock();
FLASH_CR = 0;
@@ -70,19 +72,26 @@ void dfu_protect_enable(void)
/* MD Device: Protect 2 bits with (4 * 1k pages each)*/
flash_program_option_bytes(FLASH_OBP_WRP10, 0x03FC);
}
+#endif
+ }
+ else if (mode == UPD_MODE) {
+ flash_unlock();
+ FLASH_CR = 0;
+ flash_erase_option_bytes();
+ }
}
void dfu_jump_app_if_valid(void)
{
/* Boot the application if it's valid */
- if((*(volatile u32*)APP_ADDRESS & 0x2FFE0000) == 0x20000000) {
+ if((*(volatile uint32_t*)app_address & 0x2FFE0000) == 0x20000000) {
/* Set vector table base address */
- SCB_VTOR = APP_ADDRESS & 0x1FFFFF; /* Max 2 MByte Flash*/
+ SCB_VTOR = app_address & 0x1FFFFF; /* Max 2 MByte Flash*/
/* Initialise master stack pointer */
asm volatile ("msr msp, %0"::"g"
- (*(volatile u32*)APP_ADDRESS));
+ (*(volatile uint32_t*)app_address));
/* Jump to application */
- (*(void(**)())(APP_ADDRESS + 4))();
+ (*(void(**)())(app_address + 4))();
}
}
diff --git a/src/platforms/stm32/dfu_f4.c b/src/platforms/stm32/dfu_f4.c
index 4f47c99..2ececa0 100644
--- a/src/platforms/stm32/dfu_f4.c
+++ b/src/platforms/stm32/dfu_f4.c
@@ -16,6 +16,8 @@
* 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 "general.h"
+#include "usbdfu.h"
#if defined(STM32F2)
# include <libopencm3/stm32/f2/flash.h>
@@ -24,26 +26,28 @@
#endif
#include <libopencm3/cm3/scb.h>
-#include "usbdfu.h"
-
-static u32 sector_addr[] = {0x8000000, 0x8004000, 0x8008000, 0x800c000,
- 0x8010000, 0x8020000, 0x8040000, 0x8060000,
- 0x8080000, 0x80a0000, 0x80c0000, 0x80e0000,
- 0x8100000, 0};
-static u16 sector_erase_time[12]= {500, 500, 500, 500,
- 1100,
- 2600, 2600, 2600, 2600, 2600, 2600, 2600};
-static u8 sector_num = 0xff;
+static uint32_t sector_addr[] = {
+ 0x8000000, 0x8004000, 0x8008000, 0x800c000,
+ 0x8010000, 0x8020000, 0x8040000, 0x8060000,
+ 0x8080000, 0x80a0000, 0x80c0000, 0x80e0000,
+ 0x8100000, 0
+};
+static uint16_t sector_erase_time[12]= {
+ 500, 500, 500, 500,
+ 1100, 2600, 2600, 2600,
+ 2600, 2600, 2600, 2600
+};
+static uint8_t sector_num = 0xff;
/* Find the sector number for a given address*/
-static void get_sector_num(u32 addr)
+static void get_sector_num(uint32_t addr)
{
int i = 0;
while(sector_addr[i+1]) {
if (addr < sector_addr[i+1])
break;
i++;
- }
+ }
if (!sector_addr[i])
return;
sector_num = i;
@@ -59,9 +63,8 @@ void dfu_check_and_do_sector_erase(uint32_t addr)
void dfu_flash_program_buffer(uint32_t baseaddr, void *buf, int len)
{
for(int i = 0; i < len; i += 4)
- flash_program_word(baseaddr + i,
- *(u32*)(buf+i),
- FLASH_PROGRAM_X32);
+ flash_program_word(baseaddr + i, *(uint32_t*)(buf+i),
+ FLASH_PROGRAM_X32);
}
uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum)
@@ -80,10 +83,12 @@ uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum)
void dfu_protect_enable(void)
{
+#ifdef DFU_SELF_PROTECT
if ((FLASH_OPTCR & 0x10000) != 0) {
flash_program_option_bytes(FLASH_OPTCR & ~0x10000);
flash_lock_option_bytes();
}
+#endif
}
void dfu_jump_app_if_valid(void)
@@ -91,12 +96,12 @@ void dfu_jump_app_if_valid(void)
/* Boot the application if it's valid */
/* Vector table may be anywhere in 128 kByte RAM
CCM not handled*/
- if((*(volatile u32*)APP_ADDRESS & 0x2FFC0000) == 0x20000000) {
+ if((*(volatile uint32_t*)APP_ADDRESS & 0x2FFC0000) == 0x20000000) {
/* Set vector table base address */
SCB_VTOR = APP_ADDRESS & 0x1FFFFF; /* Max 2 MByte Flash*/
/* Initialise master stack pointer */
asm volatile ("msr msp, %0"::"g"
- (*(volatile u32*)APP_ADDRESS));
+ (*(volatile uint32_t*)APP_ADDRESS));
/* Jump to application */
(*(void(**)())(APP_ADDRESS + 4))();
}
diff --git a/src/platforms/stm32/dfucore.c b/src/platforms/stm32/dfucore.c
index c1d5cfd..7b733d7 100644
--- a/src/platforms/stm32/dfucore.c
+++ b/src/platforms/stm32/dfucore.c
@@ -17,7 +17,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include "platform.h"
+#include "general.h"
#include <string.h>
#if defined(STM32F1)
@@ -34,36 +34,36 @@
usbd_device *usbdev;
/* We need a special large control buffer for this device: */
-u8 usbd_control_buffer[1024];
+uint8_t usbd_control_buffer[1024];
-static u32 max_address;
+static uint32_t max_address;
static enum dfu_state usbdfu_state = STATE_DFU_IDLE;
static char *get_dev_unique_id(char *serial_no);
static struct {
- u8 buf[sizeof(usbd_control_buffer)];
- u16 len;
- u32 addr;
- u16 blocknum;
+ uint8_t buf[sizeof(usbd_control_buffer)];
+ uint16_t len;
+ uint32_t addr;
+ uint16_t 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 = 0x1D50,
- .idProduct = 0x6017,
- .bcdDevice = 0x0100,
- .iManufacturer = 1,
- .iProduct = 2,
- .iSerialNumber = 3,
- .bNumConfigurations = 1,
+ .bLength = USB_DT_DEVICE_SIZE,
+ .bDescriptorType = USB_DT_DEVICE,
+ .bcdUSB = 0x0200,
+ .bDeviceClass = 0,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
+ .bMaxPacketSize0 = 64,
+ .idVendor = 0x1D50,
+ .idProduct = 0x6017,
+ .bcdDevice = 0x0100,
+ .iManufacturer = 1,
+ .iProduct = 2,
+ .iSerialNumber = 3,
+ .bNumConfigurations = 1,
};
const struct usb_dfu_descriptor dfu_function = {
@@ -121,13 +121,27 @@ static const char *usb_strings[] = {
DFU_IFACE_STRING,
};
-static u8 usbdfu_getstatus(u32 *bwPollTimeout)
+static const char *usb_strings_upd[] = {
+ "Black Sphere Technologies",
+ BOARD_IDENT_UPD,
+ serial_no,
+ /* This string is used by ST Microelectronics' DfuSe utility */
+ UPD_IFACE_STRING,
+};
+
+static uint32_t get_le32(const void *vp)
+{
+ const uint8_t *p = vp;
+ return ((uint32_t)p[3] << 24) + ((uint32_t)p[2] << 16) + (p[1] << 8) + p[0];
+}
+
+static uint8_t usbdfu_getstatus(uint32_t *bwPollTimeout)
{
switch(usbdfu_state) {
case STATE_DFU_DNLOAD_SYNC:
usbdfu_state = STATE_DFU_DNBUSY;
*bwPollTimeout = dfu_poll_timeout(prog.buf[0],
- *(u32 *)(prog.buf + 1),
+ get_le32(prog.buf + 1),
prog.blocknum);
return DFU_STATUS_OK;
@@ -151,9 +165,8 @@ usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req)
flash_unlock();
if(prog.blocknum == 0) {
- u32 addr = *(u32 *)(prog.buf + 1);
- if (addr < APP_ADDRESS ||
- (addr >= max_address)) {
+ uint32_t addr = get_le32(prog.buf + 1);
+ if ((addr < app_address) || (addr >= max_address)) {
flash_lock();
usbd_ep_stall_set(dev, 0, 1);
return;
@@ -165,7 +178,7 @@ usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req)
prog.addr = addr;
}
} else {
- u32 baseaddr = prog.addr +
+ uint32_t baseaddr = prog.addr +
((prog.blocknum - 2) *
dfu_function.wTransferSize);
dfu_flash_program_buffer(baseaddr, prog.buf, prog.len);
@@ -187,7 +200,7 @@ usbdfu_getstatus_complete(usbd_device *dev, struct usb_setup_data *req)
}
static int usbdfu_control_request(usbd_device *dev,
- struct usb_setup_data *req, u8 **buf, u16 *len,
+ struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
void (**complete)(usbd_device *dev, struct usb_setup_data *req))
{
(void)dev;
@@ -221,7 +234,7 @@ static int usbdfu_control_request(usbd_device *dev,
/* Upload not supported for now */
return 0;
case DFU_GETSTATUS: {
- u32 bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
+ uint32_t bwPollTimeout = 0; /* 24-bit integer in DFU class spec */
(*buf)[0] = usbdfu_getstatus(&bwPollTimeout);
(*buf)[1] = bwPollTimeout & 0xFF;
@@ -245,12 +258,14 @@ static int usbdfu_control_request(usbd_device *dev,
return 0;
}
-void dfu_init(const usbd_driver *driver)
+void dfu_init(const usbd_driver *driver, dfu_mode_t mode)
{
get_dev_unique_id(serial_no);
- usbdev = usbd_init(driver, &dev, &config, usb_strings, 4);
- usbd_set_control_buffer_size(usbdev, sizeof(usbd_control_buffer));
+ usbdev = usbd_init(driver, &dev, &config,
+ (mode == DFU_MODE)?usb_strings:usb_strings_upd, 4,
+ usbd_control_buffer, sizeof(usbd_control_buffer));
+
usbd_register_control_callback(usbdev,
USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
@@ -266,34 +281,34 @@ void dfu_main(void)
static char *get_dev_unique_id(char *s)
{
#if defined(STM32F4) || defined(STM32F2)
-#define UNIQUE_SERIAL_R 0x1FFF7A10
-#define FLASH_SIZE_R 0x1fff7A22
+# define UNIQUE_SERIAL_R 0x1FFF7A10
+# define FLASH_SIZE_R 0x1fff7A22
#elif defined(STM32F3)
-#define UNIQUE_SERIAL_R 0x1FFFF7AC
-#define FLASH_SIZE_R 0x1fff77cc
+# define UNIQUE_SERIAL_R 0x1FFFF7AC
+# define FLASH_SIZE_R 0x1fff77cc
#elif defined(STM32L1)
-#define UNIQUE_SERIAL_R 0x1ff80050
-#define FLASH_SIZE_R 0x1FF8004C
+# define UNIQUE_SERIAL_R 0x1ff80050
+# define FLASH_SIZE_R 0x1FF8004C
#else
-#define UNIQUE_SERIAL_R 0x1FFFF7E8;
-#define FLASH_SIZE_R 0x1ffff7e0
+# define UNIQUE_SERIAL_R 0x1FFFF7E8;
+# define FLASH_SIZE_R 0x1ffff7e0
#endif
- volatile uint32_t *unique_id_p = (volatile uint32_t *)UNIQUE_SERIAL_R;
+ volatile uint32_t *unique_id_p = (volatile uint32_t *)UNIQUE_SERIAL_R;
uint32_t unique_id = *unique_id_p +
*(unique_id_p + 1) +
*(unique_id_p + 2);
- int i;
-
- /* Calculated the upper flash limit from the exported data
- in theparameter block*/
- max_address = (*(u32 *) FLASH_SIZE_R) <<10;
- /* Fetch serial number from chip's unique ID */
- for(i = 0; i < 8; i++) {
- s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
- }
- for(i = 0; i < 8; i++)
- if(s[i] > '9')
- s[i] += 'A' - '9' - 1;
+ int i;
+
+ /* Calculated the upper flash limit from the exported data
+ in theparameter block*/
+ max_address = (*(uint32_t *) FLASH_SIZE_R) <<10;
+ /* Fetch serial number from chip's unique ID */
+ for(i = 0; i < 8; i++) {
+ s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
+ }
+ for(i = 0; i < 8; i++)
+ if(s[i] > '9')
+ s[i] += 'A' - '9' - 1;
s[8] = 0;
return s;
diff --git a/src/platforms/stm32/gdb_if.c b/src/platforms/stm32/gdb_if.c
index 3ea7d14..52922e7 100644
--- a/src/platforms/stm32/gdb_if.c
+++ b/src/platforms/stm32/gdb_if.c
@@ -22,18 +22,19 @@
* Serial Debugging protocol is implemented. This implementation for STM32
* uses the USB CDC-ACM device bulk endpoints to implement the channel.
*/
-#include "platform.h"
-#include <libopencm3/usb/usbd.h>
-
+#include "general.h"
+#include "cdcacm.h"
#include "gdb_if.h"
static uint32_t count_out;
-static uint32_t count_new;
static uint32_t count_in;
static uint32_t out_ptr;
static uint8_t buffer_out[CDCACM_PACKET_SIZE];
-static uint8_t double_buffer_out[CDCACM_PACKET_SIZE];
static uint8_t buffer_in[CDCACM_PACKET_SIZE];
+#ifdef STM32F4
+static volatile uint32_t count_new;
+static uint8_t double_buffer_out[CDCACM_PACKET_SIZE];
+#endif
void gdb_if_putchar(unsigned char c, int flush)
{
@@ -47,37 +48,64 @@ void gdb_if_putchar(unsigned char c, int flush)
}
while(usbd_ep_write_packet(usbdev, CDCACM_GDB_ENDPOINT,
buffer_in, count_in) <= 0);
+
+ if (flush && (count_in == CDCACM_PACKET_SIZE)) {
+ /* We need to send an empty packet for some hosts
+ * to accept this as a complete transfer. */
+ /* libopencm3 needs a change for us to confirm when
+ * that transfer is complete, so we just send a packet
+ * containing a null byte for now.
+ */
+ while (usbd_ep_write_packet(usbdev, CDCACM_GDB_ENDPOINT,
+ "\0", 1) <= 0);
+ }
+
count_in = 0;
}
}
+#ifdef STM32F4
void gdb_usb_out_cb(usbd_device *dev, uint8_t ep)
{
(void)ep;
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 1);
- count_new = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT,
- double_buffer_out, CDCACM_PACKET_SIZE);
+ count_new = usbd_ep_read_packet(dev, CDCACM_GDB_ENDPOINT,
+ double_buffer_out, CDCACM_PACKET_SIZE);
if(!count_new) {
usbd_ep_nak_set(dev, CDCACM_GDB_ENDPOINT, 0);
}
}
+#endif
+
+static void gdb_if_update_buf(void)
+{
+ while (cdcacm_get_config() != 1);
+#ifdef STM32F4
+ asm volatile ("cpsid i; isb");
+ if (count_new) {
+ memcpy(buffer_out, double_buffer_out, count_new);
+ count_out = count_new;
+ count_new = 0;
+ out_ptr = 0;
+ usbd_ep_nak_set(usbdev, CDCACM_GDB_ENDPOINT, 0);
+ }
+ asm volatile ("cpsie i; isb");
+#else
+ count_out = usbd_ep_read_packet(usbdev, CDCACM_GDB_ENDPOINT,
+ buffer_out, CDCACM_PACKET_SIZE);
+ out_ptr = 0;
+#endif
+}
unsigned char gdb_if_getchar(void)
{
- while(!(out_ptr < count_out)) {
+ while (!(out_ptr < count_out)) {
/* Detach if port closed */
- if(!cdcacm_get_dtr())
+ if (!cdcacm_get_dtr())
return 0x04;
- while(cdcacm_get_config() != 1);
- if (count_new) {
- memcpy(buffer_out, double_buffer_out,count_new);
- count_out = count_new;
- count_new = 0;
- out_ptr = 0;
- usbd_ep_nak_set(usbdev, CDCACM_GDB_ENDPOINT, 0);
- }
+ gdb_if_update_buf();
}
return buffer_out[out_ptr++];
@@ -85,22 +113,15 @@ unsigned char gdb_if_getchar(void)
unsigned char gdb_if_getchar_to(int timeout)
{
- timeout_counter = timeout/100;
+ platform_timeout_set(timeout);
- if(!(out_ptr < count_out)) do {
+ if (!(out_ptr < count_out)) do {
/* Detach if port closed */
- if(!cdcacm_get_dtr())
+ if (!cdcacm_get_dtr())
return 0x04;
- while(cdcacm_get_config() != 1);
- if (count_new) {
- memcpy(buffer_out, double_buffer_out,count_new);
- count_out = count_new;
- count_new = 0;
- out_ptr = 0;
- usbd_ep_nak_set(usbdev, CDCACM_GDB_ENDPOINT, 0);
- }
- } while(timeout_counter && !(out_ptr < count_out));
+ gdb_if_update_buf();
+ } while (!platform_timeout_is_expired() && !(out_ptr < count_out));
if(out_ptr < count_out)
return gdb_if_getchar();
diff --git a/src/platforms/stm32/gpio.h b/src/platforms/stm32/gpio.h
new file mode 100644
index 0000000..d39fd4f
--- /dev/null
+++ b/src/platforms/stm32/gpio.h
@@ -0,0 +1,71 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by 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 __GPIO_H
+#define __GPIO_H
+
+#include <libopencm3/cm3/common.h>
+
+#ifndef STM32F4
+# include <libopencm3/stm32/f1/memorymap.h>
+# include <libopencm3/stm32/f1/gpio.h>
+#else
+# include <libopencm3/stm32/f4/memorymap.h>
+# include <libopencm3/stm32/f4/gpio.h>
+#endif
+
+#define INLINE_GPIO
+
+#define gpio_set_val(port, pin, val) do { \
+ if(val) \
+ gpio_set((port), (pin)); \
+ else \
+ gpio_clear((port), (pin)); \
+} while(0)
+
+#ifdef INLINE_GPIO
+static inline void _gpio_set(uint32_t gpioport, uint16_t gpios)
+{
+ GPIO_BSRR(gpioport) = gpios;
+#ifdef STM32F4
+ GPIO_BSRR(gpioport) = gpios;
+#endif
+}
+#define gpio_set _gpio_set
+
+static inline void _gpio_clear(uint32_t gpioport, uint16_t gpios)
+{
+#ifndef STM32F4
+ GPIO_BRR(gpioport) = gpios;
+#else
+ GPIO_BSRR(gpioport) = gpios<<16;
+ GPIO_BSRR(gpioport) = gpios<<16;
+#endif
+}
+#define gpio_clear _gpio_clear
+
+static inline uint16_t _gpio_get(uint32_t gpioport, uint16_t gpios)
+{
+ return (uint16_t)GPIO_IDR(gpioport) & gpios;
+}
+#define gpio_get _gpio_get
+#endif
+
+#endif
+
diff --git a/src/platforms/stm32/jtagtap.c b/src/platforms/stm32/jtagtap.c
index d6e298b..3c45a81 100644
--- a/src/platforms/stm32/jtagtap.c
+++ b/src/platforms/stm32/jtagtap.c
@@ -23,9 +23,7 @@
#include <stdio.h>
#include "general.h"
-
#include "jtagtap.h"
-#include "platform.h"
int jtagtap_init(void)
{
@@ -42,21 +40,26 @@ int jtagtap_init(void)
void jtagtap_reset(void)
{
#ifdef TRST_PORT
- volatile int i;
- gpio_clear(TRST_PORT, TRST_PIN);
- for(i = 0; i < 10000; i++) asm("nop");
- gpio_set(TRST_PORT, TRST_PIN);
+ if (platform_hwversion() == 0) {
+ volatile int i;
+ gpio_clear(TRST_PORT, TRST_PIN);
+ for(i = 0; i < 10000; i++) asm("nop");
+ gpio_set(TRST_PORT, TRST_PIN);
+ }
#endif
jtagtap_soft_reset();
}
-void jtagtap_srst(void)
+void jtagtap_srst(bool assert)
{
-#ifdef SRST_PORT
- volatile int i;
- gpio_set(SRST_PORT, SRST_PIN);
- for(i = 0; i < 10000; i++) asm("nop");
- gpio_clear(SRST_PORT, SRST_PIN);
+ (void)assert;
+#ifdef SRST_SET_VAL
+ SRST_SET_VAL(assert);
+ if(assert) {
+ int i;
+ for(i = 0; i < 10000; i++)
+ asm volatile("nop");
+ }
#endif
}
diff --git a/src/platforms/stm32/serialno.c b/src/platforms/stm32/serialno.c
new file mode 100644
index 0000000..ef28ed2
--- /dev/null
+++ b/src/platforms/stm32/serialno.c
@@ -0,0 +1,45 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 Black Sphere Technologies Ltd.
+ * Written by 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 "general.h"
+
+char *serialno_read(char *s)
+{
+#if defined(STM32F4)
+ volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFF7A10;
+#else
+ volatile uint32_t *unique_id_p = (volatile uint32_t *)0x1FFFF7E8;
+#endif
+ uint32_t unique_id = *unique_id_p +
+ *(unique_id_p + 1) +
+ *(unique_id_p + 2);
+ int i;
+
+ /* Fetch serial number from chip's unique ID */
+ for(i = 0; i < 8; i++) {
+ s[7-i] = ((unique_id >> (4*i)) & 0xF) + '0';
+ }
+ for(i = 0; i < 8; i++)
+ if(s[i] > '9')
+ s[i] += 'A' - '9' - 1;
+ s[8] = 0;
+
+ return s;
+}
+
diff --git a/src/platforms/stm32/swdptap.c b/src/platforms/stm32/swdptap.c
index 72fb0f9..e7049d3 100644
--- a/src/platforms/stm32/swdptap.c
+++ b/src/platforms/stm32/swdptap.c
@@ -73,9 +73,9 @@ int swdptap_init(void)
/* This must be investigated in more detail.
* As described in STM32 Reference Manual... */
swdptap_reset();
- swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
+ swdptap_seq_out(0xE79E, 16); /* 0b0111100111100111 */
swdptap_reset();
- swdptap_seq_out(0, 16);
+ swdptap_seq_out(0, 16);
return 0;
}
@@ -132,7 +132,7 @@ void swdptap_seq_out(uint32_t MS, int ticks)
while(ticks--) {
swdptap_bit_out(MS & 1);
- MS >>= 1;
+ MS >>= 1;
}
}
@@ -146,7 +146,7 @@ void swdptap_seq_out_parity(uint32_t MS, int ticks)
while(ticks--) {
swdptap_bit_out(MS & 1);
parity ^= MS;
- MS >>= 1;
+ MS >>= 1;
}
swdptap_bit_out(parity & 1);
}
diff --git a/src/platforms/stm32/timing.c b/src/platforms/stm32/timing.c
new file mode 100644
index 0000000..55a217a
--- /dev/null
+++ b/src/platforms/stm32/timing.c
@@ -0,0 +1,66 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 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 "general.h"
+#include "morse.h"
+
+#include <libopencm3/cm3/systick.h>
+#include <libopencm3/cm3/scb.h>
+
+uint8_t running_status;
+
+static volatile uint32_t timeout_counter;
+
+void platform_timing_init(void)
+{
+ /* Setup heartbeat timer */
+ systick_set_clocksource(STK_CSR_CLKSOURCE_AHB_DIV8);
+ systick_set_reload(900000); /* Interrupt us at 10 Hz */
+ SCB_SHPR(11) &= ~((15 << 4) & 0xff);
+ SCB_SHPR(11) |= ((14 << 4) & 0xff);
+ systick_interrupt_enable();
+ systick_counter_enable();
+}
+
+void platform_timeout_set(uint32_t ms)
+{
+ timeout_counter = ms / 100;
+}
+
+bool platform_timeout_is_expired(void)
+{
+ return timeout_counter == 0;
+}
+
+void platform_delay(uint32_t delay)
+{
+ platform_timeout_set(delay);
+ while (platform_timeout_is_expired());
+}
+
+void sys_tick_handler(void)
+{
+ if(running_status)
+ gpio_toggle(LED_PORT, LED_IDLE_RUN);
+
+ if(timeout_counter)
+ timeout_counter--;
+
+ SET_ERROR_STATE(morse_update());
+}
+
diff --git a/src/platforms/stm32/timing.h b/src/platforms/stm32/timing.h
new file mode 100644
index 0000000..0178ff5
--- /dev/null
+++ b/src/platforms/stm32/timing.h
@@ -0,0 +1,27 @@
+/*
+ * This file is part of the Black Magic Debug project.
+ *
+ * Copyright (C) 2015 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 __TIMING_H
+#define __TIMING_H
+
+extern uint8_t running_status;
+
+void platform_timing_init(void);
+
+#endif
+
diff --git a/src/platforms/stm32/traceswo.c b/src/platforms/stm32/traceswo.c
index 01ad728..a2e704d 100644
--- a/src/platforms/stm32/traceswo.c
+++ b/src/platforms/stm32/traceswo.c
@@ -32,16 +32,12 @@
* The core can then process the buffer to extract the frame.
*/
#include "general.h"
+#include "cdcacm.h"
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/stm32/timer.h>
#include <libopencm3/stm32/f1/rcc.h>
-#include <libopencm3/usb/usbd.h>
-
-#include <string.h>
-#include "platform.h"
-
void traceswo_init(void)
{
TRACE_TIM_CLK_EN();
diff --git a/src/platforms/stm32/usbdfu.h b/src/platforms/stm32/usbdfu.h
index d331ca4..e460082 100644
--- a/src/platforms/stm32/usbdfu.h
+++ b/src/platforms/stm32/usbdfu.h
@@ -19,25 +19,25 @@
#include <libopencm3/usb/usbd.h>
-#ifdef STM32F4
-# define APP_ADDRESS 0x08010000
-#else
-# define APP_ADDRESS 0x08002000
-#endif
-
/* Commands sent with wBlockNum == 0 as per ST implementation. */
#define CMD_SETADDR 0x21
#define CMD_ERASE 0x41
+extern uint32_t app_address;
+
+typedef enum {
+ DFU_MODE = 0,
+ UPD_MODE = 1
+} dfu_mode_t;
/* dfucore.c - DFU core, common to libopencm3 platforms. */
-void dfu_init(const usbd_driver *driver);
+void dfu_init(const usbd_driver *driver, dfu_mode_t mode);
void dfu_main(void);
/* Device specific functions */
void dfu_check_and_do_sector_erase(uint32_t sector);
void dfu_flash_program_buffer(uint32_t baseaddr, void *buf, int len);
uint32_t dfu_poll_timeout(uint8_t cmd, uint32_t addr, uint16_t blocknum);
-void dfu_protect_enable(void);
+void dfu_protect(dfu_mode_t mode);
void dfu_jump_app_if_valid(void);
/* Platform specific function */
diff --git a/src/platforms/stm32/usbuart.c b/src/platforms/stm32/usbuart.c
index 1c71105..cce2904 100644
--- a/src/platforms/stm32/usbuart.c
+++ b/src/platforms/stm32/usbuart.c
@@ -21,12 +21,28 @@
#include <libopencm3/stm32/rcc.h>
#include <libopencm3/stm32/gpio.h>
#include <libopencm3/stm32/usart.h>
+#include <libopencm3/stm32/timer.h>
#include <libopencm3/cm3/nvic.h>
#include <libopencm3/cm3/scs.h>
#include <libopencm3/usb/usbd.h>
#include <libopencm3/usb/cdc.h>
-#include <platform.h>
+#include "general.h"
+#include "cdcacm.h"
+
+#define USBUART_TIMER_FREQ_HZ 1000000U /* 1us per tick */
+#define USBUART_RUN_FREQ_HZ 5000U /* 200us (or 100 characters at 2Mbps) */
+
+#define FIFO_SIZE 128
+
+/* RX Fifo buffer */
+static uint8_t buf_rx[FIFO_SIZE];
+/* Fifo in pointer, writes assumed to be atomic, should be only incremented within RX ISR */
+static uint8_t buf_rx_in;
+/* Fifo out pointer, writes assumed to be atomic, should be only incremented outside RX ISR */
+static uint8_t buf_rx_out;
+
+static void usbuart_run(void);
void usbuart_init(void)
{
@@ -37,7 +53,7 @@ void usbuart_init(void)
return;
#endif
- rcc_peripheral_enable_clock(&USBUSART_APB_ENR, USBUSART_CLK_ENABLE);
+ rcc_periph_clock_enable(USBUSART_CLK);
UART_PIN_SETUP();
@@ -56,12 +72,79 @@ void usbuart_init(void)
USBUSART_CR1 |= USART_CR1_RXNEIE;
nvic_set_priority(USBUSART_IRQ, IRQ_PRI_USBUSART);
nvic_enable_irq(USBUSART_IRQ);
+
+ /* Setup timer for running deferred FIFO processing */
+ USBUSART_TIM_CLK_EN();
+ timer_reset(USBUSART_TIM);
+ timer_set_mode(USBUSART_TIM, TIM_CR1_CKD_CK_INT,
+ TIM_CR1_CMS_EDGE, TIM_CR1_DIR_UP);
+ timer_set_prescaler(USBUSART_TIM,
+ rcc_ppre2_frequency / USBUART_TIMER_FREQ_HZ * 2 - 1);
+ timer_set_period(USBUSART_TIM,
+ USBUART_TIMER_FREQ_HZ / USBUART_RUN_FREQ_HZ - 1);
+
+ /* Setup update interrupt in NVIC */
+ nvic_set_priority(USBUSART_TIM_IRQ, IRQ_PRI_USBUSART_TIM);
+ nvic_enable_irq(USBUSART_TIM_IRQ);
+
+ /* turn the timer on */
+ timer_enable_counter(USBUSART_TIM);
+}
+
+/*
+ * Runs deferred processing for usb uart rx, draining RX FIFO by sending
+ * characters to host PC via CDCACM. Allowed to read from FIFO in pointer,
+ * but not write to it. Allowed to write to FIFO out pointer.
+ */
+static void usbuart_run(void)
+{
+ /* forcibly empty fifo if no USB endpoint */
+ if (cdcacm_get_config() != 1)
+ {
+ buf_rx_out = buf_rx_in;
+ }
+
+ /* if fifo empty, nothing further to do */
+ if (buf_rx_in == buf_rx_out) {
+ /* turn off LED, disable IRQ */
+ timer_disable_irq(USBUSART_TIM, TIM_DIER_UIE);
+ gpio_clear(LED_PORT_UART, LED_UART);
+ }
+ else
+ {
+ uint8_t packet_buf[CDCACM_PACKET_SIZE];
+ uint8_t packet_size = 0;
+ uint8_t buf_out = buf_rx_out;
+
+ /* copy from uart FIFO into local usb packet buffer */
+ while (buf_rx_in != buf_out && packet_size < CDCACM_PACKET_SIZE)
+ {
+ packet_buf[packet_size++] = buf_rx[buf_out++];
+
+ /* wrap out pointer */
+ if (buf_out >= FIFO_SIZE)
+ {
+ buf_out = 0;
+ }
+
+ }
+
+ /* advance fifo out pointer by amount written */
+ buf_rx_out += usbd_ep_write_packet(usbdev,
+ CDCACM_UART_ENDPOINT, packet_buf, packet_size);
+ buf_rx_out %= FIFO_SIZE;
+ }
}
void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
{
usart_set_baudrate(USBUSART, coding->dwDTERate);
- usart_set_databits(USBUSART, coding->bDataBits);
+
+ if (coding->bParityType)
+ usart_set_databits(USBUSART, coding->bDataBits + 1);
+ else
+ usart_set_databits(USBUSART, coding->bDataBits);
+
switch(coding->bCharFormat) {
case 0:
usart_set_stopbits(USBUSART, USART_STOPBITS_1);
@@ -73,6 +156,7 @@ void usbuart_set_line_coding(struct usb_cdc_line_coding *coding)
usart_set_stopbits(USBUSART, USART_STOPBITS_2);
break;
}
+
switch(coding->bParityType) {
case 0:
usart_set_parity(USBUSART, USART_PARITY_NONE);
@@ -108,41 +192,50 @@ void usbuart_usb_out_cb(usbd_device *dev, uint8_t ep)
gpio_clear(LED_PORT_UART, LED_UART);
}
-static uint8_t uart_usb_buf[CDCACM_PACKET_SIZE];
-static uint8_t uart_usb_buf_size;
void usbuart_usb_in_cb(usbd_device *dev, uint8_t ep)
{
- if (!uart_usb_buf_size) {
- gpio_clear(LED_PORT_UART, LED_UART);
- return;
- }
-
- usbd_ep_write_packet(dev, ep, uart_usb_buf, uart_usb_buf_size);
- uart_usb_buf_size = 0;
+ (void) dev;
+ (void) ep;
}
+/*
+ * Read a character from the UART RX and stuff it in a software FIFO.
+ * Allowed to read from FIFO out pointer, but not write to it.
+ * Allowed to write to FIFO in pointer.
+ */
void USBUSART_ISR(void)
{
char c = usart_recv(USBUSART);
- /* Don't try to write until we are configured.
- * Otherwise enumeration hanged in some cases.
- */
- if (cdcacm_get_config() != 1)
- return;
-
+ /* Turn on LED */
gpio_set(LED_PORT_UART, LED_UART);
- /* Try to send now */
- if (usbd_ep_write_packet(usbdev, CDCACM_UART_ENDPOINT, &c, 1) == 1)
- return;
-
- /* We failed, so queue for later */
- if (uart_usb_buf_size == CDCACM_PACKET_SIZE) {
- /* Drop if the buffer's full: we have no flow control */
- return;
+ /* If the next increment of rx_in would put it at the same point
+ * as rx_out, the FIFO is considered full.
+ */
+ if (((buf_rx_in + 1) % FIFO_SIZE) != buf_rx_out)
+ {
+ /* insert into FIFO */
+ buf_rx[buf_rx_in++] = c;
+
+ /* wrap out pointer */
+ if (buf_rx_in >= FIFO_SIZE)
+ {
+ buf_rx_in = 0;
+ }
+
+ /* enable deferred processing if we put data in the FIFO */
+ timer_enable_irq(USBUSART_TIM, TIM_DIER_UIE);
}
+}
+
+void USBUSART_TIM_ISR(void)
+{
+ /* need to clear timer update event */
+ timer_clear_flag(USBUSART_TIM, TIM_SR_UIF);
- uart_usb_buf[uart_usb_buf_size++] = c;
+ /* process FIFO */
+ usbuart_run();
}
+