`
dato0123
  • 浏览: 915361 次
文章分类
社区版块
存档分类
最新评论

C#程序导致MFDeploy无法ping通的问题

 
阅读更多

//=====================================================================
//TITLE:
// C#程序导致MFDeploy无法ping通的问题
//AUTHOR:
// norains
//DATE:
// Thursday 05-May-2011
//Environment:
// .Net Micro Framework Porting V4.1
// Keil MDK 4.02
// STM32F103ZE Redcow Board
// Visual Studio 2010
//=====================================================================

为了测试编写USB驱动是否正常,编写了一个C#程序,其完整的代码如下:

这段代码看起来没什么问题,用VS2010也能正常下载,并且从串口中也能看到打印出来的字符串。但奇怪的事情就此发生了,自从成功下载该程序,并且正常运行之后,我的板子插到电脑上虽然可以枚举,但通过MFDeploy的Ping指令,却经常无法正常通讯。如果用Bus Hound软件来查看,发现PC端发送一个OUT包之后就卡死了,如图所示:


如果将NAND上的C#程序给擦除,那么一切又恢复了正常。这究竟是怎么一回事呢?

通过MDK的断点调试,会发现代码一直在执行Systick中断函数,而查看Systick的寄存器,发现reload的数值非常小,如图所示:


造成频繁执行Systick中断函数的原因是否源于此呢?通过MDK来强制更改NVIC_ST_RELOAD寄存器的数值为0x00FFFFFF来试试。结果不出所料,Bus Bound监控到USB数据又开始交互,MFDeploy也不再假死,而检测到板子为TinyCLR了!

转回来想想,为什么Systick的Reload的数值太小,导致MFDeploy假死呢?原因很简单,Reload是每次systick中断的间隔,而这个时间太小,很可能在刚执行完systick中断函数的时候,下一次中断又发生了,从而导致主线程的代码没有获得CPU时间执行!

原因找到了,那么我们该如何解决这个问题呢?首先我们来看看Systick的中断函数。一般来说,根据.NMF的示例代码,我们的中断函数无非如此:

这个中断函数逻辑很简单,如果当前的ticks大于要比较的ticks值,就执行HAL_COMPLETION::DequeueAndExec()函数。我们进到该函数看看。因为该函数比较大,有一些东西并不需要我们了解,所以下面罗列的是缩减后的主要部分,如下所示:

从中可以看到,该函数其实会调用HAL_Time_SetCompare来设置下一次的中断时间。但如果我们使用MDK单步调试,却会惊讶发现,该函数一直没有被调用,因为ptrNext一直为NULL!如果再仔细点,在还没执行C#程序之前,ptrNext不是为NULL的!

根据经验推测,问题就出在于C#程序。具体点,问题在于C#的Main函数返回了!因为C#的Main函数返回,导致Node的结点被释放,于是ptrNext就为NULL。如果此时又刚好Systick的间隔很小,代码又因为ptrNext为NULL而不执行HAL_Time_SetCompare函数,那么最终结果就是:不停地发生Systick中断,而无瑕执行主线程代码!

原因找到之后,可能大家想到的最简单的解决方式就是在C#的Main函数中执行一个死循环,如下所示:

结果没错,这样更改之后,的确一切都正常了。似乎一切都很美好,不是么?但是,这样的健壮性是不够的,因为我们无法确保做应用的程序员能够遵守这个约定。而万一他们忘记的话,那么结果将是灾难性的:因为USB已经无法PING通,更谈不上下载程序,所以做应用的程序员无法凭一己之力来挽回自己的错误。除了你,.NMF的移植者,通过MDK来设置Systick的Reload寄存器,让CPU跑到正常的轨道上,除此以外,再无它法。
  
为了避免这情况,我们可以将中断函数修正一下。我们自己来检测ptrNext,如果它为NULL的话,那么我们手动调用HAL_Time_SetCompare函数即可,如下所示:

经过这么一更改,那么引发MFDeploy无法响应的问题不再存在,我们也不用再担心应用程序员忘记最后写死循环啦!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics