USB Host with netmf 4.3

Hi,

I read the new USB Host documentation (https://www.ghielectronics.com/docs/36/usb-host), and I am a little bit confused about the ConfigureUsb() method.

My application must support a USB Mass storage and a USB Serial adaptor. Is the ConfigureUsb method some kind of handler called by the framework at some point ?
My original plan is to create a Usb class, setting up two handlers in the constructor:

public Usb()
{
Controller.MassStorageConnected += Controller_MassStorageConnected;
Controller.UsbSerialConnected += Controller_UsbSerialConnected;
Controller.start();
}

Is it the right thing to do?

I am especially confused about the mass storage interface. I expect the connection handler to be called when I plug in a USB key.

Looking closer at the example in the documentation, the ConfigureUsb(MassStorage massStorage) method install a RemovableMedia.Insert handler, and mount the device before receive the event triggered by the Insert handler… How is that possible? What calls ConfigureUsb, and what set up it MassStorage-type parameter ?

Do you have a more complete example on how it works, because the one provided here seem a little off their context to me…

Thx in advance.

@ thomas@ exmakhina.com - The example was unclear. I cleaned it up a bit and removed the ConfigureUsb method, sorry for any confusion. The examples should run as-is now. As for the RemovableMedia.Insert event: when you mount a device, such as an SD card or USB mass storage, Micro Framework does some internal configuration for the filesystem. Once that is complete, it raises the RemovableMedia.Insert event to tell you that it is ready to be used. That is why the example waits for that event to be fired using an AutoResetEvent before opening a file.

much clearer now,

thx John !

Hi guys,

I finally had some time to do additional test with the USB Host, and no matter what I try, nothing is detected.
I have 3 devices: a USB key, a Prolific USB serial cable, and a FTDI USB Serial cable.

With the netmf 4.2, the USB key was working, the prolific cable was detected but didn’t work, and the FTDI cable was detected as an “unknown” device. I managed to get it working by forcing the creation of a USB serial like below:

if (device.TYPE == USBH_DeviceType.Unknown)
{
UsbSerialDevice = new USBH_Device(device.ID, device.INTERFACE_INDEX, USBH_DeviceType.Serial_FTDI, device.VENDOR_ID, device.PRODUCT_ID, device.PORT_NUMBER);
UsbSerial = new USBH_SerialUSB(UsbSerialDevice, 19200, Parity.None, 8, StopBits.One);
UsbSerial.Open();
}

I followed John’s example, and my controller and callbacks are now initialized like this (it is all embedded in a usbHardware class):


public static UsbSerial usbSerialDevice = null;
public static MassStorage massStorageDevice = null;

public usbHardware()
{
   // Setup the USB handlers. 
   Controller.DeviceConnectFailed += Controller_DeviceConnectFailed;
   Controller.UsbSerialConnected += Controller_UsbSerialConnected;    
   Controller.MassStorageConnected += Controller_MassStorageConnected;
   Controller.Start();
}

private static void Controller_DeviceConnectFailed(object sender, EventArgs e)
{
   Debug.Print("USB device connection failed");
}

private static void Controller_UsbSerialConnected(object sender, UsbSerial device)
{
   Debug.Print("Detected a USB to serial adaptor of type:" + device.Type.ToString());
 
   // The newly connected device is a USB to serial adapter:
   usbSerialDevice = device;
   usbSerialDevice.BaudRate = 19200;
   usbSerialDevice.DataBits = 8;
   usbSerialDevice.Handshake = Handshake.None;
   usbSerialDevice.Parity = Parity.None;
   usbSerialDevice.StopBits = StopBits.One;
                 
   usbSerialDevice.Disconnected += usbSerialDevice_Disconnected;
}

private static void usbSerialDevice_Disconnected(BaseDevice sender, EventArgs e)
{
   // Nothing special here...
}

private static void Controller_MassStorageConnected(object sender, MassStorage device)
{
   Debug.Print("Detected a USB Mass-storage device.");
            
   RemovableMedia.Insert += RemovableMedia_Insert;
   // The newly connected device is a USB key:
   massStorageDevice = device;
   if (!massStorageDevice.Mounted)
   {
       massStorageDevice.Mount();
       evt.WaitOne();      // Wait for the file system to be actually mounted
    }
}

private static void RemovableMedia_Insert(object sender, MediaEventArgs e)
{
   Debug.Print("File system mounted.");

    evt.Set();
}

I was trying to figure out a way to handle an event for any connection on the USB Host, and to for the creation of an object the way I used to do for my FTDI cable (force from the BaseDevice class)… But I could find any callback called when a device type “unknown” is detected…

If you had any idea on what I missed, that would be awesome !.. Until now, I have absolutely no prints on the console, telling me that none of the event (USBSerial or mass storage connection, or connection failed) are fired.

Thanks !

Hi again,

I am focusing on the mass storage first, and I realized the Controller_MassStorageConnected is actually called. However, the RemovableMedia_Insert callback is never called, meaning (to me) the file system is not mounted.

I try to simplify my code as below:

private static void Controller_MassStorageConnected(object sender, MassStorage device)
{
   RemovableMedia.Insert += RemovableMedia_Insert;
   // The newly connected device is a USB key:
   massStorageDevice = device;
   massStorageDevice.Mount();
   evt.WaitOne();      // Wait for the file system to be actually mounted
}

Any particular reason for this? I am using the exact same USB key that was working with netmf 4.2.

Thanks,

Hi Andre,

It’s FAT32. However, I am 99% sure the USB key is not the problem since I was using the same with netmf 4.2, and it was working fine…

@ thomas_exmakhina -

For test USB thumb drive, was tested on G120. Other boards need to be changed the led and button pins.

static Boolean testWrite = true;
        static OutputPort led = new OutputPort((Cpu.Pin)(47), true);
        //static InputPort button = new InputPort((Cpu.Pin)(30), false, Port.ResistorMode.PullUp); // emx
        static InputPort button = new InputPort((Cpu.Pin)(22), false, Port.ResistorMode.PullUp); // g120
        public static void Main()
        {

            led.Write(true);
         
            while (button.Read()==true) 

            {
             
                Thread.Sleep(100);
                led.Write(true);
                Thread.Sleep(100);
                led.Write(!true);
            }

            RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
            RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);
            GHI.Usb.Host.Controller.MassStorageConnected += Controller_MassStorageConnected;
            GHI.Usb.Host.Controller.Start();
             led.Write(!true);
            
            const int BLOCK_LEN = 10*1024;
            const int BLOCK_COUNT = 100; // 1M
            byte[] bufferwrite = new byte[BLOCK_LEN];
            for (int i = 0; i < BLOCK_LEN; i++)
            {
                bufferwrite[i] = (byte)(i % 0xFF);
            }
            while (true)
            {
                Thread.Sleep(100);       
                if (canWrite)
                {
                    VolumeInfo vol = VolumeInfo.GetVolumes()[0];
                    //Debug.Print("Please wait for formating..");
                    //vol.Format("FAT", 0);
                    //Debug.Print("Please formated.");
                    string root = vol.RootDirectory;
                    if (testWrite)
                    {
                        
                        FileStream fs = new FileStream(root + @ "\test.txt", FileMode.Create);
                        for (int i = 0; i < BLOCK_COUNT; i++)
                        {
                            if (i % 10 == 0)
                                Debug.Print("i = " + i);
                            fs.Write(bufferwrite, 0, BLOCK_LEN);
                        }
                        fs.Flush();
                        fs.Close();
                        ps.Unmount();
                        canWrite = false;
                        Debug.Print("Write done");
                        led.Write(true);
                        break;
                    }
                    else
                    {
                        FileStream fs = new FileStream(root + @ "\test.txt", FileMode.Open);
                        byte[] readdata = new byte[BLOCK_COUNT];
                        if (BLOCK_COUNT != fs.Read(readdata, 0, BLOCK_COUNT))
                        {
                            throw new Exception("Can not read!");
                        }
                        else
                        {
                            for (int i = 0; i < BLOCK_COUNT; i++)
                            {
                                if (readdata[i] != bufferwrite[i])
                                {
                                    throw new Exception("Read error at " +  i );
                                }
                            }
                            Debug.Print("Read OK");
                            break;
                        }

                    }
                }

            }
            Thread.Sleep(-1);
        }

        static void Controller_MassStorageConnected(object sender, MassStorage e)
        {
            ps = e;
            ps.Mount();
            Debug.Print("Thumb drive detected...");
        }

        static void Controller_DeviceConnectFailed()
        {
            Debug.Print("Device disconnected...");
           
        }


        static void RemovableMedia_Eject(object sender, MediaEventArgs e)
        {
            Debug.Print("Thumb drive unmounted...");
            canWrite = false;
        }
        static bool canWrite= false;
        static void RemovableMedia_Insert(object sender, MediaEventArgs e)
        {
            Debug.Print("Thumb drive mounted...");
            canWrite = true;
        }


        static GHI.Usb.Host.MassStorage ps;
        

    }

Thx Dat,

My mass storage interface finally work ! I believe the trick was to setup the callback below when we initialize the controller.

RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert);
RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject);

I used to do that with an [em]event.set/waitOne[/em], and the handler what initialized in the [em]Controller_MassStorageConnected[/em] handler, what I guess was not the proper way to do for timing reasons…

Now, I am back to the USB/Serial interface which is still not detected. I set up a raw device handler to see if anything pops up on that side when I plug on of my USB/Serial cable … And it happens indeed !
As far as I understands how the framework works, it means the USB device is properly detected (I checked the VID&PID using VendorId/ProductId properties of the RawDevice object), but it does not match whatever the device type criteria is to start the USBSerial driver.

Once again, I use a Prolific and a FTDI cable, which are pretty standard on the market. With the netmf 4.2, I used to have a way to force a new USBSerial object creation as show below:

UsbSerialDevice = new USBH_Device(device.ID, device.INTERFACE_INDEX, USBH_DeviceType.Serial_FTDI, device.VENDOR_ID, device.PRODUCT_ID, device.PORT_NUMBER);
UsbSerial = new USBH_SerialUSB(UsbSerialDevice, 19200, Parity.None, 8, StopBits.One);

Since my USB/Serial cables are not detected properly, what work around do I have with the 4.3 framework? I look at the USBSerial class, and there is no constructor available, meaning I can not use the same trick I used with 4.2. If there is a similar thing to do, I will be ok because I will provide my customer with the [em]U[/em]SB/Serial cable as part of the delivery package, so I can hard-code its configuration.

For your information, I output the USB descriptor of both my cables (because I assume you somehow detect the USBSerial interface based on something in the USB descriptor (VID&PID, device class, etc…))

FTDI:
[em]Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 8
idVendor 0x0403 Future Technology Devices International, Ltd
idProduct 0x6015 Bridge(I2C/SPI/UART/FIFO)
bcdDevice 10.00
iManufacturer 1
iProduct 2
iSerial 3
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 32
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0xa0
(Bus Powered)
Remote Wakeup
MaxPower 90mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 2
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 255 Vendor Specific Subclass
bInterfaceProtocol 255 Vendor Specific Protocol
iInterface 2
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0[/em]

Prolific:
[em]Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 1.10
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x067b Prolific Technology, Inc.
idProduct 0x2303 PL2303 Serial Port
bcdDevice 3.00
iManufacturer 1
iProduct 2
iSerial 0
bNumConfigurations 1
Configuration Descriptor:
bLength 9
bDescriptorType 2
wTotalLength 39
bNumInterfaces 1
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 100mA
Interface Descriptor:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 3
bInterfaceClass 255 Vendor Specific Class
bInterfaceSubClass 0
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x000a 1x 10 bytes
bInterval 1
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x02 EP 2 OUT
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x83 EP 3 IN
bmAttributes 2
Transfer Type Bulk
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 0[/em]

Thank you

@ thomas_exmakhina - Prolific support has been marked obsolete and will probably not function. As for FTDI, your 4.2 fix is no longer available in 4.3 in the current SDK. While we look into possibly adding it, what specific FTDI cable are you using?

@ John - Why was Prolific support deprecated? I use it in most of my project that use GPS. The GPS module I use requires Prolific.

@ Mike - It was actually marked obsolete several SDKs ago, back in 2013. It is still in 2014 R2 though. We didn’t remove any of the existing code, we have just focused on FTDI support.

@ John - OK, please do not focus on Prolific support. It works. ;D

1 Like

John,

I use this one:

It is the first one showing up when you look for a USB to serial adapter on the FTDI web site:
http://www.ftdichip.com/Products/Cables/USBRS232.htm

Thomas

@ thomas_exmakhina - We’ll take a look and see what we can find. In the mean time, if it helps at all, we often use FTDI’s TTL-232R-3V3 cable and it does work, though it is not RS232.

Thanks John,

However, I need to drive a RS232 port. I need a USB <-> RS232 cable and I can not replace it by a TTL serial interface (the external device I need to drive is not part of the redesign I am working on).

Hi John,

Did GHI had a time to look at the FTDI USB-RS-232 cable I having trouble with?
Btw, is there any other cable I could buy that you know is working (G120, netmf 4.3)? I have already two, but I don’t mind buying a third one if it is too long to get a fix for the FTDI CHIP-X10…

Thx,

@ thomas_exmakhina - We don’t have a specific timeline just yet. I just verified that the UMC-201RL cable from Saelig works.

I just received the USB-COM-U USB-Serial Cable (replacement for the UMC-201RL) from Saelig, and it works fine.

Thanks !