USB驱动库移植
1、在官方提供的固件库中找到USB驱动文件,全部拷贝到自己的工程中。
2、在官方的固件库例程中找到USBFS->USB_Device->MSC例程,打开该文件夹将inc和src中关于usb的文件全部拷贝到自己工程中,具体内容如下图所示:
inc文件夹打开所示:
src文件夹打开所示
我这里拷贝到了自己工程中的usb文件夹中,同时在该文件夹中创建一个usbd_norflash_access.c文件和usbd_norflash_access.h文件为后面添加外部FLASH驱动程序使用,如下图所示:
3、打开自己的工程结构,添加上面拷贝的文件,添加完成的结果如下图所示:
4、指定添加的头文件路径,同时添加USBFS的宏定义USE_USBFS,如下图所示:
由于官方给的例程使用的方式是单片机的内部SRAM模拟U盘,做完以上后可以尝试编译一下,错误应该会很少。当然也直接可以把官方提供的例程直接下载到自己单片机上,先观察一下效果。
将外部Flash的读写驱动程序添加到USB驱动中
从这里开始我们才算是添加自己的东西,前面的工作只是对官方库的移植(外部Flash的读写函数我在另一篇文章中有介绍,有兴趣的可以去查看,链接:https://www.cnblogs.com/wenhao-Web/p/14052266.html)。
1、打开usbd_norflash_access.h和usbd_norflash_access.c文件,进行如下修改:
usbd_norflash_access.c文件中的内容
#include "./usb/usb_conf.h"
#include "./usb/usbd_norflash_access.h"
#include "./gd25qxx/gd25q256.h"
/*!
\brief read data from multiple blocks of internal NORFLASH
\param[in] pbuf: pointer to user buffer
\param[in] read_addr: address to be read
\param[in] block_size: size of block
\param[in] block_num: number of block
\param[out] none
\retval operation status
*/
uint32_t norflash_multi_blocks_read (uint8_t *pbuf,
uint32_t read_addr,
uint16_t block_size,
uint32_t block_num)
{
gd25q256df_read_data(pbuf, read_addr, block_num*block_size);
return 0;
}
/*!
\brief write data from multiple blocks of internal NORFLASH
\param[in] pbuf: pointer to user buffer
\param[in] write_addr: address to be write
\param[in] block_size: size of block
\param[in] block_num: number of block
\param[out] none
\retval operation status
*/
uint32_t norflash_multi_blocks_write (uint8_t *pbuf,
uint32_t write_addr,
uint16_t block_size,
uint32_t block_num)
{
gd25q256df_write_data(pbuf, write_addr, block_num*block_size);
return 0;
}
usbd_norflash_access.h文件中的内容
#ifndef USBD_NORFLASH_ACCESS_H
#define USBD_NORFLASH_ACCESS_H
#include "gd32f30x.h"
#define NORFLASH_BLOCK_SIZE 512 /* 固定每个块大小为512 */
#define NORFLASH_BLOCK_NUM 65536 /* (1024*1024*32/512) 使用32Mbyte */
/* function declarations */
/* read data from multiple blocks of internal NORFLASH */
uint32_t norflash_multi_blocks_read (uint8_t *pbuf,
uint32_t read_addr,
uint16_t block_size,
uint32_t block_num);
/* write data from multiple blocks of internal NORFLASH */
uint32_t norflash_multi_blocks_write (uint8_t *pbuf,
uint32_t write_addr,
uint16_t block_size,
uint32_t block_num);
#endif /* USBD_NORFLASH_ACCESS_H */
上面两个文件的内容很简单,就是读和写,和官方提供的SRAM实现的写法基本一样。
2、接着是对usbd_bbb_scsi.c文件中的内容进行修改
修改的内容主要是把官方提供的SRAM的内容替换成NORFLASH的内容即可。
/* USB mass storage format capacities data */
uint8_t format_capacities_data[FORMAT_CAPACITIES_DATA_LENGTH] =
{
0x00, 0x00, 0x00, /* reserved */
0x08, /* capacity list length */
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 24), /* number of blocks (MSB) */
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 16), /* number of blocks (MSB) */
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 8), /* number of blocks (MSB) */
(uint8_t)(NORFLASH_BLOCK_NUM - 1), /* number of blocks (MSB) */
0x02, /* bit0 - bit1:descriptor code */
(uint8_t)((NORFLASH_BLOCK_SIZE) >> 16), /* block length (MSB) */
(uint8_t)((NORFLASH_BLOCK_SIZE) >> 8), /* block length (MSB) */
(uint8_t)(NORFLASH_BLOCK_SIZE) /* block length (MSB) */
};
/* USB mass storage read capacities data */
uint8_t read_capacities_data[READ_CAPACITIES_DATA_LENGTH] =
{
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 24), /* last logical block address (MSB) */
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 16), /* last logical block address (MSB) */
(uint8_t)((NORFLASH_BLOCK_NUM - 1) >> 8), /* last logical block address (MSB) */
(uint8_t)(NORFLASH_BLOCK_NUM - 1), /* last logical block address (MSB) */
(uint8_t)((NORFLASH_BLOCK_SIZE) >> 24), /* block length in bytes (MSB) */
(uint8_t)((NORFLASH_BLOCK_SIZE) >> 16), /* block length in bytes (MSB) */
(uint8_t)((NORFLASH_BLOCK_SIZE) >> 8), /* block length in bytes (MSB) */
(uint8_t)(NORFLASH_BLOCK_SIZE) /* block length in bytes (MSB) */
};
读的修改部分:
写的修改部分:
3、USB启动部分程序,其实就是把官方的那一套内容全部拷贝到自己工程中。
相关变量的定义和初始化
usb_core_handle_struct usbhs_core_dev =
{
.dev =
{
.dev_desc = (uint8_t *)&device_descripter,
.config_desc = (uint8_t *)&configuration_descriptor,
.strings = usbd_strings,
.class_init = msc_init,
.class_deinit = msc_deinit,
.class_req_handler = msc_req_handler,
.class_data_handler = msc_data_handler
},
.udelay = delay_us,
.mdelay = delay_ms
};
void usb_clock_config(void);
void usb_gpio_config(void);
void usb_interrupt_config(void);
uint8_t timer_prescaler = 0;
uint32_t usbfs_prescaler = 0;
主函数中的内容
/*!
\brief main function
\param[in] none
\param[out] none
\retval none
*/
int main(void)
{
/* configure 4 bits pre-emption priority */
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
bsp_spi1_init();
gd25q256df_init();
flash_id = gd25q256df_read_id();
if(flash_id == 0xC84019)
{
/* configure USB clock */
usb_clock_config();
/* USB timer configure */
timer_nvic_init();
/* USB device stack configure */
usbd_init(&usbhs_core_dev, USB_FS_CORE_ID);
/* USB interrupt configure */
usb_interrupt_config();
/* check if USB device is enumerated successfully */
while (usbhs_core_dev.dev.status != USB_STATUS_CONFIGURED) {}
}
while(1);
}
USB时钟配置
/*!
\brief configure USB clock
\param[in] none
\param[out] none
\retval none
*/
void usb_clock_config(void)
{
uint32_t system_clock = rcu_clock_freq_get(CK_SYS);
if (system_clock == 48000000) {
usbfs_prescaler = RCU_CKUSB_CKPLL_DIV1;
timer_prescaler = 3;
} else if (system_clock == 72000000) {
usbfs_prescaler = RCU_CKUSB_CKPLL_DIV1_5;
timer_prescaler = 5;
} else if (system_clock == 120000000) {
usbfs_prescaler = RCU_CKUSB_CKPLL_DIV2_5;
timer_prescaler = 9;
} else {
/* reserved */
}
rcu_usb_clock_config(usbfs_prescaler);
rcu_periph_clock_enable(RCU_USBFS);
}
USB驱动所使用到的中断配置
/*!
\brief configure USB interrupt
\param[in] none
\param[out] none
\retval none
*/
void usb_interrupt_config(void)
{
nvic_irq_enable((uint8_t)USBFS_IRQn, 4U, 0U);
/* enable the power module clock */
rcu_periph_clock_enable(RCU_PMU);
/* USB wakeup EXTI line configuration */
exti_interrupt_flag_clear(EXTI_18);
exti_init(EXTI_18, EXTI_INTERRUPT, EXTI_TRIG_RISING);
exti_interrupt_enable(EXTI_18);
nvic_irq_enable((uint8_t)USBFS_WKUP_IRQn, 1U, 0U);
}
USBFS中断函数
/*!
\brief this function handles USBD interrupt
\param[in] none
\param[out] none
\retval none
*/
void USBFS_IRQHandler (void)
{
usbd_isr (&usbhs_core_dev);
}
USBFS唤醒中断函数
/*!
\brief this function handles USBD wakeup interrupt request.
\param[in] none
\param[out] none
\retval none
*/
void USBFS_WKUP_IRQHandler(void)
{
if (usbhs_core_dev.cfg.low_power) {
SystemInit();
rcu_usb_clock_config(usbfs_prescaler);
rcu_periph_clock_enable(RCU_USBFS);
usb_clock_ungate(&usbhs_core_dev);
}
exti_interrupt_flag_clear(EXTI_18);
}
定时器中断函数
/*!
\brief this function handles Timer0 updata interrupt request.
\param[in] none
\param[out] none
\retval none
*/
void TIMER0_UP_TIMER9_IRQHandler(void)
{
timer_delay_irq();
}
至此编译一下,没有问题,单片机与电脑连接正常就会在电脑上显示一个U盘,如果是第一次使用还需格式化。试试向该U盘中创建、拷贝文件是否正常,最好是用一个与该U盘大小差不多的文件测试。
如下图所示,是我连接电脑模拟出的U盘效果(在使用的过程中发现一个问题,就是拷贝大文件传输速度不连续,不知道是为什么,希望有知道的给与指导):
#endif
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/lvmingzhou/article/details/137013249
|
|