关于ARM2440中断源个数的一点想法转

本文详细解析了S3C2440处理器的中断管理机制,包括内部和外部中断源的屏蔽控制、中断映射及子中断源的概念。通过具体的寄存器配置示例,解释了如何实现精确的中断控制。
S3c2440支持多达40个内部中断源和20个外部中断源,分别使用内部终端屏蔽寄存器INTMSK和外部中断寄存器MSK进行屏蔽控制。其中,外部中断源通过GPIO以复用的方式成为内部中断源的一部分。

但是我们清楚,INTMSK是一个32位的寄存器,最多只能支持32中断,它是如何对应这么多中断的呢?

首先我们先看INTMSK对应的位。
INTERRUPT MASK (INTMSK) REGISTER (Continued)
INT_ADC [31] 0 = Service available, 1 = Masked 1
INT_RTC [30] 0 = Service available, 1 = Masked 1
INT_SPI1 [29] 0 = Service available, 1 = Masked 1
INT_UART0 [28] 0 = Service available, 1 = Masked 1
INT_IIC [27] 0 = Service available, 1 = Masked 1
INT_USBH [26] 0 = Service available, 1 = Masked 1
INT_USBD [25] 0 = Service available, 1 = Masked 1
INT_NFCON [24] 0 = Service available, 1 = Masked 1
INT_UART1 [23] 0 = Service available, 1 = Masked 1
INT_SPI0 [22] 0 = Service available, 1 = Masked 1
INT_SDI [21] 0 = Service available, 1 = Masked 1
INT_DMA3 [20] 0 = Service available, 1 = Masked 1
INT_DMA2 [19] 0 = Service available, 1 = Masked 1
INT_DMA1 [18] 0 = Service available, 1 = Masked 1
INT_DMA0 [17] 0 = Service available, 1 = Masked 1
INT_LCD [16] 0 = Service available, 1 = Masked 1
INT_UART2 [15] 0 = Service available, 1 = Masked 1
INT_TIMER4 [14] 0 = Service available, 1 = Masked 1
INT_TIMER3 [13] 0 = Service available, 1 = Masked 1
INT_TIMER2 [12] 0 = Service available, 1 = Masked 1
INT_TIMER1 [11] 0 = Service available, 1 = Masked 1
INT_TIMER0 [10] 0 = Service available, 1 = Masked 1
INT_WDT_AC97 [9] 0 = Service available, 1 = Masked 1
INT_TICK [8] 0 = Service available, 1 = Masked 1
nBATT_FLT [7] 0 = Service available, 1 = Masked 1
INT_CAM [6] 0 = Service available, 1 = Masked 1
EINT8_23 [5] 0 = Service available, 1 = Masked 1
EINT4_7 [4] 0 = Service available, 1 = Masked 1
EINT3 [3] 0 = Service available, 1 = Masked 1
EINT2 [2] 0 = Service available, 1 = Masked 1
EINT1 [1] 0 = Service available, 1 = Masked 1
EINT0 [0] 0 = Service available, 1 = Masked 1

我们发现INTMSK的第5,6位对应了EINT4_7, EINT8_23,20个外部中断,也就是所,这20个GPIO引脚只能触发这两个中断。
但是当中断到来时,我们如果判断是由哪一个GPIO引脚触发的呢?这个时候我们可以通过查询EINTMASK来判断中断源。
EINTMASK Bit Description
EINT23 [23] 0 = enable interrupt 1= masked
EINT22 [22] 0 = enable interrupt 1= masked
EINT21 [21] 0 = enable interrupt 1= masked
EINT20 [20] 0 = enable interrupt 1= masked
EINT19 [19] 0 = enable interrupt 1= masked
EINT18 [18] 0 = enable interrupt 1= masked
EINT17 [17] 0 = enable interrupt 1= masked
EINT16 [16] 0 = enable interrupt 1= masked
EINT15 [15] 0 = enable interrupt 1= masked
EINT14 [14] 0 = enable interrupt 1= masked
EINT13 [13] 0 = enable interrupt 1= masked
EINT12 [12] 0 = enable interrupt 1= masked
EINT11 [11] 0 = enable interrupt 1= masked
EINT10 [10] 0 = enable interrupt 1= masked
EINT9 [9] 0 = enable interrupt 1= masked
EINT8 [8] 0 = enable interrupt 1= masked
EINT7 [7] 0 = enable interrupt 1= masked
EINT6 [6] 0 = enable interrupt 1= masked
EINT5 [5] 0 = enable interrupt 1= masked
EINT4 [4] 0 = enable interrupt 1= masked
Reserved [3:0] Reserved
但是还有一个疑问,不是说60个中断源吗?除去24个外部中断源应该还有60-24 -(32-6)=10个内部中断源啊。他们在哪呢?

其实这里涉及到了子中断源的概念。
Sub Sources Descriptions Source
INT_AC97 AC97 interrupt             INT_WDT_AC97
INT_WDT Watchdoc interrupt       INT_WDT_AC97
INT_CAM_P P-port capture interrupt in camera interface        INT_CAM
INT_CAM_C C-port capture interrupt in camera interface       INT_CAM
INT_ADC_S ADC interrupt                                                      INT_ADC
INT_TC Touch screen interrupt (pen up/down)                    INT_ADC
INT_ERR2 UART2 error interrupt                                        INT_UART2
INT_TXD2 UART2 transmit interrupt                        INT_UART2
INT_RXD2 UART2 receive interrupt                          INT_UART2
INT_ERR1 UART1 error interrupt                              INT_UART1
INT_TXD1 UART1 transmit interrupt I                        NT_UART1
INT_RXD1 UART1 receive interrupt                           INT_UART1
INT_ERR0 UART0 error interrupt                              INT_UART0
INT_TXD0 UART0 transmit interrupt                         INT_UART0
INT_RXD0 UART0 receive interrupt                          NT_UART0

这里对应了15个子中断源,其实我们明白了 INT_WDT_AC97, INT_CAM, INT_ADC, , INT_UART0, INT_UART1,INT_UART2不能算真正的中断源,真正的中断源应该是那15个中断源,这样中断源的个数就是32 - 6(外部中断) - 6(子中断源) + 24 + 15 = 59, 而并非60。
这是韦东山的相关文档c. 能不能写成文档? 这有点尴尬。 咱也不藏头藏尾了,有话直接说。 去年9月份左右,我们专心录视频,想法很美好。 我们只录视频,同时支持各家IMX6ULL开发板,大家一起把生态做好。 所以你可以看到我们的视频/文档支持野火的IMX6ULL、支持正点原子的IMX6ULL。 但是后来发现不行啊,我录收费视频,他们也录视频还免费。 虽然我自信有10几年功力,但是也挡不住免费啊。 这样下去我得没饭吃,所以我们也做了开发板,还0利润。 这就有很大的竞争关系了。 所以,我们的视频、文档是否继续支持同行的板子? 看似难以决定,想清楚后就不难了。 我们会继续支持各家的板子,不能因为会给同行带来好处就废弃承诺。 我们的裸板+同行的LCD,这是避免浪费的好事,不能因为会给我们引流而避讳。 2. 移植思路 LCD除了显示之外,它的表面通常还贴有一个触摸屏。 所以我们移植的是2个设备的驱动:LCD、触摸屏。 LCD驱动在内核中已经有了,并且很完善,我们只需要修改设备树就可以:修改时序等LCD参数,修改背光引脚等板子参数。 触摸屏的驱动在内核中一般也有了,各厂家用的触摸屏IC可能不同。需要配置内核把它加进去,同时修改设备树:指定触摸IC的信息(比如I2C地址),指定中断引脚。 如果能拿到这块LCD在别的板子上的内核源码,就可以参考它的LCD参数、触摸IC信息。 再结合你用的开发板,把涉及的GPIO找出来写入设备树。 简单吧? 开工! 3. 移植LCD驱动 注意:100ASK_IMX6ULL不能直接连接其他厂家的屏,需要接板。 IMX6ULL跟LCD的连接框图如下: IMX6ULL内部有LCD控制器,肯定是厂家对这个LCD控制器最熟悉了,所以他们为了卖芯片,一般都会在内核中做好LCD控制器的驱动程序。 而IMX6ULL可以接各种LCD,这些LCD参数各有不同。LCD控制器的驱动程序会去设备树中获得这些参数,并根据这些参数来设置LCD控制器。 所以,我们要做的事情从理论上讲很简单:根据LCD参数修改设备树。 但是,谁说厂家的驱动就没有BUG,就完美无缺了? 我们要做的事有3项:确定LCD参数,修改设备树,完善驱动。 3.1 确定LCD参数 如果还保留有LCD的芯片手册,这是最好的。可惜我碰到的大多学员早已经忘记这些资料在哪了。 野火的屏在板子背后直接写明分辨率是多少,这比较简单直接。 正点原子的屏在背后画有一个表格,如下: 上图例子中,M2、M1接地,M0接电源,所以M2M1M0为001;对比表格可知它的分辨率为800x480。 如果是从零开发,我们还需要找到芯片手册确定LCD的详细时序。 我们没有LCD的手册,即使有也懒得看。 直接看厂家的源码不就行了?直接点,直接看它的设备树不就行了? 找到LCD厂家的IMX6ULL内核源码,执行以下命令: $ cd arch/arm/boot/dts/ $ ls *imx6ull*.dts 结果如下: 可以找到2个设备树文件,我们只关心里面的LCD信息,打开任意一个看看: 3.2 修改设备树 100ASK_IMX6ULL用的内核版本是4.9.88,版本高一点,但是IMX6ULL设备树的写法完全一样。 设备树文件是arch/arm/boot/dts/100ask_imx6ull-14x14.dts,替换下图红框部分: 修改好设备树后,就可以编译了。 为方便你们操作,下面贴出编译命令,假设你已经位于我们提供的内核源码目录中: 新编译好的设备树文件为:arch/arm/boot/dts/100ask_imx6ull-14x14.dtb。 怎么更新设备树?请看我们的开发板使用手册。 更新设备树后,重启板子观察效果。 3.3 完善驱动 使用新的设备树启动板子后,你会发现一个神奇的现象:LCD有时候有显示,有时候没有,不断地冷启动偶尔会有显示。 如果你经验丰富,可以判断这是复位问题。 为验证是否复位问题,我们可以执行命令手工发出复位信号,先确定LCD复位引脚是哪个GPIO: 从上图可以确定LCD的复位引脚用到GPIO3_IO04,那我们可以使用GPIO子系统来验证。 执行某些命令让GPIO输出低电平,再输出高电平,这样就可以复位LCD了。 3.3.1 使用GPIO子系统复位LCD GPIO3_IO04在GPIO子系统中编号为:(3-1)*32+4=68,它是第68号GPIO。 板子进入Linux后,执行以下命令: $ fb-test // LCD上应该显示红绿蓝色块 $ echo 68 > /sys/class/gpio/export // 导出68号GPIO $ echo out > /sys/class/gpio/gpio68/direction // 设置为输出引脚 $ echo 0 > /sys/class/gpio/gpio68/value // 让它输出0 $ echo 1 > /sys/class/gpio/gpio68/value // 让它输出1 $ echo 68 > /sys/class/gpio/unexport // unexport 你会发现一旦执行上述命令,LCD立刻就有显示了。 所以,LCD驱动不完善,应该加上复位信号。 3.3.2 修改设备树:指定复位引脚 设备树文件为:arch/arm/boot/dts/100ask_imx6ull-14x14.dts 如下图修改: 把添加的代码写出来: reset-gpios = <&gpio3 4 GPIO_ACTIVE_LOW>; /* 100ask */ 3.3.3 修改驱动:复位LCD LCD驱动程序是哪个? 在Linux内核源码目录下执行命令: $ ls drivers/video/fbdev/*.o drivers/video/fbdev/built-in.o drivers/video/fbdev/mx3fb.o drivers/video/fbdev/mxsfb.o 发现有2个.o文件:mx3fb.o、mxsfb.o。我们是imx6ull,应该是后者。 我们在mxsfb.c中mxsfb_probe函数的后面添加复位代码,如下图修改: 为了方便读者复制代码,我把添加的代码写出来(在mxsfb.c中mxsfb_probe函数的后面添加复位代码,): /* 100ask */ printk("100ask, %s %s %d\n", __FILE__, __FUNCTION__, __LINE__); rst_gpio = of_get_named_gpio(pdev->dev.of_node, "reset-gpios", 0); if (gpio_is_valid(rst_gpio)) { ret = gpio_request(rst_gpio, "lcdif_rst"); if (ret < 0) { dev_err(&pdev->dev, "Failed to request GPIO:%d, ERRNO:%d\n", (s32)rst_gpio, ret); } else { gpio_direction_output(rst_gpio, 0); msleep(2); gpio_direction_output(rst_gpio, 1); dev_info(&pdev->dev, "Success seset LCDIF\n"); } } 修改完后,重新编译得到zImage和100ask_imx6ull-14x14.dtb,更新开发板,重启,完美! 4. 移植触摸屏驱动 4.1 确定触摸屏型号 还是那句话,如果有触摸屏数据手册,看手册就好了。 如果没有手册,怎么办? 触摸屏的主控芯片一般都是I2C接口的,那么我们可以把屏接到板子上,用i2cdetect检测出I2C设备的地址,根据地址就可以知道它的型号。 注意:100ASK_IMX6ULL不能直接连接其他厂家的屏,需要接板。 接上屏幕后,启动开发板进入Linux,执行如下命令: [root@imx6ull:~]# i2cdetect -y 1 命令解析:“-y”表示 Disable interactive mode,简单地说就是“别让我确认了,赶紧执行”;“1”表示I2C总线1(从0开始)。 结果如下: 上图中, “--”表示没有这个地址对应的I2C设备; “UU”表示这个地址的I2C设备已经有驱动在使用占用它了,那这个I2C设备肯定是存在的; 其他数值表示该地址对应的I2C设备是存在的,并且还没有驱动程序跟它匹配。 根据上图,我们可以知道0x38就是触摸屏设备,为什么!为什么不是0x60?你可以把屏幕取下,再重新执行命令,就可以看到“38”消失了。 根据0x38,我们得找到对应的芯片型号,怎么找?去内核设备树目录里找。 $ cd arch/arm/boot/dts/ $ grep "@38" * -nR 可以得到很多结果,比如: 地址为0x38的I2C芯片有不少,比如HDMI PHY,还有ft5306、ft5x06。你在百度搜一下“ft5306”,它确实就是触摸屏芯片。所以这款触摸屏的主控芯片就是ft5x06。x表示某些数字,可能有多个型号,我们暂时没不用去细分。 4.2 在设备树中指定触摸IC信息 IMX6ULL跟触摸IC的连接图如下: 所以,我们要确定的信息是: a. 它接在哪个I2C控制器上? b. 它的I2C地址是? c. 复位引脚使用哪个GPIO?低电平有效还是高电平有效? d. 中断引脚使用哪个GPIO?低电平有效还是高电平有效? 不知道怎么写?没关系,参考! a. 对于ft5x06,设备树节点中有哪些内容? b. 那些内容怎么适配100ASM_IMX6ULL板子?即怎么改成100ASK_IMX6ULL所用的GPIO引脚 前面说过,根据I2C设备的地址0x38,执行如下命令: $ cd arch/arm/boot/dts/ $ grep "@38" * -nR 我们可以得到很多结果,打开跟imx6ull最相近的imx6ul-tx6ul.dtsi,可以看到如下代码: 我们把这个结点的内容先复制下来,粘贴到哪里去? 100ASK_IMX6ULL也配有触摸屏,我们用的型号是gt9xx,把这个结点放到gt9xx结点相同位置去就可以了,如下图所示: 100ASK_IMX6ULL接标配的LCD时,触摸IC是gt9xx,用的引脚假设是 AAA; 那么同一个底板接上另一块LCD时,虽然触摸IC型号不同,但是它仍然用的是同一个引脚AAA。 所以,新加的节点,其内容可以参考gt9xx节点的内容。 下图就是改好的样子: 重新编译设备树,更新到板子上,发现触摸屏还是不能用。 这还得往内核里加驱动。 4.3 重新配置内核添加驱动 这设备节点对应哪个驱动啊?它有这个属性: compatible = "edt,edt-ft5x06" 在内核drivers/input/touchscreen目录下搜搜"edt,edt-ft5x06": $ cd drivers/input/touchscreen/ $ grep "edt,edt-ft5x06" * -nr 什么都没搜到,再搜“edt-ft5x06”: $ grep "edt-ft5x06" * -nr edt-ft5x06.c:1071: { .name = "edt-ft5x06", .driver_data = (long)&edt_ft5x06_data }, Kconfig:667: module will be called edt-ft5x06. Makefile:31:obj-$(CONFIG_TOUCHSCREEN_EDT_FT5X06) += edt-ft5x06.o 显然,驱动程序是edt-ft5x06.c,内核配置项是CONFIG_TOUCHSCREEN_EDT_FT5X06。 我们需要配置内核,把CONFIG_TOUCHSCREEN_EDT_FT5X06配置为y。 在内核目录下执行“make menuconfig”,然后搜“CONFIG_TOUCHSCREEN_EDT_FT5X06”: 在菜单里找到它,把它配置为y,如下图: 重新编译内核zImage,更新到板子上,启动。 发现触摸屏有反应,但是点不准,还得调试。 4.4 调试:找出问题 Tslib是触摸屏的库,自带有很多工具: a. ts_print_raw :打印触摸屏原始数据 b. ts_print :打印经过较准的数据 c. ts_test_mt:测试电容屏,点击触摸屏,同时就会在LCD上显示触点位置。 我们先把系统自带的QT系统去掉,在开发板执行: # mv /etc/init.d/S07hmi /root/ # reboot 然后设置环境变量,执行ts_test_mt: export TSLIB_TSDEVICE=/dev/input/event1 export TSLIB_CONFFILE=/etc/ts.conf export TSLIB_CALIBFILE=/etc/pointercal export TSLIB_PLUGINDIR=/usr/lib/ts ts_test_mt 可以在LCD屏幕上看到提示,你点击某个位置,正常的话在该位置就会显示一个标号。 我们发现有意思的现象:从左往右点,标号从上边移动到下边;从上往下点,标号从左边移动到右边。 猜测:XY坐标对调了。 再试一下,执行 ts_print_raw,然后从左往右点,现象如下: 从左往右点,x坐标应该发生变化,y坐标保持不变;但是从上图看来,这是相反的。 所以,确实是xy坐标对调了。 4.5 解决方法 可以从应用层面(比如修改设备树)解决,也可以从驱动层面(比如修改配置文件/etc/ts.conf)解决,二种方法任选其一,不要同时做。 4.5.1 修改/etc/ts.conf 如下图加上xyswap就可以了: 4.5.2 修改设备树 有时候我们并不愿意、不能修改应用层的东西,那可以修改设备树: 4.6 其他情况 100ASK_IMX6ULL标配的屏,带的触摸IC是gt9xx;但是我们发现别家的LCD即使同样使用gt9xx,但是它的xy值是反的。 什么意思呢? 你从左往右点,正常来说x值是从小变大,但是有些屏是从大变小。 你从上往下点,正常来说y值是从小变大,但是有些屏是从大变小。 这时候,你同样可以修改设备树,或是修改/etc/ts.conf。 怎么修改设备树? 参考内核文档:Documentation/devicetree/bindings/input/touchscreen,该目录下有很多I2C触摸芯片的设备树说明,比如有goodix.txt,对应gt9xx芯片;有edt-ft5x06.txt。 要让x反,或是y反,在设备节点中加入这样的属性值就可以: touchscreen-inverted-x = <1>; touchscreen-inverted-y = <1>; 有时为了测试方便,就是想临时改一下/etc/ts.conf,怎么做? 这个文件本身是有些注释的,可以参考: “x0=1024”的意思就是:x坐标,0表示1024; “y0=600”的意思是:y坐标,0表示600。 4.7 gt9xx芯片固件更新 gt9xx芯片功能强大,可以写入配置信息让它支持不同分辨率的触摸屏。 但是出厂的触摸屏IC一般都已经写好配置信息了,我们不应该让驱动程序去修改这些配置信息。 可以在设备树中加上这一句,禁止驱动去修改配置信息: goodix,driver-send-cfg = <0>; 这是我们调试过程中碰到的一个坑。
最新发布
08-05
### 3.1 修改设备树以适配4.3寸LCD 在适配 4.3 寸 LCD 屏幕时,首先需要修改设备树源文件(.dts),以匹配其分辨率和时序参数。通常,设备树文件位于内核源码目录下的 `arch/arm/boot/dts/` 路径中。例如,编辑 `imx6ull-100ask.dts` 文件: ```bash vim arch/arm/boot/dts/imx6ull-100ask.dts ``` 在文件中找到 LCD 控制器节点(通常是 `lcdif`),并修改其中的 `display-timings` 节点,以适配 4.3 寸屏幕的分辨率(480x272)和时序参数: ```dts display-timings { native-mode = "timing0"; timing0: timing0 { clock-frequency = <9200000>; hactive = <480>; vactive = <272>; hfront-porch = <8>; hback-porch = <4>; hsync-len = <41>; vfront-porch = <4>; vback-porch = <2>; vsync-len = <10>; hsync-active = <0>; vsync-active = <0>; de-active = <1>; pixelclk-active = <0>; }; }; ``` 保存并退出编辑器后,重新编译设备树: ```bash make dtbs ``` ### 3.2 编译并烧录新的内核镜像和设备树 编译内核镜像: ```bash make zImage ``` 将新生成的 `zImage` 和 `.dtb` 文件拷贝到 TFTP 或 SD 卡中的启动分区,并更新启动配置,使系统加载新的设备树。 例如,在 U-Boot 中设置启动命令: ```bash setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1 rw rootwait fbcon=rotate=1' setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-100ask.dtb; bootz 80800000 - 83000000' ``` ### 3.3 测试LCD显示 进入系统后,可以使用 `fb-test` 工具测试 LCD 是否正常显示颜色块: ```bash fb-test ``` 如果一切正常,LCD 屏幕上应显示红绿蓝色块[^1]。 ### 3.4 调整屏幕旋方向(可选) 如果屏幕方向不正确,可以通过修改 `bootargs` 添加 `fbcon=rotate=1` 来旋屏幕: ```bash setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1 rw rootwait fbcon=rotate=1' ``` 支持的旋值如下: - `rotate=0`:正常方向 - `rotate=1`:顺时针旋 90 度 - `rotate=2`:旋 180 度 - `rotate=3`:逆时针旋 90 度 ### 3.5 使用 tslib 校准触摸屏(如果使用带触摸的4.3寸屏) 安装 tslib: ```bash opkg install tslib ``` 校准触摸屏: ```bash ts_calibrate ``` 运行后按照提示完成校准。 ### 3.6 配置QT环境(可选) 如果你希望在 4.3 寸 LCD 上运行 QT 程序,需要确保 QT SDK 已正确配置。可以在 SDK 目录中找到 `qmake` 并设置环境变量: ```bash export PATH=/home/book/100ask_imx6ull-sdk/usr/bin:$PATH qmake -v ``` 然后编译并运行 QT 应用程序。 ### 3.7 GPIO控制背光(可选) 如引用中提到的,可以通过 GPIO 控制背光: ```bash echo 68 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio68/direction echo 0 > /sys/class/gpio/gpio68/value # 关闭背光 echo 1 > /sys/class/gpio/gpio68/value # 打开背光 ``` 完成后可以取消导出: ```bash echo 68 > /sys/class/gpio/unexport ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值