close

ST_logo_20130425.png

移植FatFs至STM32F429ZIT有一點要特別注意,就是版本相容性,本人實驗過各個FatFs與STM32F4xx_DSP_StdPeriph_Lib的版本,只有以下版本能成功運行,

STM32F4xx_DSP_StdPeriph_Lib_V1.3.0

FatFs R0.09b

FatFs移植至STM32F429ZIT可參照[STM32F429ZIT-MCU學習筆記]FatFs移植與使用SD Card來進行,這裡只講解USB部分,USB可以非常多的應用,主要功能有兩種設定,一種是HOST,另一種是Device,這篇先介紹HOST,就是讀取USB裝置的資訊,可以用在USB隨身碟,USB鍵盤等周遭介面,USB選用STM32_USB-Host-Device_Lib_V2.1.0,下載點如下,

STM32_USB-Host-Device_Lib_V2.1.0

下載完成壓縮檔如下,

1.JPG

解完壓縮如下,

2.JPG

\uubt-master\src\STM32_USB-Host-Device_Lib_V2.1.0\Libraries複製下圖這三個資料夾,

3.JPG

複製到專案目錄底下,

4.JPG

進入Keil uVision5引入HOST會用的.c與.h檔,建立STM32_USB_OTG_Driver,引入STM32_USB_OTG_Driver資料夾內的.c檔

5.JPG

建立STM32_USB_HOST_Library,引入STM32_USB_HOST_Library資料夾內的.c檔

6.JPG

注意usb_bsp_template.c要改成usb_bsp.c,usb_conf_template.h改成usb_conf.h,usbh_conf_template.h改成usbh_conf.h

在stm32f429 discovery開發版上有使用EMIF02-USB03F2這IC,所以在USB設定配置時須要用HS模式去做配置,

10.JPG

在Option for Target 'Target 1'切到C/C++,在Preprocessor Symbols中的Define增加,USE_USB_OTG_HS

7.JPG

在下面的Language/Code Generation設定如下,

8.JPG

.h檔增加路徑如下,

9.JPG

增加完成結果如下,

11.JPG

接下來要進行文件修改與配置,先修改usb_conf.h,增加#include "stm32f4xx.h",

12.JPG

將USB OTG HS CONFIGURATION多餘的設定移除,

13.JPG

將USB OTG FS CONFIGURATION多餘的設定移除,

15.JPG

將USE設定為USE_HOST_MODE,

14.PG.JPG

將下圖的#error移除掉

16.JPG

17.JPG

修改usb_bsp.c,Includes如下設定

18.JPG

USB_OTG_BSP_Init如下設定

/**
  * @brief  USB_OTG_BSP_Init
  *         Initilizes BSP configurations
  * @param  None
  * @retval None
  */

void USB_OTG_BSP_Init (USB_OTG_CORE_HANDLE *pdev)
{
  GPIO_InitTypeDef GPIO_InitStructure;    

  /* Configuration for USB OTG HS used in FS mode with EMBEDDED PHY */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_14 | GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
  
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource12, GPIO_AF_OTG_HS_FS) ; 
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource14, GPIO_AF_OTG_HS_FS) ; 
  GPIO_PinAFConfig(GPIOB, GPIO_PinSource15, GPIO_AF_OTG_HS_FS) ;
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;    
  GPIO_Init(GPIOB, &GPIO_InitStructure);  
    
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_OTG_HS, ENABLE);
}

USB_OTG_BSP_EnableInterrupt如下設定

/**
  * @brief  USB_OTG_BSP_EnableInterrupt
  *         Enabele USB Global interrupt
  * @param  None
  * @retval None
  */
void USB_OTG_BSP_EnableInterrupt (USB_OTG_CORE_HANDLE *pdev)
{
  NVIC_InitTypeDef NVIC_InitStructure; 
     
  NVIC_InitStructure.NVIC_IRQChannel = OTG_HS_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);  
}

USB_OTG_BSP_DriveVBUS如下設定

/**
  * @brief  BSP_Drive_VBUS
  *         Drives the Vbus signal through IO
  * @param  speed : Full, Low 
  * @param  state : VBUS states
  * @retval None
  */

void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev,uint8_t state)
{
  if (state==0)
  { 
    /* DISABLE is needed on output of the Power Switch */
    GPIO_SetBits(GPIOC, GPIO_Pin_4);
  }
  else
  {
    /*ENABLE the Power Switch by driving the Enable LOW */
    GPIO_ResetBits(GPIOC, GPIO_Pin_4);
  }
}

USB_OTG_BSP_ConfigVBUS如下設定

/**
  * @brief  USB_OTG_BSP_ConfigVBUS
  *         Configures the IO for the Vbus and OverCurrent
  * @param  Speed : Full, Low 
  * @retval None
  */

void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev)
{
  GPIO_InitTypeDef GPIO_InitStructure; 
  
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);  
  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  GPIO_SetBits(GPIOC, GPIO_Pin_4);
  
  USB_OTG_BSP_mDelay(200); 
}

USB_OTG_BSP_uDelay如下設定

/**
  * @brief  USB_OTG_BSP_uDelay
  *         This function provides delay time in micro sec
  * @param  usec : Value of delay required in micro sec
  * @retval None
  */
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
    delay_us(usec);
}

USB_OTG_BSP_mDelay如下設定
/**
  * @brief  USB_OTG_BSP_mDelay
  *          This function provides delay time in milli sec
  * @param  msec : Value of delay required in milli sec
  * @retval None
  */
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
    delay_ms(msec);
}

再增加OTG_HS_IRQHandler

void OTG_HS_IRQHandler(void)
{
      USBH_OTG_ISR_Handler(&USB_OTG_HS_Core);
}

\uubt-master\src\STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Host_Device_Examples\DRD\srcusbh_msc_usr.c

19.JPG

\uubt-master\src\STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Host_Device_Examples\DRD\incusbh_msc_usr.h

20.JPG

將以上這兩隻程式移植\STM32F429_Configuration\src\STM32F429_Configuration\inc

21.JPG

usbh_msc_usr.c裡可以完呈現USB進入系統的運作裝況,方便開發者去了解與修改,這裡只講解額外增加的部分,

22.JPG

USB_OTG_CORE_HANDLE   USB_OTG_HS_Core;
uint8_t USBH_USR_ApplicationState;
USBH_HOST USBH_Host;      
 

/*
程式名稱:USB初始化
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/6/23
程式修改日期:N/A
程式說明:

*/
uint8_t USBH_UDISK_Init(void){
    return HCD_IsDeviceConnected(&USB_OTG_HS_Core);
}

/*
程式名稱:USB狀態
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/6/23
程式修改日期:N/A
程式說明:

*/
uint8_t USBH_UDISK_Status(void){
    return USBH_USR_ApplicationState;
}

/*
程式名稱:USB讀取
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/6/23
程式修改日期:N/A
程式說明:

*/
uint8_t USBH_UDISK_Read(uint8_t* buffer, uint32_t sector, uint32_t cnt){
    uint8_t res=1;
    
    if(HCD_IsDeviceConnected(&USB_OTG_HS_Core) && USBH_USR_ApplicationState!=USH_USR_FS_INIT){              
        do{
            res = USBH_MSC_Read10(&USB_OTG_HS_Core, buffer, sector, 512*cnt);
            USBH_MSC_HandleBOTXfer(&USB_OTG_HS_Core, &USBH_Host);        
      
            if(!HCD_IsDeviceConnected(&USB_OTG_HS_Core)){
                res = 1;
                break;
            };   
        }while(res==USBH_MSC_BUSY);
    }else{ 
        res = 1;
    }
    
    if(res==USBH_MSC_OK){
        res = 0;    
    }
    return res;
}

/*
程式名稱:USB寫入
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/6/23
程式修改日期:N/A
程式說明:

*/
uint8_t USBH_UDISK_Write(uint8_t* buffer, uint32_t sector, uint32_t cnt){
    uint8_t res=1;
    
    if(HCD_IsDeviceConnected(&USB_OTG_HS_Core) && USBH_USR_ApplicationState!=USH_USR_FS_INIT){              
        do{
            res = USBH_MSC_Write10(&USB_OTG_HS_Core, buffer, sector, 512*cnt); 
            USBH_MSC_HandleBOTXfer(&USB_OTG_HS_Core, &USBH_Host);        
      
            if(!HCD_IsDeviceConnected(&USB_OTG_HS_Core)){
                res = 1;
                break;
            };   
        }while(res==USBH_MSC_BUSY);
    }else{
        res = 1;
    }        
    
    if(res==USBH_MSC_OK){
        res = 0;    
    }
    return res;
}

usbh_msc_usr.h需增加

23.JPG

extern  uint8_t USBH_USR_ApplicationState ;
extern USB_OTG_CORE_HANDLE   USB_OTG_HS_Core;
extern USBH_HOST USBH_Host;  

24.JPG

uint8_t USBH_UDISK_Init(void);//USB初始化
uint8_t USBH_UDISK_Status(void);//USB狀態
uint8_t USBH_UDISK_Read(uint8_t* buffer, uint32_t sector, uint32_t cnt);//USB讀取
uint8_t USBH_UDISK_Write(uint8_t* buffer, uint32_t sector, uint32_t cnt);//USB寫入

接下來要在FatFs/diskio.c增加USB的方法,

25.JPG

#include "diskio.h"        /* FatFs lower layer API */
#include "sdio_config.h"
#include "usbh_msc_usr.h"

26.JPG

/*-----------------------------------------------------------------------*/
/* Inidialize a Drive                                                    */
/*-----------------------------------------------------------------------*/

DSTATUS disk_initialize (
    BYTE pdrv                /* Physical drive nmuber (0..) */
)
{
    DSTATUS stat;
    int result;

    switch (pdrv) {
    case ATA :

        return stat;

    case MMC :
        result = SD_Init();
        stat = result;
        
        return stat;

    case USB :
        result = USBH_UDISK_Init();
    
        if(result==1){
            stat = RES_OK;
        }else{
            stat = RES_ERROR;
        }

        return stat;
    }
    return STA_NOINIT;
}

27.JPG

/*-----------------------------------------------------------------------*/
/* Get Disk Status                                                       */
/*-----------------------------------------------------------------------*/

DSTATUS disk_status (
    BYTE pdrv        /* Physical drive nmuber (0..) */
)
{
    DSTATUS stat;
    int result;

    switch (pdrv) {
    case ATA :
        
        return stat;

    case MMC :
        result = SD_GetStatus();
        stat = result;
    
        return stat;

    case USB :
        result = USBH_UDISK_Status();
        stat = result;
    
        return stat;
    }
    return STA_NOINIT;
}

28.JPG

/*-----------------------------------------------------------------------*/
/* Read Sector(s)                                                        */
/*-----------------------------------------------------------------------*/

DRESULT disk_read (
    BYTE pdrv,        /* Physical drive nmuber (0..) */
    BYTE *buff,        /* Data buffer to store read data */
    DWORD sector,    /* Sector address (LBA) */
    BYTE count        /* Number of sectors to read (1..128) */
)
{
    DRESULT res;
    int result;

    switch (pdrv) {
    case ATA :
        // translate the arguments here

        //result = ATA_disk_read(buff, sector, count);

        // translate the reslut code here

        return res;

    case MMC :
        if(count>1){
            result = SD_ReadMultiBlocks(buff, sector*BLOCK_SIZE, BLOCK_SIZE, count);
        }else{
            result = SD_ReadBlock(buff, sector*BLOCK_SIZE, BLOCK_SIZE);
        }
    /* Check if the Transfer is finished */
    result = SD_WaitReadOperation();
    while(SD_GetStatus() != SD_TRANSFER_OK);
        
        res = result;
        
        return res;

    case USB :
        result = USBH_UDISK_Read(buff, sector, count);      
        res = result;
    
        return res;
    }
    return RES_PARERR;
}

29.JPG

/*-----------------------------------------------------------------------*/
/* Write Sector(s)                                                       */
/*-----------------------------------------------------------------------*/

#if _USE_WRITE
DRESULT disk_write (
    BYTE pdrv,            /* Physical drive nmuber (0..) */
    const BYTE *buff,    /* Data to be written */
    DWORD sector,        /* Sector address (LBA) */
    BYTE count            /* Number of sectors to write (1..128) */
)
{
    DRESULT res;
    int result;

    switch (pdrv) {
    case ATA :
        // translate the arguments here

        //result = ATA_disk_write(buff, sector, count);

        // translate the reslut code here

        return res;

    case MMC :
        if(count>1){
            result = SD_WriteMultiBlocks((uint8_t*)buff, sector*BLOCK_SIZE, BLOCK_SIZE, count);
        }else{
            result = SD_WriteBlock((uint8_t*)buff, sector*BLOCK_SIZE, BLOCK_SIZE);
        }
    /* Check if the Transfer is finished */
    result = SD_WaitWriteOperation();
    while(SD_GetStatus() != SD_TRANSFER_OK);        
        
        res = result;

        return res;
    case USB :
        result = USBH_UDISK_Write((uint8_t*)buff, sector, count); 
        res = result;
    
        return res;
    }
    return RES_PARERR;
}
#endif

30.JPG

/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions                                               */
/*-----------------------------------------------------------------------*/

#if _USE_IOCTL
DRESULT disk_ioctl (
    BYTE pdrv,        /* Physical drive nmuber (0..) */
    BYTE cmd,        /* Control code */
    void *buff        /* Buffer to send/receive control data */
)
{
    DRESULT res;
    int result;

    switch (pdrv) {
    case ATA :
        // pre-process here

        //result = ATA_disk_ioctl(cmd, buff);

        // post-process here

        return res;

    case MMC :
        switch(cmd){  
            case CTRL_SYNC: 
        result = RES_OK;  
      break;  
            case GET_BLOCK_SIZE:  
        *(WORD*)buff = 512;  
        result = RES_OK;  
      break;  
            case GET_SECTOR_COUNT:  
        *(DWORD*)buff = 512;  
        result = RES_OK;  
      break;  
            default:  
        result = RES_PARERR;  
      break;  
    }  
        res = result;
        
        return res;

    case USB :
        switch(cmd){
            case CTRL_SYNC:
                result = RES_OK; 
          break;     
          case GET_SECTOR_SIZE:
                *(WORD*)buff = 512;
            result = RES_OK;
          break;     
          case GET_BLOCK_SIZE:
                *(WORD*)buff = 512;
            result = RES_OK;
          break;     
          case GET_SECTOR_COUNT:
                *(DWORD*)buff = USBH_MSC_Param.MSCapacity;
            result = RES_OK;
            break;
          default:
                result = RES_PARERR;
          break;
        }
        res = result;

        return res;
    }
    return RES_PARERR;
}
#endif

以上程式撰寫完成後,就要來寫測試程式,在ExtDevices_Configuration創造usbdisk.cusbdisk.h,在裡面寫USB初始化程式,

31.JPG

/*
程式名稱:USB Disk初始化
程式版本:V1.0
程式撰寫者:Michael Jheng(鄭智遠)
程式撰寫日期:2018/6/23
程式修改日期:N/A
程式說明:

*/
uint8_t USB_DiskInit(void){
    uint8_t res=0;
    
    res = f_mount(2, &usbDisk_Ptr->fatfs);
    
    if(res!=0){
        USART1_DMA_Send((uint8_t*)"f_mount ERROR\r\n", 15);
    }else{
        USART1_DMA_Send((uint8_t*)"f_mount OK\r\n", 12);
    }    
    
    USBH_Init(&USB_OTG_HS_Core, USB_OTG_HS_CORE_ID, &USBH_Host, &USBH_MSC_cb, &USR_USBH_MSC_cb);
    
    return res;
}

User/bsp.c,增加uint8_t USB_DiskInit(void)來進行初始化,

32.JPG

我的測試方式是使用一個按鍵,來觸發寫進USB資料的程式,會在外部中斷增加按鍵式觸發,在main.c增加要寫進USB資料的程式,如下所示,

if(flag==1){
                
    res = f_open(&usbDisk_Ptr->fil, "2:/123.txt", FA_WRITE | FA_CREATE_ALWAYS);
                
    if(res!=0){
        USART1_DMA_Send((uint8_t*)"f_open ERROR\r\n", 14);
    }else{
        USART1_DMA_Send((uint8_t*)"f_open OK\r\n", 11);
    }    
                
    res = f_write(&usbDisk_Ptr->fil, "ABCDEF", 6, &usbDisk_Ptr->bw);
                
    if(res!=0){
        USART1_DMA_Send((uint8_t*)"f_write ERROR\r\n", 15);
    }else{
        USART1_DMA_Send((uint8_t*)"f_write OK\r\n", 12);
    }        
                
    f_close(&usbDisk_Ptr->fil);            
                
    flag = 0;
}    

實測結果如下,初始化訊息,

33.JPG

按下寫入按鍵執行結果,

34.JPG

USB寫入的資料,

35.JPG

arrow
arrow
    文章標籤
    MCU FatFs ARM ST USB
    全站熱搜

    鄭智遠 發表在 痞客邦 留言(0) 人氣()