stm32f407的高速usb的数据发送

2019-07-20 12:33发布

本帖最后由 无苛 于 2017-7-31 14:06 编辑

关于stm32f407的高速usb ULPI接口就不多说了,按照usb3300的数据手册和stm32f407的外设引脚分配连接上就行了,我的原理图画得太差容易误导大家,就不暴露出来了。先来点干货http://pan.baidu.com/s/1nuXne45   这是STM32_USB-Host-Device_Lib_V2.1.0大家可以下载也可以使用原子哥的资料里的库,这里假设大家的硬件都没问题了,打开虚拟串口vcp工程,直接进行工程库的修改具体路径自己找,不要太懒,首先修改系统时钟官方库使用的是25M晶振,我这使用的是24M晶振,打开stm32f4xx这个文件树里面的system_stm32f4xx.c文件第155行 我这里是24修改成24即可(大多数使用的是8M晶振修改为8即可)。

修改完之后接下来继续修改ULPI接口,官方库使用的是stm32f407IGT系列一共有176个引脚使用的复用引脚跟100引脚的stm32f407vet6有所不同打开app文件树的usb_bsp.c这个文件的
void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) 函数的引脚配置,主要就两个口
//重定义配置
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource3, GPIO_AF_OTG2_HS) ; // NXT
  GPIO_PinAFConfig(GPIOC,GPIO_PinSource2,GPIO_AF_OTG2_HS) ; // DIR
//初始化
  //NXT  
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init(GPIOC, &GPIO_InitStructure);  


  //DIR
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_Init(GPIOC, &GPIO_InitStructure);  

这样就ok了,这时候编译程序下载进入usb3300的60M晶振就会起振,如果有条件可以用示波器测测,如果不起振检测一下程序是否是按上面的配置的,和硬件电路是否有问题,如果有问题先检测stm32f407的晶振和usb3300的晶振是否震荡。第一步算是完成了。接下来是收发数据,这里我是用的是vcp工程,先去掉stm32f407官方库工程文件的只读属性,打开app文件下的usbd_cdc_vcp.c文件在最底367行你可以看见串口中断函数,数据接收中断里面有一个VCP_DataTx (0,0);函数打开这个函数  ,你会发现就是往数组里面放接收数据。你可以全局搜索这个缓冲区,可以在sof帧起事件的回调函数  static void Handle_USBAsynchXfer (void *pdev)  里面发现调用端点发送函数    DCD_EP_Tx (pdev,  CDC_IN_EP, (uint8_t*)&APP_Rx_Buffer[USB_Tx_ptr],  USB_Tx_length);      发送数据,根据usb协议,这里是高速usb2.0设备所以帧事件会在125us发生一次,全速的如果我没记错的话最大是1ms一次帧事件,仔细看帧起始回调函数,实现的就是把串口缓冲数组里面的数发送到usb端点,等待主机读取。程序不难关于发送流程我们先分析到这里(其实到这里大家都应该明白了,数据往usb的发送),返回我们继续看怎么实现往上位机发数据,回到app文件树的usbd_cdc_vcp.c文件接着继续看这里有一个vcp数据接收函数  static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)  一看函数内容我想大家都明白,这是把usb接收到的数据发送到stm32f407的串口,我们这里定义一个函数把发送的数据返回回去,函数内容:
static uint16_t Custom_VCP_DataTx (uint8_t data, uint32_t Len){
//  if (linecoding.datatype == 7)
//  {
//    APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1) & 0x7F;
//  }
//  else if (linecoding.datatype == 8)
//  {
//    APP_Rx_Buffer[APP_Rx_ptr_in] = USART_ReceiveData(EVAL_COM1);
//  }   
  APP_Rx_Buffer[APP_Rx_ptr_in] = data;
  APP_Rx_ptr_in++;
  
  /* To avoid buffer overflow */
  if(APP_Rx_ptr_in == APP_RX_DATA_SIZE)
  {
    APP_Rx_ptr_in = 0;
  }  
  
  return USBD_OK;
}


把这个函数放在这个函数里面  
static uint16_t VCP_DataRx (uint8_t* Buf, uint32_t Len)
{
  uint32_t i;

  for (i = 0; i < Len; i++)
  {
    USART_SendData(EVAL_COM1, *(Buf + i) );
    while(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET);
                 
                Custom_VCP_DataTx (*(Buf + i),0);
  }

  return USBD_OK;
}

编译下载进单片机连上usb打开电脑的设备管理器你会发现,stm32f407的虚拟串口没有枚举成功,这里需要安装驱动,这里我分享给大家
链接:http://pan.baidu.com/s/1mhNLJpI 密码:6wka   
自己按照系统位数安装,安装成功后会正常枚举出一个串口来,这里我们使用原子哥的串口调试助手把这个串口打开往串口发数据,数据会自动显示回来。这里我们的实验就算成功了关于怎么发送我想也不用讲了吧,不过这里要注意:
一点千万不要直接在主函数while(1)里面调用端点发送函数直接发送这样是有问题的,会和端点状态发生冲突,导致端点异常,直接在帧同步中断里面发最好效率也最高。
我的上一篇求助贴纸就是因为在while(1)里面发送导致错误搞了一周,我一直以为是上位机和电路问题,后来反思查看源码发现这个问题,并不是我的板子不能高速发送数据而是我的板子根本就没发数据,如果要高速发送接收   
把这个去掉即可:
    USART_SendData(EVAL_COM1, *(Buf + i) );
    while(USART_GetFlagStatus(EVAL_COM1, USART_FLAG_TXE) == RESET); 。




在这里谢谢原子哥提供平台,让大家相互分享交流技术,希望和我遇到同样问题的人能看到这篇贴子,在开源的路途上我们共同努力,分享是快乐的源泉,大家有什么好的关于usb资料也请在贴纸下面,来点链接分享给大家。




个人辛苦码字分享如有不喜勿喷









友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。