7657|26

75

帖子

0

TA的资源

一粒金砂(初级)

楼主
 

被EnterCriticalSection保护的代码 也可以不被硬件中断打断么? [复制链接]

有一段语句我要连续执行,连中断都不允许打断,EnterCriticalSection可以么?
不可以的话得怎么才能实现呢?
多谢:)

最新回复

要是一定要禁止中断的话可以用InterruptDisable暂时把中断关掉,用完后再用InterruptEnable打开  详情 回复 发表于 2009-5-14 09:02
点赞 关注

回复
举报

66

帖子

0

TA的资源

一粒金砂(初级)

沙发
 
EnterCriticalSection可以满足你的要求

只不知道LZ有什么特殊的要求
 
 

回复

78

帖子

0

TA的资源

一粒金砂(初级)

板凳
 
不行,Critical 只能保证不被重入,但是不能保证连续执行。
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

4
 
实际上是这样一个问题:
ISR和用户态代码都要对外设操作,而外设又需要两次有序的读写才能完成一次有效操作,
我是怕ISR执行中间的时候用户态代码由于任务调度也恰好对外设操作,
或者用户态执行的时候恰好中断到来ISR开始执行对外设操作,
有什么办法可以避免这个问题,
以前我发过帖子问过,google回答过,可后来想想还是不对,
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

5
 
顶。太高深了,过来学习一下。
 
 
 

回复

74

帖子

0

TA的资源

一粒金砂(初级)

6
 
可以考虑定义为原子操作
 
 
 

回复

82

帖子

0

TA的资源

一粒金砂(初级)

7
 
引用 2 楼 ultrapro 的回复:
不行,Critical 只能保证不被重入,但是不能保证连续执行。

我觉得ultrapro 牛人说的对。

2、临界区
  临界区对象运行在用户模式。它能保证在临界区内所有被访问的资源不被其它线程访问,直到当前线程执行完临界区代码。


void InitializeCriticalSection ( LPCRITICAL_SECTION );
void EnterCriticalSection ( LPCRITICAL_SECTION );
void LeaveCriticalSection ( LPCRITICAL_SECTION );
void DeleteCriticalSection ( LPCRITICAL_SECTION );   

举例如下:

void CriticalSectionExample (void)
{
  CRITICAL_SECTION csMyCriticalSection;//注意这个只是定义个变量就可以了,非常好用
  InitializeCriticalSection (&csMyCriticalSection); ///初始化临界区变量,这个是不能少的
  __try
  {
    EnterCriticalSection (&csMyCriticalSection);  ///开始保护机制
    ///此处编写代码
  }
  __finally  ///异常处理,无论是否异常都执行此段代码
  {
    LeaveCriticalSection (&csMyCriticalSection); ///撤销保护机制
  }
}

//=========================================================================


 
 
 

回复

81

帖子

0

TA的资源

一粒金砂(初级)

8
 
引用 5 楼 91program 的回复:
可以考虑定义为原子操作


中断都不允许打断?可以这样做吗?

据我所知,应该是读出中断寄存器保存,然后屏蔽所有中断,最后再恢复吧。

哈哈,我是直接方法。
 
 
 

回复

57

帖子

0

TA的资源

一粒金砂(初级)

9
 
引用楼主 pyj0314 的帖子:
有一段语句我要连续执行,连中断都不允许打断,EnterCriticalSection可以么?
不可以的话得怎么才能实现呢?
多谢:)



不能被中断打断的方法是:
读出中断寄存器保存,然后屏蔽所有中断,最后再恢复吧。 ——这个在一些wince内核驱动性能测试上经常用到。
——
不能被其他线程打断的方法是EnterCriticalSection
 
 
 

回复

72

帖子

0

TA的资源

一粒金砂(中级)

10
 
引用 3 楼 pyj0314 的回复:
实际上是这样一个问题:
ISR和用户态代码都要对外设操作,而外设又需要两次有序的读写才能完成一次有效操作,
我是怕ISR执行中间的时候用户态代码由于任务调度也恰好对外设操作,
或者用户态执行的时候恰好中断到来ISR开始执行对外设操作,
有什么办法可以避免这个问题,
以前我发过帖子问过,google回答过,可后来想想还是不对,


EnterCriticalSection 貌似不能屏蔽硬件中断,就算你采用 cli 关闭中断,它也可以被非屏蔽中断打断,
故楼主的想法是不太可能实现的,只能采用其他方式。试问:是否有多个应用需要同时访问该外设?
 
 
 

回复

80

帖子

0

TA的资源

一粒金砂(初级)

11
 
引用 3 楼 pyj0314 的回复:
实际上是这样一个问题:
ISR和用户态代码都要对外设操作,而外设又需要两次有序的读写才能完成一次有效操作,
我是怕ISR执行中间的时候用户态代码由于任务调度也恰好对外设操作,
或者用户态执行的时候恰好中断到来ISR开始执行对外设操作,

有什么办法可以避免这个问题,
以前我发过帖子问过,google回答过,可后来想想还是不对,


1. WindowsCE 是 preemptive multitasking OS, 故它基本上是不希望 programmer 去乱关中断的. 而 2 楼说的很对, CriticalSection 只能保证不被重入,但是不能保证连续执行。

2. ARM 的 ISR 是没有 reentry 的, 故除非有 FIRQ, 故是不用担心ISR执行中间的时候用户态代码由于任务调度也恰好对外设操作.

3. 最好的解决方法是 ISR 中不要对 external chip access, 留到 IST 中去做.

4. 不知 "ISR 先把 Index Register 读出後保存後再修改, 离开前再改回原值." 这个方法对你有没有帮助.

Paul, Chao @ Techware
 
 
 

回复

74

帖子

0

TA的资源

一粒金砂(初级)

12
 
引用 9 楼 morris88 的回复:

EnterCriticalSection 貌似不能屏蔽硬件中断,就算你采用 cli 关闭中断,它也可以被非屏蔽中断打断,
故楼主的想法是不太可能实现的,只能采用其他方式。试问:是否有多个应用需要同时访问该外设?


不是多少个应用要访问,而是ISR和应用可能同时访问,
我的芯片是AM8530,同步串口芯片,SDLC通信,
这个芯片只有一个地址,内部有16个写寄存器,7、8个读寄存器,对他操作要先写寄存器号,然后再写数据,就像CMOS的操作一样
比如我现在要修改波特率,应用调用修改波特率函数,

a、先写波特率时间常数寄存器寄存器号
b、再写波特率时间常数寄存器值

ISR的过程:
A、写中断pending寄存器号
B、读中断pending寄存器值
C、...
D、写数据寄存器号
E、读数据
F、...

我是怕a、b之间被ISR(或者说被A、B、D、E)打断,比如a->(isr打断)->A,就是本应写入 时间常数 的 寄存器 被写入了中断pending寄存器号,
从此以后操作都乱了,
这可咋整泥。。。

 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

13
 
引用 10 楼 paul_chao 的回复:
ISR 先把 Index Register 读出後保存後再修改, 离开前再改回原值


呵呵,他只有一个地址,读不出index register,index register 对用户不可见。
读操作后的第一个写操作就是写index register,
具体操作过程如11楼

唉,我觉得这个芯片非常恶心。。。

有在ISR和用户实现互斥的方法么?

还请大家帮帮忙。。。
 
 
 

回复

60

帖子

0

TA的资源

一粒金砂(初级)

14
 
注:连 修改 中断使能寄存器 都要两次操作的,
呛死我了。。。
 
 
 

回复

68

帖子

0

TA的资源

一粒金砂(初级)

15
 
这只是一个思路,不知道实现起来是否可行:

1. 申请一块内存。此内存最好是在中断服务中申请,也就是只有内核可以访问。而且地址固定在一个其他程序不会访问到的地方。初始化为0。
2. 中断服务执行时,第一条语句检测此内存是否为1(代表应用正在使用),为1则直接退出,为0(应用没用使用),继续执行。
3. 在应用中通过内存影射方式,访问此地址内存中的数据,为0,就设为1,然后等待几毫秒,重新访问此内存,为1,就执行应用操作。
4. 操作完成之后,一定要将此内存还原为0,否则中断服务程序永远无法得到执行。

这种方法比较危险,因为在应用中操作内核区域的内存始终不是明智之举。
 
 
 

回复

73

帖子

0

TA的资源

一粒金砂(初级)

16
 
1. 看来在体制内是无解的.

2. 在 Driver 内用 CriticalSection 来保护, 应该不会有 Application 直接 access hardware 吧.

3. LZ AM8530 irq pin 应是接到 CPU 的 gpio 吧. 建议 LZ 在呼叫 CriticalSection 时顺便关掉该 gpio 中断, 用完再打开, 例如:

void Lock(void)
{
   EnterCriticalSection(&cs);
   g_pGPIO->IER &= ~(1 << ??);
   return;
}

void Unlock(void)
{
   g_pGPIO->IER |=  (1 << ??);
   LeaveCriticalSection(&cs);
   return;
}

4. 因不知 WinCE 体制内有无最佳解, 故提供的只是 "或许" 可行解, LZ 要多测试看看.

Paul, Chao @ Techware
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

17
 
引用 11 楼 pyj0314 的回复:
不是多少个应用要访问,而是ISR和应用可能同时访问,
我的芯片是AM8530,同步串口芯片,SDLC通信,
这个芯片只有一个地址,内部有16个写寄存器,7、8个读寄存器,对他操作要先写寄存器号,然后再写数据,就像CMOS的操作一样
比如我现在要修改波特率,应用调用修改波特率函数,

a、先写波特率时间常数寄存器寄存器号
b、再写波特率时间常数寄存器值

ISR的过程:
A、写中断pending寄存器号
B、读中断pending寄存器值
C、...
D、写数据寄存器号
E、读数据
F、...

我是怕a、b之间被ISR(或者说被A、B、D、E)打断,比如a->(isr打断)->A,就是本应写入 时间常数 的 寄存器 被写入了中断pending寄存器号,
从此以后操作都乱了,
这可咋整泥。。。


那就在 isr 中先关闭中断,然后原子操作 AB,然后开中断,其后就可以正常操作了
 
 
 

回复

81

帖子

0

TA的资源

一粒金砂(初级)

18
 
引用 16 楼 morris88 的回复:
那就在 isr 中先关闭中断,然后原子操作 AB,然后开中断,其后就可以正常操作了

呵呵,不行,ISR中中断本来就是关闭的,OS就给你搞定了,还是有用户被ISR打断的问题。
 
 
 

回复

69

帖子

0

TA的资源

一粒金砂(初级)

19
 
引用 14 楼 CBEMA 的回复:
这只是一个思路,不知道实现起来是否可行:

1. 申请一块内存。此内存最好是在中断服务中申请,也就是只有内核可以访问。而且地址固定在一个其他程序不会访问到的地方。初始化为0。
2. 中断服务执行时,第一条语句检测此内存是否为1(代表应用正在使用),为1则直接退出,为0(应用没用使用),继续执行。
3. 在应用中通过内存影射方式,访问此地址内存中的数据,为0,就设为1,然后等待几毫秒,重新访问此内存,为1,就执行应用操作。
4. 操作完成之后,一定要将此内存还原为0,否则中断服务程序永远无法得到执行。

这种方法比较危险,因为在应用中操作内核区域的内存始终不是明智之举。


参考CBEMA的思路,大家看看我这样的方法可以不
内核态的中断处理DLL中编写函数Write8530Reg、Read8530Reg,

  1. Write8530Reg(PAM8530_Virt pVirt, DWORD reg_index, DWORD value)
  2. {
  3.     while(pVirt->RegOperating);  //等待操作完成,ISR中调用此函数也会等待,但考虑到此位马上会被清零(用户态代码马上会结束操作),
  4.                                       //也让ISR等待,不知道可不可以
  5.     pVirt->RegOperating = TRUE;  //置位正在操作位
  6.     ...
  7.     //寄存器操作
  8.     ...
  9.     pVirt->RegOperating = FALSE; //清正在操作位
  10. }
复制代码

其中PAM8530_Virt结构体中有

  1. typedef tag_am8530_virt
  2. {
  3.     //一些驱动相关的成员
  4.      BOOL RegOperating;  //表示寄存器是否正在操作中
  5. }
复制代码

然后写IOContrl函数

  1. BOOL
  2. IOControl(
  3.             DWORD   InstanceIndex,
  4.             DWORD   IoControlCode,
  5.             LPVOID  pInBuf,
  6.             DWORD   InBufSize,
  7.             LPVOID  pOutBuf,
  8.             DWORD   OutBufSize,
  9.             LPDWORD pBytesReturned
  10.             )
  11. {
  12.     ...
  13.     case IOCTL_ISR8530_WRITE_REG:  //写寄存器操作
  14.         Write8530Reg(...);
  15.     ...
  16. }
复制代码

然后用户通过调用KernelLibIoControl用IOCTL_ISR8530_WRITE_REG操作码读写寄存器,
ISR直接用Write8530Reg操作寄存器

这样看有没有什么问题
 
 
 

回复

75

帖子

0

TA的资源

一粒金砂(初级)

20
 
Write8530Reg(PAM8530_Virt pVirt, DWORD reg_index, DWORD value)
{

do
{
pVirt->RegOperating = TRUE;  //置位正在操作位这里位置应该提前,先置位,后等待。
     sleep(时间依据具体情况调试);
}
while(pVirt->RegOperating);  //等待操作完成,ISR中调用此函数也会等待,但考虑到此位马上会被清零(用户态代码马上会结束操作),
                                      //也让ISR等待,不知道可不可以

   
    ...
    //寄存器操作
    ...
    pVirt->RegOperating = FALSE; //清正在操作位
}

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/9 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表