• 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/接口

    1. extern int InterruptHookTrace(const struct sigevent *(*__handler)(int), unsigned __flags);
    2. extern int InterruptHookIdle(void (*__handler)(_Uint64t *, struct qtime_entry *), unsigned __flags);
    3. extern int InterruptHookIdle2(void (*__handler)(unsigned, struct syspage_entry *, struct _idle_hook *), unsigned __flags);
    4. extern int InterruptHookOverdriveEvent(const struct sigevent *__event, unsigned __flags);
    5. extern int InterruptAttachEvent(int __intr, const struct sigevent *__event, unsigned __flags);
    6. extern int InterruptAttachEvent_r(int __intr, const struct sigevent *__event, unsigned __flags);
    7. extern int InterruptAttach(int __intr, const struct sigevent *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
    8. extern int InterruptAttach_r(int __intr, const struct sigevent *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
    9. extern int InterruptAttachArray(int __intr, const struct sigevent * const *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
    10. extern int InterruptAttachArray_r(int __intr, const struct sigevent * const *(*__handler)(void *__area, int __id), const void *__area, int __size, unsigned __flags);
    11. extern int InterruptDetach(int __id);
    12. extern int InterruptDetach_r(int __id);
    13. extern int InterruptWait(int __flags, const _Uint64t *__timeout);
    14. extern int InterruptWait_r(int __flags, const _Uint64t *__timeout);
    15. extern int InterruptCharacteristic(int __type, int __id, unsigned *__new, unsigned *__old);
    16. extern int InterruptCharacteristic_r(int __type, int __id, unsigned *__new, unsigned *__old);
    17. extern void InterruptEnable(void);
    18. extern void InterruptDisable(void);
    19. extern int InterruptMask(int __intr, int __id);
    20. extern int InterruptUnmask(int __intr, int __id);
    21. extern void InterruptLock(struct intrspin * __spin);
    22. extern void InterruptUnlock(struct intrspin * __spin);
    23. extern unsigned InterruptStatus(void);

     常用配置接口:

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

    3. 步骤

    3.1 I/O权限

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

     3.2 中断IO配置

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

    1. // Set up edge detection of pin
    2. if(GPIO_FAIL == gpio_set_interrupt_cfg(fd,gpio_number,trigger,NULL))
    3. {
    4. printf("Failed to setup detect pin interrupt \n");
    5. goto exit_err;
    6. }
    7. if(GPIO_FAIL == (status = gpio_get_interrupt_cfg(fd,gpio_number,&irq)))
    8. {
    9. printf("Failed to get irq corresponding to gpio %d \n",gpio_number);
    10. goto exit_err;
    11. }
    12. else
    13. {
    14. if (irq == -1)
    15. {
    16. printf(" irq corresponding to gpio %d is %d status %d - exiting\n",gpio_number,irq, status);
    17. goto exit_err;
    18. }
    19. printf(" irq corresponding to gpio %d is %d status %d\n",gpio_number,irq, status);
    20. }

     3.3 中断实现

    1. // Attach Event ISR
    2. SIGEV_INTR_INIT(&int_event);
    3. interrupt_id = InterruptAttachEvent(irq, &int_event, _NTO_INTR_FLAGS_TRK_MSK);
    4. printf("Wakeup setup successfully completed and now wait for interrupt \n");
    5. while ( 1 ) {
    6. // Wait for interrupt
    7. status = InterruptWait_r(0, NULL );
    8. if (status != EOK)
    9. {
    10. printf("InterruptWait_r failed with error %d \n",status);
    11. break;
    12. }
    13. printf("Got GPIO%d interrupt\n", gpio_number );
    14. InterruptUnmask(irq, interrupt_id);
    15. }
    16. InterruptDetach(interrupt_id);

    3.4 通知实现

    3.4.1 通知方法

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

    3.4.2 Pulse案例

    • InterruptAttach 操作实现handler: //伪代码如下
    1. #define INTR_PULSE _PULSE_CODE_MINAVAIL
    2. struct sigevent event;
    3. const struct sigevent* handler(void *area,int id){
    4. // do work
    5. return (&event); // wake up main thread
    6. }
    7. int main(){
    8. chid = ChannelCreate(0);
    9. coid = ConnectAttach(ND_LOCAL_NODE,0,chid,_NTO_SIDE_CHANNEL,0);
    10. SIGEV_PULSE_INIT(&event,coid,MyPriority,INTR_PULSE,0);
    11. InterruptAttach(intnum, handler,NULL,0,_NTO_INTR_FLAGS_TRK_MSK);
    12. for(;;){
    13. rcvid = MsgReceive(chid,...);
    14. if(rcvid == 0){
    15. // got a pulse
    16. }
    17. }
    18. return 0;
    19. }
    • 使用ionotify :  //伪代码如下
    1. if (-1 != (fd = open(“/dev/gpio/tlmm/38”, O_RDWR))) {
    2. chid = ChannelCreate( 0 );
    3. coid = ConnectAttach( 0, 0, chid, _NTO_SIDE_CHANNEL, 0 );
    4. SIGEV_PULSE_INIT(&event, coid, SIGEV_PULSE_PRIO_INHERIT,
    5. QCGPIO_TEST_CODE, 0);
    6. LOG("qcgpio_test : calling ionotify\n");
    7. rtn = ionotify(fd, _NOTIFY_ACTION_POLLARM, _NOTIFY_COND_INPUT, &event);
    8. rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL);
    9. if (rcvid != 0) {
    10. LOG("qcgpio_test : invalid pulse received\n");
    11. } else {
    12. LOG("qcgpio_test : Hurray..! pulse received.\n");
    13. }
    14. }

    4. 实操

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

  • 相关阅读:
    Qt QtCreator打开pro项目时出现假死现象
    亘古难题——前端开发or后端开发
    【React】 第九部分 react 路由
    操作系统复习(二):内存管理
    JavaScript奇淫技巧:清理无效的垃圾代码
    3.Pandas高级函数应用
    用Wireshark在本机环回接口上抓包
    统计假设检验
    OpenGL环境搭建
    深度学习 二:COVID 19 Cases Prediction (Regression)
  • 原文地址:https://blog.csdn.net/liaochaoyun/article/details/127585172