Merge branch 'sam_disable_dfu' into sam_oskar_testing

This commit is contained in:
Samuel Sadok
2018-04-24 13:41:53 -07:00
5 changed files with 64 additions and 34 deletions
+22 -18
View File
@@ -86,29 +86,33 @@ extern char _estack; // provided by the linker script
// Gets called from the startup assembly code // Gets called from the startup assembly code
void early_start_checks(void) { void early_start_checks(void) {
if(_reboot_cookie == 0xDEADFE75) {
/* The STM DFU bootloader enables internal pull-up resistors on PB10 (AUX_H)
* and PB11 (AUX_L), thereby causing shoot-through on the brake resistor
* FETs and obliterating them unless external 3.3k pull-down resistors are
* present. Pull-downs are only present on ODrive 3.5 or newer.
* On older boards we disable DFU by default but if the user insists
* there's only one thing left that might save it: time.
* The brake resistor gate driver needs a certain 10V supply (GVDD) to
* make it work. This voltage is supplied by the motor gate drivers which get
* disabled at system reset. So over time GVDD voltage _should_ below
* dangerous levels. This is completely handwavy and should not be relied on
* so you are on your own on if you ignore this warning.
*
* This loop takes 5 cycles per iteration and at this point the system runs
* on the internal 16MHz RC oscillator so the delay is about 2 seconds.
*/
for (size_t i = 0; i < (16000000UL / 5UL * 2UL); ++i) {
__NOP();
}
_reboot_cookie = 0xDEADBEEF;
}
/* We could jump to the bootloader directly on demand without rebooting /* We could jump to the bootloader directly on demand without rebooting
but that requires us to reset several peripherals and interrupts for it but that requires us to reset several peripherals and interrupts for it
to function correctly. Therefore it's easier to just reset the entire chip. */ to function correctly. Therefore it's easier to just reset the entire chip. */
if(_reboot_cookie == 0xDEADBEEF) { if(_reboot_cookie == 0xDEADBEEF) {
_reboot_cookie = 0xCAFEFEED; //Reset bootloader trigger _reboot_cookie = 0xCAFEFEED; //Reset bootloader trigger
/*
* This wait loop solves an obscure timing issue, but we don't exactly understand why.
* When the transition NVIC_SystemReset() => STM bootloader happens very quickly,
* there is a yet unexplained phenomenon where the ODrive would emit an audible click,
* followed by one the following symptoms:
* - Device reboots in normal mode (possibly due to the bootloader exiting immidiately)
* - Device goes into DFU mode and then the power supply turns off
* This manifests in the DFU script detecting the device in DFU mode but then
* losing the device immidiately after.
* There were no motors/encoders/brake resistor connected when testing this. As far as
* we can tell, the only way for the software to cause a short circuit is through the
* brake FETs.
*/
for (size_t i = 0; i < 1000000; ++i) {
__NOP();
}
__set_MSP((uintptr_t)&_estack); __set_MSP((uintptr_t)&_estack);
// http://www.st.com/content/ccc/resource/technical/document/application_note/6a/17/92/02/58/98/45/0c/CD00264379.pdf/files/CD00264379.pdf // http://www.st.com/content/ccc/resource/technical/document/application_note/6a/17/92/02/58/98/45/0c/CD00264379.pdf/files/CD00264379.pdf
void (*builtin_bootloader)(void) = (void (*)(void))(*((uint32_t *)0x1FFF0004)); void (*builtin_bootloader)(void) = (void (*)(void))(*((uint32_t *)0x1FFF0004));
+16 -4
View File
@@ -62,10 +62,22 @@ void erase_configuration(void) {
NVM_erase(); NVM_erase();
} }
void enter_dfu_mode(void) { void enter_dfu_mode() {
__asm volatile ("CPSID I\n\t":::"memory"); // disable interrupts if ((hw_version_major == 3) && (hw_version_minor >= 5)) {
_reboot_cookie = 0xDEADBEEF; __asm volatile ("CPSID I\n\t":::"memory"); // disable interrupts
NVIC_SystemReset(); _reboot_cookie = 0xDEADBEEF;
NVIC_SystemReset();
} else {
/*
* DFU mode is only allowed on board version >= 3.5 because it can burn
* the brake resistor FETs on older boards.
* If you really want to use it on an older board, add 3.3k pull-down resistors
* to the AUX_L and AUX_H signals and _only then_ uncomment these lines.
*/
//__asm volatile ("CPSID I\n\t":::"memory"); // disable interrupts
//_reboot_cookie = 0xDEADFE75;
//NVIC_SystemReset();
}
} }
extern "C" { extern "C" {
+4
View File
@@ -17,6 +17,10 @@ extern "C" {
extern osThreadId comm_thread; extern osThreadId comm_thread;
extern const uint8_t hw_version_major;
extern const uint8_t hw_version_minor;
extern const uint8_t hw_version_variant;
void init_communication(void); void init_communication(void);
void communication_task(void * ctx); void communication_task(void * ctx);
+21 -11
View File
@@ -206,7 +206,7 @@ def show_deferred_message(message, cancellation_token):
t.daemon = True t.daemon = True
t.start() t.start()
def put_odrive_into_dfu_mode(my_drive): def put_odrive_into_dfu_mode(my_drive, cancellation_token):
""" """
Puts the specified device into DFU mode Puts the specified device into DFU mode
""" """
@@ -216,15 +216,23 @@ def put_odrive_into_dfu_mode(my_drive):
"DFU with this script should work fine." "DFU with this script should work fine."
.format(my_drive.__channel__.usb_device.serial_number)) .format(my_drive.__channel__.usb_device.serial_number))
return return
print("Putting device {} into DFU mode...".format(my_drive.__channel__.usb_device.serial_number)) hw_version_major = my_drive.hw_version_major if hasattr(my_drive, 'hw_version_major') else 3
try: hw_version_minor = my_drive.hw_version_minor if hasattr(my_drive, 'hw_version_minor') else 4
my_drive.enter_dfu_mode() if hw_version_major == 3 and hw_version_minor >= 5:
except odrive.protocol.ChannelBrokenException as ex: print("Putting device {} into DFU mode...".format(my_drive.__channel__.usb_device.serial_number))
pass # this is expected because the device reboots try:
if platform.system() == "Windows": my_drive.enter_dfu_mode()
show_deferred_message("Still waiting for the device to reappear.\n" except odrive.protocol.ChannelBrokenException:
"Use the Zadig utility to set the driver of 'STM32 BOOTLOADER' to libusb-win32.", pass # this is expected because the device reboots
find_odrive_cancellation_token) if platform.system() == "Windows":
show_deferred_message("Still waiting for the device to reappear.\n"
"Use the Zadig utility to set the driver of 'STM32 BOOTLOADER' to libusb-win32.",
cancellation_token)
else:
print("Found device {}".format(my_drive.__channel__.usb_device.serial_number))
print(" DFU mode is not supported on board version 3.4 or earlier.")
print(" This is because entering DFU mode on such a device would")
print(" break the brake resistor FETs under some circumstances.")
def launch_dfu(args, app_shutdown_token): def launch_dfu(args, app_shutdown_token):
""" """
@@ -251,7 +259,9 @@ def launch_dfu(args, app_shutdown_token):
# Scan for ODrives not in DFU mode and put them into DFU mode once they appear # Scan for ODrives not in DFU mode and put them into DFU mode once they appear
# We only scan on USB because DFU is only possible over USB # We only scan on USB because DFU is only possible over USB
odrive.discovery.find_all(args.path, serial_number, put_odrive_into_dfu_mode, find_odrive_cancellation_token, app_shutdown_token) odrive.discovery.find_all(args.path, serial_number,
lambda dev: put_odrive_into_dfu_mode(dev, find_odrive_cancellation_token),
find_odrive_cancellation_token, app_shutdown_token)
# Poll libUSB until a device in DFU mode is found # Poll libUSB until a device in DFU mode is found
while not app_shutdown_token.is_set(): while not app_shutdown_token.is_set():
+1 -1
View File
@@ -256,7 +256,7 @@ class Channel(PacketSink):
self._printer("receiver thread is exiting: " + traceback.format_exc()) self._printer("receiver thread is exiting: " + traceback.format_exc())
finally: finally:
self._channel_broken.set() self._channel_broken.set()
threading.Thread(target=receiver_thread, daemon=True).start() threading.Thread(target=receiver_thread).start()
def remote_endpoint_operation(self, endpoint_id, input, expect_ack, output_length): def remote_endpoint_operation(self, endpoint_id, input, expect_ack, output_length):
if input is None: if input is None: