This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

LPC2468 USB-MSD ChanFs FAT32

Dear All

i have a problem with modified version of USB hostlite with Mr Chans FS SFAT32.

DRESULT disk_ioctl(BYTE drv, /* Physical drive number (0..) */
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
        DRESULT res;
        int result;

        (void) result;

                //The FatFs module uses only device independent commands described below. Any device dependent function is not used.
                //Command Description
                //CTRL_SYNC Make sure that the disk drive has finished pending write process. When the disk I/O module has a write back cache, flush the dirty sector immediately. This command is not required in read-only configuration.
                //GET_SECTOR_SIZE Returns sector size of the drive into the WORD variable pointed by Buffer. This command is not required in single sector size configuration, _MAX_SS is 512.
                //GET_SECTOR_COUNT Returns total sectors on the drive into the DWORD variable pointed by Buffer. This command is used by only f_mkfs function to determine the volume size to be created.
                //GET_BLOCK_SIZE Returns erase block size of the flash memory in unit of sector into the DWORD variable pointed by Buffer. This command is used by only f_mkfs function and it attempts to align data area to the erase block boundary. The allowable value is 1 to 32768 in power of 2. Return 1 if the erase block size is unknown or disk devices.
                if ( drv != 0)  return RES_PARERR;
                if (usb_status & STA_NOINIT) return RES_NOTRDY;
                res = RES_OK;
                switch(ctrl) {
                        case CTRL_SYNC:
                                // TODO
                                break;
                        case GET_SECTOR_SIZE:
                                *(WORD*)buff = blkSize;
                                break;
                        case GET_SECTOR_COUNT:
                                *(DWORD*)buff = numBlks;
                                break;
                        case GET_BLOCK_SIZE:
                                *(DWORD*)buff = 1;
                                break;
                        default:
                                res = RES_PARERR;
                                break;
                }
                return res;
}


This function CTRL_SYNC case is flushing the last f_write call, since it is empty.

Someboby could help me?

V.Nagarajan

  • > This function CTRL_SYNC case is flushing the last f_write call, since it is empty.

    Implementation of disk_ioctl( CTRL_SYNC ) depends on your disk_write() operation.

    a) In your disk_write() code, do you have any write-back cache?
    OR
    b) Is your disk_write() asynchronous one?
    ie. it issues "start write" command and returns immediately.

    If your disk_write() code would complete write operation within itself, you may leave disk_ioctl( CTRL_SYNC ) empty.

    Tsuneo

  • Hi Tsuneo

    I did not use any writeback chach except FATfs.

    First Thank You for your attention.
    The problem i face is, the last f_write is not appended to text file.
    Tried to put a delay 100ms before f_close, still no difference.
    I use in RTX environment.

    If i use new f_write with CRLF data after actual data f_write, correctly appends. This additonal CRLF does not became part of data. So flushing is not proper before file close.

    Here is the code i use to disk_write and File operations

    int WriteUSBHost(unsigned char port, unsigned char *sp, unsigned char *ep, char *fnamep)
    {
            FIL ofile;
            FRESULT res;
            unsigned int bytewritten;
    
    
            if(usbhost[port].class == MASS_STORAGE_CLASS)
            {
                    if(*fnamep == 0)
                    {
                            strcpy(fnamep, "OUTPUT.TXT");
                    }
                    res = f_open(&ofile, fnamep, FA_OPEN_ALWAYS | FA_WRITE);
                    if(res != FR_OK)
                    {
                            return FAIL;
                    }
                    f_lseek(&ofile, f_size(&ofile));        //go to end of file
                    res = f_write(&ofile, sp, ep-sp, &bytewritten);
                    f_close(&ofile);
                    if((res != FR_OK) || (bytewritten != ep-sp))
                    {
                            return FAIL;
                    }
            }
            else return(USB_CLASS_NOT_SUPPORTED);
    
            return OK;
    }
    
    
    /*-----------------------------------------------------------------------*/
    /* Write Sector(s)                                                       */
    /*-----------------------------------------------------------------------*/
    /* The FatFs module will issue multiple sector transfer request
     /  (count > 1) to the disk I/O layer. The disk function should process
     /  the multiple sector transfer properly Do. not translate it into
     /  multiple single sector transfers to the media, or the data read/write
     /  performance may be drastically decreased. */
    
    #if _READONLY == 0
    DRESULT disk_write(BYTE drv, /* Physical drive number (0..) */
            const BYTE *buff, /* Data to be written */
            DWORD sector, /* Sector address (LBA) */
            BYTE count /* Number of sectors to write (1..255) */
    )
    {
            DRESULT res;
            int result;
    
            (void) result;
    
                    if ( drv != 0)  return RES_PARERR;
                    if (usb_status & STA_NOINIT) return RES_NOTRDY;
    //              if ( MS_BulkSend( sector, count, (volatile USB_INT08U*) buff ) == OK ) {
                    memcpy((void *)UserBuffer, buff, MS_BlkSize*count);
                    if ( MS_BulkSend( sector, count, UserBuffer ) == OK ) {
                            res = RES_OK;
                    } else {
                            res = RES_ERROR;
                    }
                    return res;
    
    }
    #endif /* _READONLY */
    

    V.Nagarajan

  • Your above code doesn’t directly show any cause of your problem.
    The problem lies in elsewhere.

    > I use in RTX environment.

    Is your WriteUSBHost() called by two or more tasks, which run concurrently?
    OR does any other task call any FatFs routine?

    FatFs routines aren’t re-entrant. In these cases, your code guards the FatFs calls (a routines like your WriteUSBHost) with a semaphore, so that just a single task runs it at a time.

    Tsuneo

  • Hi Tsuneo

    I use latest revision of FATfs/ Jan 15,'14 R0.10a

    WriteUSBHost() used in one Task only called apptask and one USB host port with MSD only right now.

    There is no return error anywhere.

    Here is the basic codes of USB Host

    i use event(USBP1_WDH) to indicate end of Write back done head interrupt.

    
    int OpenUSBHost(unsigned char port)
    {
            unsigned char status;
    
            status = OK;
    
            if(port == 0)
            {
                    if(enum_status & 0x1)
                    {
                            if (os_evt_wait_or(USBP1_RHSC_DIS, 0) == OS_R_EVT)
                            {
                                            if(usbhost[port].class == MASS_STORAGE_CLASS)
                                            {
                                                    f_mount(NULL, "", 0);
                                            }
                                            usbhost[port].class = 0;
                                            enum_status &= ~0x1;
                                            usb_status = STA_NOINIT;
                                            status = USB_PORT_DISCONNECT;
                            }
                    }
                    else if (Host_EnumDev(port) == OK )
                    {
                            if(usbhost[port].class == MASS_STORAGE_CLASS)
                            {
                                    status = USB_ENUM_FAIL;
                                    if ( (MS_Init(&blkSize, &numBlks, inquiryResult) == OK) && (f_mount(&Fatfs[0],"", 0) == OK))
                                    {
                                            enum_status |= 0x1;
                                            usb_status &= ~STA_NOINIT;
                                            status = OK;
                                    }
                            }
                            else
                            {
                                    enum_status |= 0x1;
                            }
                            os_evt_wait_or(USBP1_RHSC_DIS, 0);       //clear old events
    
                    }
                    else status = USB_ENUM_FAIL;
            }
            else
            {
                    if(enum_status & 0x2)
                    {
                            if (os_evt_wait_or(USBP2_RHSC_DIS, 0) == OS_R_EVT)
                            {
                                            if(usbhost[port].class == MASS_STORAGE_CLASS)
                                            {
                                                    f_mount(NULL, "", 0);
                                            }
                                            usbhost[port].class = 0;
                                            enum_status &= ~0x2;
                                            usb_status = STA_NOINIT;
                                            status = USB_PORT_DISCONNECT;
                            }
                    }
                    else if ( Host_EnumDev(port) == OK )
                    {
                            if(usbhost[port].class == MASS_STORAGE_CLASS)
                            {
                                    status = USB_ENUM_FAIL;
                                    if (MS_Init(&blkSize, &numBlks, inquiryResult) == OK)
                                    {
                                    usb_status &= ~STA_NOINIT;
                                            if(f_mount(&Fatfs[0], "", 1) == OK)
                                            {
                                                    enum_status |= 0x2;
                                                    status = OK;
                                            }
                                            else
                                            {
                                                    usb_status = STA_NOINIT;
                                            }
                                    }
                            }
                            else
                            {
                                    enum_status |= 0x2;
                            }
                            os_evt_wait_or(USBP2_RHSC_DIS, 0);       //clear old events
                    }
                    else status = USB_ENUM_FAIL;
            }
            return status;
    }
    
    
    
    USB_INT32S  Host_ProcessTD (volatile  HCED       *ed,
                                volatile  USB_INT32U  token,
                                volatile  USB_INT08U *buffer,
                                          USB_INT32U  buffer_len)
    {
        volatile  USB_INT32U   td_toggle, rv;
    
    
    
        if (ed == EDCtrl) {
            if (token == TD_SETUP) {
                td_toggle = TD_TOGGLE_0;
            } else {
                td_toggle = TD_TOGGLE_1;
            }
        } else {
            td_toggle = 0;
        }
        TDHead->Control = (TD_ROUNDING    |
                          token           |
                          TD_DELAY_INT(0) |
                          td_toggle       |
                          TD_CC);
        TDTail->Control = 0;
        TDHead->CurrBufPtr   = (USB_INT32U) buffer;
        TDTail->CurrBufPtr   = 0;
        TDHead->Next         = (USB_INT32U) TDTail;
        TDTail->Next         = 0;
        TDHead->BufEnd       = (USB_INT32U)(buffer + (buffer_len - 1));
        TDTail->BufEnd       = 0;
    
        ed->HeadTd  = (USB_INT32U)TDHead | ((ed->HeadTd) & 0x00000002);
        ed->TailTd  = (USB_INT32U)TDTail;
        ed->Next    = 0;
    
        if (ed == EDCtrl) {
            HcControlHeadED = (USB_INT32U)ed;
            HcCommandStatus = HcCommandStatus | OR_CMD_STATUS_CLF;
            HcControl       = HcControl       | OR_CONTROL_CLE;
        } else {
            HcBulkHeadED    = (USB_INT32U)ed;
            HcCommandStatus = HcCommandStatus | OR_CMD_STATUS_BLF;
            HcControl       = HcControl       | OR_CONTROL_BLE;
        }
            rv = os_evt_wait_or(USBP1_WDH, 200);
            if((rv == OS_R_EVT) && (os_evt_wait_or(USBP1_CC_ERR, 0) == OS_R_TMO)) return (OK);
            return (ERR_TD_FAIL);
    }
    
    
    

    Tried to call f_sync() before f_close still no change.

    elm-chan.org/.../

    V.Nagarajan

  • Hi Tsuneo.

    I got it resolved by adding SCSI_SYNCHRONIZE_CACHE_10 command in CTRL_SYNC case of disk_ioctl().

    Could i please have your feedback on this.

    
    
    //----------------------------------------------------------------------------
    USB_INT32S  MS_SynchnoniseCache (void)
    {
        USB_INT32S  rc;
    
    
        Fill_MSCommand(0, 0, 0, MS_DATA_DIR_NONE, SCSI_SYNCHRONIZE_CACHE_10, 6);
        rc = Host_ProcessTD(EDBulkOut, TD_OUT, TDBuffer, CBW_SIZE);
        if (rc == OK) {
            rc = Host_ProcessTD(EDBulkIn, TD_IN, TDBuffer, CSW_SIZE);
            if (rc == OK) {
                if (TDBuffer[12] != 0) {
                    rc = ERR_MS_CMD_FAILED;
                }
            }
        }
        return (rc);
    }
    
    
    DRESULT disk_ioctl(BYTE drv, /* Physical drive number (0..) */
    BYTE ctrl, /* Control code */
    void *buff /* Buffer to send/receive control data */
    )
    {
            DRESULT res;
            int result;
    
            (void) result;
    
    
                    if ( drv != 0)  return RES_PARERR;
                    if (usb_status & STA_NOINIT) return RES_NOTRDY;
                    res = RES_OK;
                    switch(ctrl) {
                            case CTRL_SYNC:
                                    // TODO
                                    MS_SynchnoniseCache();
                                    break;
                            case GET_SECTOR_SIZE:
                                    *(WORD*)buff = blkSize;
                                    break;
                            case GET_SECTOR_COUNT:
                                    *(DWORD*)buff = numBlks;
                                    break;
                            case GET_BLOCK_SIZE:
                                    *(DWORD*)buff = 1;
                                    break;
                            default:
                                    res = RES_PARERR;
                                    break;
                    }
                    return res;
    }
    
    void  Fill_MSCommand (USB_INT32U   block_number,
                          USB_INT32U   block_size,
                          USB_INT16U   num_blocks,
                          MS_DATA_DIR  direction,
                          USB_INT08U   scsi_cmd,
                          USB_INT08U   scsi_cmd_len)
    {
                USB_INT32U  data_len;
        static  USB_INT32U  tag_cnt = 0;
                USB_INT32U  cnt;
    
    
        for (cnt = 0; cnt < CBW_SIZE; cnt++) {
             TDBuffer[cnt] = 0;
        }
        switch(scsi_cmd) {
    
            case SCSI_CMD_TEST_UNIT_READY:
                 data_len = 0;
                 break;
            case SCSI_CMD_READ_CAPACITY:
                 data_len = 8;
                 break;
            case SCSI_CMD_REQUEST_SENSE:
                 data_len = 18;
                 break;
            case SCSI_CMD_INQUIRY:
                     data_len = 36;
                     break;
            default:
                 data_len = block_size * num_blocks;
                 break;
        }
        WriteLE32U(TDBuffer, CBW_SIGNATURE);
        WriteLE32U(&TDBuffer[4], tag_cnt);
        WriteLE32U(&TDBuffer[8], data_len);
        TDBuffer[12]     = (direction == MS_DATA_DIR_NONE) ? 0 : direction;
        TDBuffer[14]     = scsi_cmd_len;                                   /* Length of the CBW                 */
        TDBuffer[15]     = scsi_cmd;
            if(scsi_cmd == SCSI_SYNCHRONIZE_CACHE_10)
            {
                    return;
            }
            else if ((scsi_cmd == SCSI_CMD_REQUEST_SENSE)
         || (scsi_cmd == SCSI_CMD_INQUIRY)) {
            TDBuffer[19] = (USB_INT08U)data_len;
        } else {
            WriteBE32U(&TDBuffer[17], block_number);
        }
        WriteBE16U(&TDBuffer[22], num_blocks);
    }
    
    <\PRE>
    
    Once again thank you for pointing problem somewhere in earlier post.
    V.Nagarajan