[活动专区] 【AT-START-F423测评】+3.USB主机读取U盘信息并进行文件读写操作

[复制链接]
2358|1
 楼主| hjl2832 发表于 2023-11-2 22:10 | 显示全部楼层 |阅读模式
#申请原创#
前面2次,我们进行了USB从机的测试,利用USB虚拟串口进行数据转发服务,今天我来测试USB主机功能,读取U盘信息并进行文件操作。
首先,我们打开库文件,找到USB主机相关的例程,路径如下:先打开库目录的模板文件夹“AT32F423_Firmware_Library_V2.0.2\project\at_start_f423\examples”,在文件夹中,我们找到usb_host文件夹,这里就是USB主机相关的例程。
5947965439d29384e7.png
打开usb_host文件夹后,选择并复制“msc_only_fat32”文件夹到其它非中文目录下,这里即是USB驱动U盘的例程。
我们用keil 5打开工程后,来分析代码构成。
6346365439e9fb558b.png
在左边我们可以看到代码主要包含USB主机的底层驱动库、相关的USB配置接口函数、磁盘文件系统处理、USB主机用户层驱动函数、USB主机磁盘驱动函数等。
其中“usbh_user.c”主要实现了USB主机相关的初始化、打印调试信息等,“usbh_msc_diskio.c”主要实现磁盘读写操作等函数,其中关键代码如下:
  1. /*-----------------------------------------------------------------------*/
  2. /* Read Sector(s)                                                        */
  3. /*-----------------------------------------------------------------------*/
  4. DRESULT disk_read (
  5.   BYTE pdrv,    /* Physical drive nmuber to identify the drive */
  6.   BYTE *buff,    /* Data buffer to store read data */
  7.   LBA_t sector,  /* Start sector in LBA */
  8.   UINT count    /* Number of sectors to read */
  9. )
  10. {
  11.   usb_sts_type status;

  12.   status = usbh_msc_read(&otg_core_struct.host, sector, count, buff, pdrv);

  13.   if(status == USB_OK)
  14.     return RES_OK;

  15.   return RES_ERROR;
  16. }

磁盘数据读取函数的内部是调用了USB主机的读数据函数“usbh_msc_read”,这个函数在上面说的USB主机数据处理接口函数“usbh_msc_class.c”中,通过usbh_msc_read调用USB主机的数据读写中断控制函数“usbh_msc_rw_handle”来执行相应的数据处理。在这里要注意,因为是读取数据,所以函数中先赋值了“pmsc->l_unit_n[lun].state = USBH_MSC_READ10;”来告诉事件执行读数据处理。
  1. usb_sts_type usbh_msc_read(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun)
  2. {
  3.   usbh_core_type *puhost = (usbh_core_type *)uhost;
  4.   usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
  5.   uint32_t timeout = 0;
  6.   if(puhost->conn_sts == 0 || puhost->global_state != USBH_CLASS
  7.     || pmsc->l_unit_n[lun].state != USBH_MSC_IDLE)
  8.   {
  9.     return USB_FAIL;
  10.   }
  11.   pmsc->bot_trans.msc_struct = &usbh_msc;
  12.   pmsc->l_unit_n[lun].state = USBH_MSC_READ10;
  13.   pmsc->use_lun = lun;

  14.   timeout = puhost->timer;

  15.   while(usbh_msc_rw_handle(uhost, address, len, buffer, lun) == USB_WAIT)
  16.   {
  17.     if(puhost->conn_sts == 0 || (puhost->timer - timeout) > (len * 10000))
  18.     {
  19.       pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
  20.       return USB_FAIL;
  21.     }
  22.   }
  23.   return USB_OK;
  24. }

然后"usbh_msc_rw_handle"通过调用“usb_sts_type usbh_msc_bot_scsi_read”创建“usbh_cmd_read”函数读取数据。
  1. usb_sts_type usbh_msc_bot_scsi_read(void *uhost, msc_bot_trans_type *bot_trans,
  2.                                      uint32_t address, uint8_t *read_data,
  3.                                      uint32_t read_len, uint8_t lun)
  4. {
  5.   usb_sts_type status = USB_WAIT;
  6.   switch(bot_trans->cmd_state)
  7.   {
  8.     case CMD_STATE_SEND:
  9.       usbh_bot_cbw(&bot_trans->cbw, read_len * 512,
  10.                    MSC_READ_CMD_LEN, MSC_CBW_FLAG_IN);
  11.       bot_trans->cbw.bCBWLUN = lun;
  12.       usbh_cmd_read(bot_trans, bot_trans->cbw.CBWCB, lun, read_len, address, read_data);
  13.       bot_trans->cmd_state = CMD_STATE_WAIT;
  14.       bot_trans->bot_state = BOT_STATE_SEND_CBW;
  15.     break;

  16.     case CMD_STATE_WAIT:
  17.       status = usb_bot_request(uhost, bot_trans);
  18.       if(status == USB_OK)
  19.       {
  20.          bot_trans->cmd_state = CMD_STATE_SEND;
  21.       }
  22.       if(status == USB_FAIL)
  23.       {
  24.         bot_trans->cmd_state = CMD_STATE_SEND;
  25.       }
  26.       break;
  27.     default:
  28.       break;
  29.   }
  30.   return status;
  31. }
写数据的处理过程类似,这里不再详述。
USB主机的事件处理,在main.c中,通过“usbh_init(&otg_core_struct,USB_FULL_SPEED_CORE_ID, USB_ID, &uhost_msc_class_handler, &usbh_user_handle)”中定义“uhost_msc_class_handler”和“usbh_user_handle”创建USB主机接口和用户数据处理接口。
然后通过主while循环不断调用“usbh_loop_handler(&otg_core_struct.host)”事件处理USB接口状态监测及相关事件处理。
在“uhost_msc_class_handler”中申明了USB接口主机相关的底层接口处理事件。
  1. usbh_class_handler_type uhost_msc_class_handler =
  2. {
  3. uhost_init_handler,
  4. uhost_reset_handler,
  5. uhost_request_handler,
  6. uhost_process_handler,
  7. &usbh_msc
  8. };
而在“usbh_user_handler"中又申明了用户层相关的事件处理函数。
  1. usbh_user_handler_type usbh_user_handle =
  2. {
  3.   usbh_user_init,
  4.   usbh_user_reset,
  5.   usbh_user_attached,
  6.   usbh_user_disconnect,
  7.   usbh_user_speed,
  8.   usbh_user_mfc_string,
  9.   usbh_user_product_string,
  10.   usbh_user_serial_string,
  11.   usbh_user_enumeration_done,
  12.   usbh_user_application,
  13.   usbh_user_active_vbus,
  14.   usbh_user_not_support,
  15. };
在这里执行U盘数据读写的函数就在“usbh_user_application”中;它的代码如下:
  1. static usb_sts_type usbh_user_application(void)
  2. {
  3.   usb_sts_type status = USB_OK;
  4.   FRESULT res;

  5.   uint32_t len;
  6.   uint8_t write_data[] = "usb host msc demo";
  7.   uint8_t read_data[32] = {0};

  8.   switch(usr_state)
  9.   {
  10.     case USR_IDLE:
  11.       usr_state = USR_APP;
  12.       break;
  13.     case USR_APP:
  14.       res = f_mount(&fs, "", 0);
  15.       if(res == FR_OK)
  16.       {
  17.         /* start write data */
  18.         if(f_open(&file, "0:AT32.txt", FA_CREATE_ALWAYS | FA_WRITE) != FR_OK)
  19.         {
  20.           // error
  21.           USBH_DEBUG("Open AT32.txt failed");
  22.         }
  23.         else
  24.         {
  25.           res = f_write(&file, write_data, sizeof(write_data), &len);
  26.           if(res != FR_OK || len == 0)
  27.           {
  28.             //write error
  29.             USBH_DEBUG("Write AT32.txt failed");
  30.           }
  31.           else
  32.           {
  33.             //write success
  34.             USBH_DEBUG("Write AT32.txt Success");
  35.           }
  36.           f_close(&file);
  37.         }

  38.         /* start read file */
  39.         if(f_open(&file, "0:AT32.txt", FA_READ) != FR_OK)
  40.         {
  41.           // error
  42.           USBH_DEBUG("Open AT32.txt failed");
  43.         }
  44.         else
  45.         {
  46.           res = f_read(&file, read_data, sizeof(read_data), &len);
  47.           if(res != FR_OK || len == 0)
  48.           {
  49.             //read error
  50.             USBH_DEBUG("Read AT32.txt failed");
  51.           }
  52.           else
  53.           {
  54.             //read success
  55.             USBH_DEBUG("Read AT32.txt Success");
  56.           }
  57.           f_close(&file);
  58.         }
  59.         f_mount(NULL, "", 0);
  60.       }
  61.       usr_state = USR_FINISH;
  62.       break;
  63.     case USR_FINISH:
  64.       break;
  65.   }
  66.   return status;
  67. }
在这段代码中,通过“f_mount”创建&挂载一个U盘的工作区,然后通过“f_open”在U盘根目录下创建一个名为“AT32.TXT”的文件,如果文件创建成功,则在打开的AT32.TXT文件中插入"usb host msc demo"文字字符。创建完文件后,再次利用f_open”打开“AT32.TXT”文件,并用DEBUG PRINTF输出相应的状态信息。最后关闭文件系统,并使用“f_mount(NULL, "", 0)”卸载U盘上创建的工作区。
程序分析完成,最后我们编绎并下载到开发板,将开发板上的J8调试串口通过USB转串口模块连接到PC上,在开发板上的USB主机接口(TYPE-A)中插入一个在PC上格式化好的U盘(注意U盘格式化时,要选择格式为FAT32),这时有串口调试助手上会打印出开发板检测到U盘执行的相关事件信息。
289626543ac6bf3031.png
当串口助手打印出“Read AT32.txt Success”的信息后,从开发板上拨出U盘,再插到电脑上,打开U盘,会发现在U盘的根目录下,开发板往U盘里创建了一个名为"AT32.TXT"的文件,打开这个txt文件,可以发现里面写入了代码中写入的字符“usb host msc demo”。
979756543ad8441a4c.png
996786543ad9635fb5.png
至此,本次测试完成,相关的代码分析也完成。
回忆酱 发表于 2023-11-4 14:59 | 显示全部楼层
认真学习 顶
您需要登录后才可以回帖 登录 | 注册

本版积分规则

27

主题

1091

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部