文章目录
- 1、USB库下载
- 2、移植(slave)
- 2.1、工程准备
- 2.2、USB库准备
- 2.3、移植
- 1、新建USB相关文件夹
- 2、拷贝
- 3、添加USB相关代码
- 4、添加头文件路径
- 5、修改相关内容
- 1、修改usb_conf.h
- 2、定义全局宏USE_USB_OTG_FS
- 3、修改usbd_storage_msd.c
- 4、修改usbd_usr.c
- 5、修改usb_bsp.c
- 4、修改主函数
1、USB库下载
访问官网:https://www.st.com,搜索UM1021
选择STSW-STM32046
下拉到下面,获取下载即可
下载下来解压后的文件如下图所示:
2、移植(slave)
2.1、工程准备
准备基础工程一份,这里以W25Qxx工程为例,直接拷贝原子的工程过来
2.2、USB库准备
打开库文件,定位到当前目录
这三个从上到下分别为USB从机驱动库,USB主机驱动库,USB_OTG内核驱动代码
2.3、移植
1、新建USB相关文件夹
打开工程,新建USB文件夹并拷贝USB驱动库,在拷贝的目录下并新建一个USB_APP文件夹
2、拷贝
MSC相关代码到USB_APP文件夹内相关代码,即:en.stm32_f105-07_f2_f4_usb-host-device_libProjectUSB_Device_ExamplesMSCsrc 下的部分代码:usb_bsp.c 、usbd_storage_msd.c、usbd_desc.c和 usbd_usr.c等4 个.c 文件,
同时拷贝 en.stm32_f105-07_f2_f4_usb-host-device_libProjectUSB_Device_ExamplesMSCinc 下面的:usb_conf.h、usbd_conf.h 和 usbd_desc.h 等三个文件,添加完成后如下图所示:
3、添加USB相关代码
工程添加USB相关代码,如下图所示:
根据ST官方的MSC例程,新建USB_OTG组,存放USB_OTG内核驱动代码,新建USB_DEVICE组,存放USB从机与MSC相关代码,新建USB_APP存放用户配置相关驱动代码
USB_OTG组代码路径为USB\STM32_USB_OTG_Driver\src
USB_DEVICE组代码路径为USB\STM32_USB_Device_Library\Core\src以及USB\STM32_USB_Device_Library\Class\msc\src
USB_APP组代码路径为USB\USB_APP内
我们重点要修改的就是 USB_APP 文件夹下面的代码。
其他代码(USB_OTG 和 USB_DEVICE 文件夹下的代码)一般不用修改。
usb_bsp.c 提供了几个 USB 库需要用到的底层初始化函数,包括:IO 设置、中断设置、VBU配置以及延时函数等,需要我们自己实现。USB Device(Slave)和 USB Host 共用这个.c 文件。
usbd_desc.c 提供了 USB 设备类的描述符,直接决定了 USB 设备的类型、断点、接口、字符串、制造商等重要信息。这里:usbd_desc.c 里面的:usbd 即 device 类,同样:usbh 即 host 类
usbd_usr.c 提供用户应用层接口函数,即 USB 设备类的一些回调函数,当 USB 状态机处理完不同事务的时候,会调用这些回调函数,我们通过这些回调函数,就可以知道 USB 当前状态, 比如:是否枚举成功了?是否连接上了?是否断开了?等
usbd_storage_msd.c 提供一些磁盘操作函数,包括支持的磁盘个数,以及每个磁盘的初始化
和读写等函数。
4、添加头文件路径
5、修改相关内容
编译代码,根据报错提示,修改相关内容
1、修改usb_conf.h
①,usb_conf.h,include部分,使用如下代码替代:
#include "stm32f4xx.h"
另外,屏蔽#define VBUS_SENSING_ENABLED,关闭VBUS检测
2、定义全局宏USE_USB_OTG_FS
②,在C/C++选项卡,定义全局宏:USE_USB_OTG_FS,选择使用USB OTG FS,如图所示:
3、修改usbd_storage_msd.c
3.1,添加头文件
#include "w25qxx.h"
3.2,修改:#define STORAGE_LUN_NBR的值为2,以支持2个磁盘,这里仅使用W25Q一个,所以默认为1即可。
3.3,添加USB_STATUS_REG变量,记录磁盘操作状态。
自己定义的一个标记USB状态的寄存器///
//bit0:表示电脑正在向其写入数据
//bit1:表示电脑正从内部读出数据
//bit2:写数据错误标志位
//bit3:读数据错误标志位
//bit4:1,表示电脑有轮询操作(表明连接还保持着)
vu8 USB_STATUS_REG=0;
3.4,修改STORAGE_Inquirydata数组,和上面3.2的磁盘个数相对应,有几个就新增几个磁盘的描述,比如下面是两个的磁盘描述符,本次只有一个,所以就不用修改:
//USB Mass storage 标准查询数据(每个lun占36字节)
const int8_t STORAGE_Inquirydata[] = {
/* LUN 0 */
0x00,
0x80,
0x02,
0x02,
(USBD_STD_INQUIRY_LENGTH - 4),
0x00,0x00,0x00,
'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K', ' ',//Vendor Identification,9字节
'S', 'P', 'I', ' ', 'F', 'l', 'a', 's', 'h',' ','D', 'i', 's', 'k', ' ',//Product Identification,15字节
'1', '.', '0', ' ', //Product Revision Level,4字节
/* LUN 1 */
0x00,
0x80,
0x02,
0x02,
(USBD_STD_INQUIRY_LENGTH - 4),
0x00,0x00,0x00,
'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K',' ', //Vendor Identification,9字节
'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ','D', 'i', 's', 'k', ' ',' ',//Product Identification,15字节
'1', '.', '0' ,' ', //Product Revision Level,4字节
};
3.5,修改STORAGE_Init函数为:
int8_t STORAGE_Init (uint8_t lun)
{
W25QXX_Init();
return 0;
}
3.6,修改STORAGE_GetCapacity函数为:
int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size)
{
*block_size=512;
*block_num=1024*1024*12/512;//SPI FLASH的前面12M字节,文件系统用
return 0;
}
3.7,修改STORAGE_IsReady函数为:
int8_t STORAGE_IsReady (uint8_t lun)
{
USB_STATUS_REG|=0X10;//标记轮询
return 0;
}
3.8,修改STORAGE_Read函数为:
int8_t STORAGE_Read (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len)
{
int8_t res=0;
USB_STATUS_REG|=0X02;//标记正在读数据
W25QXX_Read(buf,blk_addr*512,blk_len*512);
return res;
}
3.9,修改STORAGE_Write函数为:
int8_t STORAGE_Write (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len)
{
int8_t res=0;
USB_STATUS_REG|=0X01;//标记正在写数据
W25QXX_Write(buf,blk_addr*512,blk_len*512);
return res;
}
4、修改usbd_usr.c
其实就是将LCD显示信息修改为printf输出
4.1,删除lcd_log.h,并添加usb_dcd_int.h等,如下所示:
#include "usbd_usr.h"
#include "usb_dcd_int.h"
#include <stdio.h>
#include <usart.h>
4.2,添加bDeviceState变量,记录USB连接状态,并添加USB中断处理函数(官方例程在stm32fxxx_it.c里面处理)到本.c文件,如下所示
//表示USB连接状态
//0,没有连接;
//1,已经连接;
vu8 bDeviceState=0; //默认没有连接
extern USB_OTG_CORE_HANDLE USB_OTG_dev; //在main函数定义!!
//USB OTG 中断服务函数
//处理所有USB中断
void OTG_FS_IRQHandler(void)
{
USBD_OTG_ISR_Handler(&USB_OTG_dev);
}
4.3,修改USBD_USR_Init函数为:
void USBD_USR_Init(void)
{
printf("USBD_USR_Init\r\n");
}
官方的又很多的其他初始化,以及LCD的信息显示,直接替换为我们使用的代码即可。
4.4,修改USBD_USR_DeviceReset函数为:
void USBD_USR_DeviceReset (uint8_t speed)
{
switch (speed)
{
case USB_OTG_SPEED_HIGH:
printf("USB Device Library v1.1.0 [HS]\r\n");
break;
case USB_OTG_SPEED_FULL:
printf("USB Device Library v1.1.0 [FS]\r\n");
break;
default:
printf("USB Device Library v1.1.0 [??]\r\n");
break;
}
}
4.4,修改USBD_USR_DeviceConfigured函数为:
void USBD_USR_DeviceConfigured (void)
{
printf("MSC Interface started.\r\n");
}
4.5,修改USBD_USR_DeviceSuspended函数为:
void USBD_USR_DeviceSuspended(void)
{
printf("Device In suspend mode.\r\n");
}
4.6,修改USBD_USR_DeviceResumed函数为:
void USBD_USR_DeviceResumed(void)
{
printf("Device Resumed\r\n");
}
4.7,修改USBD_USR_DeviceConnected函数为:
void USBD_USR_DeviceConnected (void)
{
bDeviceState=1;
printf("USB Device Connected.\r\n");
}
4.8,修改USBD_USR_DeviceDisconnected函数为:
void USBD_USR_DeviceConnected (void)
{
bDeviceState=1;
printf("USB Device Connected.\r\n");
}
5、修改usb_bsp.c
5.1,新增sys.h和delay.h,,如下所示:
#include "usb_bsp.h"
#include "usbd_conf.h"
#include "sys.h"
#include "delay.h"
5.2,添加USB_HOST_PWRCTRL宏,用于控制USB HOST接口的对外供电(本次是slave,所以可以忽略此步骤),如下所示:
//USB主机电源控制口
#define USB_HOST_PWRCTRL PAout(15) //PA15
5.3,修改USB_OTG_BSP_Init函数为:
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE);//使能USB OTG时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;//PA11/12复用功能输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出功能
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化
USB_HOST_PWRCTRL=1; //开启USB HOST电源供电
GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG_FS);//PA11,AF10(USB)
GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);//PA12,AF10(USB)
}
5.4,修改USB_OTG_BSP_EnableInterrupt函数为:
void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;//子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
NVIC_Init(&NVIC_InitStructure);//配置
}
5.5,修改USB_OTG_BSP_uDelay函数为:
void USB_OTG_BSP_uDelay (const uint32_t usec)
{
delay_us(usec);
}
5.6,修改USB_OTG_BSP_mDelay函数为:
void USB_OTG_BSP_mDelay (const uint32_t msec)
{
delay_ms(msec);
}
4、修改主函数
添加头文件
#include "usbd_msc_core.h"
#include "usbd_usr.h"
#include "usbd_desc.h"
#include "usb_conf.h"
USB相关定义声明
USB_OTG_CORE_HANDLE USB_OTG_dev;
extern vu8 USB_STATUS_REG; //USB状态
extern vu8 bDeviceState; //USB连接 情况
主函数
int main(void)
{
u8 offline_cnt=0;
u8 tct=0;
u8 USB_STA;
u8 Divece_STA;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
KEY_Init(); //按键初始化
W25QXX_Init(); //初始化W25Q128
if(W25QXX_ReadID()!=W25Q128)printf("W25Q128 Error!\r\n"); //检测W25Q128错误
else //SPI FLASH 正常
{
printf("SPI FLASH Size:12MB\r\n");
}
printf("USB Connecting...\r\n");//提示正在建立连接
USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&USBD_MSC_cb,&USR_cb);
delay_ms(1800);
while(1)
{
delay_ms(1);
if(USB_STA!=USB_STATUS_REG)//状态改变了
{
if(USB_STATUS_REG&0x01)//正在写
{
LED1=0;
printf("USB Writing...\r\n");//提示USB正在写入数据
}
if(USB_STATUS_REG&0x02)//正在读
{
LED1=0;
printf("USB Reading...\r\n");//提示USB正在读出数据
}
if(USB_STATUS_REG&0x04)printf("USB Write Err \r\n");//提示写入错误
if(USB_STATUS_REG&0x08)printf("USB Read Err \r\n");//提示读出错误
USB_STA=USB_STATUS_REG;//记录最后的状态
}
if(Divece_STA!=bDeviceState)
{
if(bDeviceState==1)printf("USB Connected \r\n");//提示USB连接已经建立
else printf("USB DisConnected \r\n");//提示USB被拔出了
Divece_STA=bDeviceState;
}
tct++;
if(tct==200)
{
tct=0;
LED1=1;
LED0=!LED0;//提示系统在运行
if(USB_STATUS_REG&0x10)
{
offline_cnt=0;//USB连接了,则清除offline计数器
bDeviceState=1;
}else//没有得到轮询
{
offline_cnt++;
if(offline_cnt>10)bDeviceState=0;//2s内没收到在线标记,代表USB被拔出了
}
USB_STATUS_REG=0;
}
};
}
编译有三个错,一个是头文件没有定义,屏蔽掉即可,一个是新版本对局部变量定义的位置有先后顺序要求,修改下位置即可,然后就可以下载进去测试,亲测成功