aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile10
-rwxr-xr-xsupport/scripts/robotis-loader.py94
-rw-r--r--wirish/usb_serial.cpp26
3 files changed, 130 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 80653a7..c632ee8 100644
--- a/Makefile
+++ b/Makefile
@@ -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);
}