STM32 USB虚拟串口问题汇总

发布者:MysticMoon最新更新时间:2016-12-20 来源: eefocus关键字:STM32  USB  虚拟串口 手机看文章 扫描二维码
随时随地手机看文章

汇总1:STM32的USB例程修改步骤,来自http://blog.csdn.net/cy757/archive/2010/01/01/5117610.aspx 以下是笔者将ST的Custom_HID例程修改为“自定义USB设备”例程时总结出来的,因为笔者也是刚刚学USB开发不久,某些方面理解错误在所难免,请各位大虾指正。

 

一、usb_desc.c文件 根据你程序使用的通信方式修改。usb_desc.h文件中定义要根据usb_desc.c文件中的数组的大小;ConfigDescriptor[SIZ_CONFIG_DESC]下添加需要处理的端点;根据需要添加或删除报告描述符(主要用于HID)和CDC接口描述符(主要用于实现USB转串口)等。具体方法可以下载个“电脑圈圈”使用D12编写的例子。

 

二、Usb_conf.h文件: 1、修改需要处理那些中断 CNTR_CTRM 处理数据正确传输后控制,比如说响应主机 CNTR_DOVRM /* DMA OVeR/underrun Mask */ CNTR_ERRM /* ERRor Mask */ CNTR_WKUPM 0 /* WaKe UP Mask */ CNTR_SUSPM /* SUSPend Mask */ CNTR_RESETM 主要处理USB复位后进行一些初始化任务 CNTR_SOFM /* Start Of Frame Mask */ CNTR_ESOFM /* Expected Start Of Frame Mask */ 如: usb_conf.h中的#define IMR_MSK (CNTR_CTRM | CNTR_SOFM | CNTR_RESETM )是决定USB_CNTR寄存器中的那个USB相关中断启动还是屏蔽。

 

2、根据需要增加端点缓存地址,要根据缓存区的地址修改,防止数据重叠 如下为根据每个缓冲区的大小为64字节修改: #define ENDP1_TXADDR (0xC0) #define ENDP1_RXADDR (0xD0) #define ENDP2_TXADDR (0x100) #define ENDP2_RXADDR (0x140) #define ENDP3_TXADDR (0x180) #define ENDP3_RXADDR (0x1C0) 3、修改/* CTR service routines */下的EPX_IN_Callback和EPX_OUT_Callback。注释掉需要处理的函数。NOP_Process表示不处理。

 

三usb_prop.c文件 1、修改void XX_Reset(void)(如:void Joystick_Reset(void)) 一般/* Initialize Endpoint 0 */的不用修改,如下为举例说明端点1的初始化,其他端口原理一样。 SetEPType(ENDP1, EP_INTERRUPT);//设置端点1类型 /*EP_BULK 批量端点 EP_CONTROL 控制端点 EP_ISOCHRNOUS 同步端点 EP_INTERRUPT 中断端点*/ SetEPTxAddr(ENDP1, ENDP1_TXADDR); //设置端点1缓冲区基地址 SetEPTxCount(ENDP1, 64);// 配置Tx 缓冲计数器 SetEPRxStatus(ENDP1, EP_RX_DIS);// //设置端点接收关闭 SetEPTxStatus(ENDP1, EP_TX_NAK);// //设置端点1发送不应答 /* #define EP_RX_DIS (0x0000) // EndPoint RX DISabled 端点接收关闭 #define EP_RX_STALL (0x1000) // EndPoint RX STALLed 端点接收延迟 #define EP_RX_NAK (0x2000) // EndPoint RX NAKed 端点接收不应答 #define EP_RX_VALID (0x3000) // EndPoint RX VALID端点接收有效 #define EP_TX_DIS (0x0000) //EndPoint TX DISabled #define EP_TX_STALL (0x0010) // EndPoint TX STALLed #define EP_TX_NAK (0x0020) // EndPoint TX NAKed #define EP_TX_VALID (0x0030) // EndPoint TX VALID */ 2、删除不相干的描述符等。 如自定义的USB设备就不需要以下结构体初始化: ONE_DESCRIPTOR Joystick_Report_Descriptor ONE_DESCRIPTOR Mouse_Hid_Descriptor 3、修改RESULT XX_Data_Setup(u8 RequestNo)的数据类请求处理。 如Custom_HID例程修改为“自定义USB设备”例程时可以将以下代码删除 if ((RequestNo == GET_DESCRIPTOR) && (Type_Recipient == (STANDARD_REQUEST | INTERFACE_RECIPIENT)) && (pInformation->USBwIndex0 == 0)) { if (pInformation->USBwValue1 == REPORT_DESCRIPTOR) { CopyRoutine = Joystick_GetReportDescriptor; } else if (pInformation->USBwValue1 == HID_DESCRIPTOR_TYPE) { CopyRoutine = Joystick_GetHIDDescriptor; } }

 

4、删除不相干的获得描述符返回函数 如自定义的USB设备就不需要以下函数: Joystick_GetReportDescriptor Joystick_GetHIDDescriptor 四、usb_endp.c文件 1、增加之前定义的中断数据处理函数 如: void EP1_OUT_Callback(void) { 这些写接收代码 } 五、数据发送和接收,举例说明 1、数据接收 u8 DataLen; DataLen = GetEPRxCount(ENDP1); PMAToUserBufferCopy(TX1_buffer, ENDP1_RXADDR, DataLen); SetEPRxValid(ENDP1); USART1_Send(DataLen); count_out = 1; 2、数据发送 UserToPMABufferCopy(InBuffer, GetEPTxAddr(ENDP1), 64); SetEPTxCount(ENDP1, 64); SetEPTxValid(ENDP1);

 

=========================================================================== 汇总2:STM32 USB 程序将BULK EP改成双缓冲机制后,一直狂飚到了1MB/S!来自:http://www.powermcu.com/bbs/viewthread.php?tid=693 前天测试自己编写的USB驱动程序时候发现从主机到STM32的OUT传输(主机到设备)速率竟然只有最高33KB/S,实在是晕死了。经过研究后发现是驱动程序中设置的PIPE MaxTransferSize参数的关系,原先设置64只能33KB/S,后参考其他USB设备驱动程序的值,设置成了65535,再测试USB OUT的速度,达到了500KB/S,终于解决了驱动程序的瓶颈。不过算下USB 2.0全速的通讯速率是12Mb/S,排除掉CRC、令牌、SOF等等开销怎么也应该不止最大500KB/S啊。到网上看了看,基本上应该能达到600KB/S~700KB/S以上,我现在的速度应该还有很大的提升才是。 看看程序,发现 void EP3_OUT_Callback(void)//EP3 OUT的回调函数,当EP3接收到数据时候中断调用该函数 { count_out = GetEPRxCount(ENDP3);//获得接收到的数据长度 PMAToUserBufferCopy(buffer_out, ENDP3_RXADDR, count_out);//将数据从USB EP3 RX的缓冲区拷贝到用户指定的数组中 SetEPRxValid(ENDP3); //完成拷贝后置有效状态,从而EP3发送ACK主机可以进行下一个数据包的发送 } 试着将PMAToUserBufferCopy这句注释掉(这样STM32就不处理接收到的数据了)后再测试速度,惊奇地发现速度竟然达到了997KB/S!晚上仔细想了想,数据肯定是要使用的,这个数据拷贝的过程的时间消费总是少不了的;由于通常情况下USB设备BULK数据接收的步骤就是:接收到数据,置NAK->将缓冲区数据拷贝到用户区(用户处理过程)->发ACK通知主机完成了完整的接收可以发送下一个->主机发送下一个,按照以上的步骤USB接收一步步的进行,只要STM32不完成数据处理,状态就一直是NAK,主机就会不停地发送该数据包,浪费了带宽,因此就会导致我上面最大速度500KB/S难以再增加的情况!不甘心啊~~

 

昨天晚上又仔细研究了STM32的技术参考手册的USB章节内容,里面提到BULK可以采用双缓冲机制(PING-PONG)进行处理,正好可以解决上面的情况。双缓冲机制的原理就是分配2块接收缓冲,STM32的用户处理和USB接口可以分别交替占用2个缓冲区,当USB端点接收数据写其中一个缓冲区的时候,用户的应用程序可以同时处理另一个缓冲区,这样缓冲区依次交换占有者,只要用户处理程序在USB端点接收的时间片段内完成处理,就能够完全不影响USB的通讯速度! 程序部分修改

 

一、EP3_OUT的设置修改, //ZYP:修改EP3为BULK双缓冲方式------------------------- SetEPType(ENDP3, EP_BULK); SetEPDoubleBuff(ENDP3); SetEPDblBuffAddr(ENDP3, ENDP3_BUF0Addr, ENDP3_BUF1Addr); SetEPDblBuffCount(ENDP3, EP_DBUF_OUT, VIRTUAL_COM_PORT_DATA_SIZE); ClearDTOG_RX(ENDP3); ClearDTOG_TX(ENDP3); ToggleDTOG_TX(ENDP3); SetEPRxStatus(ENDP3, EP_RX_VALID); SetEPTxStatus(ENDP3, EP_TX_DIS); //------------------------------------------------------

 

二、EP3_OUT回调函数的修改 void EP3_OUT_Callback(void) { //ZYP:以下是修改成EP3双缓冲OUT后的处理函数 if (GetENDPOINT(ENDP3) & EP_DTOG_TX)//先判断本次接收到的数据是放在哪块缓冲区的 { FreeUserBuffer(ENDP3, EP_DBUF_OUT); //先释放用户对缓冲区的占有,这样的话USB的下一个接收过程可以立刻进行,同时用户并行进行下面处理 count_out = GetEPDblBuf0Count(ENDP3);//读取接收到的字节数 PMAToUserBufferCopy(buffer_out, ENDP3_BUF0Addr, count_out); } else { FreeUserBuffer(ENDP3, EP_DBUF_OUT); count_out = GetEPDblBuf1Count(ENDP3); PMAToUserBufferCopy(buffer_out, ENDP3_BUF1Addr, count_out); } } 经过上面的修改,终于解决了STM32在处理接收数据时导致主机等待的情况,用BUS HOUND软件测试了下 哈哈,这下终于爽了。 PS:上面的FreeUserBuffer(ENDP3, EP_DBUF_OUT); 这句话的上下位置是关键,如果放到函数的后面,则仍旧会有主机等待STM32处理数据的情况,速度仍然是500KB/S! 把这句话放在拷贝函数的前面的话就真正把双缓冲PING-PONG机制用起来了。大致算了下PMAToUserBufferCopy(buffer_out, ENDP3_BUF1Addr, count_out);这句话当count_out为最大值64的时候STM32执行需要302个周期,72MHZ情况下约4.2微秒执行时间,而USB传输按照12Mb/s的线速度传输64字节的数据至少也得40微秒,因此只要PMAToUserBufferCopy的时间不超过40微秒,就不会导致缓冲区竞争的情况。

 

=============================================================================== 汇总3:STM32的USB中断说明,来自:http://bbs.ednchina.com/BLOG_ARTICLE_238817.HTM STM32的USB模块可以产生三种中断:USB唤醒中断、USB高优先级中断和USB低优先级中断,在STM32的参考手册中没有详细说明这三种中断对应哪些事件,现说明如下: 1)USB唤醒中断:在中断向量表中的位置是42。这个中断在USB设备从暂停模式唤醒时产生,唤醒事件由USB_ISTR寄存器的WKUP位标识。 2)USB高优先级中断:在中断向量表中的位置是19。这个中断仅由USB同步(Isochronous)模式传输或双缓冲块(Bulk)传输模式下的正确传输事件产生,正确传输事件由USB_ISTR寄存器的CTR位标识。 3)USB低优先级中断:在中断向量表中的位置是20。这个中断由所有其它的USB事件产生,例如正确传输(不包括同步模式和双缓冲块模式)、USB复位等,事件标志位在USB_ISTR寄存器中。 在STM32的USB开发包的例子中包含了上述中断的处理,例如在USB扬声器的例子中,CTR_HP函数处理USB高优先级中断;在所有例子中都有USB_Istr()函数处理USB低优先级中断

 

=============================================================================== 汇总4:如何使用STM32的USB库支持控制端点0,来自:http://bbs.ednchina.com/BLOG_ARTICLE_242276.HTM 首先我们先回顾一下控制端点的传输方式: 控制端点的传输有三个阶段,SETUP阶段、数据阶段和状态阶段;数据阶段又分为数据入(DATA IN)和数据出(DATA OUT),控制端点传输可以没有数据阶段;状态阶段有状态入(STATUS IN)和状态出(STATUS OUT)。 总结起来,控制端点有如下三种可能的传输过程(以下括号中的0或1表示DATA0或DATA1传输): 一、 SETUP DATA_IN(0) DATA_IN(1) DATA_IN(0) ...... STATUS_OUT(1) 二、 SETUP DATA_OUT(0) DATA_OUT(1) DATA_OUT(0) ...... STATUS_IN(1) 三、 SETUP STATUS_IN(1) 这里做一个约定,把上述过程一定义为“数据入过程”,过程二定义为“数据出过程”,过程三定义为“无数据过程”。所有的USB控制端点的数据传输都可以而且只用这三种传输过程表示。HID的SET_REPORT是数据出过程,HID的GET_REPORT是数据入过程,USB的GET DEVICE DESCRIPTOR是数据入过程,USB的SET CONFIGURATION是无数据过程,等等。 接下来,我们看看STM32的USB库是如何处理控制端点0的传输。 根据USB协议,每个SETUP包都由8个字节构成,用户程序可以通过结构体Device_Info(类型DEVICE_INFO)访问SETUP包的数据,因为在整个的USB处理中都要用到结构体Device_Info的内容,库中定义了一个全局的指针pInformation指向这个结构体,用户可以通过这个指针访问结构体的内容。 对应SETUP包的8个字节,用户可以用下述方式访问: pInformation->USBbmRequestType (字节类型) pInformation->USBbRequest (字节类型) pInformation->USBwValue (双字节类型) pInformation->USBwIndex (双字节类型) pInformation->USBwLength (双字节类型) 使用pInformation->USBwValue0访问wValue的低字节,pInformation->USBwValue1访问wValue的高字节。 使用pInformation->USBwIndex0访问USBwIndex的低字节,pInformation->USBwIndex1访问USBwIndex的高字节。 使用pInformation->USBwLength0访问USBwLength的低字节,pInformation->USBwLength1访问USBwLength的高字节。 通过分析SETUP包的8个字节,可以判断出一个SETUP的传输过程是属于数据入过程、数据出过程还是无数据过程。STM32的USB库中处理了所有的USB协议文本中定义的标准SETUP命令,对于USB协议文本中未定义的命令,USB库按照数据入过程、数据出过程或无数据过程通过回调函数交给用户程序处理。 全局变量Device_Property(DEVICE_PROP类型)封装了所有的回调函数,DEVICE_PROP定义如下: typedef struct _DEVICE_PROP { void (*Init)(void); // 设备初始化回调函数 void (*Reset)(void); // USB复位回调函数 void (*Process_Status_IN)(void); // STATUS_IN阶段处理回调函数 void (*Process_Status_OUT)(void); // STATUS_OUT阶段处理回调函数 RESULT (*Class_Data_Setup)(u8 RequestNo); // 数据入/出过程处理回调函数 RESULT (*Class_NoData_Setup)(u8 RequestNo); // 无数据过程处理回调函数 RESULT (*Class_Get_Interface_Setting)(u8 Interface, u8 AlternateSetting); // GET_INTERFACE 回调函数 u8* (*GetDeviceDescriptor)(u16 Length); // GET_DEVICE_DESCRIPTION回调函数 u8* (*GetConfigDescriptor)(u16 Length); // GET_CONFIGURATION_DESCRIPTION回调函数 u8* (*GetStringDescriptor)(u16 Length); // GET_STRING_DESCRIPTION回调函数 u8 MaxPacketSize; // 最大包长度 } DEVICE_PROP; 结合SETUP的三种传输过程,用户通过实现不同的回调函数即可完成对各种USB类命令的处理,下面以HID的SET REPORT为例说明。 在介绍具体实现之前,先介绍一下另一个回调函数CopyRoutine的概念,这个函数的原型是: u8 *CopyRoutine(u16 length); // 返回一个缓冲区指针 USB库通过这个函数获得用户的数据缓冲区地址,从而可以在数据出过程中把收到的数据拷贝到用户缓冲区,或在数据入过程中把用户缓冲区的数据拷贝到USB发送缓冲区。每个数据出过程可能有若干次DATA_OUT传输,USB库每完成一次这样的传输都会调用一次回调函数CopyRoutine,参数length是本次传输所收到的数据字节数目,CopyRoutine必须返回一个缓冲区指针,这个缓冲区必须能够容纳length字节的数据,CopyRoutine返回到USB库之后,USB库将把收到的数据拷贝到用户指定的缓冲区。同样每个数据入过程也可能有若干次DATA_IN传输,每次需要向主机传输数据时,USB库都会调用一次回调函数CopyRoutine,参数length是本次传输所要发送的数据字节数目,CopyRoutine必须返回一个缓冲区指针,这个缓冲区中必须包含要求的数据字节,USB库将把用户缓冲区的数据拷贝到USB缓冲区并择机发送出去。 当以length=0调用CopyRoutine时,CopyRoutine需要返回用户缓冲区的长度,因为CopyRoutine的返回类型是一个指针,所以需要通过类型的强制转换返回缓冲区长度。这个功能是为了处理用户缓冲区的长度与主机SETUP数据请求长度不符的情况,而不至于造成用户缓冲区的溢出。 介绍完上述若干概念和回调函数,再看SET_REPORT的实现就很容易了。 SET_REPORT是一个数据出过程,因此需要实现一个Class_Data_Setup回调函数,示例如下: RESULT HID_Data_Setup(u8 RequestNo) { u8 *(*CopyRoutine)(u16 length); CopyRoutine = NULL; if (pInformation->USBbmRequestType == CLASS_REQUEST|INTERFACE_RECIPIENT && RequestNo == SET_REPORT) CopyRoutine = My_Data_Request; if (CopyRoutine == NULL) return USB_UNSUPPORT; pInformation->Ctrl_Info.CopyData = CopyRoutine; pInformation->Ctrl_Info.Usb_wOffset = 0; pInformation->Usb_wLength = (*CopyRoutine)(0); return USB_SUCCESS; } // End of HID_Data_Setup() u8 My_Buffer[10]; u8 *My_Data_Request(u16 length) { if (length == 0) return (u8*)10; // 假定你的REPORT长度和Buffer长度为10 return My_Buffer; } 上面介绍的CopyRoutine用于把多次传输的数据包合并到一个完整的缓冲区中,因此只有到STATUS阶段才能够指导一次SETUP传输是否结束,所以用户程序需要在回调函数Process_Status_IN中处理从SET_REPORT接收到的数据。因为所有的回调函数都是USB中断处理的一部分,所以更好的办法是在Process_Status_IN中设置一个标记,然后在用户主程序中判断这个标记并做处理。 注意,STM32的USB库设计成以回调函数处理用户命令请求,包含类命令请求,是为了能够清晰地区分库程序和用户程序,使这两者不会混在一起,这样的好处是非常明显的,当USB库需要更新升级时,只需替换掉相应的程序模块,而不必修改用户已经完成的程序。 以上的介绍都可以在STM32 USB库的说明手册中找到。 上述示意代码是以My_Buffer长度为10字节为例,而USB库的默认包长度为16字节,因此My_Data_Request并没有多包的处理。 关于多包的缓冲区处理的示意代码可以是这样的: u8 *My_Data_Request(u16 length) { if (length == 0) return (u8*)100; // 假定你的REPORT长度和Buffer长度为100 return &My_Buffer[pInformation->Ctrl_Info.Usb_wOffset]; } 这里有一个库中使用的变量pInformation->Ctrl_Info.Usb_wOffset,这个变量回在传输每个数据包时候由库中的程序按数据包长度增加,如最大包长为16字节时,第一次调用My_Data_Request时Usb_wOffset=0,第二次调用My_Data_Request时Usb_wOffset=16,第三次调用My_Data_Request时Usb_wOffset=32,依此类推。这样就可以使用Usb_wOffset作为My_Buffer的下标从My_Data_Request返回。 对于提问“如何传递length?在上面没有看到这个参数的传递过程”的回答: 参数length是用于检测缓冲区长度是否足够,如果你有足够长的缓冲区,可以不必检测,上述示例中使用了一个固定的缓冲区,所以不必使用参数length检测缓冲区长度。


关键字:STM32  USB  虚拟串口 引用地址:STM32 USB虚拟串口问题汇总

上一篇:《Cortex-M0权威指南》之绪论
下一篇:STM32_USB之完全双缓存(包括发送和接收) -- 更新中断处理

推荐阅读最新更新时间:2024-03-16 15:26

Intel 8系列芯片组未发布便遭遇USB 3.0 bug
Intel 7系列芯片组就开始原生支持USB 3.0,将于年终配合Haswell处理器发布的8系列自然也会继续,但是来自Intel内部的一份文档显示,Intel碰到了一条“虫子”。 Intel在这份文档中警告主板厂商,Haswell处理器、8系列芯片组的系统如果从S3睡眠模式中恢复,那些通过USB 3.0接口连接的设备便会出现问题,之前访问中的程序和/或数据就会失去响应,必须重新开启。 举例来说,如果你使用Adobe Reader打开了USB 3.0 U盘上的一个PDF文档,睡眠再恢复后文档就会显示一片空白,必须重新打开这个文档,甚至是重启Adobe Reader。 不过此bug并不会导致数据丢失等后果,因此Inte
[半导体设计/制造]
Intel 8系列芯片组未发布便遭遇<font color='red'>USB</font> 3.0 bug
STM32】STM32CubeMX教程--功能介绍
功能介绍: 我们首先看下CubeMx的主界面,模块分类大体是这样,我们接下来一一讲解。 已存在工程 Open Existing Projects:打开项目工程 新建工程 ·Start My project from MCU:从MCU开始我的项目 ·Start My project from STBoard:从ST开发板开始我的项目 ·Start My project from Cross Selector:从交叉选择器启动我的项目 软件包管理 ·CHECK FOR UPDATE:检查更新 ·INSTALL/REMOVE:安装/移除
[单片机]
【<font color='red'>STM32</font>】STM32CubeMX教程--功能介绍
STM32 USB 之从0开始移植笔记
-----------------------------------动机----------------------------------- 写在前面的话:最近逛淘宝无意间发现RC522居然只要10元左右就可以包邮买到,真是太便宜了,就忍不住买了个回来玩玩。到货移植到我的板子上OK 后突然发现我的USB口紧张了,一个用来给板子供电一个插jlink 一个插入usb转串口给RC522下命令。就想着将板子供电和RC522传输用一个USB接口来实现。这就是这次折腾USB的来由~-~ ----------------------------------开始折腾USB----------------------------- 首
[单片机]
<font color='red'>STM32</font> <font color='red'>USB</font> 之从0开始移植笔记
STM32F105 USB管脚Vbus的处理
对于STM32F105/107来说,为了监测USB的连接问题,程序默认是通过Vbus管脚进行检查的。但是Vbus管脚和UART1的TXD复用,导致我们在使用UART1发送数据时候,USB重启的问题。为了解决这个问题,本人查了大量的资料和咨询了不太靠谱的STM32技术支持,一直没有得到解决的方法。 在STM32F105数据手册上是这样说的 如果另一个共享的外设要使用OTG_FS_VBUS引脚(PA9)或把它作为通用I/O口,必须激活PHY的断电模式(清除OTG_FS_GCCFG寄存器的位16)。 这个位在程序中的定义如下: gccfg.d32 = 0; gccfg.b.vbussensingB = 1; gc
[单片机]
STM32到CONST的全局变量
程序如下: const int globalConstDat = 12; int globalDat = 11; int main(void) { int localDat = 6; const int localConstDat = 7; USART_Configuration(); //ptint to PC from USART1 printf( &globalConstDat = 0x%p, &globalDat = 0x%prnrn , &globalConstDat, &globalDat); printf( &localDat = 0x%p, &localConstDat = 0x%prn , &localDat
[单片机]
整理STM32GPIO输出速率问题
GPIO 引脚输出速度有:GPIO_Speed_2MHz (10MHz, 50MHz) 官方一点的解释: GPIO口的驱动电路响应速度,不是输出信号的速度。输出信号的速度与程序有关,通过选择速度来选择不同的驱动电路,降低功耗控制噪声。 又称输出驱动电路的响应速度:(芯片内部在I/O口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路,通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。) 可理解为: 输出驱动电路的带宽:即一个驱动电路可以不失真地通过信号的最大频率。 (如果一个信号的频率超过了驱动电路的响应速度,就有可能信号失真。失真因素?) 如果信号频
[单片机]
STM32在keil下使用jlink时产生错误的解决方法
当STM32在keil下使用jlink时产生错误得时候该怎么办? 最近一段时间一直在学习STM32和ucos的移植,使用的开发环境是keil u4版本。仿真器是80元买的jlink。 在学习了STM32固件库和ucos内核与移植相关的程序之后,写了一个流水灯程序,准备下载到板子上看看情况。哪知程序还没有下进去,在debug时,keil的错误提示到:Error: Flash download failed- Cortex-M3 感觉这么错误很普遍,也是初学者常常遇到的错误,下面我就将这个错误产生的原因和解决方法赘述一下: 错误产生的原因和分析,解决。 首先,我们看到提示信息是有关flash的,那么我们来查看一下STM3
[单片机]
<font color='red'>STM32</font>在keil下使用jlink时产生错误的解决方法
基于STM32调用固件库实现点灯
相信学过单片机的同学,对于调库这个操作都不陌生,大多数人都是从调别人的库阶段过来的。 今天看到一个评论说,如果只会调库,到了公司后会发现自己啥都不是。其实这话说的一点也不假,如果只会调库的话,你的单片机水平还停留在C语言阶段,并不能称为真正的单片机开发。 但我们要有这么一个概念:调库是自己编写的开始,如果上来就给你讲寄存器这些,我相信很多初学者都接收不了、理解不了这写寄存器到底在干啥。可是,如果从调别人库开始学习单片机,我们就会对单片机有个初始概念,对于后面的学习非常有帮助。 所以,今天我们就来看一下如何从调库工程师成为真正的开发工程师。 1. 什么是调库? 如果你通过机构的培训视频,比如野火的STM32单片机开
[单片机]
基于<font color='red'>STM32</font>调用固件库实现点灯
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved