第一个USB工程例子:USB存储盘。因为手边没有SPI或I2C接口的Flash, 就权且用单片机的RAM虚拟一下吧。这个"U盘"容量标成160kB, 实际上有效的存储只有10kB,用一点扇区映射的技巧骗过操作系统,当然存放文件只能几kB了。
ST官方提供了一个 STM32F0 的USB固件库,(URL http://www.st.com/st-web-ui/static/active/en/st_prod_software_internet/resource/technical/software/firmware/stsw-stm32092.zip),包括了硬件库、核心库和类库的C头文件和源文件。我cruelfox琢磨了一整天,还是没搞清楚怎么调用这些函数,只好照着个Example改吧。
于是就用MassStorage类的例子来下手了,这个目录里面的主文件 app.c 非常简单
- /**
- * @file app.c
- */
-
- /* Includes ------------------------------------------------------------------*/
- #include "usbd_msc_core.h"
- #include "usbd_usr.h"
-
- USB_CORE_HANDLE USB_Device_dev ;
-
- int main(void)
- {
-
- USBD_Init(&USB_Device_dev,
- &USR_desc,
- &USBD_MSC_cb,
- &USR_cb);
-
- while (1)
- {
- }
- }
-
- #ifdef USE_FULL_ASSERT
- void assert_failed(uint8_t* file, uint32_t line)
- {
- while (1)
- {}
- }
- #endif
-
复制代码 一切USB相关的东西都在 USBD_init() 这个函数里面了。追查源代码,可以发现这个函数调用其实是向库函数提供了一堆回调函数的接口,也就是说写一些子程序,让驱动程序在需要的时候调用。这样开发USB的我们就不用去管中断什么的了,要做的就是实现各种USB的请求——其实程序库里面已经把大部分的请求应答都实现了,而具体的类库(比如我这里用的MassStorage类)又处理了剩余的大部分,所以只剩下功能性的需要自己写。 在 usbd_desc.c 这个程序里面可以看到描述符是怎么创建和返回的 - /**
- ******************************************************************************
- * @file usbd_desc.c
- * @author MCD Application Team
- * @version V1.0.0
- * @date 31-January-2014
- * @brief This file provides the USBD descriptors and string formating method.
- ******************************************************************************
- * @attention
- *
- * <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
-
- /* Includes ------------------------------------------------------------------*/
- #include "usbd_desc.h"
-
- /* Private typedef -----------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- #define USBD_VID 0x0483
- #define USBD_PID 0x5720
-
- #define USBD_LANGID_STRING 0x409
- #define USBD_MANUFACTURER_STRING "STMicroelectronics"
-
- #define USBD_PRODUCT_FS_STRING "Mass Storage in FS Mode"
-
- #define USBD_CONFIGURATION_FS_STRING "MSC Config"
- #define USBD_INTERFACE_FS_STRING "MSC Interface"
- /* Private macro -------------------------------------------------------------*/
- /* Private variables ---------------------------------------------------------*/
- char USBD_SERIALNUMBER_FS_STRING[26];
-
- USBD_DEVICE USR_desc =
- {
- USBD_USR_DeviceDescriptor,
- USBD_USR_LangIDStrDescriptor,
- USBD_USR_ManufacturerStrDescriptor,
- USBD_USR_ProductStrDescriptor,
- USBD_USR_SerialStrDescriptor,
- USBD_USR_ConfigStrDescriptor,
- USBD_USR_InterfaceStrDescriptor,
-
- };
-
- /* USB Standard Device Descriptor */
- const uint8_t USBD_DeviceDesc[USB_SIZ_DEVICE_DESC] =
- {
- 0x12, /*bLength */
- USB_DEVICE_DEscriptOR_TYPE, /*bDescriptorType*/
- 0x00, /*bcdUSB */
- 0x02,
- 0x00, /*bDeviceClass*/
- 0x00, /*bDeviceSubClass*/
- 0x00, /*bDeviceProtocol*/
- USB_MAX_EP0_SIZE, /*bMaxPacketSize*/
- LOBYTE(USBD_VID), /*idVendor*/
- HIBYTE(USBD_VID), /*idVendor*/
- LOBYTE(USBD_PID), /*idVendor*/
- HIBYTE(USBD_PID), /*idVendor*/
- 0x00, /*bcdDevice rel. 2.00*/
- 0x02,
- USBD_IDX_MFC_STR, /*Index of manufacturer string*/
- USBD_IDX_PRODUCT_STR, /*Index of product string*/
- USBD_IDX_SERIAL_STR, /*Index of serial number string*/
- USBD_CFG_MAX_NUM /*bNumConfigurations*/
- } ; /* USB_DeviceDescriptor */
-
- /* USB Standard Device Descriptor */
- const uint8_t USBD_DeviceQualifierDesc[USB_LEN_DEV_QUALIFIER_DESC] =
- {
- USB_LEN_DEV_QUALIFIER_DESC,
- USB_DESC_TYPE_DEVICE_QUALIFIER,
- 0x00,
- 0x02,
- 0x00,
- 0x00,
- 0x00,
- 0x40,
- 0x01,
- 0x00,
- };
-
- /* USB Standard Device Descriptor */
- const uint8_t USBD_LangIDDesc[USB_SIZ_STRING_LANGID] =
- {
- USB_SIZ_STRING_LANGID,
- USB_DESC_TYPE_STRING,
- LOBYTE(USBD_LANGID_STRING),
- HIBYTE(USBD_LANGID_STRING),
- };
-
- uint8_t USBD_StringSerial[USB_SIZ_STRING_SERIAL] =
- {
- USB_SIZ_STRING_SERIAL, /* bLength */
- USB_STRING_DEscriptOR_TYPE, /* bDescriptorType */
- };
-
- /* Private function prototypes -----------------------------------------------*/
- /* Private functions ---------------------------------------------------------*/
- static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len);
-
- /**
- * @brief return the device descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_DeviceDescriptor( uint8_t speed , uint16_t *length)
- {
- *length = sizeof(USBD_DeviceDesc);
- return (uint8_t*)USBD_DeviceDesc;
- }
-
- /**
- * @brief return the LangID string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_LangIDStrDescriptor( uint8_t speed , uint16_t *length)
- {
- *length = sizeof(USBD_LangIDDesc);
- return (uint8_t*)USBD_LangIDDesc;
- }
-
-
- /**
- * @brief return the product string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_ProductStrDescriptor( uint8_t speed , uint16_t *length)
- {
- USBD_GetString ( (uint8_t*)USBD_PRODUCT_FS_STRING, USBD_StrDesc, length);
- return USBD_StrDesc;
- }
-
- /**
- * @brief return the manufacturer string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_ManufacturerStrDescriptor( uint8_t speed , uint16_t *length)
- {
- USBD_GetString ( (uint8_t*)USBD_MANUFACTURER_STRING, USBD_StrDesc, length);
- return USBD_StrDesc;
- }
-
- /**
- * @brief return the serial number string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_SerialStrDescriptor( uint8_t speed , uint16_t *length)
- {
- *length = USB_SIZ_STRING_SERIAL;
- return USBD_StringSerial;
- }
-
- /**
- * @brief return the configuration string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_ConfigStrDescriptor( uint8_t speed , uint16_t *length)
- {
- USBD_GetString ( (uint8_t*)USBD_CONFIGURATION_FS_STRING, USBD_StrDesc, length);
- return USBD_StrDesc;
- }
-
-
- /**
- * @brief return the interface string descriptor
- * @param speed : current device speed
- * @param length : pointer to data length variable
- * @retval pointer to descriptor buffer
- */
- uint8_t * USBD_USR_InterfaceStrDescriptor( uint8_t speed , uint16_t *length)
- {
- USBD_GetString ( (uint8_t*)USBD_INTERFACE_FS_STRING, USBD_StrDesc, length);
- return USBD_StrDesc;
- }
-
- /**
- * @brief Create the serial number string descriptor
- * @param None
- * @retval None
- */
- void Get_SerialNum(void)
- {
- uint32_t Device_Serial0, Device_Serial1, Device_Serial2;
-
- Device_Serial0 = *(uint32_t*)Device1_Identifier;
- Device_Serial1 = *(uint32_t*)Device2_Identifier;
- Device_Serial2 = *(uint32_t*)Device3_Identifier;
-
- Device_Serial0 += Device_Serial2;
-
- if (Device_Serial0 != 0)
- {
- IntToUnicode (Device_Serial0, &USBD_StringSerial[2] ,8);
- IntToUnicode (Device_Serial1, &USBD_StringSerial[18] ,4);
- }
- }
-
- /**
- * @brief Convert Hex 32Bits value into char
- * @param value: value to convert
- * @param pbuf: pointer to the buffer
- * @param len: buffer length
- * @retval None
- */
- static void IntToUnicode (uint32_t value , uint8_t *pbuf , uint8_t len)
- {
- uint8_t idx = 0;
-
- for( idx = 0 ; idx < len ; idx ++)
- {
- if( ((value >> 28)) < 0xA )
- {
- pbuf[ 2* idx] = (value >> 28) + '0';
- }
- else
- {
- pbuf[2* idx] = (value >> 28) + 'A' - 10;
- }
-
- value = value << 4;
-
- pbuf[ 2* idx + 1] = 0;
- }
- }
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
复制代码 插一句: 开发USB设备,有很重要的一部分是编写描述符(当然也要借用已有的模板),设备叫什么,功能是什么等等都从描述符体现。只要设备向主机成功返回了描述符,主机就会提示找到硬件。 设计到U盘读写操作的部分在 usbd_storage_msd.c 里面,我就是在例子程序上改的 - /**
- ******************************************************************************
- * @file usbd_storage_msd.c
- * @author MCD application Team
- * @version V1.0.0
- * @date 31-January-2014
- * @brief This file provides the disk operations functions.
- ******************************************************************************
- * @attention
- *
- * <h2><center>© COPYRIGHT 2014 STMicroelectronics</center></h2>
- *
- * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
- * You may not use this file except in compliance with the License.
- * You may obtain a copy of the License at:
- *
- * http://www.st.com/software_license_agreement_liberty_v2
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- ******************************************************************************
- */
- #include <string.h>
-
- /* Includes ------------------------------------------------------------------*/
- #include "usbd_msc_mem.h"
-
- /* Private typedef -----------------------------------------------------------*/
- /* Private define ------------------------------------------------------------*/
- #define STORAGE_LUN_NBR 1
-
- /* Private macro -------------------------------------------------------------*/
- /* Private variables ---------------------------------------------------------*/
- /* USB Mass storage Standard Inquiry Data */
- const int8_t STORAGE_Inquirydata[] = {
-
- /* LUN 0 */
- 0x00,
- 0x80,
- 0x02,
- 0x02,
- (USBD_STD_INQUIRY_LENGTH - 5),
- 0x00,
- 0x00,
- 0x00,
- 'S', 'T', 'M', ' ', ' ', ' ', ' ', ' ', /* Manufacturer : 8 bytes */
- 'm', 'i', 'c', 'r', 'o', 'S', 'D', ' ', /* Product : 16 Bytes */
- 'F', 'l', 'a', 's', 'h', ' ', ' ', ' ',
- '1', '.', '0' ,'0', /* Version : 4 Bytes */
- };
-
- __IO uint32_t count = 0;
- /* Private function prototypes -----------------------------------------------*/
- int8_t STORAGE_Init (uint8_t lun);
-
- int8_t STORAGE_GetCapacity (uint8_t lun,
- uint32_t *block_num,
- uint32_t *block_size);
-
- int8_t STORAGE_IsReady (uint8_t lun);
-
- int8_t STORAGE_IsWriteProtected (uint8_t lun);
-
- int8_t STORAGE_Read (uint8_t lun,
- uint8_t *buf,
- uint32_t blk_addr,
- uint16_t blk_len);
-
- int8_t STORAGE_Write (uint8_t lun,
- uint8_t *buf,
- uint32_t blk_addr,
- uint16_t blk_len);
-
- int8_t STORAGE_GetMaxLun (void);
-
-
- USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops =
- {
- STORAGE_Init,
- STORAGE_GetCapacity,
- STORAGE_IsReady,
- STORAGE_IsWriteProtected,
- STORAGE_Read,
- STORAGE_Write,
- STORAGE_GetMaxLun,
- (int8_t *)STORAGE_Inquirydata,
- };
-
- USBD_STORAGE_cb_TypeDef *USBD_STORAGE_fops = &USBD_MICRO_SDIO_fops;
-
- /* Private functions ---------------------------------------------------------*/
-
- /**
- * @brief Initialize the storage medium
- * @param lun : logical unit number
- * @retval Status
- */
-
- uint8_t dummy_disk[20][512];
- uint16_t sec_index[20]; // sector usage
-
- int8_t STORAGE_Init (uint8_t lun)
- {
- static char init=0;
- if(!init)
- {
- short int i;
- for(i=0;i<20;i++)
- sec_index[i]=0xffff;
- init=1;
- }
- return (0);
- }
-
- /**
- * @brief return medium capacity and block size
- * @param lun : logical unit number
- * @param block_num : number of physical block
- * @param block_size : size of a physical block
- * @retval Status
- */
- int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size)
- {
-
- *block_size = 512;
- *block_num = 40*9;
-
- return (0);
- }
-
- /**
- * @brief check whether the medium is ready
- * @param lun : logical unit number
- * @retval Status
- */
- int8_t STORAGE_IsReady (uint8_t lun)
- {
- static uint8_t status = 0;
-
- return (0);
- }
-
- /**
- * @brief check whether the medium is write-protected
- * @param lun : logical unit number
- * @retval Status
- */
- int8_t STORAGE_IsWriteProtected (uint8_t lun)
- {
- return 0;
- }
-
- /**
- * @brief Read data from the medium
- * @param lun : logical unit number
- * @param buf : Pointer to the buffer to save data
- * @param blk_addr : address of 1st block to be read
- * @param blk_len : number of blocks to be read
- * @retval Status
- */
- int8_t STORAGE_Read (uint8_t lun,
- uint8_t *buf,
- uint32_t blk_addr,
- uint16_t blk_len)
- {
- short int i;
- for(i=0;i<blk_len;i++)
- {
- short int j;
- for(j=0;j<20;j++)
- {
- if(sec_index[j]==blk_addr+i)
- {
- memcpy(buf+i*512,dummy_disk[j],512);
- break;
- }
- }
- if(j>=20)
- {
- for(j=0;j<512;j++)
- buf[i*512+j]=0x00;
- }
- }
- /* if( SD_ReadMultiBlocks (buf,
- blk_addr * 512,
- 512,
- blk_len) != 0)
- {
- return 5;
- }
- */
- return 0;
- }
-
- /**
- * @brief Write data to the medium
- * @param lun : logical unit number
- * @param buf : Pointer to the buffer to write from
- * @param blk_addr : address of 1st block to be written
- * @param blk_len : number of blocks to be read
- * @retval Status
- */
- int8_t STORAGE_Write (uint8_t lun,
- uint8_t *buf,
- uint32_t blk_addr,
- uint16_t blk_len)
- {
- short int i;
- for(i=0;i<blk_len;i++)
- {
- short int j;
- char zero=1;
- unsigned char avail=0xff;
- for(j=0;j<512;j++)
- if(buf[j+i*512])
- zero=0;
- for(j=0;j<20;j++)
- {
- if(sec_index[j]==blk_addr+i)
- break;
- if(avail==0xff && sec_index[j]==0xffff)
- avail=j;
- }
- if(zero)
- {
- if(j<20)
- sec_index[j]=0xffff; // free
- return 0;
- }
- if(j>=20)
- {
- if(avail<20)
- j=avail;
- else // No free sectors
- {
- j=1+rand()%19;
- }
- }
- memcpy(dummy_disk[j],buf+i*512,512);
- sec_index[j]=blk_addr+i;
- }
- return (0);
- }
-
- /**
- * @brief Return number of supported logical unit
- * @param None
- * @retval number of logical unit
- */
-
- int8_t STORAGE_GetMaxLun (void)
- {
- return (STORAGE_LUN_NBR - 1);
- }
- /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
-
复制代码 主要是需要完成 报告容量、读、写 三个函数。如果有可实现存储的硬件,接口连起来即可。我上面是用了10kB的RAM来存放,动态分配20个扇区来存储。如果检测到要写的整个扇区都是0,那么就忽略。于是这样就做成了虚拟的U盘。 附件包含了所有需要的程序源代码,USB库的部分在lib子目录下面。build.bat 中是编译的命令。依靠这个USB函数库开发起来还算不难吧,只要看懂了例子,mass storage class还比较简单,因为硬件涉及就是读扇区、写扇区。 USB HID设备五花八门,就不是这么简单了,继续研究去。
查看评论 回复
游客 | 2018-09-01 15:22:52 |
[color=#000000]stm32F042做usb价格高了一点。[/color]//回复:@匿名: 用stm32F042做usb接口还是很方便的,stm编译器的库很好用 |
1楼
回复本楼 匿名 | 2018-07-09 21:56:58 |
用stm32F042做usb接口还是很方便的,stm编译器的库很好用 |
2楼
回复本楼