New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issues with Device Firmware Upgrade (DFU) #179

Open
StrikeEagleCC opened this Issue Jun 21, 2018 · 9 comments

Comments

6 participants
@StrikeEagleCC

StrikeEagleCC commented Jun 21, 2018

EDIT by @madcowswe:
This issue has come to describe a collection of issues regarding DFU, with the following final error messages:

  • ValueError: The device has no langid
  • RuntimeError: An error occured. Device Status: (0, 2, 0, 0)
  • IndexError: array index out of range (DfuDevice.py:67)

when running "odrivetool dfu" on unflashed v2.5 ODrive:

$ odrivetool dfu
ODrive control utility v0.4.0.post3
Waiting for ODrive...
Traceback (most recent call last):
  File "/home/ben/pyenvs/odrive/bin/odrivetool", line 141, in <module>
    odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
  File "/home/ben/pyenvs/odrive/lib/python3.5/site-packages/odrive/dfu.py", line 450, in launch_dfu
    update_device(device, firmware, logger, cancellation_token)
  File "/home/ben/pyenvs/odrive/lib/python3.5/site-packages/odrive/dfu.py", line 257, in update_device
    serial_number = device.serial_number
  File "/home/ben/pyenvs/odrive/lib/python3.5/site-packages/usb/core.py", line 830, in serial_number
    self._serial_number = util.get_string(self, self.iSerialNumber)
  File "/home/ben/pyenvs/odrive/lib/python3.5/site-packages/usb/util.py", line 314, in get_string
    raise ValueError("The device has no langid")
ValueError: The device has no langid

New v3.5 ODrive board, not yet flashed with firmware.
Ubuntu 16.04
python 3.5.2
Let me know if there is anything else I can provide to be helpful.

@madcowswe

This comment has been minimized.

Show comment
Hide comment
@madcowswe

madcowswe Jun 21, 2018

Owner

As far as I can tell, it seems that the bug is that the udev rules are not set for the STM32 DFU device (different vendor/product id than the main ODrive).
See: pyusb/pyusb#139

Maybe we should include the dfu device in the udev rules we install with the pip package. @samuelsadok do you think that's a good idea?

Owner

madcowswe commented Jun 21, 2018

As far as I can tell, it seems that the bug is that the udev rules are not set for the STM32 DFU device (different vendor/product id than the main ODrive).
See: pyusb/pyusb#139

Maybe we should include the dfu device in the udev rules we install with the pip package. @samuelsadok do you think that's a good idea?

@madcowswe madcowswe added this to Features IN PROGRESS in ODrive Development Jun 21, 2018

@madcowswe madcowswe moved this from Features IN PROGRESS to TODO in ODrive Development Jun 27, 2018

@cculbreath

This comment has been minimized.

Show comment
Hide comment
@cculbreath

cculbreath Jul 2, 2018

I'm seeing the same issue with Python 3.7.0rc1 running MacOS 10.14 (Mojave Beta, I know I'm asking for trouble running a beta OS). Is there a work around?

cculbreath commented Jul 2, 2018

I'm seeing the same issue with Python 3.7.0rc1 running MacOS 10.14 (Mojave Beta, I know I'm asking for trouble running a beta OS). Is there a work around?

@madcowswe

This comment has been minimized.

Show comment
Hide comment
@madcowswe

madcowswe Jul 2, 2018

Owner

As a workaround I think it may work to do sudo odrivetool dfu. Someone please confirm?

Owner

madcowswe commented Jul 2, 2018

As a workaround I think it may work to do sudo odrivetool dfu. Someone please confirm?

@cculbreath

This comment has been minimized.

Show comment
Hide comment
@cculbreath

cculbreath Jul 2, 2018

Hasn't worked for me. And I set up on another computer using 10.13 (High Sierra) just to make sure that it wasn't the beta OS giving me trouble.

cculbreath commented Jul 2, 2018

Hasn't worked for me. And I set up on another computer using 10.13 (High Sierra) just to make sure that it wasn't the beta OS giving me trouble.

@cculbreath

This comment has been minimized.

Show comment
Hide comment
@cculbreath

cculbreath Jul 2, 2018

I'm seeing the error intermittently; sometimes the firmware flashes and verifies ok. Sometimes I get the langid error above, and sometimes I see this:

Erasing... done            
Flashing... (sector 1/6)  
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/bin/odrivetool", line 142, in <module>
    odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfu.py", line 450, in launch_dfu
    update_device(device, firmware, logger, cancellation_token)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfu.py", line 381, in update_device
    dfudev.write_sector(sector, data)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfuse/DfuDevice.py", line 187, in write_sector
    raise RuntimeError("An error occured. Device Status: {!r}".format(status))
RuntimeError: An error occured. Device Status: (0, 2, 0, 0)

cculbreath commented Jul 2, 2018

I'm seeing the error intermittently; sometimes the firmware flashes and verifies ok. Sometimes I get the langid error above, and sometimes I see this:

Erasing... done            
Flashing... (sector 1/6)  
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.7/bin/odrivetool", line 142, in <module>
    odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfu.py", line 450, in launch_dfu
    update_device(device, firmware, logger, cancellation_token)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfu.py", line 381, in update_device
    dfudev.write_sector(sector, data)
  File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/odrive/dfuse/DfuDevice.py", line 187, in write_sector
    raise RuntimeError("An error occured. Device Status: {!r}".format(status))
RuntimeError: An error occured. Device Status: (0, 2, 0, 0)
@cculbreath

This comment has been minimized.

Show comment
Hide comment
@cculbreath

cculbreath Jul 2, 2018

I'm going to try my Ubuntu system and see if that works out.

cculbreath commented Jul 2, 2018

I'm going to try my Ubuntu system and see if that works out.

@samuelsadok

This comment has been minimized.

Show comment
Hide comment
@samuelsadok

samuelsadok Jul 24, 2018

Collaborator

I don't think it's a permission issue given that it's intermittent. It seems to me more like the device hasn't properly initialized the USB system by the time we fetch the serial number.

I have seen the langid issue too occasionally, but IIRC it occurred only when the device was powered up while already connected to a PC with odrivetool running. This would support the thesis that it has to do with a race condition at initialization.

Some things you can try (independently):

  1. Before this line insert time.sleep(1)
  2. Before the same line insert device._langids = (1033,) (source)
  3. Force the device into DFU mode using the DIP switch and power it up before connecting to the PC

@madcowswe For some reason unknown to me I never had to add udev rules for the DFU device, it worked by default. If there turn out to be actual permission issues yeah you can add the rules to the setup_udev_rules routine.

Collaborator

samuelsadok commented Jul 24, 2018

I don't think it's a permission issue given that it's intermittent. It seems to me more like the device hasn't properly initialized the USB system by the time we fetch the serial number.

I have seen the langid issue too occasionally, but IIRC it occurred only when the device was powered up while already connected to a PC with odrivetool running. This would support the thesis that it has to do with a race condition at initialization.

Some things you can try (independently):

  1. Before this line insert time.sleep(1)
  2. Before the same line insert device._langids = (1033,) (source)
  3. Force the device into DFU mode using the DIP switch and power it up before connecting to the PC

@madcowswe For some reason unknown to me I never had to add udev rules for the DFU device, it worked by default. If there turn out to be actual permission issues yeah you can add the rules to the setup_udev_rules routine.

@madcowswe madcowswe changed the title from Flashing v3.5 board on Ubuntu gets "device has no langid" to Issues with DFU mode Aug 8, 2018

@madcowswe madcowswe changed the title from Issues with DFU mode to Issues with Device Firmware Upgrade (DFU) Aug 8, 2018

@martyman-au

This comment has been minimized.

Show comment
Hide comment
@martyman-au

martyman-au Aug 12, 2018

I am seeing a slightly different problem trying to flash my new Odrives. It is the same as the one described by alonks on the forum.

  • Windows 7
  • Anaconda3 (Python 3.6.5)
  • I have tried both with DFU switch set and not
  • I have set the stm32 bootloader driver to libusb-win32 using zadiag
  • Firmware: v0.4.1-dev (As received)
  • Odrive: 3.5-48v

When trying to run odrivetool dfu I get the following result.

(base) C:\Users\martin>odrivetool dfu
ODrive control utility v0.4.1
Waiting for ODrive...
Found ODrive 375F36623137 (v3.5-48V) with firmware [unknown version] in DFU mode

Checking online for newest firmware... found v0.4.2
Downloading firmware v0.4.2...
The configuration cannot be backed up because the device is already in DFU mode.
 The configuration may be lost after updating. Do you want to continue anyway? [
Y/n] y
Erasing... (sector 0/6)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
~\Anaconda3\Scripts\odrivetool in <module>()
    140         print_version()
    141         import odrive.dfu
--> 142         odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
    143
    144     elif args.command == 'liveplotter':

~\Anaconda3\lib\site-packages\odrive\dfu.py in launch_dfu(args, logger, cancellation_token)
    448     firmware = FirmwareFromFile(args.file) if args.file else None
    449
--> 450     update_device(device, firmware, logger, cancellation_token)
    451
    452

~\Anaconda3\lib\site-packages\odrive\dfu.py in update_device(device, firmware, logger, cancellation_token)
    370         for i, (sector, data) in enumerate(touched_sectors):
    371             print("Erasing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
--> 372             dfudev.erase_sector(sector)
    373         print('Erasing... done            \r', end='', flush=True)
    374     finally:

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in erase_sector(self, sector)
    166
    167     def erase_sector(self, sector):
--> 168         self.set_alternate_safe(sector['alt'])
    169         self.erase(sector['addr'])
    170         status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY, timeout=sector['len']/32)

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in set_alternate_safe(self, alt)
    148     def set_alternate_safe(self, alt):
    149         self.set_alternate(alt)
--> 150         if self.get_state() == DfuState.DFU_ERROR:
    151             self.clear_status()
    152             self.wait_while_state(DfuState.DFU_ERROR)

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in get_state(self)
     65
     66     def get_state(self):
---> 67         return self.control_msg(DFU_REQUEST_RECEIVE, DFU_GETSTATE, 0, 1)[0]
     68
     69     def abort(self):

IndexError: array index out of range

This seems to be failing at the firmware erase step, which is earlier than the errors seen above.

martyman-au commented Aug 12, 2018

I am seeing a slightly different problem trying to flash my new Odrives. It is the same as the one described by alonks on the forum.

  • Windows 7
  • Anaconda3 (Python 3.6.5)
  • I have tried both with DFU switch set and not
  • I have set the stm32 bootloader driver to libusb-win32 using zadiag
  • Firmware: v0.4.1-dev (As received)
  • Odrive: 3.5-48v

When trying to run odrivetool dfu I get the following result.

(base) C:\Users\martin>odrivetool dfu
ODrive control utility v0.4.1
Waiting for ODrive...
Found ODrive 375F36623137 (v3.5-48V) with firmware [unknown version] in DFU mode

Checking online for newest firmware... found v0.4.2
Downloading firmware v0.4.2...
The configuration cannot be backed up because the device is already in DFU mode.
 The configuration may be lost after updating. Do you want to continue anyway? [
Y/n] y
Erasing... (sector 0/6)
---------------------------------------------------------------------------
IndexError                                Traceback (most recent call last)
~\Anaconda3\Scripts\odrivetool in <module>()
    140         print_version()
    141         import odrive.dfu
--> 142         odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
    143
    144     elif args.command == 'liveplotter':

~\Anaconda3\lib\site-packages\odrive\dfu.py in launch_dfu(args, logger, cancellation_token)
    448     firmware = FirmwareFromFile(args.file) if args.file else None
    449
--> 450     update_device(device, firmware, logger, cancellation_token)
    451
    452

~\Anaconda3\lib\site-packages\odrive\dfu.py in update_device(device, firmware, logger, cancellation_token)
    370         for i, (sector, data) in enumerate(touched_sectors):
    371             print("Erasing... (sector {}/{})  \r".format(i, len(touched_sectors)), end='', flush=True)
--> 372             dfudev.erase_sector(sector)
    373         print('Erasing... done            \r', end='', flush=True)
    374     finally:

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in erase_sector(self, sector)
    166
    167     def erase_sector(self, sector):
--> 168         self.set_alternate_safe(sector['alt'])
    169         self.erase(sector['addr'])
    170         status = self.wait_while_state(DfuState.DFU_DOWNLOAD_BUSY, timeout=sector['len']/32)

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in set_alternate_safe(self, alt)
    148     def set_alternate_safe(self, alt):
    149         self.set_alternate(alt)
--> 150         if self.get_state() == DfuState.DFU_ERROR:
    151             self.clear_status()
    152             self.wait_while_state(DfuState.DFU_ERROR)

~\Anaconda3\lib\site-packages\odrive\dfuse\DfuDevice.py in get_state(self)
     65
     66     def get_state(self):
---> 67         return self.control_msg(DFU_REQUEST_RECEIVE, DFU_GETSTATE, 0, 1)[0]
     68
     69     def abort(self):

IndexError: array index out of range

This seems to be failing at the firmware erase step, which is earlier than the errors seen above.

@dkraft

This comment has been minimized.

Show comment
Hide comment
@dkraft

dkraft Aug 26, 2018

I'm on W10, anaconda and upgraded to 4.1 but cant get 4.2 on same setup..

(base) C:\Users\Alien>odrivetool dfu
ODrive control utility v0.4.1
Waiting for ODrive...
Found ODrive 366533793037 (v3.5-48V) with firmware v0.4.1-dev
Checking online for newest firmware... found v0.4.2
Downloading firmware v0.4.2...
Saving configuration to C:\Users\Alien\AppData\Local\Temp\odrive-config-366533793037.json...
The file C:\Users\Alien\AppData\Local\Temp\odrive-config-366533793037.json already exists. Do you want to override it? [Y/n]
Configuration saved.
Putting device 366533793037 into DFU mode...
---------------------------------------------------------------------------
USBError                                  Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\fibre\usbbulk_transport.py in process_packet(self, usbBuffer)
     96     try:
---> 97       ret = self.epw.write(usbBuffer, 0)
     98       if self._was_damaged:

C:\ProgramData\Anaconda3\lib\site-packages\usb\core.py in write(self, data, timeout)
    386         """
--> 387         return self.device.write(self, data, timeout)
    388

C:\ProgramData\Anaconda3\lib\site-packages\usb\core.py in write(self, endpoint, data, timeout)
    947                 _interop.as_array(data),
--> 948                 self.__get_timeout(timeout)
    949             )

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in bulk_write(self, dev_handle, ep, intf, data, timeout)
    532                             intf,
--> 533                             data, timeout)
    534

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in __write(self, fn, dev_handle, ep, intf, data, timeout)
    615                         length,
--> 616                         timeout
    617                     )))

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in _check(ret)
    430             return ret
--> 431     raise USBError(errmsg, ret)
    432

USBError: [Errno None] b'libusb0-dll:err [submit_async] submitting request failed, win error: The device does not recognize the command.\r\n'

During handling of the above exception, another exception occurred:

TimeoutError                              Traceback (most recent call last)
C:\ProgramData\Anaconda3\Scripts\odrivetool in <module>()
    140         print_version()
    141         import odrive.dfu
--> 142         odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
    143
    144     elif args.command == 'liveplotter':

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in launch_dfu(args, logger, cancellation_token)
    448     firmware = FirmwareFromFile(args.file) if args.file else None
    449
--> 450     update_device(device, firmware, logger, cancellation_token)
    451
    452

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in update_device(device, firmware, logger, cancellation_token)
    347     if dfudev is None:
    348         find_odrive_cancellation_token = Event(cancellation_token)
--> 349         put_into_dfu_mode(device, find_odrive_cancellation_token)
    350         stm_device = find_device_in_dfu_mode(serial_number, cancellation_token)
    351         find_odrive_cancellation_token.set()

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in put_into_dfu_mode(device, cancellation_token)
    224     print("Putting device {} into DFU mode...".format(device.__channel__.usb_device.serial_number))
    225     try:
--> 226         device.enter_dfu_mode()
    227     except fibre.ChannelBrokenException:
    228         pass # this is expected because the device reboots

C:\ProgramData\Anaconda3\lib\site-packages\fibre\remote_object.py in __call__(self, *args)
    122         for i in range(len(args)):
    123             self._inputs[i].set_value(args[i])
--> 124         self._parent.__channel__.remote_endpoint_operation(self._trigger_id, None, True, 0)
    125         if len(self._outputs) > 0:
    126             return self._outputs[0].get_value()

C:\ProgramData\Anaconda3\lib\site-packages\fibre\protocol.py in remote_endpoint_operation(self, endpoint_id, input, expect_ack, output_length)
    294                     self._my_lock.acquire()
    295                     try:
--> 296                         self._output.process_packet(packet)
    297                     except ChannelDamagedException:
    298                         attempt += 1

C:\ProgramData\Anaconda3\lib\site-packages\fibre\usbbulk_transport.py in process_packet(self, usbBuffer)
    104         raise fibre.protocol.ChannelBrokenException()
    105       elif ex.errno is None or ex.errno == 60 or ex.errno == 110: # timeout
--> 106         raise TimeoutError()
    107       else:
    108         self._logger.debug("error in usbbulk_transport.py, process_packet")

TimeoutError:

dkraft commented Aug 26, 2018

I'm on W10, anaconda and upgraded to 4.1 but cant get 4.2 on same setup..

(base) C:\Users\Alien>odrivetool dfu
ODrive control utility v0.4.1
Waiting for ODrive...
Found ODrive 366533793037 (v3.5-48V) with firmware v0.4.1-dev
Checking online for newest firmware... found v0.4.2
Downloading firmware v0.4.2...
Saving configuration to C:\Users\Alien\AppData\Local\Temp\odrive-config-366533793037.json...
The file C:\Users\Alien\AppData\Local\Temp\odrive-config-366533793037.json already exists. Do you want to override it? [Y/n]
Configuration saved.
Putting device 366533793037 into DFU mode...
---------------------------------------------------------------------------
USBError                                  Traceback (most recent call last)
C:\ProgramData\Anaconda3\lib\site-packages\fibre\usbbulk_transport.py in process_packet(self, usbBuffer)
     96     try:
---> 97       ret = self.epw.write(usbBuffer, 0)
     98       if self._was_damaged:

C:\ProgramData\Anaconda3\lib\site-packages\usb\core.py in write(self, data, timeout)
    386         """
--> 387         return self.device.write(self, data, timeout)
    388

C:\ProgramData\Anaconda3\lib\site-packages\usb\core.py in write(self, endpoint, data, timeout)
    947                 _interop.as_array(data),
--> 948                 self.__get_timeout(timeout)
    949             )

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in bulk_write(self, dev_handle, ep, intf, data, timeout)
    532                             intf,
--> 533                             data, timeout)
    534

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in __write(self, fn, dev_handle, ep, intf, data, timeout)
    615                         length,
--> 616                         timeout
    617                     )))

C:\ProgramData\Anaconda3\lib\site-packages\usb\backend\libusb0.py in _check(ret)
    430             return ret
--> 431     raise USBError(errmsg, ret)
    432

USBError: [Errno None] b'libusb0-dll:err [submit_async] submitting request failed, win error: The device does not recognize the command.\r\n'

During handling of the above exception, another exception occurred:

TimeoutError                              Traceback (most recent call last)
C:\ProgramData\Anaconda3\Scripts\odrivetool in <module>()
    140         print_version()
    141         import odrive.dfu
--> 142         odrive.dfu.launch_dfu(args, logger, app_shutdown_token)
    143
    144     elif args.command == 'liveplotter':

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in launch_dfu(args, logger, cancellation_token)
    448     firmware = FirmwareFromFile(args.file) if args.file else None
    449
--> 450     update_device(device, firmware, logger, cancellation_token)
    451
    452

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in update_device(device, firmware, logger, cancellation_token)
    347     if dfudev is None:
    348         find_odrive_cancellation_token = Event(cancellation_token)
--> 349         put_into_dfu_mode(device, find_odrive_cancellation_token)
    350         stm_device = find_device_in_dfu_mode(serial_number, cancellation_token)
    351         find_odrive_cancellation_token.set()

C:\ProgramData\Anaconda3\lib\site-packages\odrive\dfu.py in put_into_dfu_mode(device, cancellation_token)
    224     print("Putting device {} into DFU mode...".format(device.__channel__.usb_device.serial_number))
    225     try:
--> 226         device.enter_dfu_mode()
    227     except fibre.ChannelBrokenException:
    228         pass # this is expected because the device reboots

C:\ProgramData\Anaconda3\lib\site-packages\fibre\remote_object.py in __call__(self, *args)
    122         for i in range(len(args)):
    123             self._inputs[i].set_value(args[i])
--> 124         self._parent.__channel__.remote_endpoint_operation(self._trigger_id, None, True, 0)
    125         if len(self._outputs) > 0:
    126             return self._outputs[0].get_value()

C:\ProgramData\Anaconda3\lib\site-packages\fibre\protocol.py in remote_endpoint_operation(self, endpoint_id, input, expect_ack, output_length)
    294                     self._my_lock.acquire()
    295                     try:
--> 296                         self._output.process_packet(packet)
    297                     except ChannelDamagedException:
    298                         attempt += 1

C:\ProgramData\Anaconda3\lib\site-packages\fibre\usbbulk_transport.py in process_packet(self, usbBuffer)
    104         raise fibre.protocol.ChannelBrokenException()
    105       elif ex.errno is None or ex.errno == 60 or ex.errno == 110: # timeout
--> 106         raise TimeoutError()
    107       else:
    108         self._logger.debug("error in usbbulk_transport.py, process_packet")

TimeoutError:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment