【200分】中断驱动+应用层同步响应的问题咨询

camy_wang   2010-1-14 15:26 楼主
问题描述:

1.一个流式驱动,工作流程是硬件触发一个中断,系统采集到数据信息后通过xxx_READ将采集到的数据发给应用层;

2.驱动通过一个线程函数来获取GPIO的中断信号,并读取值从打印信息打印出。
(这里的处理正常,有多少中断都接受到,并且值采集正确)

3.读取到中断后,系统通过一个采集函数将数据信息采集,并将数据存放在一个全局变量中,并设定一个事件a;

4.XXX_READ函数中等待事件信号a,等待到了就将数据送到xxx_read函数的status接口上;

5.应用层创建一个线程,在线程中实现一个readfile功能去读取xxx_Read传送出来的值;

问题点:
1.现在驱动层打印信息看,在驱动层每次都获取到了,但是应用层上,我在实际操作的时候发现产生数据是如果速度过快每次只能获取到一个数值,如果产生数据慢的时候就能很准的获取并在响应应用层的功能;

请教下各位大牛这个问题如何解决?也就是中断响应的问题,如何实现驱动层响应中断和应用层响应中断同步??

分不够再加。

慢速正确的信息

  1. the 0 number  SentOut Value for point variable is bb//来自驱动层
  2. the 0 number  SentOut Value for point variable is bb来自驱动层
  3. READ EFFECT VALUE!
  4. Volume value : 36
  5. SEND ADDR ACK RECEIVER OK!!!
  6. SEND DATA ACK RECEIVER OK!!!
  7. Volume set Ok!!!


快速数据时产生的错误信息

  1. the 0 number  SentOut Value for point variable is aa
  2. the 0 number  SentOut Value for point variable is aa
  3. the 0 number  SentOut Value for point variable is aa
  4. the 0 number  SentOut Value for point variable is aa
  5. the 0 number  SentOut Value for point variable is aa
  6. the 0 number  SentOut Value for point variable is aa
  7. the 0 number  SentOut Value for point variable is aa
  8. //产生了很多数据但是只响应了最后一个。
  9. READ EFFECT VALUE!
  10. Volume value : 3c
  11. SEND ADDR ACK RECEIVER OK!!!
  12. SEND DATA ACK RECEIVER OK!!!
  13. Volume set Ok!!!

回复评论 (22)

刚想了下是不是我readfile和XXX_READ这个地方没有用对?但是一下也没想出来如何去处理这个问题。。自己顶一下
点赞  2010-1-14 15:32
关注下。
没怎么看懂,楼主能说详细点吗?
点赞  2010-1-14 15:38
引用: 引用 2 楼 flandy1982 的回复:
关注下。
没怎么看懂,楼主能说详细点吗?

就是硬件IO会产生一个中断-》采集一个数据送到应用层-》应用层分析数据-》应用层调用驱动程序实现功能

我给了打印信息,就是说,数据产生的很慢的时候上面的流程就很正常执行
但是速度快了的时候就只能采集到数据,但是应用层好像就都没有响应到,只能响应到最后一个数据。

比如说上面我给的打印信息

  1. the 0 number  SentOut Value for point variable is aa
  2. the 0 number  SentOut Value for point variable is aa
  3. the 0 number  SentOut Value for point variable is aa
  4. the 0 number  SentOut Value for point variable is aa
  5. the 0 number  SentOut Value for point variable is aa
  6. the 0 number  SentOut Value for point variable is aa
  7. the 0 number  SentOut Value for point variable is aa
  8. 这些里面都每一个都得响应的。。。但是这里只在驱动层采集到了数据但是应用层上没响应到所有的,只有最后一个响应到了。。

我用READFILE+驱动的XXX_READ来做值传递,难道是这个传递一次只能传递一个,即使用信号量来控制也是??
还是我信号量送的有问题?
点赞  2010-1-14 15:44
提示: 作者被禁止或删除 内容自动屏蔽
点赞  2010-1-14 16:02

6楼 ian 

两次中断之间时间间隔短吗?如果比较长的话可以在驱动中中断来了之后采集完全部数据后向上层发个消息或者事件,应用层接收到这个事件之后再去读驱动中的数据。
如果过快的话可能底层都已经开始更新下次的数据了,应用层还没读完呢。
点赞  2010-1-14 16:03
引用: 引用 8 楼 veabol 的回复:
两次中断之间时间间隔短吗?如果比较长的话可以在驱动中中断来了之后采集完全部数据后向上层发个消息或者事件,应用层接收到这个事件之后再去读驱动中的数据。
如果过快的话可能底层都已经开始更新下次的数据了,应用层还没读完呢。

牛人。两次中断间隔的时间快起来会非常短。可能是1ms单位甚至500us。现在的情况应该是数据还没处理完下好几次的数据就已经过去了。
但是又要保持实时性。。。诶。这个比较头痛。数据慢的时候还可以接受。快了可能丢掉10个左右的数据
点赞  2010-1-14 16:07
把interruptdone() 移到XXX_read中复制数据的后面吧.
点赞  2010-1-14 16:13
ReadFile的次数和你产生的中断没有直接的关系.
你需要在XXX_READ里面开个足够大的BUFFER把数据存下来,并且对接收的数据进行计数处理。
点赞  2010-1-14 16:13
中断产生了N个信号,但你的ReadFile可能读不到那么多,就被ResetEvent了。
点赞  2010-1-14 16:14
引用: 引用 12 楼 flandy1982 的回复:
中断产生了N个信号,但你的ReadFile可能读不到那么多,就被ResetEvent了。

可能是。。。。一次只有一个值
引用: 引用 10 楼 rushonin 的回复:
把interruptdone() 移到XXX_read中复制数据的后面吧.

好的我试试
点赞  2010-1-14 16:20
学习。
“两次中断间隔的时间快起来会非常短。可能是1ms单位甚至500us。”
LZ的这个中断速度也真够快的啊。
点赞  2010-1-14 16:30
引用: 引用 14 楼 flandy1982 的回复:
建议楼主改用CreateSemaphore吧, IST每次都ReleaseSemaphore, 这样只要保证中断不是一直不间断的产生, 数据就不会丢失, 实时性也只与ReadFile线程处理的速度相关。。

呃。现在有个情况。。。丢是没有丢了。。但是一次出了2个中断,但是速度块起来也只是响应到2个中断,其他中断都丢弃了。。晕。如果用CreateSemaphore的话

我在init初始化gReadKeyEvent[0] = CreateSemaphore(NULL, 0, cMax, NULL);
然后在xxx_DetectThread里面

  1.   if (!ReleaseSemaphore(
  2.                 gReadKeyEvent[0], // 要增加的信号量。
  3.                 1,           // 增加1.
  4.                 NULL) )      // 不想返回前一次信号量。
  5.         {}

。。。难道哪里又弄错了?
点赞  2010-1-14 18:01
如果lz的数据处理速度慢,而中断上来快的话,这个问题基本没得解。肯定会丢掉东西,要么丢掉数据,要么丢掉中断,相信这2种情况都不是lz想要的。所以lz还是要想办法尽量提高数据处理速度。

另外,lz可以考虑使用循环缓冲buffer的方式来做。数据一来就把它存到缓冲区,然后马上取走去处理,这样的话即使你处理稍微慢一点,缓冲区里面的是数据总是不会丢掉的。就想往水杯里面倒水,但是这个杯子底部又有一个洞漏水一样。
点赞  2010-1-14 18:30
在驱动里缓存一些数据,然后通知应用程序集中处理,其他似乎没有太好的办法。

实在不行,可以考虑使用FIQ,快速中断。以前做数据采集设备时,曾尝试过这种方法。
点赞  2010-1-14 18:31
结贴。搞定。用了上面两个高手提供的方法实现。谢谢了
点赞  2010-1-14 18:51
引用: 引用 18 楼 ricky_hu 的回复:
如果lz的数据处理速度慢,而中断上来快的话,这个问题基本没得解。肯定会丢掉东西,要么丢掉数据,要么丢掉中断,相信这2种情况都不是lz想要的。所以lz还是要想办法尽量提高数据处理速度。

另外,lz可以考虑使用循环缓冲buffer的方式来做。数据一来就把它存到缓冲区,然后马上取走去处理,这样的话即使你处理稍微慢一点,缓冲区里面的是数据总是不会丢掉的。就想往水杯里面倒水,但是这个杯子底部又有一个洞漏水一样。

谢谢建议。非常感谢!
点赞  2010-1-14 18:51
引用: 引用 19 楼 sunrain_hjb 的回复:
在驱动里缓存一些数据,然后通知应用程序集中处理,其他似乎没有太好的办法。

实在不行,可以考虑使用FIQ,快速中断。以前做数据采集设备时,曾尝试过这种方法。

哈哈哈HJB大牛,谢谢啦。已经搞定。最近怎么没看到你的博客发帖子啊。期待新作。

FLandY1982非常感谢。方法很好!
点赞  2010-1-14 18:52
驱动层的BUFFER开得足够大吗?会不会出现应用层还未处理完,新的中断又产生的情况?
IST的优先级和采集线程的优先级怎么设置的?
点赞  2010-1-14 15:49
驱动层部分代码

  1. /////////////////////////////////////////////////////////////////////
  2. //=============================================================================
  3. //Title : xxx_IntrThread
  4. //Detail: Receive INTR EVENT from gpio for xxx communication
  5. //Input : PVOID pArg
  6. //Output: DWORD
  7. //Author: Mercury                
  8. //Data  : 2009-12-26
  9. //=============================================================================
  10. DWORD xxx_DetectThread(PVOID pArg)
  11. {
  12.    //变量定义
  13.     //Sleep(1);       
  14.     while (1)
  15.     {
  16.         dwRet = WaitForMultipleObjects(2, rghEvents, FALSE, INFINITE);
  17.         if(pMcuCtl->bDeinit) {
  18.       
  19.             return 0;       
  20.         }                       
  21.         switch(dwRet) {
  22.         case WAIT_OBJECT_0:
  23.             RETAILMSG(1, (TEXT("mcu_DetectThread Wait deinit\r\n")));
  24.             //deinit event
  25.             return 0;
  26.         break;
  27.                
  28.         case WAIT_OBJECT_0+1:
  29.                      OperationCS8953(READ, &sendOut[0], 2);       
  30.                         #if 1
  31. RETAILMSG(1,(TEXT("the %d number  SentOut Value for point variable is %x\r\n"),i,sendOut[i]));
  32.                         #endif
  33.         SetEvent(gReadKeyEvent[0]);        /* 通知读函数, 外部中断产生 */               
  34.                         }
  35.         break;
  36.         default:
  37.             //error
  38.             dwAction = 0x00;//MCU_STAT_NOCHANGE;
  39.         break;
  40.         }
  41.                  //do real action
  42.     }  
  43.     return 0;
  44. }
  45. extern "C" DWORD XXX_Init(DWORD Index)
  46. {


  47.     RETAILMSG(1,(TEXT("++XXX_Init!\r\n ")));   
  48.    //事件创建部分。。省略部分代码
  49.     pXXXCtl->hDetectThread = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) XXX_DetectThread, (LPVOID)pXXXCtl, 0, &IDThread);
  50.     if (pXXXCtl->hDetectThread == 0)
  51.     {
  52.          RETAILMSG(1,(TEXT("XXX_Init::: CreateThread Failed\r\n")));
  53.          goto Error;
  54.     }

  55.    //初始化中断 。。省略部分代码
  56.     return(DWORD)pXXXCtl;       
  57.        
  58. Error:
  59.     (VOID)XXX_Deinit((DWORD)pXXXCtl);
  60.     RETAILMSG(1,(TEXT("--error !XXX_Init!\r\n ")));   
  61.         #endif
  62.     return(0);
  63. }

  64. extern "C" DWORD xxx_Read(DWORD dwData,
  65.                LPVOID pBuf,
  66.                DWORD Len)
  67. {
  68.         DWORD ret;
  69.         unsigned char  *pReadBuffer = NULL;

  70.         if ((pBuf == NULL) || (Len <= 0))
  71.                 return 0;

  72.         pReadBuffer = (unsigned char  *)MapPtrToProcess(pBuf, GetCallerProcess());
  73.         *pReadBuffer = NULL;
  74.        
  75.             ret = WaitForMultipleObjects(2, gReadKeyEvent, FALSE, INFINITE);       
  76.         if (ret == WAIT_OBJECT_0)
  77.         {
  78.                 ResetEvent(gReadKeyEvent[0]);
  79.                 *pReadBuffer = sendOut[0];               
  80.                 RETAILMSG(1,(TEXT("READ EFFECT VALUE!\r\n")));/* 获取有效值 */
  81.                 //return 1;
  82.         }
  83.         else if(ret == (WAIT_OBJECT_0 + 1))
  84.         {
  85.                 ResetEvent(gReadKeyEvent[1]);               
  86.                 RETAILMSG(1,(TEXT("OUT\r\n")));/* 驱动关闭 */
  87.                 //return 1;               
  88.         }

  89.     return(0);
  90. }

点赞  2010-1-14 15:52
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复