Added unfinished, untested upgrade tool.

This commit is contained in:
Gareth McMullin 2012-01-18 20:45:18 +13:00
parent a7f14e3cc0
commit f2f5fd2fa1
8 changed files with 605 additions and 0 deletions

22
upgrade/Makefile Normal file
View File

@ -0,0 +1,22 @@
CC = $(CROSS_COMPILE)gcc
CFLAGS = -Wall -Wextra -std=gnu99 -O0 -g -MD
LDFLAGS = -lusb
OBJ = bindata.o \
dfu.o \
stm32mem.o \
main.o
all: bmp_upgrade
bmp_upgrade: $(OBJ)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
.PHONY: clean
clean:
-rm -rf bmp_upgrade *.d *.o
-include *.d

28
upgrade/bindata.S Normal file
View File

@ -0,0 +1,28 @@
/*
* 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/>.
*/
.section .rodata
.global _bindata, _bindatalen
_bindata:
.incbin "../src/blackmagic.bin"
_bindatalen:
.word . - _bindata

32
upgrade/bindata.h Normal file
View File

@ -0,0 +1,32 @@
/*
* 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/>.
*/
#ifndef __BINDATA_H
#define __BINDATA_H
#ifndef WIN32
#define bindatalen _bindatalen
#define bindata _bindata
#endif
extern const uint32_t bindatalen;
extern const uint8_t bindata[];
#endif

150
upgrade/dfu.c Normal file
View File

@ -0,0 +1,150 @@
/*
* 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/>.
*/
#include <usb.h>
#include "dfu.h"
/* DFU Requests: Refer to Table 3.2 */
#define DFU_DETACH 0x00
#define DFU_DNLOAD 0x01
#define DFU_UPLOAD 0x02
#define DFU_GETSTATUS 0x03
#define DFU_CLRSTATUS 0x04
#define DFU_GETSTATE 0x05
#define DFU_ABORT 0x06
#define USB_DEFAULT_TIMEOUT 1000
#define DFU_DETACH_TIMEOUT 1000
int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout)
{
return usb_control_msg(dev,
USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_DETACH, wTimeout, iface, NULL, 0,
USB_DEFAULT_TIMEOUT);
}
int dfu_dnload(usb_dev_handle *dev, uint16_t iface,
uint16_t wBlockNum, void *data, uint16_t size)
{
return usb_control_msg(dev,
USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_DNLOAD, wBlockNum, iface, data, size,
USB_DEFAULT_TIMEOUT);
}
int dfu_upload(usb_dev_handle *dev, uint16_t iface,
uint16_t wBlockNum, void *data, uint16_t size)
{
return usb_control_msg(dev,
USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_DNLOAD, wBlockNum, iface, data, size,
USB_DEFAULT_TIMEOUT);
}
int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status)
{
return usb_control_msg(dev,
USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_GETSTATUS, 0, iface, (void*)status, sizeof(dfu_status),
USB_DEFAULT_TIMEOUT);
}
int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface)
{
return usb_control_msg(dev,
USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_CLRSTATUS, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT);
}
int dfu_getstate(usb_dev_handle *dev, uint16_t iface)
{
int i;
uint8_t state;
do {
i = usb_control_msg(dev,
USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_GETSTATE, 0, iface, &state, 1, USB_DEFAULT_TIMEOUT);
} while(i == 0);
if(i > 0)
return state;
else
return i;
}
int dfu_abort(usb_dev_handle *dev, uint16_t iface)
{
return usb_control_msg(dev,
USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
DFU_ABORT, 0, iface, NULL, 0, USB_DEFAULT_TIMEOUT);
}
int dfu_makeidle(usb_dev_handle *dev, uint16_t iface)
{
int i;
dfu_status status;
for(i = 0; i < 3; i++) {
if(dfu_getstatus(dev, iface, &status) < 0) {
dfu_clrstatus(dev, iface);
continue;
}
i--;
switch(status.bState) {
case STATE_DFU_IDLE:
return 0;
case STATE_DFU_DOWNLOAD_SYNC:
case STATE_DFU_DOWNLOAD_IDLE:
case STATE_DFU_MANIFEST_SYNC:
case STATE_DFU_UPLOAD_IDLE:
case STATE_DFU_DOWNLOAD_BUSY:
case STATE_DFU_MANIFEST:
dfu_abort(dev, iface);
continue;
case STATE_DFU_ERROR:
dfu_clrstatus(dev, iface);
continue;
case STATE_APP_IDLE:
dfu_detach(dev, iface, DFU_DETACH_TIMEOUT);
continue;
case STATE_APP_DETACH:
case STATE_DFU_MANIFEST_WAIT_RESET:
usb_reset(dev);
return -1;
default:
return -1;
}
}
return -1;
}

86
upgrade/dfu.h Normal file
View File

@ -0,0 +1,86 @@
/*
* 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/>.
*/
#ifndef __DFU_H
#define __DFU_H
#include <stdint.h>
#include <usb.h>
/* DFU states as returned by DFU_GETSTATE and DFU_GETSTATUS request in bState field.
* Refer to Section 6.1.2
* Refer to Figure A.1 for state diagram
*/
#define STATE_APP_IDLE 0x00
#define STATE_APP_DETACH 0x01
#define STATE_DFU_IDLE 0x02
#define STATE_DFU_DOWNLOAD_SYNC 0x03
#define STATE_DFU_DOWNLOAD_BUSY 0x04
define STATE_DFU_DOWNLOAD_IDLE 0x05
#define STATE_DFU_MANIFEST_SYNC 0x06
#define STATE_DFU_MANIFEST 0x07
#define STATE_DFU_MANIFEST_WAIT_RESET 0x08
#define STATE_DFU_UPLOAD_IDLE 0x09
#define STATE_DFU_ERROR 0x0a
/* DFU status codes as returned by DFU_GETSTATUS request in bStatus field.
* Refer to Section 6.1.2 */
#define DFU_STATUS_OK 0x00
#define DFU_STATUS_ERROR_TARGET 0x01
#define DFU_STATUS_ERROR_FILE 0x02
#define DFU_STATUS_ERROR_WRITE 0x03
#define DFU_STATUS_ERROR_ERASE 0x04
#define DFU_STATUS_ERROR_CHECK_ERASED 0x05
#define DFU_STATUS_ERROR_PROG 0x06
#define DFU_STATUS_ERROR_VERIFY 0x07
#define DFU_STATUS_ERROR_ADDRESS 0x08
#define DFU_STATUS_ERROR_NOTDONE 0x09
#define DFU_STATUS_ERROR_FIRMWARE 0x0a
#define DFU_STATUS_ERROR_VENDOR 0x0b
#define DFU_STATUS_ERROR_USBR 0x0c
#define DFU_STATUS_ERROR_POR 0x0d
#define DFU_STATUS_ERROR_UNKNOWN 0x0e
#define DFU_STATUS_ERROR_STALLEDPKT 0x0f
/* Device status structure returned by DFU_GETSTATUS request.
* Refer to Section 6.1.2 */
typedef struct dfu_status {
uint8_t bStatus;
uint32_t bwPollTimeout:24;
uint8_t bState;
uint8_t iString;
} __attribute__((packed)) dfu_status;
int dfu_detach(usb_dev_handle *dev, uint16_t iface, uint16_t wTimeout);
int dfu_dnload(usb_dev_handle *dev, uint16_t iface,
uint16_t wBlockNum, void *data, uint16_t size);
int dfu_upload(usb_dev_handle *dev, uint16_t iface,
uint16_t wBlockNum, void *data, uint16_t size);
int dfu_getstatus(usb_dev_handle *dev, uint16_t iface, dfu_status *status);
int dfu_clrstatus(usb_dev_handle *dev, uint16_t iface);
int dfu_getstate(usb_dev_handle *dev, uint16_t iface);
int dfu_abort(usb_dev_handle *dev, uint16_t iface);
int dfu_makeidle(usb_dev_handle *dev, uint16_t iface);
#endif

160
upgrade/main.c Normal file
View File

@ -0,0 +1,160 @@
/*
* 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/>.
*/
#include <stdio.h>
#include <usb.h>
#include <string.h>
#include "dfu.h"
#include "stm32mem.h"
#include "bindata.h"
#define VERSION "1.0"
#define LOAD_ADDRESS 0x8002000
void banner(void)
{
puts("\nBlack Magic Probe -- Firmware Upgrade Utility -- Version " VERSION);
puts("Copyright (C) 2011 Black Sphere Technologies Ltd.");
puts("License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n");
}
struct usb_device * find_dev(void)
{
struct usb_bus *bus;
struct usb_device *dev;
struct usb_dev_handle *handle;
char man[40];
char prod[40];
usb_find_busses();
usb_find_devices();
for(bus = usb_get_busses(); bus; bus = bus->next) {
for(dev = bus->devices; dev; dev = dev->next) {
/* Check for ST Microelectronics vendor ID */
if(dev->descriptor.idVendor != 0x483) continue;
handle = usb_open(dev);
usb_get_string_simple(handle, dev->descriptor.iManufacturer, man,
sizeof(man));
usb_get_string_simple(handle, dev->descriptor.iProduct, prod,
sizeof(prod));
#if 0
printf("%s:%s [%04X:%04X] %s : %s\n", bus->dirname, dev->filename,
dev->descriptor.idVendor, dev->descriptor.idProduct, man, prod);
#endif
usb_close(handle);
if((dev->descriptor.idProduct == 0x5740) &&
!strcmp(man, "Black Sphere Technologies") &&
!strcmp(prod, "Black Magic Probe"))
return dev;
if((dev->descriptor.idProduct == 0xDF11) &&
!strcmp(man, "Black Sphere Technologies") &&
!strcmp(prod, "Black Magic Probe (Upgrade)"))
return dev;
}
}
return NULL;
}
usb_dev_handle * get_dfu_interface(struct usb_device *dev, uint16_t *interface)
{
int i, j, k;
struct usb_config_descriptor *config;
struct usb_interface_descriptor *iface;
usb_dev_handle *handle;
for(i = 0; i < dev->descriptor.bNumConfigurations; i++) {
config = &dev->config[i];
for(j = 0; j < config->bNumInterfaces; j++) {
for(k = 0; k < config->interface[j].num_altsetting; k++) {
iface = &config->interface[j].altsetting[k];
if((iface->bInterfaceClass == 0xFE) &&
(iface->bInterfaceSubClass = 0x01)) {
handle = usb_open(dev);
//usb_set_configuration(handle, i);
usb_claim_interface(handle, j);
//usb_set_altinterface(handle, k);
*interface = j;
return handle;
}
}
}
}
return NULL;
}
int main(void)
{
struct usb_device *dev;
usb_dev_handle *handle;
uint16_t iface;
int state;
uint32_t offset;
banner();
usb_init();
retry:
if(!(dev = find_dev()) || !(handle = get_dfu_interface(dev, &iface))) {
puts("FATAL: No compatible device found!\n");
return -1;
}
state = dfu_getstate(handle, iface);
if((state < 0) || (state == STATE_APP_IDLE)) {
puts("Resetting device in firmware upgrade mode...");
dfu_detach(handle, iface, 1000);
usb_release_interface(handle, iface);
usb_close(handle);
#ifdef WIN32
Sleep(3000);
#else
sleep(1);
#endif
goto retry;
}
printf("Found device at %s:%s\n", dev->bus->dirname, dev->filename);
dfu_makeidle(handle, iface);
for(offset = 0; offset < bindatalen; offset += 1024) {
printf("Progress: %d%%\r", (offset*100)/bindatalen);
fflush(stdout);
stm32_mem_erase(handle, iface, LOAD_ADDRESS + offset);
stm32_mem_write(handle, iface, (void*)&bindata[offset], 1024);
}
stm32_mem_manifest(handle, iface);
usb_release_interface(handle, iface);
usb_close(handle);
puts("All operations complete!\n");
return 0;
}

97
upgrade/stm32mem.c Normal file
View File

@ -0,0 +1,97 @@
/*
* 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/>.
*/
#include <usb.h>
#include <string.h>
#ifdef WIN32
# include <windows.h>
#else
# include <unistd.h>
#endif
#include "dfu.h"
#include "stm32mem.h"
#define STM32_CMD_GETCOMMANDS 0x00
#define STM32_CMD_SETADDRESSPOINTER 0x21
#define STM32_CMD_ERASE 0x41
static int stm32_download(usb_dev_handle *dev, uint16_t iface,
uint16_t wBlockNum, void *data, int size)
{
dfu_status status;
int i;
if((i = dfu_dnload(dev, iface, wBlockNum, data, size)) < 0) return i;
while(1) {
if((i = dfu_getstatus(dev, iface, &status)) < 0) return i;
switch(status.bState) {
case STATE_DFU_DOWNLOAD_BUSY:
#ifdef WIN32
Sleep(status.bwPollTimeout);
#else
usleep(status.bwPollTimeout * 1000);
#endif
break;
case STATE_DFU_DOWNLOAD_IDLE:
return 0;
default:
return -1;
}
}
}
int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr)
{
uint8_t request[5];
request[0] = STM32_CMD_ERASE;
memcpy(request+1, &addr, sizeof(addr));
return stm32_download(dev, iface, 0, request, sizeof(request));
}
int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size)
{
return stm32_download(dev, iface, 2, data, size);
}
int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface)
{
dfu_status status;
int i;
if((i = dfu_dnload(dev, iface, 0, NULL, 0)) < 0) return i;
while(1) {
if((i = dfu_getstatus(dev, iface, &status)) < 0) return 0;
#ifdef WIN32
Sleep(status.bwPollTimeout);
#else
usleep(status.bwPollTimeout * 1000);
#endif
switch(status.bState) {
case STATE_DFU_MANIFEST:
return 0;
default:
return -1;
}
}
}

30
upgrade/stm32mem.h Normal file
View File

@ -0,0 +1,30 @@
/*
* 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/>.
*/
#ifndef __STM32MEM_H
#define __STM32MEM_H
#include <usb.h>
int stm32_mem_erase(usb_dev_handle *dev, uint16_t iface, uint32_t addr);
int stm32_mem_write(usb_dev_handle *dev, uint16_t iface, void *data, int size);
int stm32_mem_manifest(usb_dev_handle *dev, uint16_t iface);
#endif