0x01 为什么要写这篇文章

  1. 官方sample针对的是stm提供的开发板,而我们往往使用的是自己买的或者diy的开发板,硬件上有一些不同,而对于新手来说,官方的sample有许多宏来配置针对他自己的开发板,导致新手看代码看起来很晕。
  2. 很多人并不想从头了解USB的协议,如何枚举,如何写描述符,只是想快速的搭建一个VCP。

0x02 sample的思路

以下内容都是从网上收集的

目前发布的STM32_USB-FS-Device_Lib中有一个USB虚拟串口的例程,这个例程演示了把STM32配置为一个USB虚拟串口设备,STM32从它的USART接口接收数据并通过USB传送到上位机,反之STM32也从USB接收上位机送来的数据并从USART接口发送出去。

在从USART接口接收数据再向USB端口发送数据的这个方向上,例程采取的策略是:在每次从USART接口收到一个字节后,就做成一个USB数据包并发送出去。这种方法的好处是程序简单明了,但如果USART端出现连续的数据流时,容易造成数据丢失的问题。

0x03 软硬件环境

所谓移植就是因为我们用的开发板和STM的开发板的硬件上是有区别,STM开发板可以通过IO口控制上拉电阻,以达到控制USB连接的目的,我们这个板子是1.5k电阻直接接在VCC上。

硬件环境(我的开发板)

软件环境

  • eclipse-cpp-kepler-SR2-macosx-cocoa.tar.gz
  • gcc-arm-none-eabi–4_8–2014q3–20140805-mac.tar.bz2
  • ilg.gnuarmeclipse.repository–2.4.2–201411261616.zip
  • JLink_MacOSX_V510c.pkg
  • STM32_USB-FS-Device_Lib_V3.3.0

0x04 开始移植



修改项目include配置

基础工作做好了,可以开始修改里面的代码了

现在我们开始从上到下修改一遍文件

hw_config.c

去掉include文件

#include "platform_config.h"
#include "stm32_eval.h"

添加include文件

#include "stm32f10x_conf.h"
#include "usb_conf.h"

注释掉下面这段,因为我们不用GPIO控制USB通断

  /* Enable USB_DISCONNECT GPIO clock */RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT, ENABLE);/* Configure USB pull-up pin */GPIO_InitStructure.GPIO_Pin = USB_DISCONNECT_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_Init(USB_DISCONNECT, &GPIO_InitStructure);

注释掉下面这段,因为我们不用从USART接收数据再发送到USB,我们移植后肯定有自己的逻辑

  /* Enable USART Interrupt */NVIC_InitStructure.NVIC_IRQChannel = EVAL_COM1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_Init(&NVIC_InitStructure);

注释掉下面这段,同上,我们不用GPIO控制USB通断

  if (NewState != DISABLE){GPIO_ResetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);}else{GPIO_SetBits(USB_DISCONNECT, USB_DISCONNECT_PIN);}

注释掉函数内部的内容,同上,USART是例子中的我们不用

void USART_Config_Default(void)

注释掉函数内部的内容,原理同上

bool USART_Config(void)

注释掉函数内部的内容

void USB_To_USART_Send_Data(uint8_t* data_buffer, uint8_t Nb_bytes)

注释掉函数内部的内容

void USART_To_USB_Send_Data(void)

这句没啥用,也注释掉吧

extern LINE_CODING linecoding;

stm32f10x_it.c

去掉include文件

#include "platform_config.h"
#include "stm32_eval.h"

注释掉函数内部的内容

void EVAL_COM1_IRQHandler(void)

main.c

#include "usb_lib.h"
#include "usb_desc.h"
#include "hw_config.h"
#include "usb_pwr.h"int main(int argc, char* argv[]) {Set_System();Set_USBClock();USB_Interrupts_Config();USB_Init();while (1) {// Add your code here.}
}

至此项目就可以编译生成hex了,接下来我们把hex传到开发板上,我用的是JLink SWD方式

在项目的根目录建一个文本文件,命名为JLinkCommand.jlink,内容如下

r
speed 4000
device STM32F103RC
loadbin /Users/xuwen/Documents/workspace/MCU/stm32f103rcvirtualcom/Debug/stm32f103rcvirtualcom.hex 0x08000000
g
qc



xuwendeMacBook-Pro:~ xuwen$ /Applications/SEGGER/JLink/JLinkExe -device STM32F103RC -if SWD -speed 4000 -autoconnect 1 -CommanderScript /Users/xuwen/Documents/workspace/MCU/vcpdemo/JLinkCommand.jlink

将开发板接到机器上就可以看结果了,这里我测试win7可以自动安装驱动,osx不需要安装驱动。 但是上面的移植改造只是让系统能识别到串口,并没有啥实际功能,这里再放一段代码实现个简单的数据发送功能。

#include "usb_lib.h"
#include "usb_desc.h"
#include "hw_config.h"
#include "usb_pwr.h"
#include "usb_conf.h"
#include "stdio.h"uint8_t buff[16] = { 0 };void delay_ms(u16 nms) {u32 temp;SysTick->LOAD = 9000 * nms;SysTick->VAL = 0X00; //清空计数器SysTick->CTRL = 0X01; //使能,减到零是无动作,采用外部时钟源do {temp = SysTick->CTRL; //读取当前倒计数值} while ((temp & 0x01) && (!(temp & (1 << 16)))); //等待时间到达SysTick->CTRL = 0x00; //关闭计数器SysTick->VAL = 0X00; //清空计数器
}int main(int argc, char* argv[]) {Set_System();Set_USBClock();USB_Interrupts_Config();USB_Init();while (1) {// Add your code here.sprintf(buff, "temp:%9.3f\r\n", 3.145);UserToPMABufferCopy(buff, ENDP1_TXADDR, 16);SetEPTxCount(ENDP1, 16);SetEPTxValid(ENDP1);delay_ms(1000);}
}

0x05 网上资料

下面是我在做上面工作的时候在网上搜索的内容,感觉对移植工作理解有所帮助也就拷贝下来了

网上参考:usb stm32f103rc 虚拟串口的数据收发 2011–12–06 17:19阅读:855 1、时钟定义 //由72M分频1.5后得到 RCC_USBCLKConfig(RCC_USBCLKSource_PLLCLK_1Div5); RCC_APB1PeriphClockCmd(RCC_APB1Periph_USB, ENABLE); 2、中断向量定义 NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); 3、中断函数 void USB_LP_CAN1_RX0_IRQHandler(void) {//添加usb中断的处理函数 USB_Istr(); } 4、例程中用的是端点1发数据,端点3收数据,数据的处理函数放入下表中 void (pEpInt_IN[7])(void) = { EP1_IN_Callback,—– }; void (pEpInt_OUT[7])(void) = { EP3_OUT_Callback,—- }; 5、USB的相关初始化在STM公司提供的例程中有,主线是把握中断方式,在主机隔一段时间查询是否有数据收发时处理数据。

网上参考:使用STM32F102/103 USB函数库 进行USB通信

第一步: 根据应用的需求,定义使用到的端点数量

usb_conf.h

define EP_NUM (3)

以上意味着应用需要使用到EP0,EP1和EP2 第二步: 初始化每个使用到的端点

usb_prop.c

SetEPType(ENDP2, EP_INTERRUPT); 定义端点2为中断端点

SetEPTxAddr(ENDP2, ENDP2_TXADDR); 如果需要进行EP2 IN通信,需要定义端点2的发送缓存区的地址,也就是在Packet Buffer中的偏移地址

SetEPRxAddr(ENDP2, ENDP2_RXADDR); 如果需要进行EP2 OUT通信,需要定义端点2的接收缓存区在Packet Buffer中的偏移地址

SetEPRxStatus(ENDP2, EP_RX_NAK); 设置端点2的接收状态为NAK,设备将以NAK来响应主机发起的所有OUT通信。

SetEPTxStatus(ENDP2, EP_TX_NAK); 设置端点2的发送状态为NAK,设备将以NAK来响应主机发起的所有IN通信。

第三步: 使能端点的通信

对于IN端点的使能: UserToPMABufferCopy(Send_Buffer, ENDP2_TXADDR, 8); 拷贝用户数据到端点2的发送缓存区

SetEPTxCount(ENDP2, 8); 设置端点2发送数据长度

SetEPTxValid(ENDP2); 设置端点2的发送状态为VALID

以上三句可以在应用代码的任意位置调用,一旦调用,即使能了一次USB IN通信。

USB设备将在收到主机的IN TOKEN后,自动发送缓存区中的数据到主机,并在发送完毕后产生EP2_IN_Callback中断,同时将端点2的发送状态自动改为NAK。

如果需要再次进行数据传送,需要再次调用以上的三句函数。

对于OUT端点的使能:

SetEPRxValid(ENDP2); 设置端点2的接收状态为VALID。

以上的这句函数即使能了端点2的OUT通信,可以在任意位置调用。

一旦调用,即使能了一次OUT通信。USB设备将以ACK来响应主机随后的OUT通信,并在接收数据完毕后,产生EP2_OUT_Callback中断,同时自动将端点的接收状态改为NAK。

在EP2_OUT_Callback中断函数中调用 USB_SIL_Read(EP2_OUT, Receive_Buffer); 可以将端点2接收缓存区中收到的数据拷贝到用户数据区

转载于:https://www.cnblogs.com/bh4lm/p/8057802.html

STM VCP移植笔记相关推荐

  1. AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17

    AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17 手上板子原来自带的是2.4.19的内核, 打算移植新的2.6的内核,从网上下了2.6.17的kernel,下载 ...

  2. 以太网芯片W3100A到W3150A+的移植笔记(一)

    最近很多用户咨询 W3100A,由于W3100A已经停产.在此希望给大家介绍一下,W3100A可移植到其他芯片的方式及途径,供大家更好的拓展您项目的沿用性,期待能对您有所帮助.今天先为大家介绍第一部分 ...

  3. 【TINY4412】U-BOOT移植笔记:(9)SD卡启动U-BOOT

    [TINY4412]U-BOOT移植笔记:(9)SD卡启动U-BOOT 宿主机 : 虚拟机 Ubuntu 16.04 LTS / X64 目标板[底板]: Tiny4412SDK - 1506 目标板 ...

  4. micropython STM32移植笔记(一)

    micropython STM32移植笔记(一) 首先,我是一个搞硬件的,说白了是做电路的,呵呵... 一直想学一些软件,只会搞硬件的工程师是没有灵魂的,画了7年的PCB板卡了,但是每次调试硬件都要求 ...

  5. AWTK 在腾讯 TOS 上的移植笔记

    AWTK 在腾讯 TOS 上的移植笔记 本文以 STM32f103ze 为例,介绍了 AWTK 在 RTOS 上移植的经验.与其说移植,倒不如说是集成.因为 RTOS 通常没有提供标准的 LCD 驱动 ...

  6. 瑞芯微 | 摄像头ov13850移植笔记

    <1.瑞芯微rk356x板子快速上手> <2.Linux驱动|瑞芯微rtc-hym8563移植笔记> <3.Linux驱动 | Linux内核 RTC时间架构-基于瑞芯微 ...

  7. stm32 u8g2移植笔记

    STM32 u8g2 移植笔记 前言 当初想写一个单色屏菜单时,曾移植过u8g2到STM32平台(这里用的是keil MDK),不过当时一直有一个问题没有搞懂:为什么u8g2用在flash为32k,r ...

  8. u8g2 stm32移植笔记

    U8g2移植笔记 下载地址 移植步骤 部分源码简要分析 下载地址 U8g2下载地址U8g2项目Github. 移植步骤 我移植U8g2采用的是stm32硬件SPI,可以提供更高的通讯速率,移植时只需要 ...

  9. FreeModbus 移植笔记- 1-认识FreeModbus

    FreeModbus 移植笔记 目录 1 FreeMODBUS介绍 2 FreeMODBUS官网及源码下载地址 3 移植之前的准备 3.1 FreeModbus V1.6 ​​​​​​​3.2 Mod ...

最新文章

  1. 没用上5G的One World演唱会,视频会议软件Zoom和思科WebEX立功了
  2. java栈和队列验证回文串_栈和队列的基本操作及其应用(回文判断)
  3. Silverlight 游戏开发小技巧:技能冷却效果1(Cooldown)
  4. 学习GRPC(一) 简单实现
  5. Eclipse导出WAR包
  6. SpringMVC注解@RequestParam(转)
  7. rgba转16进制颜色
  8. 利用python爬取租房信息_Python实战:爬取租房信息
  9. oracle 建同义词语句,Oracle 同义词的创建
  10. 数据库视频总结之概念篇
  11. 如何在HTML网页里添加CSS边框,css如何设置边框?
  12. 诺基亚老年机信息中心设置路径
  13. win10网络不出现计算机列表,win10笔记本WiFi网络列表不显示内容的解决方法
  14. 怎么用计算机算出出生日期,算农历出生日期计算器,根据出生日期怎么算年龄?...
  15. 会声会影视频剪辑详细教程
  16. 进程间通信——消息队列(Message queue)
  17. 西安的IT要怎么才能发展?
  18. 【实训项目】教师工作量管理系统(完整程序)
  19. 抽奖活动设计 php,如何设计高并发下的抽奖?
  20. 62、视频监控画面花屏、卡顿、网络延迟如何解决?

热门文章

  1. ROS2可视化利器---Foxglove Studio
  2. 有4个圆塔,圆心分别为(2,2)、(-2,2)、(-2,-2)、(2,-2),圆半径为1。这4个塔的高度为10m,塔以外无建筑物。今输入任一点的坐标,求该点的建筑高度(塔外的高度为0)
  3. 2019年秋冬季读书笔记
  4. Single Channel Speech Enhancement Using Temporal Convolutional Recurrent Neural Networks
  5. 互斥锁的应用与pthread_mutex_destory的出错
  6. ant jeecg vue 前端通过dom节点 导出xlsx表格
  7. HTTP 所有状态码
  8. 组装一台台式计算机的流程,如何组装电脑?组装电脑的操作流程!
  9. ARM9的存储结构~~大端存储和小端存储
  10. ARM体系结构2:汇编指令集