Linux汇编LED驱动

MX6U的IO口作为GPIO的步骤总结:

  1. 使能GPIO对应的时钟
  2. 设置寄存器IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用为 GPIO 功能。
  3. 设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。
  4. 第2步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使
    用中断、默认输出电平等。

总结:类似于stm32的初始化,先使能时钟,在对引脚初始化,然后设置高低电平输入输出。在MX6U的IO口复用为GPIO时的时钟使能,需要对CCM(ClockController Module)里面的寄存器做设置,开发手册上的例子就是控制GPIO的时钟在寄存器的31和30位,按手册设置就行。

GUN汇编语法知识:

  • 语句有三个可选部分:  label:instruction @ comment  ,这里的label是标号,instruction是指令,@符号是注释。举个例子: 这里的add:就是标号,@后面为注释,中间为代码指令。
    add:
    MOVS R0, #0X12 @设置 R0=0X12

     

     

    处理器内部数据的传输指令:
    指令 目的 描述
    MOV R0 R1 将R1里面的数据复制到R0中

    MRS

    (只能用于特殊寄存器数据传给通用寄存器)

    R0 CPSR 将特殊寄存器CPSR里面的数据复制到R0中

    MSR

    (只能用于通用寄存器的数据传给特殊寄存器)

    CPSR R1 将R1里面的数据复制到特殊寄存器CPSR中
    举个例子:
    MOV R0,R1 @将寄存器 R1 中的数据传递给 R0,即 R0=R1
    MOV R0, #0X12 @将立即数 0X12 传递给 R0 寄存器,即 R0=0X12

     

    存储器访问指令:(最常用)
    指令

    描述

    LDR Rd, [Rn , #offset]

    从存储器 Rn+offset 的位置读取数据存放到 Rd 中。

    STR Rd, [Rn, #offset]

    将 Rd 中的数据写入到存储器中的 Rn+offset 位置。

    举个例子:
    LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
    LDR R1, [R0] @读取地址 0X0209C004 中的数据到 R1 寄存器中
    LDR R0, =0X0209C004 @将寄存器地址 0X0209C004 加载到 R0 中,即 R0=0X0209C004
    LDR R1, =0X20000002 @R1 保存要写入到寄存器的值,即 R1=0X20000002
    STR R1, [R0] @将 R1 中的值写入到 R0 中所保存的地址中

     

    压栈和出栈指令:
    指令 描述

    PUSH <reg list>

    将寄存器列表存入栈中。

    POP <reg list>

    从栈中恢复寄存器列表。

    举个例子:
    PUSH {R0~R3, R12} @将 R0~R3 和 R12 压栈
    还有一种写法:
    STMFD SP!,{R0~R3, R12} @R0~R3,R12 入栈
    STMFD SP!,{LR} @LR 入栈 34 LDMFD SP!, {LR} @先恢复 LR
    LDMFD SP!, {R0~R3, R12} @再恢复 R0~R3, R12

     

    跳转指令:
    指令 描述

    B <label>

    跳转到 label,如果跳转范围超过+/-2KB,可以指定 B.W<label>使用 32 位版本的跳转指令, 这样可以得到较大范围的跳转

    BX <Rm>

    间接跳转,跳转到存放于 Rm 中的地址处,并且切换指令集

    BL <label>

    跳转到标号地址,并将返回地址保存在 LR 中。

    BLX <Rm>

    结合 BX 和 BL 的特点,跳转到 Rm 指定的地址,并将返回地址保存在 LR 中,切换指令集。

    举个例子:
    _start: 
    
        ldr sp,=0X80200000 @设置栈指针
        b main @跳转到 main 函数

     

    上面是典型的在汇编中初始化C运行环境,然后跳转到C文件的main函数中运行。(这里不会跳转回来继续运行)
    push {r0, r1} @保存 r0,r1
    cps #0x13 @进入 SVC 模式,允许其他中断再次进去
    
    bl system_irqhandler @加载 C 语言中断处理函数到 r2 寄存器中
    
    cps #0x12 @进入 IRQ 模式
    pop {r0, r1} 
    str r0, [r1, #0X10] @中断执行完成,写 EOIR
    上面用bl就是C语言中的中断处理函数,还要回来继续处理执行下面的程序。
  • 还有算数运算指令和逻辑运算指令,比较简单,用到就可以理解。

总结:看到后面发现自己对汇编这里的知识还有所不熟练,特地重新针对文档看一遍,记录一下基础的知识点

GPIO的8个寄存器介绍:

  1. DR寄存器:是数据寄存器,32位,控制高低电平,当GPIO被配置为输出功能,向指定位写入数据那么相应的IO就会输出相应的高低电平。例如:根据GPIO1_IO03的后面的3来选择移动几位来控制电平。
    /* 3、初始化GPIO,GPIO1_IO03设置为输出*/
    	GPIO1->GDIR |= (1 << 3);	 
    
    	/* 4、设置GPIO1_IO03输出低电平,打开LED0*/
    	GPIO1->DR &= ~(1 << 3);
    
    //这里补充一点将GPIO设置为输入输出(从GPIO驱动初始化那边的复制来的)
    
    void gpio_init(GPIO_Type *base, int pin, gpio_pin_config_t *config)
    {
    	if(config->direction == kGPIO_DigitalInput) /* 输入 */
    	{
    		base->GDIR &= ~( 1 << pin);
    	}
    	else										/* 输出 */
    	{
    		base->GDIR |= 1 << pin;
    		gpio_pinwrite(base,pin, config->outputLogic);/* 设置默认输出电平 */
    	}
    }
  2. GDIR寄存器:设置某个IO的工作方向,是输出还是输入。输入0输出1
  3. PSR状态寄存器:功能和输入状态下的DR寄存器一样
  4. ICR1和ICR2寄存器:中断控制寄存器,ICR1用于配置低16个的GPIO,ICR2用于配置高16个的GPIO,00-低电平触发;01-高电平触发;10-上升沿触发;11-下降沿触发。举个例子:如果要设置GPIO1_IO15为上升沿触发中断,那么GPIO1.ICR1=2<<30
  5. IMR寄存器:用来控制GPIO的中断禁止和使能
  6. SIR寄存器:读取中断是否发生,类似于中断标志位,处理完中断后需要清除中断标志位。
  7. EDGE_SEL寄存器:设置边沿中断,会覆盖ICR1和2的设置。
posted @ 2022-10-30 21:11  祈愿树下  阅读(49)  评论(0编辑  收藏  举报
// 侧边栏目录 // https://blog-static.cnblogs.com/files/douzujun/marvin.nav.my1502.css