mirror of
https://github.com/odriverobotics/ODrive.git
synced 2026-09-27 22:38:10 +08:00
Merge branch 'sam_disable_dfu' into sam_oskar_testing
This commit is contained in:
@@ -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));
|
||||||
|
|||||||
@@ -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" {
|
||||||
|
|||||||
@@ -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
@@ -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():
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
Reference in New Issue
Block a user