历史上的今天
返回首页

历史上的今天

今天是:2025年02月11日(星期二)

正在发生

2020年02月11日 | 基于设备树的TQ2440的中断(1)

2020-02-11 来源:eefocus

一、基础知识

关于这部分请参考S3C2440的芯片手册或者博文TQ2440中断系统

下面简单介绍:

从图中可以看到,中断主要分为两级,我们可以理解为是两个中断控制器的嵌套或者级联。S3C2440总共支持60个中断源,包含了主中断源和子中断源。

寄存器功能介绍:

1、SRCPND 地址: 0x4A000000 功能:每一位代表一个主中断,置1表示有对应的主中断请求,对应位写入1可以清除中断

2、INTMOD 地址: 0x4A000004 功能:设置对应的主中断为IRQ还是FIQ, 置1表示FIQ

3、INTMSK 地址: 0x4A000008 功能:置1表示对应的主中断被屏蔽(不会影响SRCPND)

4、INTPND 地址: 0x4A000010 功能:表示对应的主中断被request,只可能有一位被置位,写入1可以清除中断

5、INTOFFSET 地址:0x4A000014 功能:存放的是发生中断请求的主中断号

6、SUBSRCPND 地址:0x4A000018 功能:每一位代表一个子中断,置一表示对应子中断请求,对应位写入1清除子中断请求

7、INTSUBMSK 地址:0x4A00001C 功能:置1表示对应的子中断被屏蔽

32个主中断:

图一

15个子中断:

图二

 

图三

外部中断:

EINT0~7对应的GPIO是GPF0~7

EINT8~23对应的GPIO是GPG0~15

二、设备树

1、中断控制器

intc:interrupt-controller@4a000000 {

compatible = "samsung,s3c2410-irq";

reg =

interrupt-controller;

#interrupt-cells =

};


2、引用


serial@50000000 {

compatible = "samsung,s3c2440-uart";

reg =

interrupts =

status = "okay";

clock-names = "uart";

clocks =

pinctrl-names = "default";

pinctrl-0 =

};

 

i2c:i2c@54000000 {

compatible = "samsung,s3c2410-i2c";

reg =

interrupts =

#address-cells =

#size-cells =

};


上面的serial和i2c设备比较典型,一个引用的是主中断,另一个引用的是子中断。从中断控制器的#interrupt-cells属性知道,要描述一个中断需要四个参数,每一个参数的含义需要由中断控制器的驱动来解释,具体是有中断控制器的irq_domain_ops中的xlate来解释,对于s3c2440就是drivers/irqchip/irq-s3c24xx.c中的s3c24xx_irq_xlate_of。

 1 /* Translate our of irq notation

 2  * format:

 3  */

 4 static int s3c24xx_irq_xlate_of(struct irq_domain *d, struct device_node *n,

 5             const u32 *intspec, unsigned int intsize,

 6             irq_hw_number_t *out_hwirq, unsigned int *out_type)

 7 {

 8     struct s3c_irq_intc *intc;

 9     struct s3c_irq_intc *parent_intc;

10     struct s3c_irq_data *irq_data;

11     struct s3c_irq_data *parent_irq_data;

12     int irqno;

13 

14     if (WARN_ON(intsize < 4))  //如果参数个数不能小于4

15         return -EINVAL;

16         // 从这里知道,第一个参数不能大于2,只能是0和1, 0表示主中断,2表示子中断

17     if (intspec[0] > 2 || !s3c_intc[intspec[0]]) {

18         pr_err("controller number %d invalidn", intspec[0]);

19         return -EINVAL;

20     }

21         // s3c_intc[0]表示主中断控制器,s3c_intc[1]表示子中断控制器

22     intc = s3c_intc[intspec[0]];

23 

24         // 第三个参数表示的是硬件中断号,从这里知道,主中断的硬件中断是0~31,子中断的硬件中断是32及其以上

25     *out_hwirq = intspec[0] * 32 + intspec[2];

26         // 第四个参数表示的是中断类型,可以查看IRQ_TYPE_SENSE_MASK定义,就知道含义:

27         // 1表示上升沿触发,2表示下降沿触发,3表示双边沿触发,4表示高电平触发,8表示低电平触发,12表示高低电平触发

28     *out_type = intspec[3] & IRQ_TYPE_SENSE_MASK;

29         // 如果是主中断,则intc->parent为NULL, 否则非空

30     parent_intc = intc->parent;

31     if (parent_intc) {  // 子中断

32         irq_data = &intc->irqs[intspec[2]];

33                 // 对于子中断,第二个参数才有意义,表示该子中断所隶属的主中断的硬件中断号

34         irq_data->parent_irq = intspec[1];

35         parent_irq_data = &parent_intc->irqs[irq_data->parent_irq];

36         parent_irq_data->sub_intc = intc;

37                 // sub_bits中记录该主中断下的子中断被被使用的情况

38         parent_irq_data->sub_bits |= (1UL << intspec[2]);

39                 // 将主中断号映射成虚拟中断号

40         /* parent_intc is always s3c_intc[0], so no offset */

41         irqno = irq_create_mapping(parent_intc->domain, intspec[1]);

42         if (irqno < 0) {

43             pr_err("irq: could not map parent interruptn");

44             return irqno;

45         }

46                 // 这里设置irqno对应的irq_desc的handle_irq为s3c_irq_demux

47                 // 从函数名称中就可以看出, 这个函数会再次进行检测该主中断的哪个子中断被请求

48         irq_set_chained_handler(irqno, s3c_irq_demux);

49     }

50 

51     return 0;

52 }

从这里我们知道,interrupts属性中的四个参数中的含义:


以串口的




三、中断控制器驱动

中断控制器驱动:drivers/irqchip/irq-s3c24xx.c

初始化入口:

 1 static struct s3c24xx_irq_of_ctrl s3c2410_ctrl[] = {

 2     { // 主中断

 3         .name = "intc",

 4         .offset = 0,

 5     }, { // 子中断

 6         .name = "subintc",

 7         .offset = 0x18,  // 寄存器地址偏移

 8         .parent = &s3c_intc[0],

 9     }

10 };

11 

12 int __init s3c2410_init_intc_of(struct device_node *np,

13             struct device_node *interrupt_parent)

14 {

15     return s3c_init_intc_of(np, interrupt_parent,

16                 s3c2410_ctrl, ARRAY_SIZE(s3c2410_ctrl));

17 }

18 IRQCHIP_DECLARE(s3c2410_irq, "samsung,s3c2410-irq", s3c2410_init_intc_of);

在内核启动的时候,函数s3c2410_init_intc_of会被调用。


下面我们分析函数s3c_init_intc_of:

 1 static int __init s3c_init_intc_of(struct device_node *np,

 2             struct device_node *interrupt_parent,

 3             struct s3c24xx_irq_of_ctrl *s3c_ctrl, int num_ctrl)

 4 {

 5     struct s3c_irq_intc *intc;

 6     struct s3c24xx_irq_of_ctrl *ctrl;

 7     struct irq_domain *domain;

 8     void __iomem *reg_base;

 9     int i;

10 

11         // 对中断控制器的reg属性所表示地址空间进行映射

12     reg_base = of_iomap(np, 0);

13         

14         // 为该中断控制器创建irq_domain,一共支持64个中断,对应的irq_domain_ops是s3c24xx_irq_ops_of

15     domain = irq_domain_add_linear(np, num_ctrl * 32,

16                              &s3c24xx_irq_ops_of, NULL);

17         // 依次处理两个中断控制器

18     for (i = 0; i < num_ctrl; i++) {

19         ctrl = &s3c_ctrl[i];

20 

21         pr_debug("irq: found controller %sn", ctrl->name);

22                 // 主和子中断控制器各分配一个s3c_irq_intc

23         intc = kzalloc(sizeof(struct s3c_irq_intc), GFP_KERNEL);

24                 // 主和子中断控制器共享一个irq_domain

25         intc->domain = domain;

26                 // 为主和子中断控制器下的每个中断各分配一个s3c_irq_data结构体

27         intc->irqs = kzalloc(sizeof(struct s3c_irq_data) * 32,

28                      GFP_KERNEL);

29 

30         if (ctrl->parent) {  // 子中断控制器

31             intc->reg_pending = reg_base + ctrl->offset; // SUBSRCPND

32             intc->reg_mask = reg_base + ctrl->offset + 0x4; // INTSUBMSK

33                         

34                         // 由于先处理的是s3c2410_ctrl[0],所以在处理子中断的时候,*(ctrl->parent)非空

35                         // 是主中断控制器对应的s3c_irq_intc

36             if (*(ctrl->parent)) {

37                 intc->parent = *(ctrl->parent);

38             } else {

39                 pr_warn("irq: parent of %s missingn",

40                     ctrl->name);

41                 kfree(intc->irqs);

42                 kfree(intc);

43                 continue;

44             }

45         } else {  // 主中断控制器

46             intc->reg_pending = reg_base + ctrl->offset;  //SRCPND

47             intc->reg_mask = reg_base + ctrl->offset + 0x08; //INTMSK

48             intc->reg_intpnd = reg_base + ctrl->offset + 0x10; //INTPND

49         }

50 

51         s3c24xx_clear_intc(intc);  // 清除中断

52         s3c_intc[i] = intc;

53     }

54         // 将handle_arch_irq设置为s3c24xx_handle_irq, 这样在发生中断后,会从汇编entry-armv.S中

55         // 调转到s3c24xx_handle_irq

56     set_handle_irq(s3c24xx_handle_irq);

57 

58     return 0;

59 }

中断控制启动的初始化,结构体s3c24xx_irq_ops_of中的map和xlate还没有分析,放到下面分析。


四、interrupts属性的解析

在内核启动期间解析设备树,将device_node转换为platform_device的时候会处理节点中的interrupts属性,将其转换为irq resource,同时在所属的irq domain中建立起hwirq到virq的映射,下面列出主要的函数调用,期间就会调用上面中断控制器的irq_domain的s3c24xx_irq_ops_of中的xlate和map:

推荐阅读

史海拾趣

FTCAP Fischer & Tausche Capacitor Group公司的发展小趣事

FTCAP Fischer & Tausche Capacitor Group公司的发展故事

故事一:德国制造的坚持

FTCAP Fischer & Tausche Capacitor Group自成立以来,始终坚守在德国本土进行电容器的生产和研发。这一决策源于公司对产品质量的不懈追求。在电子行业,德国制造以其精湛的工艺和严格的质量控制而闻名,FTCAP也不例外。通过缩短研发与生产之间的距离,FTCAP能够确保高效的生产流程和与客户的紧密协作,从而快速响应市场需求,提供高质量的产品。

故事二:多样化的产品线

FTCAP的产品线涵盖了从薄膜电容器到铝电解电容器的广泛范围,满足了不同行业对电容器的多样化需求。公司不仅生产标准规格的电容器,还根据客户的特定需求提供定制化的解决方案。这种灵活性和创新性使得FTCAP在竞争激烈的电子市场中脱颖而出,赢得了众多客户的信赖和好评。

故事三:技术创新与产品升级

近年来,FTCAP不断投入资源进行技术创新和产品升级。例如,公司推出的Enlight Energy Cap系列薄膜电容器,经过重新设计后,不仅性能更加优越,还增加了“Enlight”这一附加属性,进一步提升了产品的市场竞争力。此外,FTCAP还致力于提高电容器的能效和可靠性,以满足日益严格的环保和能效标准。

故事四:行业内的替代解决方案

凭借超过70年的电容器研发和生产经验,FTCAP在行业内建立了良好的声誉。当一些客户面临竞争对手产品无法满足其需求时,FTCAP能够提供定制化的电容器作为替代解决方案。这些定制产品不仅性能优越,而且能够完美匹配客户的设备和应用场景,帮助客户解决燃眉之急。

故事五:团队建设与企业文化

FTCAP的成功离不开其优秀的团队和独特的企业文化。公司注重员工的培训和发展,鼓励员工创新思维和团队合作。在FTCAP,员工们不仅拥有专业的技能和知识,还具备高度的责任感和使命感。他们共同努力,为公司的发展贡献自己的力量。此外,FTCAP还定期举办各种团建活动,增强员工之间的凝聚力和归属感,营造了一个和谐、积极的工作氛围。

ERP公司的发展小趣事

在21世纪初,一家名为“电子智链”的ERP公司在中国电子行业崭露头角。创始人李明是一位资深电子工程师,他意识到电子企业面临的管理挑战和数字化转型的机遇。电子智链初期专注于为中小型电子企业提供定制化的ERP解决方案,帮助企业优化供应链管理、生产计划和财务管理。通过不断创新和积累客户反馈,电子智链逐渐在电子行业树立了良好的口碑。

Diode Laser Concepts公司的发展小趣事

为了拓展更广阔的市场,Diode Laser Concepts公司开始实施国际化战略。公司先是在亚洲和欧洲设立了办事处,随后又在美国等地建立了生产基地。通过与国际知名企业的合作,公司不仅将产品销售到了全球各地,还积累了丰富的国际经验,提升了品牌影响力。

Concurrent Logic公司的发展小趣事

随着技术的不断进步,Concurrent Logic成功开发出了一款具有革命性的并行计算芯片。这款芯片在市场上引起了巨大的反响,因其出色的并行处理能力和高效的逻辑运算,很快得到了众多电子设备和数据中心的青睐。这一技术的突破不仅为公司带来了可观的收入,更让Concurrent Logic在电子行业中崭露头角。

Hong Kong X'Tals Ltd公司的发展小趣事
选择合适的电阻和电容,以确保定时精度和电路稳定性。同时,注意元件的温漂和老化对定时时间的影响。
CEVA, Inc公司的发展小趣事

CEVA, Inc.最初于1999年11月22日在美国特拉华州注册成立,起初的名称并非CEVA。随着公司的业务扩展和技术积累,其在2002年11月进行了更名,成为ParthusCeva公司。这一更名反映了公司业务的进一步发展和市场定位的调整。随后,在2003年12月,公司再次更名为CEVA公司,这一名称沿用至今,成为无线连接和智能传感技术领域的知名品牌。

问答坊 | AI 解惑

关于IO0PIN指令的疑惑

关于IO0PIN指令的疑惑 最近在调一个键盘程序(LPC2103),用到了IO0PIN读端口指令(据说这是飞利浦系列的BUG),发现这个指令没有手册上说的那么简单呐,直接读是读不出来的。有人说要读一个输入状态的端口,要先把它设为输出,然后置高,最后再设 ...…

查看全部问答>

为什么我的按键中断在程序启动的时候总自动进入

为什么我的按键中断在程序启动的时候总自动进入,不是按下按键以后,而是程序一运行的时候就自动进入中断函数,请问这是什么原因呢?…

查看全部问答>

?哪里有Wince5.0 Pocket PC SDK

微软下载中心验证我的操作系统不是正版下不下来,请哪为高手帮忙?急需非常感谢!!!!…

查看全部问答>

SIM卡费用问题

我以前没接触过GMS,现在正在开发一个项目,需要用到GSM短信。我手头有个GSM模块的资料,但里面没有有关SIM卡剩余话费。请问各位大侠都是怎么解决的?我希望如果话费余额不足能在软件中提前显示出来。…

查看全部问答>

怎样从内存中读取摄像头采集的数据保存成bmp格式

我已经从把摄像头采集的数据保存使用 mmap 内存映射来获取了图像,当用write函数得出的是jpeg格式的 我想得到bmp格式的图片怎么做,跪求,急用。谢谢各位。 …

查看全部问答>

用verilog HDL 实现网络加密算法md5

用verilog HDL 实现一个网络加密的算法(md5),有没有哪位高手能给点帮助,我邮箱是poppy220@126.com 先谢过啦!^_^ …

查看全部问答>

一个很莫名其妙的问题

最近刚刚开始接触STM32,今天调试串口的时候发现一个很无奈的问题,源代码基本都是使用keil自带的demo,就不列举了。修改以下这些设置:/* PLLCLK = 12MHz * 6= 72 MHz */     RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6 ...…

查看全部问答>

STM32rtc有电池,确认起振后是不是就后顾无忧了?

                                 我的问题是如果我有外部电池给RTC供电,只要在厂测试RTC已经工作了后,只要电池有电就不会出现晶振不起振的情况吗 ...…

查看全部问答>

求指导

老师最近给了一个电动汽车电池管理系统(BMS)设计的方向,小弟有一点编程、数电、模电、fpga的基础。也看了一些BMS相关论文的论文,但始终不知道如何着手去做。 求高人指导,比如还应学习什么基础知识之类的…

查看全部问答>

想了想,还是把它出掉好了,STM32+W5100+SPI Flash+TFT,有点给力

这其实不是个开发板,而是个接近完成的产品(接近完成是指研发流程已经走完,但还未能进入市场)但资源比较给力--------------->    STM32ZET6,带外部总线于是可以用总线挂TFT--------------->    W5100,硬件TCP/IP协议 ...…

查看全部问答>