Friday, December 31, 2010

A.R. Drone USB (Updated)

A word of warning: You should not do anything like the following if you do not know what you do. You may ruin your drone.

As A.R. Drone has an USB OTG Port, it should be possible to use this port for extending the functionality of A.R. Drone.

But sadly Parrot disabled this port and only allows to use it for flashing purpose. Luckily they provide the source code for the driver [1].

So... let's have a closer look to this USB port..

First, Parrot defined the port as device only.

arch/arm/parrot6/mykonos.c, line 109:
static dwc_otg_info_t usb0_info = {
 .ctrl_mode = 2,
 .sof_filter = 7,
 .reset_pin = -1,
 .vbus_detection = 0,
 .fiq_enable = 0,
};

According to dwc_otg driver:
drivers/parrot/usb/dwc_otg/dwc_otg_cil.h
 /**
  * Controller mode
  * 0 - OTG
  * 1 - host only
  * 2 - device only
  */
 int32_t ctrl_mode;
#define DWC_OTG_HOST_DEVICE 0
#define DWC_OTG_HOST_ONLY   1
#define DWC_OTG_DEVICE_ONLY 2

In order to enable the USB host mode, it is required to overwrite/ignore the usb0_info defined in mykonos.c.

This can be achieved by patching dwc_otg_driver.c where the platform data is copied to the local parameter data. This is done by function "dwc_otg_set_specific_param". Also, by default (if not overwritten by platform data) the local parameters are configured as DWC_OTG_HOST_DEVICE. So simply not copying this parameter would prevent the driver from going to DEVICE_ONLY mode.

Thus the driver is modified and the assignment "params->ctrl_mode = info->ctrl_mode" is removed:
drivers/parrot/usb/dwc_otg/dwc_otg_driver.c, line 224:

/**
 * This function is called to set specific configuration parameters
 */
static void 
dwc_otg_set_specific_param
(
dwc_otg_info_t *info,
dwc_otg_core_params_t *params,
int port
)
{
 params->sof_filter = info->sof_filter;
 params->reset_pin = info->reset_pin;
 params->speed = info->speed;
 if (port == 0) {
  //params->ctrl_mode = info->ctrl_mode;
  //params->vbus_detection = info->vbus_detection;
 }
 if (port == 1 && !usb1_disable_fiq) {
  params->fiq_enable = info->fiq_enable;
 }
}

[Update]
As noted by MAPGPS [3], there is still an issue with the driver causing Oops. To fix this issue, it is necessary to change the overcurrent_pin from 89 to -1:

drivers/parrot/usb/dwc_otg/dwc_otg_driver.c, line 135:

.overcurrent_pin = -1, /* default */
[/Update]



After compiling, ftp-ing the module to the drone and calling

# insmod dwc_otg.ko

Oh no! dmesg shows that something gone wrong.. also VBus is still +0 V :-(

[   39.862534] dwc_otg: version 2.70a-parrot 22/03/2009
[   39.862703] dwc_otg dwc_otg.0: dwc_otg_driver_probe(c034d578)
[   39.862736] dwc_otg dwc_otg.0: start=0xc0400000
[   39.862851] dwc_otg dwc_otg.0: base=0xc8e00000
[   39.862883] dwc_otg dwc_otg.0: specific configuration
[   39.862914] dwc_otg dwc_otg.0: dwc_otg_device=0xc7a0b6e0
[   39.873574] DWC_otg: dwc_otg_core_reset() HANG! Soft Reset
 GRSTCTL=80000001
[   39.980233] DWC_otg: dwc_otg_core_reset() HANG! Soft Reset
 GRSTCTL=80000001

Looking at the drivers code, it seems like this HANG! message indicates a communication problem with the PHY. Checking the voltage levels of the PHY, it seems like almost all pins are tri-stated.

Having a look at the PCB, a SMSC USB3317 can be identified. According to its datasheet there is a pin named RESETB. When this pin is set to low the PHY is suspended and all I/O are tri-stated.

By monitoring RESETB it can be observed that RESETB is toggled by program.elf. So dumping all GPIO registers before and after starting program.elf the pin can be found.

And voilá: GPIO_127 is used to enable/disable the PHY. Program.elf sets it to output a high level which then switches a transistor and pulls RESETB to low.

In order to activate the USB as host GPIO_127 needs to be set to input level. This can be done either by ioctl or by the gpio command:

# gpio 127 -d i

After re-inserting dwc_otg.ko, dmesg no longer shows the HANG! message and VBUS has +5V :-)

Let's try to connect an USB device. The pinout for the USB connector is described in [2]. I use an old USB thumb drive (128MB) for testing.

dmesg shows:

[ 1675.054378] usb-storage: USB Mass Storage device detected
[ 1675.054650] usb-storage: -- associate_dev
[ 1675.054680] usb-storage: Vendor: 0x0ea0, Product: 0x2168,
 Revision: 0x0200
[ 1675.054707] usb-storage: Interface Subclass: 0x06, Protocol:
 0x50
[ 1675.054741] usb-storage: Transport: Bulk
[ 1675.054761] usb-storage: Protocol: Transparent SCSI
[ 1675.055439] scsi1 : SCSI emulation for USB Mass Storage devices
[...]
[ 1680.071311] scsi 1:0:0:0: Direct-Access              128MB       
     2.00 PQ: 0 ANSI: 2

Seems to work :-)


[1] https://projects.ardrone.org/documents/show/19
[2] https://projects.ardrone.org/attachments/167/ARDrone-USB-Cable.png
[3] http://www.ardrone-flyers.com/forum/viewtopic.php?p=5823#p5823

14 comments:

  1. Hey, I've received a drone a couple of days ago and I've recompiled the USB module with your patch for the mode. If I load the module while program.elf is running, the drone freezes. If I do it the other way around, it works but program.elf can't initialize the cameras anymore. Do you observe different behavior? If so, can you tell me the md5 sum of your firmware so I can cross check? Thank you so much :)

    Also, do you have an email address or any other means of communication that you'd be willing to share with me? Good job on the gpio!

    Herik

    ReplyDelete
  2. Hey Henrik,

    the problem is the overcurrent_pin (dwc_otg_driver.c, line 135). By default, it is set to 89 which is normally used as CAM0_VSYNC.

    Change this pin to -1. It should work then.

    Thanks to MAPGPS (http://www.ardrone-flyers.com/forum/viewtopic.php?f=8&t=829) for this info.

    Best regards

    ReplyDelete
  3. Hi!

    I'm very new to all this ... but I'm also very interested to improve my skills ...

    So before making something irreparable can you please suggest some link to know more about driver patch and so on?

    Many thanks!

    Marco

    ReplyDelete
  4. Hi Marco,

    if you are not that familiar with linux kernel modules, I recommend these documents:

    http://www.ibm.com/developerworks/linux/library/l-lkm/index.html

    http://tldp.org/HOWTO/Module-HOWTO/x73.html

    http://tldp.org/LDP/lkmpg/2.6/html/lkmpg.html

    They should give you a good overview about how kernel modules work and what they do.

    Also you need to download the toolchain, kernel + config from parrots page:

    https://projects.ardrone.org/documents/show/20
    https://projects.ardrone.org/documents/show/19
    https://projects.ardrone.org/documents/show/18

    If you do not know how to cross compile, you should also read this:

    http://www.kernel.org/doc/#cross_compiling

    And finally: you just need to do "make modules" :-)

    Best regards

    ReplyDelete
  5. Hi Henrik!
    Thanks for the post!!
    I have a lil question, Do you think is possible to connect a webcam to that usb port?.. and then send it via wifi in order to have 3 video streams.
    Thanks in advance!

    ReplyDelete
  6. Hi,

    I'm having a little bit of trouble. I've modified the dwc_otg_driver.c file and am trying to compile the module.

    I type something like:
    make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- modules

    I think this part is right. My problem is that I cannot figure how to configure the kernel sources so that the usb ko module is built. How do I go about finding the things to change when I run 'make menuconfig' in the kernel directory. BTW, I have downloaded the kernel from the parrot site, so I think that the patch is already applied. (I hope I'm making sense.)

    Thanks,
    Dave

    ReplyDelete
  7. Hi,

    I'm currently working on the A.R. Drone USB ports :
    I can plug and use a GPS device (via usb_serial.ko and pl2303.ko, with your modified dwc_otg).

    By now, I need to add a second sensor on the drone, so I tried to add a usb hub, but it stucks the usb port : the gps device, plugged on the hub is always on, but is no more seen by the drone (with or without the hub), until I reboot.

    It seems that the Drone doesn't support hubs on its USB port, at least without more modules.
    Does anyone tried to work on that ?

    Thanks for answers,
    Thomas

    P.S.: Here are the corrsponding lines I get on dmesg :

    [ 35.755192] hub 1-0:1.0: unable to enumerate USB device on port 1
    [ 35.804582] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
    [ 35.804677] hub 1-0:1.0: port 1, status 0503, change 0001, 480 Mb/s
    [ 35.981561] hub 1-0:1.0: debounce: port 1: total 100ms stable 100ms status 0x503
    [ 36.042486] hub 1-0:1.0: port 1 not reset yet, waiting 50ms
    [ 36.161591] usb 1-1: new high speed USB device using dwc_otg and address 3
    [ 36.221609] hub 1-0:1.0: port 1 not reset yet, waiting 50ms
    [.. same for addresses 4 to 5 ..]
    [ 36.341940] usb 1-1: device descriptor read/64, error -71
    [ 38.182773] hub 1-0:1.0: port 1 not reset yet, waiting 50ms
    [ 38.307717] usb 1-1: new high speed USB device using dwc_otg and address 6
    [ 38.723069] usb 1-1: device not accepting address 6, error -71
    [ 38.723181] hub 1-0:1.0: unable to enumerate USB device on port 1
    [ 38.723233] hub 1-0:1.0: state 7 ports 1 chg 0000 evt 0002
    [ 38.723279] hub 1-0:1.0: port 1 enable change, status 00000501

    ReplyDelete
  8. Can i extend the flying range with a 3g usb stick?
    how?

    ReplyDelete
  9. I figured out that this configuration only works for firmware version 1.3.3. With higher version u can enable the usb device but if u want to read from it the drone reboots! Does anyone hv a solution for this?

    ReplyDelete
  10. can the usb port be used to control a small relay, would there be control from within the android app?

    ReplyDelete
  11. I'm following this but am unable to get the dwc_otg_pcd file to compile as part of the kernel module needed. When I go into menuconfig and disable the Parrot USB driver (System Type -> Parrot Drivers -> PARROT6 USB driver (Synopsys)), then it builds, but without the needed module of course :).

    Any help in debugging would be much appreciated.

    $ make ARCH=arm CROSS_COMPILE=arm-none-linux-gnueabi- modules
    scripts/kconfig/conf -s arch/arm/Kconfig
    CHK include/linux/version.h
    make[1]: `include/asm-arm/mach-types.h' is up to date.
    CHK include/linux/utsrelease.h
    CALL scripts/checksyscalls.sh
    :1097:2: warning: #warning syscall fadvise64 not implemented
    :1265:2: warning: #warning syscall migrate_pages not implemented
    :1321:2: warning: #warning syscall pselect6 not implemented
    :1325:2: warning: #warning syscall ppoll not implemented
    :1365:2: warning: #warning syscall epoll_pwait not implemented
    CC [M] drivers/parrot/usb/dwc_otg/dwc_otg_driver.o
    CC [M] drivers/parrot/usb/dwc_otg/dwc_otg_attr.o
    CC [M] drivers/parrot/usb/dwc_otg/dwc_otg_cil.o
    CC [M] drivers/parrot/usb/dwc_otg/dwc_otg_cil_intr.o
    CC [M] drivers/parrot/usb/dwc_otg/dwc_otg_pcd.o
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1689:8: error: variable 'dwc_driver' has initializer but incomplete type
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1690:2: error: unknown field 'register_driver' specified in initializer
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1690:2: warning: excess elements in struct initializer
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1690:2: warning: (near initialization for 'dwc_driver')
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1691:2: error: unknown field 'unregister_driver' specified in initializer
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1691:2: warning: excess elements in struct initializer
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1691:2: warning: (near initialization for 'dwc_driver')
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c: In function 'dwc_otg_pcd_init':
    drivers/parrot/usb/dwc_otg/dwc_otg_pcd.c:1719:2: error: implicit declaration of function 'usb_gadget_register_udc'
    make[2]: *** [drivers/parrot/usb/dwc_otg/dwc_otg_pcd.o] Error 1
    make[1]: *** [drivers/parrot/usb/dwc_otg] Error 2
    make: *** [drivers/parrot] Error 2

    ReplyDelete
  12. As an additional note, I'm trying to compile for the original AR.Drone version.

    For the kernel source and base config, I used:
    https://projects.ardrone.org/attachments/387/ARDrone_Version_20110401.tar.bz2
    https://projects.ardrone.org/attachments/388/kernel.config

    ReplyDelete
  13. Fixed these errors last semester. In the file include/linux/usb/gadget.h, comment out the line #ifdef CONFIG_USB_GADGET_MULTIUDC and its matching #endif. Then rebuild the modules.

    This gets rid of the compiler errors, but I'm having trouble inserting the dwc_otg.ko kernel module into the drone. I get the error message "cannot insert 'dwc_otg.ko': invalid module format". Looking at the file /var/log/messages, I see that the version magic numbers don't match:
    version magic '2.6.27.47-parrot preempt mod_unload ARMv5 ' should be '2.6.32.9-g0d605ac pree
    mpt mod_unload ARMv7 '
    I'm still working on how to fix this...

    ReplyDelete
  14. I am wondering if it is possible for me to write a pulse to the TX serial pin using this code or something similar. My goal is to send a PPM signal to a servo using the serial pin.

    Anyone able to set me in the right direction?

    Thanks! =]

    ReplyDelete