stm32 按键外部中断开发代码 可对照database理解,汇编代码看中文注释即可

#include <stm32mp1xx_gpio.h>

#include <stm32mp1xx_exti.h>

#include <stm32mp1xx_gic.h>

#include <stm32mp1xx_rcc.h>

void hal_gpio_init(void);

void hal_exti_init(void);

void hal_gicd_init(void);

void hal_gicc_init(void);

extern void printf(const char *fmt, ...);



 

void mydelay_ms(int ms)

{

    int i, j;

    while(ms--)

    {

        for (i = 0; i < 10000; i++)

            for (j = 0; j < 10000; j++);

    }

}


 

void do_irq(void)

{

    unsigned int irq_num;

    irq_num = GICC.IAR & (0x3FF);

    switch(irq_num)

    {

        case 38:

            // 中断处理程序,此处只打印一条语句

            printf("put on \n");

            EXTI.FPR1 |= (0x1 << 0);          //下降边沿挂起寄存器  写0防止一直进入

            GICD.ICPENDR[1] |= (0x1 << 6);      // 清除GICD层中断 挂起清除

            break;

        case 39:

            break;

    }

    // 清除GICC层中断 将38号写进去结束

    GICC.EOIR = (GICC.EOIR & (~0x3FF)) | irq_num;

}



 

void hal_gpio_init(void)

{

    // 使能GPIOA组的时钟使能, 在  RCC_MP_AHB4ENSETR

    RCC.MP_AHB4ENSETR |= (0x1 << 0);

    GPIOA->MODER &= (~0x3 << 0);                   //按键配置      输入功能

    GPIOA->PUPDR &= ~(0x3 << 0);                   //无上、下拉

}

/*

 * PA0引脚对应的外部中断事件是EXTI[0]

 * 对应着Event Input 0

 * 具体的外设和EXTI对应的关系在21.3章节

 * 按键中断设置为下降沿触发中断事件的检测

 * */

void hal_exti_init(void)

{

    // 设置为下降沿触发选择寄存器

    EXTI.FTSR1 |= (0x1 << 0);

    // 设置外部中断选择寄存器 连接到PA0上

    EXTI.EXTICR1 &= (~(0xff << 0));

    // 设置EXTI CPU1唤醒中断屏蔽寄存器

    EXTI.C1IMR1 |= (0x1 << 0);

    // 设置EXTI CPU1唤醒事件屏蔽寄存器

//  EXTI.C1EMR1 |= (0x1 << 0);

}

/*

 * PA0引脚属于EXTI0

 * EXTI0 对应的中断ID为 38

 * 对应关系在芯片手册的21.2章节

 * */

void hal_gicd_init(void)

{

    GICD.ISENABLER[1] |= (0x1 << 6);                                                //中断号为38  GICD中断使能

    GICD.IPRIORITYR[9] &= ~(0x1f << 19);

    GICD.IPRIORITYR[9] |=  (0x10 << 19);                                            //中断优先级,设置为16

    GICD.ITARGETSR[9] |= (0x3 << 16);     //选择处理器处理控制器转发的中断  但是为啥写0x3                                          //中断处理器目标寄存器

    GICD.CTLR |= (0x1 << 0);                                                        //全局使能

    //由于默认38号外部中断用group 0 处理所以这里不用设置组别

}

void hal_gicc_init(void)

{

    GICC.CTLR |= (0x1 << 0);        // 设置GICC层 中断全局使能寄存器  enable group 0 interrupts

    GICC.PMR |= (0x1f << 3);        // 设置GICC层 中断屏蔽寄存器 

}




 

int main()

{

    hal_gpio_init();

    hal_gicc_init();

    hal_gicd_init();

    hal_exti_init();


 

    while(1)

    {

    }

    return 0;

}

汇编代码:

.text

.global _start

_start:

        b       reset

        ldr     pc,_undefined_instruction

        ldr     pc,_software_interrupt

        ldr     pc,_prefetch_abort

        ldr     pc,_data_abort

        ldr     pc,_not_used

        ldr     pc,_irq //跳转到_irq标志处

        ldr     pc,_fiq

_undefined_instruction: .word  _undefined_instruction

_software_interrupt:    .word  _software_interrupt

_prefetch_abort:        .word  _prefetch_abort

_data_abort:            .word  _data_abort

_not_used:              .word  _not_used

_irq:                   .word  irq_handler  //跳转到irq_handler标志处

_fiq:                   .word  _fiq

//    mrc p15,0,r0,c1,c1,2

//  movw      r1, #0x3fff

//  movt      r1, #0x0004

//  orr  r0,r0,r1

//    mcr  p15,0,r0,c1,c1,2

reset:

    ldr r0,= _start

    mcr p15,0,r0,c12,c0,0       // 通过协处理器将中断向量表地址定向到最前面的_start,如果一有IRQ发生,就跳到_start寻找irq异常

        mrs     r0,cpsr

        bic     r0,r0,#0x1f

        orr     r0,r0,#0xd3

        msr     cpsr,r0        //  Enable svc mode of cpu


 

init_stack:

        ldr     r0,stacktop         /*get stack top pointer*/

    /********svc mode stack********/

        mov     sp,r0

        sub     r0,#128*4          /*512 byte  for irq mode of stack*/

    /****irq mode stack**/

        msr     cpsr,#0xd2

        mov     sp,r0

        sub     r0,#128*4          /*512 byte  for irq mode of stack*/

    /***fiq mode stack***/

        msr     cpsr,#0xd1

        mov     sp,r0

        sub     r0,#0

    /***abort mode stack***/

        msr     cpsr,#0xd7

        mov     sp,r0

        sub     r0,#0

    /***undefine mode stack***/

        msr     cpsr,#0xdb

        mov     sp,r0

        sub     r0,#0

   /*** sys mode and usr mode stack ***/

        msr     cpsr,#0x10

        mov     sp,r0             /*1024 byte  for user mode of stack*/


 

    bl main

    .align  4

    /****  swi_interrupt handler  ****/


 

    /****  irq_handler  ****/

irq_handler:

    sub  lr,lr,#4   //因为三级流水线的原因,中断模式lr保存的地址的下下条指令的地址,如果我们从中断回来后想跳到下一条指令,那么这里需要人为的

    //对lr进行-4操作

    stmfd sp!,{r0-r12,lr}//对r0-r12寄存器为IRQ和user模式的共有寄存器,转到IRQ模式之后需要将她们压栈保护现场,对lr进行压栈防止在下面指令中lr被修改就回不去中断之前的地方了

    .weak do_irq

    bl  do_irq  //跳到中断处理函数中  这个处理函数是用c语言写的

    ldmfd sp!,{r0-r12,pc}^ //1.将r0-r12出栈 2.将lr直接压到PC返回中断前的位置 3.^符号是将spsr寄存器中存好的中断之前的cpsr状态

    //给到user模式中的cpsr寄存器

stacktop:    .word      stack+4*512

.data

stack:   .space  4*512

loop:

    b loop

    .end





 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值