aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc5
-rw-r--r--support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc5
-rw-r--r--support/make/board-includes/cm900.mk5
-rw-r--r--support/make/board-includes/opencm904.mk5
-rwxr-xr-xsupport/scripts/robotis-loader.py94
-rw-r--r--wirish/boards.cpp4
-rw-r--r--wirish/usb_serial.cpp26
9 files changed, 164 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 1f19f37..c632ee8 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,12 @@ BOARD_INCLUDE_DIR := $(MAKEDIR)/board-includes
BOARD ?= maple
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
@@ -56,7 +62,8 @@ TARGET_FLAGS += -I$(LIBMAPLE_PATH)/include/libmaple \
TARGET_FLAGS += -I$(LIBRARIES_PATH) # for internal lib. includes, e.g. <Wire/WireBase.h>
GLOBAL_CFLAGS := -Os -g3 -gdwarf-2 -nostdlib \
-ffunction-sections -fdata-sections \
- -Wl,--gc-sections $(TARGET_FLAGS)
+ -Wl,--gc-sections $(TARGET_FLAGS) \
+ -DBOOTLOADER_$(BOOTLOADER)
GLOBAL_CXXFLAGS := -fno-rtti -fno-exceptions -Wall $(TARGET_FLAGS)
GLOBAL_ASFLAGS := -x assembler-with-cpp $(TARGET_FLAGS)
LDFLAGS = $(TARGET_LDFLAGS) $(TOOLCHAIN_LDFLAGS) -mcpu=cortex-m3 -mthumb \
@@ -101,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/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc
new file mode 100644
index 0000000..2c03ea9
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-flash.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08003000, LENGTH = 108K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc
new file mode 100644
index 0000000..20fbec0
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-jtag.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 128K
+}
diff --git a/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc
new file mode 100644
index 0000000..f02453b
--- /dev/null
+++ b/support/ld/stm32/mem/sram_20k_flash_128k_robotis/mem-ram.inc
@@ -0,0 +1,5 @@
+MEMORY
+{
+ ram (rwx) : ORIGIN = 0x20000C00, LENGTH = 17K
+ rom (rx) : ORIGIN = 0x08005000, LENGTH = 0K
+}
diff --git a/support/make/board-includes/cm900.mk b/support/make/board-includes/cm900.mk
index f9a09ac..9f70a1b 100644
--- a/support/make/board-includes/cm900.mk
+++ b/support/make/board-includes/cm900.mk
@@ -7,4 +7,9 @@ MCU_F1_LINE := performance
# This crap is due to ld-script limitations. If you know of a better
# way to go about this (like some magic ld switches to specify MEMORY
# at the command line), please tell us!
+ifeq ($(BOOTLOADER),maple)
LD_MEM_DIR := sram_20k_flash_128k
+endif
+ifeq ($(BOOTLOADER),robotis)
+LD_MEM_DIR := sram_20k_flash_128k_robotis
+endif
diff --git a/support/make/board-includes/opencm904.mk b/support/make/board-includes/opencm904.mk
index f3a4aa7..64d3351 100644
--- a/support/make/board-includes/opencm904.mk
+++ b/support/make/board-includes/opencm904.mk
@@ -7,4 +7,9 @@ MCU_F1_LINE := performance
# This crap is due to ld-script limitations. If you know of a better
# way to go about this (like some magic ld switches to specify MEMORY
# at the command line), please tell us!
+ifeq ($(BOOTLOADER),maple)
LD_MEM_DIR := sram_20k_flash_128k
+endif
+ifeq ($(BOOTLOADER),robotis)
+LD_MEM_DIR := sram_20k_flash_128k_robotis
+endif
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/boards.cpp b/wirish/boards.cpp
index a693fa6..77a05de 100644
--- a/wirish/boards.cpp
+++ b/wirish/boards.cpp
@@ -144,7 +144,11 @@ static void setup_clocks(void) {
* present. If no bootloader is present, the user NVIC usually starts
* at the Flash base address, 0x08000000.
*/
+#if defined(BOOTLOADER_maple)
#define USER_ADDR_ROM 0x08005000
+#elif defined(BOOTLOADER_robotis)
+#define USER_ADDR_ROM 0x08003000
+#endif
#define USER_ADDR_RAM 0x20000C00
extern char __text_start__;
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);
}