当前位置: 首页 > article >正文

(3)STM32 USB设备开发-USB存储设备

例程:STM32USBdevice: 基于STM32的USB设备例子程序 - Gitee.com

本篇为使用芯片内部flash作为USB存储设备的例程,没有知识,全是实操,按照步骤就能获得一个STM32的U盘。本例子是在野火F103MINI开发板上验证的,如果代码中出现一些外设的配置,可以参考野火F103MINI开发板原理图对照。

设置外部晶振,必须要使用外部晶振,因为USB控制器需要48M的系统时钟,内部晶振无法倍频出48M。

配置外部时钟

配置调试口和系统基准源

开启USB设备

中间件中设备USB设备类型

标蓝色的部分需要根据你之前有没有使用过这两VID和PID,如果使用过最好换一下,避免使用之前的驱动引起一些奇奇怪怪的问题。

STM32扇区大小如下

Flash大小为64KB ,单个扇区大小:1KB=0x400;Flash大小为128KB,单个扇区大小:1KB=0x400;

Flash大小为256KB,单个扇区大小:2KB=0x800;Flash大小为512KB,单个扇区大小:2KB=0x800;

STM32容量划分

大容量:256-512k的Flash,主要为:STM32F103xC, STM32F103xD,STM32F103xE

中容量:64-128k的Flash,主要为:STM32F103x8 STM32F103xB

小容量:16-32k的Flash,主要为:STM32F103x4 STM32F103x6

如果你使用的是大容量,MSC_MEDIA_PACKET需要配置为2048,如果不是大容量设备这里需要配置为1024

我使用了freertos v2

配置外部系统时钟

分配较大的堆栈空间,使U盘读写转存更快

配置独立C和H文件

代码需要修改如下:

首先我们需要知道代码使用了多大,我们需要使用没有被使用的那部分flash

我们把我们代码编译后会看到编译信息,

text 代码和常量

data 初始化的全局变量

bss 未初始化的变量

dec 就是前面三个的加和

我们可以使用Build Analyzer查看已经使用的flash

其实就是text+data=48,832=47.6875KB

所以我们需要使用48KB之后的flash,我们这里使用60KB之后的flash

/* USER CODE BEGIN PRIVATE_DEFINES */
//这里定义读写的FLASH起始地址和大小
#define FLASH_START_NBR 0x0800F000 // 从60K地址开始
#define FLASH_PAGE_NBR 100  // 100k
/* USER CODE END PRIVATE_DEFINES */

其中F000就是60KB,0x08000000是flash起始地址。

简单讲解几个重要函数

static int8_t STORAGE_Init_FS(uint8_t lun);

存储的初始化函数,如果有SD卡或者片外FLASH初始化可以放在这里。

static int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size);

获取存储容量大小;

static int8_t STORAGE_IsReady_FS(uint8_t lun);

设备是否准备好;

static int8_t STORAGE_IsWriteProtected_FS(uint8_t lun);

设备是否是写保护,类似于大的SD卡边上的小卡扣,如果是写保护则没有写权限;

static int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

存储读函数;

static int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len);

存储写函数;

int8_t STORAGE_GetCapacity_FS(uint8_t lun, uint32_t *block_num, uint16_t *block_size)
{
  /* USER CODE BEGIN 3 */
  *block_num  = FLASH_PAGE_NBR; //  块数量为100
  *block_size = FLASH_PAGE_SIZE; //  块大小为2048字节
  return (USBD_OK);
  /* USER CODE END 3 */
}

FLASH_PAGE_SIZE宏是STM32固件库提供的,如果是大容量就是2k

int8_t STORAGE_Read_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 6 */
  if (lun == 0) { //  如果lun为0,则将FLASH_BLK_NBR + blk_addr * FLASH_BLK_SIZ地址处的数据复制到buf中,长度为blk_len * FLASH_BLK_SIZ字节
    memcpy(buf, (uint8_t*) (FLASH_START_NBR + blk_addr * FLASH_PAGE_SIZE), blk_len * FLASH_PAGE_SIZE);
    return USBD_OK;
  }
  return (USBD_FAIL);
  /* USER CODE END 6 */
}
int8_t STORAGE_Write_FS(uint8_t lun, uint8_t *buf, uint32_t blk_addr, uint16_t blk_len)
{
  /* USER CODE BEGIN 7 */
  if (lun == 0) {          //  如果lun为0,则执行以下操作
    uint16_t i;          //  定义一个变量i
    HAL_FLASH_Unlock();  //  解锁Flash

    FLASH_EraseInitTypeDef f;                                  //  定义一个结构体f,用于存储擦除Flash的参数
    f.TypeErase = FLASH_TYPEERASE_PAGES;                       //  设置擦除类型为页擦除
    f.PageAddress = FLASH_START_NBR + blk_addr * FLASH_PAGE_SIZE;  //  设置要擦除的页地址
    f.NbPages = blk_len;                                       //  设置要擦除的页数
    uint32_t PageError = 0;                                    //  定义一个变量PageError,用于存储擦除错误信息
    HAL_FLASHEx_Erase(&f, &PageError);                         //  执行擦除操作

    for (i = 0; i < blk_len * FLASH_PAGE_SIZE; i += 4)  //  循环写入数据到Flash中
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, FLASH_START_NBR + blk_addr * FLASH_PAGE_SIZE + i,
                          *(uint32_t *)(&buf[i])); //  将buf中的数据写入到Flash中

    HAL_FLASH_Lock();  //  锁定Flash
  }
  return (USBD_OK);  //  返回USBD_OK
  /* USER CODE END 7 */
}

至此可以下载程序了,下载好后第一次接入电脑需要格式化U盘,格式化之后就可以正常使用了。

因为我这里还有200多KB的空闲,所以我可以分配200KB的flash。


http://www.kler.cn/a/513075.html

相关文章:

  • 解决conda create速度过慢的问题
  • 微服务知识——4大主流微服务架构方案
  • JDBC实验测试
  • 淘宝关键词页面爬取绘图进行数据分析
  • 计算机系统原理:一些断言
  • 数据结构漫游记:队列的动态模拟实现(C语言)
  • GoFrame 缓存组件
  • 为医院量身定制做“旧改”| 全视通物联网智慧病房
  • Streamlit可视化之设计案例分析小助手
  • SVM模型(理论知识3)
  • 什么是PCB的Mark点?如何进行设计Mark点?
  • 他把智能科技引入现代农业领域
  • Rabbitmq高级特性之消费方确认
  • Flutter中PlatformView在鸿蒙中的使用
  • Elixir语言的数据库编程
  • CKS认证 | Day1 K8s集群部署与安全配置
  • 部门管理查询部门,nginx反向代理,前端如何访问到后端Tomcat 注解@RequestParam
  • 博客之星2024年度-技术总结:技术探险家小板的一年的征程
  • AF3 AttentionPairBias类源码解读
  • 三、I2C客户端驱动 —— htu21d
  • uboot剖析之命令行延时
  • C++ 学习:深入理解 Linux 系统中的冯诺依曼架构
  • python爬虫入门(实践)
  • 基于Springboot+Redis秒杀系统 demo
  • 【2024年华为OD机试】 (JavaScriptJava PythonC/C++)
  • 网络安全态势感知技术综述