USBHostMBed5 FileRead.ino Fails with Crash

It takes a while. But just a heads up on stuff

  1. Tried enable exFAT by changing config settings in mbed_config but that didn't seem to help.
  2. Partitioned USB drives don't seem to be supported.

Think I have a couple of posts on that last one :slight_smile:

@KurtE @Merlin513 - I have finally figured out what was causing:

Starting USB File Write example...
Mounting USB device...
Open /usb/numbers.txt
Writing numbers (0/10)
Writing numbers (1/10)
Writing numbers (2/10)
Writing numbers (3/10)
Writing numbers (4/10)
Writing numbers (5/10)
Writing numbers (6/10)
Writing numbers (7/10)
Writing numbers (8/10)
Writing numbers (9/10)
File closing
fclose error:I/O error (-5)

This error only happens when opening a file for write:

  FILE *f = fopen("/usb/numbers.txt", "w+");

I am not sure why yet. In an effort to see if a USB keyboard, mouse and USB would play nice together I put together some sketches to test with. Short answer, they don't. But after a lot of exploring and testing I localized on what is causing the problem.
In "USBHostConf.h" there is a define:

#define ARC_USB_FULL_SIZE 1

at the end of the file. If this is defined the USB keyboard and mouse work but then we get the fclose error for a file write. If I comment out the define then the USB mouse and keyboard are not recognized and file writing works.
I know that the above define is a fix for a USB interrupt flooding issue. I gave up trying to setup debugging with 2.2.1 Arduino IDE. I scoured the internet and the forum for an applicable working setup but nothing seems to be current or complete for the GIGA. So using KDiff3 and a process of elimination I was able to find the problem area.
I'll keep playing with it. Any advise would be helpful :grinning:

1 Like

@wwatson @Merlin513 @BobTheDog and all.

Not sure yet. Been taking a break from that :exploding_head: issues for simpler topic :face_with_head_bandage: of getting the ILI9341 display driver to work with DMA. Now that, appears to work, I will get back to playing with the USBHost stuff. LIke why I can not get a USB LS keyboard to work when it is plugged into a hub...

Today I experimented with the same setup but running on a Teensy Micromod. Earlier I could not easily capture the USB when the HUB was plugged in as it will run at USB HS, and I can not capture that... But now I have a new USB 1.1 HUB (from 2003. And I can now capture it.

I was also experimenting with a USB Breakout board, that I can plug in between the HUB and device and easily capture from there as well. My MicroMod breakout board has the D+ and D- broken out so easy to capture.

Probably done for today, but hopefully tomorrow will get back into USBHost stuff.

1 Like

Looks like to much fun :grinning: I made a little progress today. I truned on level 4 debug in dbg.h and redirected stdout to serial and found exactly where the error is showing up at.

[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/targets/TARGET_STM/USBEndpoint_STM.cpp:137]
 st = 18

[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/targets/TARGET_STM/USBEndpoint_STM.cpp:159](SS)HAL_HCD_HC_Init(0x2400139c 2 129 2 1 2 64)

[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:243]Send CBW
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:249]data stage
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:266]Read CSW
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:275]recv csw: status: 0
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:243]Send CBW
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:249]data stage
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:266]Read CSW
[USB_DBG: /home/wwatson/Arduino/libraries/Arduino_USBHostMbed5-usb_host_fixes_lowspeed/src/USBHostMSD/USBHostMSD.cpp:275]recv csw: status: 0
fclose error:I/O error (-5)

The line numbers might be offset a little as I have been adding USB_DBG's here and there. It seems to be falling into an error state at line #137 (st == USB_TYPE_ERROR). One other strange happening is if I comment out everything except the file open and file close in FileWrite.ino and have the debug level at 4 then it completes without error. If I then uncomment fprintf(f, "%d\n", i); it fails again. Kinda stumped at this point. After kdiff3ing most all of the source code I am getting a better idea of what's going on. Is that one of your MicroMod homemade boards?

I had been working on some code that gets hubs and multiple devices working correctly.

It is a level on top of the existing code and the user has to develop a driver at this level, drivers are automatically used by the system if registered.

I have been doing this for multiple Midi devices, but also have an example of an Interrupt driven driver as well.

If anyone is interested I could get it up into GitHub for you to play with?

This is the interface that the driver needs to implement:

#pragma once
#include "USBHost/USBHostConf.h"
#include "USBHost/USBHost.h"

class IUSBHostMultiDriver 
{
public:
  // mandatory
  virtual std::string     GetDriverName(void) = 0;
  virtual bool            IsEndpointSupported(ENDPOINT_TYPE endpointType) = 0;
  virtual bool            IsInterfaceSupported(uint8_t uClass, uint8_t uSubclass, uint8_t uProtocol) = 0;
  virtual void            RecievedUSBData(uint8_t uDeviceIndex, uint8_t *pData, uint16_t uLength) = 0;

  // optional
  virtual void            ParseConfigEntry(uint8_t type, uint8_t sub_type, uint8_t *data, uint32_t len) {};
  virtual void            DeviceConnected(uint8_t uDeviceIndex) {};
  virtual void            DeviceDisconnected(uint8_t uDeviceIndex) {};
  virtual bool            HandleTransfersAutomatically(void) { return true; };
};

And an example of how you register devices:

USBHostMulti                  *pMultiHost = nullptr;

USBHostMultiMidiDriver        *pMultiMidiDriver = nullptr;
USBHostMultiHIDKeyboardDriver *pMultiHIDKeyboardDriver = nullptr;


void setup()
{
  USE_SERIAL.begin(115200);

  pinMode(PA_15, OUTPUT); //enable the USB-A port
  digitalWrite(PA_15, HIGH);

  printf("Starting MIDI driver test\r\n");

  pMultiHost = new USBHostMulti();
  pMultiMidiDriver = new USBHostMultiMidiDriver(pMultiHost);
  pMultiHIDKeyboardDriver = new USBHostMultiHIDKeyboardDriver(pMultiHost);

}

After drivers are registered the system handles everything, when the device is connected, the correct driver is used and transfers are automatically handled. When the device is disconnected the driver is disabled.

Here is a simple test USB HID keyboard test which doesn't do much but shows the basics:

#include "USBHostMultiHIDKeyboardDriver.h"
#include "USBHostMultiInterface.h"
#include "USBHostMulti.h"


USBHostMultiHIDKeyboardDriver::USBHostMultiHIDKeyboardDriver(USBHostMulti *pHostMulti)
: m_pHostMulti(pHostMulti)
{
  m_pHostMulti->AddDriver(this);
}

USBHostMultiHIDKeyboardDriver::~USBHostMultiHIDKeyboardDriver(void)
{

}

std::string USBHostMultiHIDKeyboardDriver::GetDriverName(void)
{
  return "HID Keyboard Driver example";
}

void USBHostMultiHIDKeyboardDriver::RecievedUSBData(uint8_t uDeviceIndex, uint8_t *pData, uint16_t uLength)
{
  if(uLength > 0)
  {
    printf("Keyboard data received : ");
    for(uint_fast8_t u = 0; u < uLength; u++)
      printf("0x%.2x%s", pData[u], u==uLength-1 ? "\r\n" : ", ");
  }
}

bool USBHostMultiHIDKeyboardDriver::IsEndpointSupported(ENDPOINT_TYPE endpointType)
{
  return INTERRUPT_ENDPOINT == endpointType;
}

bool USBHostMultiHIDKeyboardDriver::IsInterfaceSupported(uint8_t uClass, uint8_t uSubclass, uint8_t uProtocol)
{
  return((uClass == HID_CLASS) && (uSubclass == 0x01) && (uProtocol == 0x01));
}
1 Like

One thing that is currently missing is the code to support IUSBHostMultiDriver::HandleTransfersAutomatically{}

Currently it is only set up for automatic transfers, so I need to implement that which is quick, then a tidy up and get a clean branch into GitHub, which is not quick.

I meant to have had all this done but my back went again so I haven't been looking at it for over a week. :frowning:

Not sure I mentioned it in this thread or not but before getting distracted with DMA I was trying to get 2 joysticks working on a hub. Unfortunately couldn't getting them working nicely. Both would be recognized and the loose one after a second and would only see data from one of joysticks. This may getting playing nice together.

@BobTheDog - Sorry to hear about your back. It sucks being stuck on your back for weeks :frowning_face: I assumed (incorrectly) that using multiple USB devices was already available. That kinda gives me an idea of where USB Host development on the GIGA is at. I can help with testing and such.

Thanks for the info.

Yes mostly... That is I had the board fabricated and partially assembled (5 of them) by PCBWay

Hope your back is better!

It will be interesting to try out. It is too early in morning and I have not had enough :coffee: yet to ask informed questions, things like:

a) I would have thought the HUB code, and the like would handle most of this, but then again...

b)

Your example you use pointers and new operators. Is this required or can I instead simply have:

USBHostMulti                  MultiHost;
...

c) Is this new class class used as a replacement or in addition to the current base class IUSBEnumerator ?

Gut says replacement. Will be interesting to see if I can still get all of the additional information like, I am doing some of our extended classes. Currently most of them are based off of an extended version of it:

GIGA_USBHostMBed5_devices/src/IUSBEnumeratorEX.h at main ยท KurtE/GIGA_USBHostMBed5_devices (github.com)

Maybe I should have said:

But rather:

I had been working on some code that gets hubs and multiple devices working more easily.

So it is really just a way of getting the "drivers" connected to USB devices automatically, rather than the existing way. Also a single "driver" can handle multiple devices, the way the existing "drivers" are written doesn't seem to offer this ability.

So it is a level on top of the existing stuff to simplify things, so an addition.

You don't need to use pointers:

USBHostMulti multiTest;
USBHostMultiMidiDriver midiDriver(&multiTest);

I had a quick look at IUSBEnumeratorEX, in the stuff I have done everything there is available in the higher level device USBHostMultiDevice apart from getStringDesc() but that could be added.

Also I think for the lower level stuff like your HID dumper I would need to add some sort of getter functions to get at the underlying MBED/STM gubbins.

At the moment it is more a proof of concept, I wanted a way that multiple different USB devices could be connected and everything was connected up automatically. So a starting point really.

I am attempting to get a version of Arduino_USBHostMbed5 for the usb_host_fixes branch working at the moment, for some reason disconnecting has stopped working and I can't work out why. Works fine in my hacking branch but you don't want that!

2 Likes

Sounds good, will give it a try when you have a version you like.

I thought that now that I have the ILI9341 display code working pretty well, that I might port over the Picture Viewer example or at least a subset...

Not sure if this should be part of this or new thread, but it appears like there is only a few of us up here looking anyway so...

First quick notes:
I miss the Teensy unifying FS/File classes that extend across SD, USB and MTP. Maybe I have missed it, but I don't think there is an implementation of MTP?
So I thought I would start with USB as there is no SD card on these boards...

Right now trying to understand some of the current capabilities, in particular can I get some of the same information about the Files and Directories, that I can get from other setups including SDFat. Things like:
On File system: How big is it and how much space is free (or used)
For Files, Can I get the size of it, plus when was it created? When was it last updated?

I am assuming I can find out if the file is a directory or not:

struct dirent {
    char d_name[NAME_MAX + 1]; ///< Name of file
    uint8_t d_type;          ///< Type of file
};

But now, I am sort of confused (not that unusual). The example sketches use
DIR and FILE... whereas if I look at the MBed6 documentation, it sort of looks like there are unifying classes. Would have thought:

That instead of: fopen... there would be calls like: usb.open(...) or usb.opendir(..)
that would return File and Dir instead of FILE and DIR ...

Probably does not help that the File read and write examples have:

  mbed::fs_file_t file;
  struct dirent *ent;
  int dirIndex = 0;
  int res = 0;
  Serial.println("Open file..");
  FILE *f = fopen("/usb/Arduino.txt", "r+");

where the file end ent objects or structures are not used...

But I am probably missing something!

Here is a link that explains dirent including the DIR entry types:
https://www.gnu.org/software/libc/manual/html_node/Directory-Entries.html

The most common way of getting the file size I have seen is this:

fseek(f, 0, SEEK_END); // seek to end of file
size = ftell(f); // get current file pointer
fseek(f, 0, SEEK_SET); // seek back to beginning of file

Where you open the file for read, seek to the end of the file, use ftell to report the current file position pointer, seek back to the beginning of the file and then close the file.

With the ext4 filesystem you have something like this:

/********************************FILE DESCRIPTOR*****************************/

/**@brief   File descriptor. */
typedef struct ext4_file {

	/**@brief   Mount point handle.*/
	struct ext4_mountpoint *mp;

	/**@brief   File inode id.*/
	uint32_t inode;

	/**@brief   Open flags.*/
	uint32_t flags;

	/**@brief   File size.*/
	uint64_t fsize;

	/**@brief   Actual file position.*/
	uint64_t fpos;
} ext4_file;

/*****************************DIRECTORY DESCRIPTOR***************************/

/**@brief   Directory entry descriptor. */
typedef struct ext4_direntry {
	uint32_t inode;
	uint16_t entry_length;
	uint8_t name_length;
	uint8_t inode_type;
	uint8_t name[255];
} ext4_direntry;

/**@brief   Directory descriptor. */
typedef struct ext4_dir {
	/**@brief   File descriptor.*/
	ext4_file f;
	/**@brief   Current directory entry.*/
	ext4_direntry de;
	/**@brief   Next entry offset.*/
	uint64_t next_off;
} ext4_dir;

This is from my Teensy version of LWext4 which I am thinking of porting to the GIGA.

Hope this helps :slightly_smiling_face:

1 Like

Thanks,

You are right that one option to find the file sizes is to open the file and seek to the end and close the file... But if I remember correctly on some File systems it would then have to read through all of the cluster information....,

I had already figured they are setup using the C stdio calls for a lot of this.
But I guess, what I am really trying to ask is: why?

Especially since their library name is: Arduino_USBHostMbed5.. and this is Arduino where you are doing c++ classes for most things, I am surprised that
Would have thought that maybe it would have thought they would follow along the same lines.

Sorry I am probably just whining and maybe I should just punt here and go back to
trying it out with SD, as SDFat uses classes and the like.

Thanks again!

Yeah, I remember when you optimized Fat32 cluster counting for SD's and MSC.
What they have done is wrap the stdio calls around Chan's FatFS library. I discovered this when I was setting up Arduino_core to recompile for debugging. It's been a long time since played with FatFS. That was back when I wrote the MSC library and adapted it to the uSDFS library which used FatFS. Their motivation was to stick with Fat32. I also tried turning on ExFat which FatFS now supports but was unsuccessful.

Right now I took a break and went back to trying to get the IDE debug to work...

Tried that as well but when I was digging around mbedos found a comment that its not supported since it would require a license from Microsoft. Forgot where I found that but all I know is you can't get there from here.

Other issue is you can not use multiple partitions on a USB drive. Tried using fatfs directly and no dice.

Good to know. I did not see that but it makes sense. Thanks :smile:

Which hardware debugger are you trying to use?

Just the one builtin to the IDE. I have the ST-Link V2 but I have not been able to get it to work. Right now I am using the default 'openocd' which should call up GDB through cortex-debug, I think.

I started a thread specific to the issue:
https://forum.arduino.cc/t/arduino-ide-2-2-1-debug-failure/1195757
which I think you just found :smile:

I now have a version of the TFT Picture viewer, which is converted over to use
the USBHost... Fat32 files.

It is starting to sort of work, but! The performance sucks!

I freshly formatted an 8GB USB Stick using the SDFormatter. I then copied the contents of an SD Card that I use to run the picture viewer on a Teensy Micromod.
The code on the Teensy is setup currently to run with an SD card, plus it has MTP in it, and I can copy files to and from...

Some debug output:

Loop looking for image file

Loading JPG image '/usb/DSC00445.jpg'
Image size: 480x640Scale: 1/2 Image Offsets (40, -40)
!!File:/usb/DSC00445.jpg Time:4436 writeRect calls:0

Loop looking for image file

Loading JPG image '/usb/DSC01511.JPG'
Image size: 2560x1920Scale: 1/8 Image Offsets (0, 0)
!!File:/usb/DSC01511.JPG Time:169468 writeRect calls:0

Loop looking for image file

Loading JPG image '/usb/DSC03201.JPG'
Image size: 3072x2304Scale: 1/8 Image Offsets (-32, -24)
!!File:/usb/DSC03201.JPG Time:283710 writeRect calls:0

Loop looking for image file

Loading JPG image '/usb/halloween.jpg'
Image size: 216x242Scale: 1/1 Image Offsets (52, -1)
!!File:/usb/halloween.jpg Time:1796 writeRect calls:0

Loop looking for image file

Loading JPG image '/usb/Jake-and-Clare-In-Car.jpg'
Image size: 1024x768Scale: 1/4 Image Offsets (32, 24)
!!File:/usb/Jake-and-Clare-In-Car.jpg Time:6293 writeRect calls:0

Or easier to see data version: GIGA USB drive

DSC00445.jpg  Image size: 480x640 Time:4436
DSC01511.JPG Image size: 2560x1920 Time:169468 
DSC03201.JPG Image size: 3072x2304 Time:283710 
halloween.jpg Image size: 216x242 Time:1796
Jake-and-Clare-In-Car.jpg size:1024x768Scale:  Time:6293 
Laiik-is-Tired.bmp Image size: 320x240 Time:31598 

Teensy MicroSD:

!!File:DSC00445.jpg Time:22
!!File:DSC01511.JPG Time:269
!!File:DSC03201.JPG Time:436
!!File:halloween.jpg Time:11
!!File:Jake-and-Clare-In-Car.jpg Time:19
!!File:Laiik-is-Tired.bmp Time:130

So for example DSC01511.JPG on Teensy about 1/4 second on GIGA almost 3 minutes!
:astonished:

1 Like