打印
[研电赛技术支持]

GD32F470 SD卡模拟U盘

[复制链接]
840|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-4-1 08:47 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
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

使用特权

评论回复
沙发
suncl110| | 2024-4-1 15:42 | 只看该作者
好是好,无奈没有附源码呀

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1364

主题

13994

帖子

8

粉丝