STM VCP移植笔记
0x01 为什么要写这篇文章
- 官方sample针对的是stm提供的开发板,而我们往往使用的是自己买的或者diy的开发板,硬件上有一些不同,而对于新手来说,官方的sample有许多宏来配置针对他自己的开发板,导致新手看代码看起来很晕。
- 很多人并不想从头了解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移植笔记相关推荐
- AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17
AT91RM9200Linux移植笔记(三)-移植Linux kernel 2.6.17 手上板子原来自带的是2.4.19的内核, 打算移植新的2.6的内核,从网上下了2.6.17的kernel,下载 ...
- 以太网芯片W3100A到W3150A+的移植笔记(一)
最近很多用户咨询 W3100A,由于W3100A已经停产.在此希望给大家介绍一下,W3100A可移植到其他芯片的方式及途径,供大家更好的拓展您项目的沿用性,期待能对您有所帮助.今天先为大家介绍第一部分 ...
- 【TINY4412】U-BOOT移植笔记:(9)SD卡启动U-BOOT
[TINY4412]U-BOOT移植笔记:(9)SD卡启动U-BOOT 宿主机 : 虚拟机 Ubuntu 16.04 LTS / X64 目标板[底板]: Tiny4412SDK - 1506 目标板 ...
- micropython STM32移植笔记(一)
micropython STM32移植笔记(一) 首先,我是一个搞硬件的,说白了是做电路的,呵呵... 一直想学一些软件,只会搞硬件的工程师是没有灵魂的,画了7年的PCB板卡了,但是每次调试硬件都要求 ...
- AWTK 在腾讯 TOS 上的移植笔记
AWTK 在腾讯 TOS 上的移植笔记 本文以 STM32f103ze 为例,介绍了 AWTK 在 RTOS 上移植的经验.与其说移植,倒不如说是集成.因为 RTOS 通常没有提供标准的 LCD 驱动 ...
- 瑞芯微 | 摄像头ov13850移植笔记
<1.瑞芯微rk356x板子快速上手> <2.Linux驱动|瑞芯微rtc-hym8563移植笔记> <3.Linux驱动 | Linux内核 RTC时间架构-基于瑞芯微 ...
- stm32 u8g2移植笔记
STM32 u8g2 移植笔记 前言 当初想写一个单色屏菜单时,曾移植过u8g2到STM32平台(这里用的是keil MDK),不过当时一直有一个问题没有搞懂:为什么u8g2用在flash为32k,r ...
- u8g2 stm32移植笔记
U8g2移植笔记 下载地址 移植步骤 部分源码简要分析 下载地址 U8g2下载地址U8g2项目Github. 移植步骤 我移植U8g2采用的是stm32硬件SPI,可以提供更高的通讯速率,移植时只需要 ...
- FreeModbus 移植笔记- 1-认识FreeModbus
FreeModbus 移植笔记 目录 1 FreeMODBUS介绍 2 FreeMODBUS官网及源码下载地址 3 移植之前的准备 3.1 FreeModbus V1.6 3.2 Mod ...
最新文章
- 没用上5G的One World演唱会,视频会议软件Zoom和思科WebEX立功了
- java栈和队列验证回文串_栈和队列的基本操作及其应用(回文判断)
- Silverlight 游戏开发小技巧:技能冷却效果1(Cooldown)
- 学习GRPC(一) 简单实现
- Eclipse导出WAR包
- SpringMVC注解@RequestParam(转)
- rgba转16进制颜色
- 利用python爬取租房信息_Python实战:爬取租房信息
- oracle 建同义词语句,Oracle 同义词的创建
- 数据库视频总结之概念篇
- 如何在HTML网页里添加CSS边框,css如何设置边框?
- 诺基亚老年机信息中心设置路径
- win10网络不出现计算机列表,win10笔记本WiFi网络列表不显示内容的解决方法
- 怎么用计算机算出出生日期,算农历出生日期计算器,根据出生日期怎么算年龄?...
- 会声会影视频剪辑详细教程
- 进程间通信——消息队列(Message queue)
- 西安的IT要怎么才能发展?
- 【实训项目】教师工作量管理系统(完整程序)
- 抽奖活动设计 php,如何设计高并发下的抽奖?
- 62、视频监控画面花屏、卡顿、网络延迟如何解决?
热门文章
- ROS2可视化利器---Foxglove Studio
- 有4个圆塔,圆心分别为(2,2)、(-2,2)、(-2,-2)、(2,-2),圆半径为1。这4个塔的高度为10m,塔以外无建筑物。今输入任一点的坐标,求该点的建筑高度(塔外的高度为0)
- 2019年秋冬季读书笔记
- Single Channel Speech Enhancement Using Temporal Convolutional Recurrent Neural Networks
- 互斥锁的应用与pthread_mutex_destory的出错
- ant jeecg vue 前端通过dom节点 导出xlsx表格
- HTTP 所有状态码
- 组装一台台式计算机的流程,如何组装电脑?组装电脑的操作流程!
- ARM9的存储结构~~大端存储和小端存储
- ARM体系结构2:汇编指令集