0 参考资料
STM32MP13xx参考手册.pdf(RM0475)
ARM Generic Interrupt Controller Architecture version 2.0 - Architecture Specification.pdf
1 基于Cortex-A7的GIC配置API配置GIC
前面我们已经了解了GIC几个关键的寄存器,通过这几个关键寄存器,我们就可以按照NVIC的用法,使用GIC对中断进行管理。操作步骤概括如下:
(1)设置中断优先级掩码寄存器GICC_PMR,确定中断优先级位数
(2)设置中断抢占优先级和响应优先级配置寄存器GICC_BPR,确定中断抢占优先级和响应优先级的位数
(3)设置中断优先级配置寄存器GICD_IPRIORITYRn,指定中断优先级
(4)设置中断使能寄存器GICD_ISENABLERn/中断失能寄存器GICD_ICENABLERn来使能/失能中断
相关代码如下:
/**
* @brief GIC初始化
*
* @param prio_bits 中断优先级位数0-5
* @param main_prio_bits 中断抢占优先级(主优先级)位数(不得为0)
* @return int
*/
int gic_init(u32 prio_bits, u32 main_prio_bits)
{
u32 i;
u32 pmr_mask = 0;
if (prio_bits > STM32MP13XX_PRIO_MAX_BITS)
{
return -1;
}
if ((main_prio_bits > prio_bits) || (main_prio_bits == 0))
{
return -1;
}
/* 构造GIMC_PMR寄存器值 */
for (i = 0; i < prio_bits; i++)
{
pmr_mask |= (1 << i);
}
pmr_mask = pmr_mask << 3;
/* 将pmr_mask值写入GIMC_PMR寄存器,设置中断优先级位数 */
GIC_SetInterfacePriorityMask(pmr_mask);
imx_printf("pmr_mask : 0x%x\r\n", pmr_mask);
/* 将抢占优先级设置值写入GICC_BPR寄存器 */
GIC_SetBinaryPoint(7 - main_prio_bits);
imx_printf("7 - main_prio_bits : 0x%x\r\n", 7 - main_prio_bits);
gic_cfg.prio_bits = prio_bits;
gic_cfg.main_prio_bits = main_prio_bits;
return 0;
}
/**
* @brief GIC中断优先级配置
*
* @param IRQn 中断ID
* @param main_prio 主优先级
* @param sub_prio 子优先级
* @return int 0:成功 -1:失败
*/
int gic_prio_config(IRQn_Type IRQn, u32 main_prio, u32 sub_prio)
{
u32 priority = 0;
/* 如果主优先级大于主优先级位数表示的最大值 */
if (main_prio > ((1 << (gic_cfg.main_prio_bits)) - 2))
{
return -1;
}
/* 只有当主优先级位数小于优先级位数时才检查子优先级是否合理 */
if (gic_cfg.main_prio_bits != gic_cfg.prio_bits)
{
if (sub_prio > ((1 << (gic_cfg.prio_bits - gic_cfg.main_prio_bits)) - 1))
{
return -1;
}
}
if (gic_cfg.main_prio_bits == gic_cfg.prio_bits)
{
/* 仅包含主优先级 */
priority = main_prio << 3;
}
else
{
/* 包含主优先级和子优先级 */
priority = ((main_prio << (gic_cfg.prio_bits - gic_cfg.main_prio_bits)) | (sub_prio)) << 3;
}
imx_printf("priority : 0x%x\r\n", priority);
GIC_SetPriority(IRQn, priority);
return 0;
}
使用实例:
以配置GIC优先级位数为5,主优先级位数为3,ETH1_IRQn主优先级为5,子优先级为0为例,相关代码如下:
void config_eth1_gic_example(void)
{
gic_init(5, 3);
gic_prio_config(ETH1_IRQn, 5, 0);
}