imx6ull gpio 中断

本文使用100ask_imx6ull_mini开发板来做实验,内容参考百问网开发手册

一、整体流程

imx6ull gpio 中断_第1张图片
GPIO 作为中断源,本实验使用KEY1(GPIO5_1)和KEY5(GPIO4_IO14)两个按键作为中断源,主要工作如下:
设置GPIO模块
设置GIC模块
使能各个路径的中断
编写中断函数

二、GPIO模块相关设置

1.设置gpio管脚模式为GPIO模式(alt5),并设置相应上下拉等特性。

     /* KEY1 pins GPIO5_1 SNVS_TAMPER1 */
	IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 0U);
	IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER1_GPIO5_IO01, 
						IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
						IOMUXC_SW_PAD_CTL_PAD_SPEED(2U) |
						IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |
						IOMUXC_SW_PAD_CTL_PAD_HYS_MASK);

	/* KEY2 pins GPIO4_IO14 */
	IOMUXC_SetPinMux(IOMUXC_NAND_CE1_B_GPIO4_IO14, 0U);
	IOMUXC_SetPinConfig(IOMUXC_NAND_CE1_B_GPIO4_IO14, 
						IOMUXC_SW_PAD_CTL_PAD_DSE(6U) |
						IOMUXC_SW_PAD_CTL_PAD_SPEED(2U) |
						IOMUXC_SW_PAD_CTL_PAD_PKE_MASK |
						IOMUXC_SW_PAD_CTL_PAD_HYS_MASK);

2.设置gpio 中断相关寄存器

    使能gpiox的时钟
    CCM->CCGR4 = 0xFFFFFFFFU;
    CCM->CCGR5 = 0xFFFFFFFFU;
    
	设置中断触发类型为双边沿触发
	GPIO5->EDGE_SEL |= (1 << 1);
	/*gpio模块中对应引脚的中断使能 if set 1, unmasked, Interrupt n is enabled */
	GPIO5->IMR |= (1 << 1);
	/* clear interrupt first to avoid unexpected event */
	GPIO5->ISR |= (1 << 1);

	GPIO4->EDGE_SEL |= (1 << 14);
	GPIO4->IMR |= (1 << 14);
	GPIO4->ISR |= (1 << 14);

3.查询GPIO对应的中断号

查询IMX6ULLRM.pdf 手册第三章 可知中断号分别为72+32 和 74+32:

72 gpio4 - Combined interrupt indication for GPIO4 signal 0 throughout 15

74 gpio5 - Combined interrupt indication for GPIO5 signal 0 throughout 15

三、GIC 模块相关设置

void gic_init(void)
{
	u32 i, irq_num;

	GIC_Type *gic = get_gic_base();

	//D_TYPER低5位表示gic支持的ITLinesNumber。如果ITLinesNumber = N,则最大中断数为32*(N+1)。
	irq_num = (gic->D_TYPER & 0x1F) + 1;
	/* On POR, all SPI is in group 0, level-sensitive and using 1-N model */
	/* Disable all PPI, SGI and SPI */
	for (i = 0; i < irq_num; i++)
	  gic->D_ICENABLER[i] = 0xFFFFFFFFUL;

	//设置支持的优先级个数,IMX6ULL支持32位,所以设置为 0b11111000
	gic->C_PMR = (0xFFUL << (8 - 5)) & 0xFFUL;
	
	/* No subpriority, all priority level allows preemption */
    //imx6ull的优先级位数为5(32个优先级),所以设置为2,具体可查寄存器相关的表
	gic->C_BPR = 7 - 5;
	
	/* Enables the forwarding of pending interrupts from the Distributor to the CPU interfaces.
	 * Enable group0 distribution
	 */
	gic->D_CTLR = 1UL;
	
	/* Enables the signaling of interrupts by the CPU interface to the connected processor
	 * Enable group0 signaling 
	 */
	gic->C_CTLR = 1UL;
}

void gic_enable_irq(IRQn_Type nr)
{
	GIC_Type *gic = get_gic_base();

	/* The GICD_ISENABLERs provide a Set-enable bit for each interrupt supported by the GIC.
	 * Writing 1 to a Set-enable bit enables forwarding of the corresponding interrupt from the
	 * Distributor to the CPU interfaces. Reading a bit identifies whether the interrupt is enabled.
	 */
	gic->D_ISENABLER[nr >> 5] = (uint32_t)(1UL << (nr & 0x1FUL));

}
//使能对应中断
gic_enable_irq(GPIO5_Combined_0_15_IRQn);
gic_enable_irq(GPIO4_Combined_0_15_IRQn);

四、cpu全局中断使能

/* 使能IRQ中断 */
	mrs r0, cpsr		/* 读取cpsr寄存器值到r0中 			*/
	bic r0, r0, #0x80	/* 将r0寄存器中bit7清零,也就是CPSR中的I位清零,表示允许IRQ中断 */
	msr cpsr, r0		/* 将r0重新写入到cpsr中 
	
或者使用 
cpsie i	  //cpsid i	关闭全局中断

五、中断处理过程

void handle_irq_c(void)
{
	int nr;

	GIC_Type *gic = get_gic_base();
	/* The processor reads GICC_IAR to obtain the interrupt ID of the
	 * signaled interrupt. This read acts as an acknowledge for the interrupt
	 */
	nr = gic->C_IAR;
	
	irq_table[nr].irq_handler(nr, irq_table[nr].param);

	/* write GICC_EOIR inform the CPU interface that it has completed 
	 * the processing of the specified interrupt 
	 */
	gic->C_EOIR = nr;
}

你可能感兴趣的:(imx6ull,裸机,nxp)