05-SA8155 QNX Hypervisor BSP之Interrupts中断

1. 背景

之前一篇文章:中断知识(重温)

搞BSP的同学,在Android/Linux 系统肯定很清楚中断处理方法,那么QNX 系统下中断又是怎么做的呢?  众所周知,QNX是RTOS,有些跟Linux不同的方法论。

1.1  中断Handle

其中中断有优先级,导致中断处理也具备了优先级.

  • 高优先级的中断优先处理, 在中断处理的过程遇到更高优先级的中断,当前中断处理暂停,进行更高优先级中断的处理.
  • 相同优先级的中断,按先后顺序依次处理
  • 中断的优先级天然高于线程(thread)的优先级

1.2 中断调度

1.2.1 无优先级

如上图可以看出,taskB运行过程收到interrupt,并未立刻执行,而是等待TaskB执行完成之后再执行taskC。 

1.2.1 优先级

 如上图可以看出,taskB运行过程收到interrupt,立刻执行taskC,taskC执行完成后再调度执行之前任务taskB。 

2. API/接口

extern int InterruptHookTrace(const struct sigevent *(*__handler)(int), unsigned __flags);
extern int InterruptHookIdle(void (*__handler)(_Uint64t *, struct qtime_entry *), unsigned __flags);
extern int InterruptHookIdle2(void (*__handler)(unsigned, struct syspage_entry *, struct _idle_hook *), unsigned __flags);
extern int InterruptHookOverdriveEvent(const struct sigevent *__event, unsigned __flags);
extern int InterruptAttachEvent(int __intr, const struct sigevent *__event, unsigned __flags);
extern int InterruptAttachEvent_r(int __intr, const struct sigevent *__event, unsigned __flags);
extern int InterruptAttach(int __intr, const struct sigevent *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
extern int InterruptAttach_r(int __intr, const struct sigevent *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
extern int InterruptAttachArray(int __intr, const struct sigevent * const *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
extern int InterruptAttachArray_r(int __intr, const struct sigevent * const *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
extern int InterruptDetach(int __id);
extern int InterruptDetach_r(int __id);
extern int InterruptWait(int __flags, const _Uint64t *__timeout);
extern int InterruptWait_r(int __flags, const _Uint64t *__timeout);
extern int InterruptCharacteristic(int __type, int __id, unsigned *__new, unsigned *__old);
extern int InterruptCharacteristic_r(int __type, int __id, unsigned *__new, unsigned *__old);

extern void InterruptEnable(void);
extern void InterruptDisable(void);
extern int  InterruptMask(int __intr, int __id);
extern int  InterruptUnmask(int __intr, int __id);
extern void InterruptLock(struct intrspin * __spin);
extern void InterruptUnlock(struct intrspin * __spin);
extern unsigned InterruptStatus(void);

 常用配置接口:

extern int ThreadCtl(int __cmd, void *__data);
extern int InterruptAttachEvent(int __intr, const struct sigevent *__event, unsigned __flags);
extern int InterruptWait_r(int __flags, const _Uint64t *__timeout);
extern int  InterruptUnmask(int __intr, int __id);
extern int InterruptDetach(int __id);

3. 步骤

3.1 I/O权限

//get I/O privileges
if (-1 == ThreadCtl(_NTO_TCTL_IO, 0)) {
    printf("Failed to get IO privileges!");
    goto exit_err;
}

 3.2 中断IO配置

int32_t gpio_set_interrupt_cfg(int fd, uint32_t gpio, uint32_t trigger, void *event)

// Set up edge detection of pin
if(GPIO_FAIL == gpio_set_interrupt_cfg(fd,gpio_number,trigger,NULL))
{
	printf("Failed to setup detect pin interrupt \n");
	goto exit_err;
}

if(GPIO_FAIL == (status = gpio_get_interrupt_cfg(fd,gpio_number,&irq)))
{
	printf("Failed to get irq corresponding to gpio %d \n",gpio_number);
	goto exit_err;
} 
else 
{
	if (irq == -1)
	{
		printf(" irq corresponding to gpio %d is %d status %d - exiting\n",gpio_number,irq, status);
		goto exit_err;                
	}
	printf(" irq corresponding to gpio %d is %d status %d\n",gpio_number,irq, status);
}

 3.3 中断实现

// Attach Event ISR
SIGEV_INTR_INIT(&int_event);
interrupt_id = InterruptAttachEvent(irq, &int_event, _NTO_INTR_FLAGS_TRK_MSK);

printf("Wakeup setup successfully completed  and now wait for interrupt \n");

while ( 1 ) {
	// Wait for interrupt
	status = InterruptWait_r(0, NULL );
	if (status != EOK)
	{
		printf("InterruptWait_r failed with error %d \n",status);
		break;
	} 

	printf("Got GPIO%d interrupt\n", gpio_number );
	InterruptUnmask(irq, interrupt_id);
}

InterruptDetach(interrupt_id);

3.4 通知实现

3.4.1 通知方法

  • SIGEV_INTR/InterruptWait()
    • 最简单也最快速
    • 必须在一个线程里
    • 队列里元素只有有1个
  • Pulse
    • 可以在多线程下等待接收channel上的消息
    • 可以队列化
    • 最灵活
  • Signal
    • 如果使用signal handler,那将是开销最大的方案
    • 可以队列化

3.4.2 Pulse案例

  • InterruptAttach 操作实现handler: //伪代码如下
#define INTR_PULSE _PULSE_CODE_MINAVAIL
struct sigevent event;

const struct sigevent* handler(void *area,int id){
  // do work
  return (&event); // wake up main thread
}

int main(){
  chid = ChannelCreate(0);
  coid = ConnectAttach(ND_LOCAL_NODE,0,chid,_NTO_SIDE_CHANNEL,0);
  SIGEV_PULSE_INIT(&event,coid,MyPriority,INTR_PULSE,0);
  InterruptAttach(intnum, handler,NULL,0,_NTO_INTR_FLAGS_TRK_MSK);
  for(;;){
    rcvid = MsgReceive(chid,...);
    if(rcvid == 0){
      // got a pulse
    }
  }
  return 0;
}
  • 使用ionotify :  //伪代码如下
if (-1 != (fd = open(“/dev/gpio/tlmm/38”, O_RDWR))) {
	chid = ChannelCreate( 0 );
	coid = ConnectAttach( 0, 0, chid, _NTO_SIDE_CHANNEL, 0 );
	SIGEV_PULSE_INIT(&event, coid, SIGEV_PULSE_PRIO_INHERIT,
	QCGPIO_TEST_CODE, 0);
	LOG("qcgpio_test : calling ionotify\n");
	rtn = ionotify(fd, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT, &event);
	rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL);
	if (rcvid != 0) {
		LOG("qcgpio_test : invalid pulse received\n");
	} else {
		LOG("qcgpio_test : Hurray..! pulse received.\n");
	}
}

4. 实操

测试demo:qnx_ap/AMSS\platform\services\applications\tlmm_gpio_interrupt_test.c

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

村里小码农

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值