diff options
-rw-r--r-- | Makefile | 10 | ||||
-rwxr-xr-x | support/scripts/robotis-loader.py | 94 | ||||
-rw-r--r-- | wirish/usb_serial.cpp | 26 |
3 files changed, 130 insertions, 0 deletions
@@ -35,6 +35,9 @@ MEMORY_TARGET ?= flash # Chooses the bootloader, available: maple and robotis BOOTLOADER ?= maple +# This is the serial port used by robotis bootloader +ROBOTIS_PORT ?= /dev/ttyACM0 + # $(BOARD)- and $(MEMORY_TARGET)-specific configuration include $(MAKEDIR)/target-config.mk @@ -105,12 +108,19 @@ include $(SRCROOT)/build-targets.mk # USB ID for DFU upload -- FIXME: do something smarter with this BOARD_USB_VENDOR_ID := 1EAF BOARD_USB_PRODUCT_ID := 0003 + +ifeq ($(BOOTLOADER),maple) UPLOAD_ram := $(SUPPORT_PATH)/scripts/reset.py && \ sleep 1 && \ $(DFU) -a0 -d $(BOARD_USB_VENDOR_ID):$(BOARD_USB_PRODUCT_ID) -D $(BUILD_PATH)/$(BOARD).bin -R UPLOAD_flash := $(SUPPORT_PATH)/scripts/reset.py && \ sleep 1 && \ $(DFU) -a1 -d $(BOARD_USB_VENDOR_ID):$(BOARD_USB_PRODUCT_ID) -D $(BUILD_PATH)/$(BOARD).bin -R +endif + +ifeq ($(BOOTLOADER),robotis) +UPLOAD_flash := $(SUPPORT_PATH)/scripts/robotis-loader.py $(ROBOTIS_PORT) $(BUILD_PATH)/$(BOARD).bin +endif # Conditionally upload to whatever the last build was install: INSTALL_TARGET = $(shell cat $(BUILD_PATH)/build-type 2>/dev/null) diff --git a/support/scripts/robotis-loader.py b/support/scripts/robotis-loader.py new file mode 100755 index 0000000..95d4e71 --- /dev/null +++ b/support/scripts/robotis-loader.py @@ -0,0 +1,94 @@ +#!/usr/bin/python + +# This script sends a program on a robotis board (OpenCM9.04 or CM900) +# using the robotis bootloader (used in OpenCM IDE) +# +# Usage: +# python robotis-loader.py <serial port> <binary> +# +# Example: +# python robotis-loader.py /dev/ttyACM0 firmware.bin +# +# https://github.com/Gregwar/robotis-loader + +import serial, sys, os, time + +print('~~ Robotis loader ~~') +print('') + +# Reading command line +if len(sys.argv) != 3: + exit('! Usage: robotis-loader.py <serial-port> <binary>') +pgm, port, binary = sys.argv + +# Helper to prints a progress bar +def progressBar(percent, precision=65): + threshold=precision*percent/100.0 + sys.stdout.write('[ ') + for x in xrange(0, precision): + if x < threshold: sys.stdout.write('#') + else: sys.stdout.write(' ') + sys.stdout.write(' ] ') + sys.stdout.flush() + +# Opening the firmware file +try: + stat = os.stat(binary) + size = stat.st_size + firmware = file(binary, 'rb') + print('* Opening %s, size=%d' % (binary, size)) +except: + exit('! Unable to open file %s' % binary) + +# Opening serial port +try: + s = serial.Serial(port, baudrate=115200) +except: + exit('! Unable to open serial port %s' % port) + +print('* Resetting the board') +s.setRTS(True) +s.setDTR(False) +time.sleep(0.1) +s.setRTS(False) +s.write('CM9X') +s.close() +time.sleep(1.0); + +print('* Connecting...') +s = serial.Serial(port, baudrate=115200) +s.write('AT&LD') +print('* Download signal transmitted, waiting...') + +# Entering bootloader sequence +while True: + line = s.readline().strip() + if line.endswith('Ready..'): + print('* Board ready, sending data') + cs = 0 + pos = 0 + while True: + c = firmware.read(2048) + if len(c): + pos += len(c) + sys.stdout.write("\r") + progressBar(100*float(pos)/float(size)) + s.write(c) + for k in range(0,len(c)): + cs = (cs+ord(c[k]))%256 + else: + break + print('') + s.setDTR(True) + print('* Checksum: %d' % (cs)) + s.write(chr(cs)) + print('* Firmware was sent') + else: + if line == 'Success..': + print('* Success, running the code') + print('') + s.write('AT&RST') + s.close() + exit() + else: + print('Board -> '+line) diff --git a/wirish/usb_serial.cpp b/wirish/usb_serial.cpp index d21766f..3bb1923 100644 --- a/wirish/usb_serial.cpp +++ b/wirish/usb_serial.cpp @@ -36,6 +36,7 @@ #include <libmaple/nvic.h> #include <libmaple/usb_cdcacm.h> #include <libmaple/usb.h> +#include <libmaple/iwdg.h> #include <wirish/wirish.h> @@ -179,6 +180,7 @@ static void ifaceSetupHook(unsigned hook, void *requestvp) { return; } +#if defined(BOOTLOADER_maple) // We need to see a negative edge on DTR before we start looking // for the in-band magic reset byte sequence. uint8 dtr = usb_cdcacm_get_dtr(); @@ -196,13 +198,25 @@ static void ifaceSetupHook(unsigned hook, void *requestvp) { reset_state = dtr ? DTR_HIGH : DTR_LOW; break; } +#endif + +#if defined(BOOTLOADER_robotis) + uint8 dtr = usb_cdcacm_get_dtr(); + uint8 rts = usb_cdcacm_get_rts(); + + if (rts && !dtr) { + reset_state = DTR_NEGEDGE; + } +#endif } #define RESET_DELAY 100000 +#if defined(BOOTLOADER_maple) static void wait_reset(void) { delay_us(RESET_DELAY); nvic_sys_reset(); } +#endif #define STACK_TOP 0x20000800 #define EXC_RETURN 0xFFFFFFF9 @@ -215,7 +229,12 @@ static void rxHook(unsigned hook, void *ignored) { if (usb_cdcacm_data_available() >= 4) { // The magic reset sequence is "1EAF". +#if defined(BOOTLOADER_maple) static const uint8 magic[4] = {'1', 'E', 'A', 'F'}; +#endif +#if defined(BOOTLOADER_robotis) + static const uint8 magic[4] = {'C', 'M', '9', 'X'}; +#endif uint8 chkBuf[4]; // Peek at the waiting bytes, looking for reset sequence, @@ -227,6 +246,7 @@ static void rxHook(unsigned hook, void *ignored) { } } +#if defined(BOOTLOADER_maple) // Got the magic sequence -> reset, presumably into the bootloader. // Return address is wait_reset, but we must set the thumb bit. uintptr_t target = (uintptr_t)wait_reset | 0x1; @@ -251,6 +271,12 @@ static void rxHook(unsigned hook, void *ignored) { [exc_return] "r" (EXC_RETURN), [cpsr] "r" (DEFAULT_CPSR) : "r0", "r1", "r2"); +#endif + +#if defined(BOOTLOADER_robotis) + iwdg_init(IWDG_PRE_4, 10); +#endif + /* Can't happen. */ ASSERT_FAULT(0); } |