2020-06-03 07:15 AM
I've created two USB MSC host applications with CubeMX (1.3.1) for two STM32H743 boards. One of them is a stock Nucleo-H743ZI2 using the OTG_FS interface, the other one is a custom board with STM32H743II using OTG_HS with the internal transceiver.
Then tried it with a couple of flash drives lying around. Reading files worked well on all drives. Writing stuff worked on all of them except one, where the directory entry was apparently not updated.
I've removed the fatfs stuff to test single-sector write and got this:
(I hope it goes without saying that you don't try it on a drive with valuable data. Sector 9 was unused on my drives, it might contain the root directory on yours.)
#include "main.h"
#include "string.h"
#include "fatfs.h"
#include "usb_host.h"
extern USBH_HandleTypeDef hUsbHostFS;
#define SECTOR 9
#define BS 512
uint32_t buf2[BS/4];
void usbtest(void) {
int r;
uint32_t j;
while(1) {
setleds(5);
while(!USBH_MSC_IsReady(&hUSB_Host)) // wait until a USB drive is inserted
MX_USB_HOST_Process();
memset(buf2, 6, BS); // clear buffer
r = USBH_MSC_Read(&hUSB_Host, 0, SECTOR, (void*)buf2, 1); // read one sector
while(r != USBH_OK) {
setleds(4);
__NOP();
}
j = buf2[0];
setleds(j);
buf2[0] = (j + 1) & 3; // modify sector data
r = USBH_MSC_Write(&hUSB_Host, 0, SECTOR, (void*)buf2, 1); // write it back
while(r != USBH_OK)
__NOP();
#if 0 // workaround
r = USBH_MSC_Read(&hUSB_Host, 0, SECTOR, (void*)buf2, 1); // read the sector again
while(r != USBH_OK)
__NOP();
#endif
while(USBH_MSC_IsReady(&hUSB_Host)) // wait until the drive is removed
MX_USB_HOST_Process();
}
}
Reading succeeds, writing fails silently (i.e. return value is USBH_OK, but the sector is not modified) on that one drive, succeeds on the rest. Unless I enable the workaround, reading back the sector I've just written (or any other sector).
The offending drive is a 8 to 10 years old 16 GB Intenso Business Line, which still works perfectly in my PC.
I am quite clueless about USB, so my questions are bit vague
2020-06-03 08:00 AM
Welcome to the world of widely used crappy standards with many ambiguous interpretations, decades of historical layers and decades of ignoring the details in the implementations.
I luckily never needed (and I hope I never will) to write through MSC. Quick skimming of the crap documentation I've gathered points to using the FUA bit in the SCSI Write commands.
JW
2020-06-03 08:14 AM
Looking into CubeF4, it appears that in USBH_MSC_SCSI_Write() you'd need to add
MSC_Handle->hbot.cbw.field.CB[1] |= 1 << 3; // FUA is bit 3 -- An FUA bit set to one specifies that the device server shall write the logical blocks to non-volatile cache (if any) or the medium.
JW
2020-06-04 05:01 AM
Setting the FUA bit (or DPO or both) in the write command had no effect.
So I've found the SYNCHRONIZE CACHE (10) command, and set out to add it to the host MSC . I've used REQUEST SENSE (which was already implemented) as a template and sent it after every write command. And it worked, all files and directories are properly written now.
Now I'm going to turn the copied REQUEST SENSE into a proper SYNCHRONIZE CACHE command, and issue it after unmounting. And START STOP UNIT too, because SYNCHRONIZE CACHE is apparently not universally supported. And add a dummy read for good measure.
2020-06-04 06:22 AM
Interesting, thanks.
I'd leave the FUA bit there, and I'd recommend you to test significantly more drives.
In my case, out of a dozen of drives I was unable to use three, although neither was SCSI-voodoo related - one was a non-class device, two had nonstandard partitions (this one may or may not apply if you can format the drive, or use it as a purely sector-oriented device). I've also heard of flash drives which contain a hub. Of course, all of these "work well with PC".
JW
2020-06-05 05:56 AM
In case you've missed it, expect this kind of joy if you plan to support any flash drive which "works well with PC"...
Jan
2020-06-05 07:30 AM
As a long time Linux user, I'm already familiar with the "works well with Windows" variant, so I'm not surprised.
I'm already looking into this pile of ... code layers, and have the feeling that it will keep me occupied for some time. Something doesn't work? Cast some value into a random unsigned type. Need some waiting? Don't bother with extending the state machine, just throw in a delay.