历史上的今天
返回首页

历史上的今天

今天是:2024年09月20日(星期五)

正在发生

2018年09月20日 | STM32 UVC学习笔记3

2018-09-20 来源:eefocus

主机环境:Windows 7 SP1

开发环境:MDK5.18

目标板:STM32F103C8T6

开发库:STM32F1Cube库和STM32_USB_Device_Library

继续昨天的学习笔记,之前提到从USBTrace软件中抓取的数据跟图像原始数据做对比是没有丢失数据的,只是在传输过程中有一半的数据包出现了错误,由此导致我们在PC上一直无法获取到正常的图像,从而一直显示黑屏,这个原因也找了好久,而且心浮气躁,调试一会儿就去干别的事了,对于调试来说分析出问题点才能更好的去解决问题,大家可以思考一下为什么是有一半的数据包出错,而不是个别数据包错误,也不是三分之一,四分之一出错等,联想到STM32中同步传输是使能了双缓冲特性,只有这一特性是跟我们的错误点二分之一相关的,因此,很有可能是双缓冲这里出现了问题,现在问题就来了,关于STM32 的同步传输的双缓冲传输特性,在上层应用中是没有跟其相关的,我们的传输函数只使用了USBD_LL_Transmit()函数,因此就从该函数查起,最后进入了stm32f1xx_ll_usb.c文件中的USB_EPStartXfer()函数,在这个函数中我们把数据写入PMA中,如下:


如果DTOG_TX置位则访问DBUF1,否则访问DBUF0,关于STM32中USB的双缓冲机制大家可以去阅读STM32F103C8T6参考手册的USB章节,里面会有详细讲解,我们知道STM32的USB提供了8个双向端点,而如果一个端点使能了某一方向的双缓冲机制,则TX和RX这两块区域就都由同一方向管理,可以看下分组缓冲区的的示例,如下:


重点可以看下双缓冲模式下IN端点3的缓冲区,此时,RX区域由TX_1接管了,在代码中由用于指定了TX_0和TX_1的地址,并通过PCD_SET_EP_DBUFx_CNT()指定这段缓冲中待发送数据的长度,而追溯PCD_SET_EP_DBUFx_CNT()的定义,就发现了问题,如下:

#define PCD_SET_EP_DBUF0_CNT(USBx, bEpNum, bDir, wCount)  { \
    if((bDir) == PCD_EP_DBUF_OUT)\
      /* OUT endpoint */ \
    {PCD_SET_EP_RX_DBUF0_CNT((USBx), (bEpNum),(wCount));} \
    else if((bDir) == PCD_EP_DBUF_IN)\
      /* IN endpoint */ \
      *PCD_EP_TX_CNT((USBx), (bEpNum)) = (uint32_t)(wCount);  \
  } /* SetEPDblBuf0Count*/
 
#define PCD_SET_EP_DBUF1_CNT(USBx, bEpNum, bDir, wCount)  { \
    if((bDir) == PCD_EP_DBUF_OUT)\
    {/* OUT endpoint */                                       \
      PCD_SET_EP_RX_CNT((USBx), (bEpNum),(wCount));           \
    }                                                         \
    else if((bDir) == PCD_EP_DBUF_IN)\
    {/* IN endpoint */                                        \
      *PCD_EP_TX_CNT((USBx), (bEpNum)) = (uint32_t)(wCount); \
    }                                                         \
  } /* SetEPDblBuf1Count */
可以看到这两个IN端点的缓冲长度设置居然是使用的同一个接口--*PCD_EP_TX_CNT((USBx), (bEpNum)) = (uint32_t)(wCount);所以这就是问题的所在,该接口定义如下:

#define PCD_EP_TX_ADDRESS(USBx, bEpNum) ((uint32_t *)(((USBx)->BTABLE+(bEpNum)*8)*2+     ((uint32_t)(USBx) + 0x400)))
#define PCD_EP_TX_CNT(USBx, bEpNum) ((uint32_t *)(((USBx)->BTABLE+(bEpNum)*8+2)*2+  ((uint32_t)(USBx) + 0x400)))
#define PCD_EP_RX_ADDRESS(USBx, bEpNum) ((uint32_t *)(((USBx)->BTABLE+(bEpNum)*8+4)*2+  ((uint32_t)(USBx) + 0x400)))
#define PCD_EP_RX_CNT(USBx, bEpNum) ((uint32_t *)(((USBx)->BTABLE+(bEpNum)*8+6)*2+  ((uint32_t)(USBx) + 0x400)))
在前面那个分组缓冲的示例中我们就知道了,TX_1是接管的RX区域,因此,DBUF1_CNT应该是使用的PCD_EP_RX_CNT()接口而不是PCD_EP_TX_CNT()接口,因此ST的库代码也不一定是完好的,至少这个问题点还没有修复,修改库代码,如下:

#define PCD_SET_EP_DBUF0_CNT(USBx, bEpNum, bDir, wCount)  { \
    if((bDir) == PCD_EP_DBUF_OUT)\
      /* OUT endpoint */ \
    {PCD_SET_EP_RX_DBUF0_CNT((USBx), (bEpNum),(wCount));} \
    else if((bDir) == PCD_EP_DBUF_IN)\
      /* IN endpoint */ \
      *PCD_EP_TX_CNT((USBx), (bEpNum)) = (uint32_t)(wCount);  \
  } /* SetEPDblBuf0Count*/
 
#define PCD_SET_EP_DBUF1_CNT(USBx, bEpNum, bDir, wCount)  { \
    if((bDir) == PCD_EP_DBUF_OUT)\
    {/* OUT endpoint */                                       \
      PCD_SET_EP_RX_CNT((USBx), (bEpNum),(wCount));           \
    }                                                         \
    else if((bDir) == PCD_EP_DBUF_IN)\
    {/* IN endpoint */                                        \
      *PCD_EP_RX_CNT((USBx), (bEpNum)) = (uint32_t)(wCount); \
    }                                                         \
  } /* SetEPDblBuf1Count */
然后重新编译代码烧录进单板中,运行后就终于得到我们想要的图像了,结果如下:

然后重新编译代码烧录进单板中,运行后就终于得到我们想要的图像了,结果如下:



就是图像小了一些,大家可以自行换个大一些的图像,至此,使用STM32 的USB进行MJPEG的UVC简单传输到此就结束了。万里长征的第一步已经完成,下面就可以着手进行下一步了研究MJPEG编码或研究其他负载格式的传输,毕竟我们传输单张图片太静态了,如果研究了编码图像就可以动起来了也更直观,MJPEG是基于帧格式的传输,这个学习起来容易一些,还有一些基于流的格式,大家有时间可以研究一下,UVC文档中提到了8种负载格式,有兴趣的可以挨个试试。同时UVC协议中有一些其他的特性这里都没有用到,诸如:图像捕获、以及一些控制请求,文档中也提到不仅可以使用同步传输来传输视频还可以使用批量传输来传输视频,UVC的很多特性有待大家去挖掘。最后,我们的UVC库还有待完善,可以改善成跟AUDIO、CDC、HID、MSC库相等的接口以便于使用。

下面是工程代码下载地址:http://download.csdn.net/detail/key123zhangxing/9551843
PS:昨天上传的代码没有清理干净,编译的话会出错,需要把main.c中去掉uart_init()函数调用,以及去掉main.h文件中的包含的uart.h头文件。


推荐阅读

史海拾趣

艾华集团(AISHI)公司的发展小趣事

2020年,受全球疫情影响,许多中小电容器厂家面临供应链中断、生产受阻等困境。然而,艾华集团凭借其在行业内的深厚积累和强大的研发实力,迅速调整生产策略,优化供应链管理,成功应对了疫情带来的挑战。同时,公司还加大了对新兴市场的开拓力度,进一步巩固了在全球市场的地位。

德力西(DELIXI)公司的发展小趣事

1984年,胡成中偕其弟胡成国等人在浙江省乐清市创立了“乐清县求精开关厂”,这便是德力西的前身。当时,企业仅有3位股东,5万元的资本,8名员工,以及单一的热继电器产品。凭借“以质取胜”的经营理念和灵活的机制,德力西在温州市电器行业中逐渐崭露头角。

DUBILIER公司的发展小趣事

DUBILIER公司非常重视人才的培养和发展。公司建立了完善的人才培训体系,为员工提供各种培训和发展机会。通过内部培训和外部引进相结合的方式,DUBILIER公司培养了一支高素质、专业化的技术和管理团队。这些人才不仅为公司的发展提供了强大的支持,还为公司赢得了更多的商业机会和合作伙伴。

Gore公司的发展小趣事
由于电压应力降低,开关器件的开关损耗也相应减少,系统的发热量也较少。
BAND-IT公司的发展小趣事

在电子行业的推动下,大型基础设施的建设也迎来了快速发展。韦拉札诺海峡大桥作为连接斯塔顿岛和布鲁克林的世界上最长的吊桥,其建设过程对紧固件的需求量大且要求严格。BAND-IT公司凭借其大型不锈钢卡箍产品,成功参与了这一重大工程的建设。这些卡箍不仅具有强大的承重能力,而且安装简便、安全可靠,为大桥的稳定性和安全性提供了有力保障。

Excel-Display Corporation公司的发展小趣事

EDC深知人才是企业发展的核心动力。因此,公司一直致力于人才培养和团队建设。

公司建立了完善的人才培养机制,为员工提供各种培训和学习机会,帮助他们不断提升自己的专业能力和综合素质。同时,EDC还注重员工的福利待遇和职业发展,为员工创造了一个良好的工作环境和发展空间。

在团队建设方面,EDC注重营造积极向上的企业文化和团队合作精神。公司定期组织各种团队活动和文化交流活动,增强员工的凝聚力和归属感。这些举措不仅提高了员工的工作积极性和效率,也为公司的长远发展提供了有力保障。

问答坊 | AI 解惑

電子元器件的識別及測試--入门提升篇

電子元器件的識別及測試--入门提升篇 不同的電子原器件有不同的性能及參數要求 對於一個電子零件掌握它的識別和測試 判別其好壞、了解其性能和參數 不但是對電子技術工程人員的一項基本要求 并且作為一名電子部品的檢查員 對於這方面的基礎知 ...…

查看全部问答>

最新硬件测试技术

对硬件设计人员和测试人员提高设计测试水平有益。59页的内容包括: 硬件测试概述 硬件测试前准备 硬件测试的种类与操作 硬件测试的级别 可靠性测试 测试问题解决 测试效果评估 硬件测试参考的通信技术标准 测试规范制定 测试人员的培养…

查看全部问答>

CE控制面板中大部分图标都不见了?

重新编译了下NK,没有添加或者删除组件。下载到开发板后运行,却发现在“控制面板”中,原来的“校准”等图标都没有 了,请问哪位知道什么原因?是不是误删了什么文件?…

查看全部问答>

请教一下语音采集芯片aic23的问题

aic23输出结果的是声音波形的采样值,还是经过编码或压缩后的数据? 把数据拿出来 绘制成波形,怎么看都不像声音信号,当然也不能播放出声音。 …

查看全部问答>

NK.lib的问题

各位前辈好!我最近在编译WINCE5.0的OAL时遇到不能连接NK.lib的问题,我在PB5.0的帮助文件中知道了NK.lib是由 Cefnk.lib,Hal.lib,Nkcompr.lib,Nkmapfile.lib,Nknocomp.lib,Nknofnk.lib,Nknomapfile.lib组成,以上 几个lib都能在PUBLIC下的OAK的lib文 ...…

查看全部问答>

请问,cc2430串口不能中断接收的问题

cc2430给的样例程序中的串口接收不是中断方式的。我写了一个串口中断方式接收的程序,发现明明收到东西了,可它怎么也不进中断。下面是我的程序,波特率。 void URX0Init(void) {   U0CSR |= UART_ENABLE_RECEIVE;   URX0I ...…

查看全部问答>

转让2个华为GPRS模块 GTM900C

去年买的。 画了板子在STM32上玩了下,一个玩过,一个全新的。 150元两个。 附加全程指导,直到会为止。哈哈。 51 stm32 2440 6410木有问题。 要的发邮件 clever0725@gmail.com…

查看全部问答>

ise 仿真结果均为高阻态

在用fpga产生正弦波,调用ISE 的ROM 内核,但是在仿真时,结果输出均为高阻态。ROM的数据由MATLAB产生,请问是为什么?? module sincose(data,we,clk,ce,reset,sine     );          input we;//enabl ...…

查看全部问答>

【求助】共享库查找路径被修改导致现在终端命令不可用,如何恢复共享库路径?

昨天为了安装qt的编译环境,对环境变量进行了设置,其中包括共享库的查找路径,本来是应该进行一个临时设置的,但是我当时为了省时间,就在/etc/bash.bashrc里修改了“LD_LIBRARY_PATH”,结果昨晚关机前忘了把这个路径改回来了,导致今天登陆ubunt ...…

查看全部问答>