历史上的今天
今天是: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头文件。
史海拾趣
|
電子元器件的識別及測試--入门提升篇 不同的電子原器件有不同的性能及參數要求 對於一個電子零件掌握它的識別和測試 判別其好壞、了解其性能和參數 不但是對電子技術工程人員的一項基本要求 并且作為一名電子部品的檢查員 對於這方面的基礎知 ...… 查看全部问答> |
|
重新编译了下NK,没有添加或者删除组件。下载到开发板后运行,却发现在“控制面板”中,原来的“校准”等图标都没有 了,请问哪位知道什么原因?是不是误删了什么文件?… 查看全部问答> |
|
cc2430给的样例程序中的串口接收不是中断方式的。我写了一个串口中断方式接收的程序,发现明明收到东西了,可它怎么也不进中断。下面是我的程序,波特率。 void URX0Init(void) { U0CSR |= UART_ENABLE_RECEIVE; URX0I ...… 查看全部问答> |
|
去年买的。 画了板子在STM32上玩了下,一个玩过,一个全新的。 150元两个。 附加全程指导,直到会为止。哈哈。 51 stm32 2440 6410木有问题。 要的发邮件 clever0725@gmail.com… 查看全部问答> |
|
在用fpga产生正弦波,调用ISE 的ROM 内核,但是在仿真时,结果输出均为高阻态。ROM的数据由MATLAB产生,请问是为什么?? module sincose(data,we,clk,ce,reset,sine ); input we;//enabl ...… 查看全部问答> |
|
【求助】共享库查找路径被修改导致现在终端命令不可用,如何恢复共享库路径? 昨天为了安装qt的编译环境,对环境变量进行了设置,其中包括共享库的查找路径,本来是应该进行一个临时设置的,但是我当时为了省时间,就在/etc/bash.bashrc里修改了“LD_LIBRARY_PATH”,结果昨晚关机前忘了把这个路径改回来了,导致今天登陆ubunt ...… 查看全部问答> |




