话说使用STM32 CUBEMX这种初始化代码神器,估计大多数人都会了,但是生成的代码出了问题,去追踪分析问题并且解决的朋友可能就不会了。
在这里,笔者分享一下自己使用cubeMX生成虚拟串口,然后出错不能用并解决的方法。
如何生成代码的过程就不介绍了,直接进入主题。
出错现象:编译成功,下载成功,但是电脑提示设备无法启动,如下图所示。
思考1:跟大多数网友一样,第一反映肯定想到:驱动不对,重新安装一下就好了。
验证:作者在L432KC是使用过虚拟串口的,是可以用的,电脑上的驱动是没问题的,推翻思考1。
思考2:cubeMX生成的代码有问题。
验证:目前只有两种可能了,那就追踪一下代码,看看是哪里出错了。
打开代码分析一下,main函数没什么特别,调用一些HAL和时钟的和USB的初始化。
- int main(void)
- {
- /* USER CODE BEGIN 1 */
- /* USER CODE END 1 */
- /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
- HAL_Init();
- /* Configure the system clock */
- SystemClock_Config();
- /* Initialize all configured peripherals */
- MX_GPIO_Init();
- MX_USB_DEVICE_Init();
- /* USER CODE BEGIN 2 */
- /* USER CODE END 2 */
- /* Infinite loop */
- /* USER CODE BEGIN WHILE */
- while (1)
- {
- /* USER CODE END WHILE */
- /* USER CODE BEGIN 3 */
- }
- /* USER CODE END 3 */
- }
使用调试仿真一下,运气很好,一下子就发现异常了,如下图所示。
这里给 pdev->pClassData 自动分配内存,分配失败,所以返回NULL了。
- pdev->pClassData = USBD_malloc(sizeof (USBD_CDC_HandleTypeDef));
-
- if(pdev->pClassData == NULL)
- {
- ret = 1;
- }
很好,找到问题点,那就好解决了。
计算一下USBD_CDC_HandleTypeDef这个结构体的size。
- #define <font color="#ff0000">CDC_DATA_HS_MAX_PACKET_SIZE </font> 512 /* Endpoint IN & OUT Packet size */
- #define CDC_DATA_FS_MAX_PACKET_SIZE 64 /* Endpoint IN & OUT Packet size */
- #define CDC_CMD_PACKET_SIZE 8 /* Control Endpoint Packet size */
- typedef struct
- {
- uint32_t data[<font color="#ff0000">CDC_DATA_HS_MAX_PACKET_SIZE</font>/4]; /* Force 32bits alignment */
- uint8_t CmdOpCode;
- uint8_t CmdLength;
- uint8_t *RxBuffer;
- uint8_t *TxBuffer;
- uint32_t RxLength;
- uint32_t TxLength;
- __IO uint32_t TxState;
- __IO uint32_t RxState;
- }
- USBD_CDC_HandleTypeDef;
512+1+1+4+4+4+4+4+4=538
是这样算的么,其实不对的,这里要考虑的内存字节对齐,uint8_t CmdOpCode;uint8_t CmdLength;只占了2字节,但是需要4字节对齐,所以编译器会自动在后面补2字节
所以是:512+4+4+4+4+4+4+4=540
下面说说stack和heap的区别,以下内容摘自:http://blog.csdn.net/slj_win/article/details/16906141
(1)栈区(stack):由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似 于数据结构中的栈。 (2)堆区(heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配 方式类似于数据结构中的链表。
使用malloc分配的内存是在heap上的,可以判断,初始化的时候,分配的heap太小了,导致上面的内存分配失败。
查看一下startup_stm32f767xx.s文件,可以看到分配给heap的大小只有0x200字节,也就是512字节,那明显是不够的,上面的结构体就占了540字节了。
解决方法:在startup_stm32f767xx.s加大分配给heap的字节大小。Heap_Size 加大为 0x400
重新编译下载,OK,成功。
|