嵌入式pc(嵌入式电脑)

在国内,嵌入式编程的朋友很少是计算机专业认真毕业的,都是自动控制和电子相关专业毕业的。这些童鞋有丰富的实践经验,但缺乏理论知识;计算机专业毕业的童鞋,很大一部分

在国内,嵌入式编程的朋友很少是计算机专业认真毕业的,都是自动控制和电子相关专业毕业的。这些童鞋有丰富的实践经验,但缺乏理论知识;计算机专业毕业的童鞋,很大一部分是用于更高层次的应用,比如网络游戏,网页,这些都是独立于操作系统的。我不想从事嵌入式行业,毕竟这条路不好走。他们有很强的理论知识,但缺乏电路等相关知识。嵌入式系统的一些具体知识很难学。

从PC机编程看嵌入式问题是第一步;学会使用嵌入式编程思想,这是第二步;第三步,将PC的思想和嵌入式系统的思想结合起来,应用到实际项目中。很多朋友从PC编程转到了嵌入式编程。在国内,嵌入式编程的朋友很少是计算机专业认真毕业的,都是自动控制和电子相关专业毕业的。这些童鞋有丰富的实践经验,但缺乏理论知识;计算机专业毕业的童鞋,很大一部分是用于更高层次的应用,比如网络游戏,网页,这些都是独立于操作系统的。我不想从事嵌入式行业,毕竟这条路不好走。他们有很强的理论知识,但缺乏电路等相关知识。嵌入式系统的一些具体知识很难学。虽然我没有做过行业研究,但是从我看到的和招聘的情况来看,从事嵌入式行业的工程师要么缺乏理论知识,要么缺乏实践经验。很少有人两者都有。原因是中国大学教育的问题。这里不讨论这个问题,避免口水战。我想从我的实践中列举几个例子。引起了人们在做嵌入式项目时对一些问题的关注。第一个问题:我同事开发了一个uC/OS-II下的串口驱动,但是测试中无论是驱动还是接口都没有发现问题。应用程序中开发了通信程序,串口驱动提供了查询驱动缓冲区字符的函数:GetRxBuffCharNum()。较高级别需要接受一定数量的字符,然后才能解析包。一个同事写的代码,用伪代码表示如下:

这段代码判断当前缓冲区中有超过30个字符,并读取缓冲区中的所有字符,直到读取成功。逻辑清晰,思路清晰。但是这个代码不能正常工作。如果是在PC上,肯定没有问题,工作不正常。但是在嵌入式系统中真的不知道。同事情绪低落,不知道为什么。来找我解决问题。我看到代码就问他,GetRxBuffCharNum()是怎么实现的?打开一看:

显然,在循环中,interruput_disable()和interrupt_enable()之间有一个全局临界区,保证了gRxBufCharNum的完整性。但是在外层的do {} while()循环中,CPU频繁的关闭和打开,所以这个时间很短。实际上,CPU可能无法正常响应UART的中断。当然这跟uart的波特率,硬件缓冲区的大小,CPU的速度有关系。我们用的波特率很高,3Mbps左右。Uart起始信号和停止信号占用一位。一个字节需要10个周期。3Mbps的波特率传输一个字节大约需要3.3us。3.3 US US可以执行多少条CPU指令?100MHz ARM可以执行150条左右的指令。结果,关闭中断需要多长时间?一般ARM关闭中断需要4条以上指令,开启中断需要4条以上指令。事实上,代码中有20多条指令用于接收uart中断。所以这种方式可能会出现通信数据丢失的Bug,反映到系统层面就是通信不稳定。修改这段代码其实很简单。最简单的方法是从顶层开始修改。即:

这样CPU就有时间执行中断的代码,避免了频繁关闭中断导致的中断代码执行不及时和信息丢失。在嵌入式系统中,大多数RTOS应用程序都没有串口驱动程序。自己设计代码的时候,没有充分考虑代码和内核的结合。导致代码中深层次的问题。RTOS因其对事件的快速反应而被称为RTOS;事件的快速响应取决于CPU对中断的响应速度。在Linux系统中,驱动程序与内核高度集成,一起在内核状态下运行。RTOS不能复制linux的结构,但可以借鉴。从上面的例子可以看出,嵌入式需要开发人员清楚地了解代码的各个方面。第二个例子:同时驱动一个14094的串并芯片。串行信号是用IO模拟的,因为没有专用的硬件。同事写了一个驱动,调试了3、4天,还是有问题。我实在看不下去了,就去看看。对照组的平行信号有时正常,有时异常。我看了一下代码,大概是:

在每个高电平,8位数据从位0至位7顺序发送。应该是正常的。我看不出有什么问题。我仔细想了想,然后看了14094的数据表,我明白了。原来14094要求时钟的高电平要持续10 ns,低电平也要持续10 ns。这段代码只做高电平延时,不做低电平延时。如果中断在低电平之间工作,那么这段代码是正常的。但是,如果CPU不中断低级别的执行,就不能正常工作。所以有好有坏。修改也相对简单:

这是完全正常的。但这仍然是一个不能很好移植的代码,因为一旦编译器优化,这两个延迟循环就可能丢失。丢失,无法保证高电平和低电平对10ns的要求,无法正常工作。因此,真正的可移植代码应该使这个循环成为纳秒DelayNs(10);和Linux一样,你上电的时候,先测一下nop指令执行需要多长时间,10ns执行了多少nop指令。只需执行某些nop指令。使用编译器来防止优化的编译指令或特殊关键字来防止延迟循环被编译器优化。就像在海湾合作委员会

从这个例子可以明显看出,写一段好的代码需要大量的知识支持。你说什么?嵌入式系统往往得不到操作系统的支持或支持,但由于种种限制,操作系统提供的功能少得可怜。所以很多代码不能像PC编程那样野空运行。今天我们来谈谈内存分配的问题,内存碎片。可能大家都很熟悉。但是在嵌入式系统中,最怕的就是内存碎片,这也是系统稳定性的头号杀手。我曾经做过一个项目。系统中有很多malloc和free,大小不一,从60多字节到64KB不等。使用RTOS作为支撑。当时我有两个选择,一个是使用malloc和free的C系统库,一个是使用操作系统提供的固定内存分配。我们的系统设计要求能稳定运行3个月以上。其实连续操作6天左右就下去了。各种问题都被怀疑过,最后还是决定在内存分配上。事实上,在长时间分配大量内存后,系统的内存变得分散,无法连续。虽然有大空房间,但是无法分配连续的空房间。有大型空应用的时候,只能是宕机。为了让系统达到最初的设计要求,我们在PC上模拟了整个硬件,在PC上运行了嵌入式代码,重载了malloc和free,做了一个复杂的统计程序。系统的统计记忆行为。运行几天后,提取数据并进行分析。虽然应用内存花了五块钱八个门,但是还是有一些规矩的。我们把100字节以下的归为一类,512B的归为一类,1KB的归为一类,2KB的归为一类,64KB以下的归为一类。统计每个品类的数量,在原有基础上增加30%的保证金。做一个固定的内存应用,大大延长了系统稳定持续运行的时间。这样嵌入式系统不怕方法原始,就怕性能达不到要求。内存溢出问题,内存溢出问题嵌入式系统比PC系统更可怕!往往会在不被察觉的情况下溢出。很难想到,尤其是初学C/C++的人,对指针不熟悉,不会检查。因为PC系统有MMU,当内存严重越界时,有MMU保护,不会造成严重的灾难后果。而嵌入式系统往往没有MMU,差别很大,系统代码被破坏后依然可以运行。只有上帝和CPU知道什么在运行。让我们来看看这段代码:

这段代码是代码的字符串副本,PC这样写,基本够用了。但是嵌入式系统需要注意的一点是,src实际上是以& # 39;[11]'结束了。否则,这将是一个悲剧。什么时候才能结束,呵呵,只有天知道了。如果这段代码侥幸运行,估计程序就不能正常运行了。因为dest指向的内存区域几乎被破坏。为了兼容标准C/C++库,实在没有什么好办法,所以这个问题只能留给程序员自己去查了。一样,

复制同样的内存问题,当心N传一个负值进去。这是复制的字节数,负值被强制输入为正值。它变成一个大正数,导致dest之后的所有内存都被销毁...嵌入式系统中的内存指针必须经过严格检查才能使用,内存的大小也必须经过严格调试。否则,悲剧难以避免。例如函数指针,尽管在嵌入式系统中赋值为NULL,0。如果是ARM,连异常都没有,直接复位,因为调用这个函数指针甚至让代码从0开始运行。0是ARM上电后运行的第一个代码的位置。尤其是在ARM7上。这种悲剧比PC上的悲剧要难过得多,MMU必须给出一个指令未定义的错误。吸引程序员的注意力。在嵌入式系统中,这都是留给程序员去发现的。内存溢出随时都会发生。你给整个前后台系统(或者操作系统)分配多大的堆?堆栈有多大?正常情况下系统的调用深度(最大)是多少,占用多少栈?光看程序的正确功能是不够的,还要统计这些参数。否则只要一个地方有溢出。这对系统是致命的。嵌入式系统需要长时间连续工作,对其稳定性和可靠性要求很高。仔细研究这些系统需要一些时间。

嵌入式系统的调试往往比较复杂,可用的手段没有PC编程那么多,开发成本也比PC系统高很多。嵌入式系统的主要调试方法有以JTAG为代表的单步跟踪法和printf箝位法。

这两种调试方法都不能解决嵌入式系统中的问题。Jtag要求调试器有一个调试设备(可能很贵)并连接到目标系统。使用GDB客户端等软件登录调试设备,跟踪运行程序。讲真,这种方法是嵌入式系统的终极调试方法,也是比较好的调试方法。但是,仍然存在一些不足。当断点过多时,就超出了硬件的限制,一些低档CPU不支持更多的断点,所以JTAG需要使用软件模拟或者软件陷阱(软中断或者异常)来实现断点。机理比较复杂,简单来说,1。长期无法调试,不稳定;2.可能影响程序运行时间的行为,程序的运行时间受时序的影响。JTAG系统接入后,硬件实现的断点不会影响系统的运行速度,但软件实现的断点必须牺牲一些性能。可靠性也会受到损害。当断点太多,系统进入临界区时,断点可能不起作用。因为全局临界区的嵌入式实现经常需要关闭中断,所以有些CPU没有未屏蔽的中断。当断点数量超过一定数量时,使用软件断点,当工作中断时需要使用软件断点...JTAG不是很有帮助,特别是对于调试定时问题和高速通信代码。通信过程往往很快,通信包一个接一个,才能完成一个完整的动作。如果是高速通信,断点无法让程序完成工作。所以只能用printf夹点法,很好。不过也要注意几个问题:嵌入式系统往往没有屏幕,printf输出是通过串口输出的。串口有两种工作模式,一种是查询,一种是中断,或者DMA。在任何情况下,调试的printf输出只能通过查询输出,不能通过中断或DMA输出。无论是前台还是后台程序,还是操作系统,都有一些不方便,比如在全局临界(中断关闭)打印,在中断中打印(不允许嵌套中断)或者在一些驱动程序中打印(很多配合设备没有初始化,内存分配和中断不好用)。在这些情况下,使用Uart中断来输出字符是不明智的。因此,调试输出只能使用查询方法。不要幻想用什么伟大的方法,没必要。一句话,不靠谱!既然调试,可靠的输出结果是第一要求。正因为如此,printf也会影响代码的工作效率。串口最高波特率115200bps,CPU越快,浪费的时间越多,因为要等待最后一个字符的输出,完全被空传送消耗掉了。所以使用printf需要有一定的技巧,然后在不影响某些键定时的位置打印出来,而不是随意打字...淹没窃听器。以上两种方法都不能很好的解决所有问题。在实际操作中,如果嵌入式系统有一两个LED灯,特殊情况下尽量用IO口打开和关闭,也可以指示程序的状态。这种方法适用于调试中断和临界区等问题。LED灯点亮需要很短的时间,基本上就是一个内存读写命令,如果IO口寄存器是CPU统一寻址的话。基本上影响微乎其微。在调试一些复杂的时序时,也可以利用空的空闲IO口,特殊情况下下拉上拉,然后用数字示波器或逻辑分析仪抓取,进行详细分析。尤其是分析一段代码的执行频率、执行时间和优化效果。这对整体性能的提高具有重要意义。对于简单的单片机,厂家开发的软件有定时统计的功能。但对于带缓存和MMU的单片机,定时统计并不准确,往往不如示波器测得的准确。如果没有示波器,可以用CPU内部的时间计数器来计时,所以需要结合printf。我的一个同事调试飞利浦ARM7。因为飞利浦ARM7的外接RAM都是静态RAM,所以即使CPU崩溃,只要上电,SRAM中的数据也不会丢失。因为SRAM和内部SRAM是统一寻址的,所以访问只是一个读写指令,速度非常快。利用这个特性,他标记了程序的所有模块和点。当系统运行不正常时,ARM7复位后,ARM7的第一项工作就是将复位前的数据取出并打印出来。由此可以调试ARM7代码,这是一个非常巧妙的方法。如果只有SDRAM的朋友不能用这种方法,因为只要系统复位,不刷新SDRAM,数据就会丢失。

大家都知道,嵌入式系统最大的挑战在于硬件和软件的同时成熟。有一个问题。不知道是软件问题还是硬件问题。当然,大多数问题都可以用虚拟的手段解决,但虚拟终究是虚拟。不,实际上,在实际的板上仍然有许多问题。嵌入式领域,尤其是底层技术,由软件(驱动程序)和硬件组成。要解决这个问题,我们需要两部分知识,这就要求人员素质更高。我遇到过很多棘手的问题,都是复杂的系统问题。1.一个系统需要连续24小时工作。即使断电,也要保持断电状态。供电正常时,必须恢复到断电前的状态,继续工作。其实软件我们也做过,但是实际效果并不是我们想象的那样。一万次停电,总有几十次不正常;没有办法复制它。只是猜测而已。因为系统关机,这也不好调试。JTAG挂起,系统关机,目标板关机。没有办法调试跟踪步骤。最初的设计思路是,控制电路利用电容储存的部分能量在断电后继续工作,保存状态,保存后进入待机状态。经过断电信号测试,没有问题。后来这个问题成了悬念问题……这个系统分为两个模块,工作模块和控制模块。控制模块有电容继续供电,而工作模块没有电容工作;因此,当断电时,整个系统不会同时断电。当控制模块检测到掉电时,实际上所有工作模块都掉电了,工作模块无法正确回传相关数据,导致控制模块无法正常工作。两次停电时间非常接近,无法判断其先后顺序。解决方案也很简单,就是掉电检测模块和工作模块同步,这样就没有问题了。2.还是断电保护的问题。在我们用继电器模拟断电上万次后,终于进行了整机实验。因此,我们经常发现电源故障无法得到妥善保护。仔细看电路,没什么异常。都一样。结果工程部指责我们R&D部检测不仔细,送出去的东西都有问题。哦,悲伤。经过仔细分析,我们认为软件异常的可能性很小。主要问题是硬件。硬件上的超级电容在频繁断电的情况下可能存储不了足够的能量,让系统完成保护过程。那么是什么原因导致频繁停电呢?按照设计要求,超级电容在3~5s内会充满80%的能量,理论上足够了。不到3~5s经常停电是怎么回事?说出来很不可思议。它是通过使用数字示波器连续跟踪控制面板的电源发现的。原来三相交流电需要接一个断相保护器,系统工作时会频繁开关(可能和系统的状态有关)。解决方法是简单地将控制器的电源连接到相位保护器的前面。这些问题看起来都是硬件问题,在产品调试过程中经常会遇到。对于这些问题,软件人员需要确认软件中的bug是否会造成这种情况,然后硬件工程师需要对硬件进行确认。当然,硬件确认过程漫长复杂,调试手段非常有限;相比硬件,嵌入式软件的调试会有更好的成本和效果。所以嵌入式软件人员往往需要花费大量的时间来确认软件问题,最后怀疑硬件。作为嵌入式开发人员,了解硬件的基本原理,结合软件的工作原理,配合硬件工程师在实验中定位错误,是非常有效的方法。网上的一些朋友经常问我一些问题。有一些关于底层的知识,包括一些多处理器的问题。关于多处理器的问题,我不太熟悉。我来和大家探讨一下多CPU在嵌入式领域的应用。嵌入式系统是计算机科学的应用领域之一。既然是计算科学的应用领域之一,要做好这个领域,就要有过硬的计算机理论知识。

首先,多处理器有几种。处理器是相同的型号,它们都是相同的,并且它们通过通信方式连接,例如多端口RAM、rapidIO、千兆以太网或PCI-E等。处理器的型号不同,甚至架构也完全不同。它们通过如上所述的通信模式连接,例如多端口RAM、RapidIO等。多个CPU集成在同一个芯片上。这些CPU共享一切,属于一个比多端口RAM耦合更紧密的系统。为什么要使用多个处理器?

大规模并行操作;我想利用多个CPU的特性,比如DM642,将其应用到复杂的视频方案中。我想利用DSP的浮点运算能力和ARM的事务运算能力。简单地提高系统的性能。对于普通应用,提升系统性能是基本出发点。然而,在嵌入式系统中应用多处理器并不是一件简单的事情。多处理器软件设计难度很大,调试也是个大问题。如果不使用操作系统进行处理,则使用前后系统。然后我还要设计一个通信算法和一个结果整合系统。这样的系统自己设计很多东西,其中总线的可靠性和容错性设计非常重要。所以,如果可能的话,使用成熟稳定的操作系统来支持多处理器可以降低很多开发难度。然而,要找到这样的操作系统并不容易。首先明确你的应用,需要线程进程迁移吗?需要处理器平衡吗?对于多处理器来说,如果不支持线程进程的迁移,处理器任务的动态平衡就无从谈起。否则,我们只能预先指定线程进程运行在哪个处理器上。对于异构多处理器,线程迁移和进程迁移的实际意义不大。对于逐利的公司来说,目前没有实用价值。因此,迁移仅限于对称处理器。但是,对称处理器不是一个可以迁移的进程。对于对称处理器,操作系统封装了底层,这样用户可以像重新开发CPU一样开发它。当然不能和单个CPU完全一致,但至少降低了很多难度。很多朋友问我RTEMS能不能像x86一样运行在CMP多处理器上。当然可以。然而,该设计不同于常见的对称多处理器。因为CMP处理器上的CPU共享很多东西,比如中断、内存、总线,它们的寻址空基本都是一样的。对于RTEMS等RTOS,它采用异构的方式支持对称处理器,即几个CPU要运行几个RTEMS。那么沟通就显得尤为重要。多个RTEMS需要多系统的TICK。蜱从何而来?CMP共享大量资源,要求用户必须手动为RTEMS指定中断源,划分内存空。这就造成了虽然CMP上的多个CPU都运行RTEMS,但是很多CPU驱动是不一样的。这个紧密耦合的系统非常困难。

和CMP相比,同样的CPU组成的SMP更简单,因为所有的驱动都是一样的。可能因为通讯方式的原因,通讯驱动需要特殊处理,但这样会大大减轻开发的压力和调试的难度。总像一个CPU一个核心,要崩溃了。尤其是调试问题,所以从经济角度来说,我更喜欢这种由多个相同的单CPU组成的多处理器系统。

很多时候,对于异构处理器,当然RTEMS也可以轻松处理,但这仍然是个问题。多核需要自己的RTEMS支持,不方便开发。此外,操作系统的调试也很复杂。所以现实世界的解决方案是,负责事务操作的处理器在异构处理器之间运行操作系统,而负责计算的处理器采用前后台系统,简单的通过共享内存进行通信,响应操作系统的计算请求。这大大降低了开发难度。反正操作系统把DSP当成硬件寄存器,你写几个寄存器就能得到结果,或者输入一组天文数据就能得到复杂的结果。反正一句话,这种反应式处理是大多数项目采用的方法。它简单、可靠、实用。嵌入式系统中的多处理器似乎与应用高度相关。

嵌入式pc(嵌入式电脑)插图

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。

作者:美站资讯,如若转载,请注明出处:https://www.meizw.com/n/109854.html

发表回复

登录后才能评论