0


Linux——GPIO输入输出裸机实验

学习了正点原子Linux环境下的GPIO的输入输出的裸机实验学习,现在进行一下小结:

启动文件start.S的编写

  1. .global _start
  2. .global _bss_start
  3. _bss_start:
  4. .word __bss_start
  5. .global _bss_end
  6. _bss_end:
  7. .word __bss_end
  8. _start:
  9. /*设置处理器进入SVC模式*/
  10. mrs r0, cpsr /*读取cpsr到r0*/
  11. bic r0, r0, #0x1f /*清除cpsr的bit4-0*/
  12. orr r0, r0, #0x13 /*使用SVC模式*/
  13. msr cpsr, r0 /*将r0写入到cpsr*/
  14. /*清除bss段*/
  15. ldr r0, =_bss_start
  16. ldr r1, =_bss_end
  17. mov r2, #0
  18. bss_loop:
  19. stmia r0!, {r2}
  20. cmp r0, r1
  21. ble bss_loop
  22. /*设置sp指针*/
  23. ldr sp, =0x80200000
  24. b main /*跳转到C语言main函数*/

.global指令用于定义全局变量

.word指令定义了两个符号

  1. _bss_start

  1. _bss_end

,它们都初始化为对应的符号

  1. __bss_start

  1. __bss_end

的地址(在后面讲到的链接脚本文件imx6u.lds中有为这两个符号赋值地址)。这些符号通常用于标识程序中BSS段的开始和结束。

BSS段(Block Started by Symbol)是程序数据段的一部分,用于存储未初始化的全局变量和静态变量。在程序启动时,BSS段会被清零,并且其大小会被计算到程序的总内存占用中,尽管它在磁盘上的表示可能非常小或甚至没有。

程序启动会先从启动文件开始执行,默认从_start处开始执行。

Makefile编写

通过make指令可以执行目录下的Makefile文件,我们可以在Makefile文件里编写编译过程的一系列指令,方便开发。

Makefile文件以及相应的注释如下:

  1. #变量赋值,?=如果前面已经有赋值,则用前面的,没有就用等号后面的
  2. CROSS_COMPILE ?= arm-linux-gnueabihf-
  3. TARGET ?= beep
  4. CC := $(CROSS_COMPILE)gcc
  5. LD := $(CROSS_COMPILE)ld
  6. OBJCOPY := $(CROSS_COMPILE)objcopy
  7. OBJDUMP := $(CROSS_COMPILE)objdump
  8. #保存头文件所在目录的变量
  9. # \ 表示本行和下一行属于同一行。为换行符
  10. INCUDIRS := project \
  11. imx6u \
  12. bsp/clk \
  13. bsp/led \
  14. bsp/delay \
  15. bsp/beep
  16. #保存源文件所在目录的变量
  17. SRCDIRS := project \
  18. bsp/clk \
  19. bsp/led \
  20. bsp/delay \
  21. bsp/beep
  22. #将变量INCUDIRS里的值都加上-I前缀
  23. #加-I是以为makefile语法指定头文件目录时候前面要加-I
  24. #patsubst语法:在INCUDIRS中所有的单词前加上-I,因为%为通配符
  25. INCLUDE := $(patsubst %,-I%,$(INCUDIRS))
  26. #foreach作用是将SRCDIRS变量的值赋值给dir然后执行最后的表达式wildcard,
  27. #wildcard的作用是将dir目录下的所有.S文件(前面带着目录)都存入SFILES变量
  28. SFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.S))
  29. CFILES := $(foreach dir, $(SRCDIRS), $(wildcard $(dir)/*.c))
  30. #notdir作用是删除SFILES变量的目录成分,只留文件名
  31. SFILENDIR := $(notdir $(SFILES))
  32. CFILENDIR := $(notdir $(CFILES))
  33. #将没有目录的SFILENDIR的值都加上obj/前缀,并将.S.c替换成.o
  34. SOBJS := $(patsubst %.S,obj/%.o,$(SFILENDIR))
  35. COBJS := $(patsubst %.c,obj/%.o,$(CFILENDIR))
  36. #保存所有的.o文件
  37. OBJS := $(SOBJS) $(COBJS)
  38. #如果当前目录找不到目标文件和依赖文件,就到指定的路径去找
  39. VPATH := $(SRCDIRS)
  40. #伪目标
  41. .PHONY:clean
  42. # 目标文件 : 依赖文件
  43. #-T后面接链接脚本
  44. #-o 指定输出文件名
  45. #$^表示所有的依赖文件,指令的作用是链接所有的依赖文件成可执行文件.elf
  46. #-O表示指定输出的格式为纯二进制文件
  47. #-S表示剥除符号表和重定义表,无调试信息
  48. #$@表示目标文件
  49. #-D表示输出汇编文件 -m表示指定目标架构arm
  50. #>是shell中的重定向操作符,将输出文件重定向到文件.dis
  51. $(TARGET).bin : $(OBJS)
  52. $(LD) -Timx6u.lds -o $(TARGET).elf $^
  53. $(OBJCOPY) -O binary -S $(TARGET).elf $@
  54. $(OBJDUMP) -D -m arm $(TARGET).elf > $(TARGET).dis
  55. #-Wall表示显示警告信息
  56. #-nostdlib表示在链接时不使用标准库
  57. #-c表示只进行编译和汇编,不进行链接
  58. #$@表示目标文件 $<表示规则中的第一个依赖文件
  59. $(SOBJS) : obj/%.o : %.S
  60. $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
  61. $(COBJS) : obj/%.o : %.c
  62. $(CC) -Wall -nostdlib -c -O2 $(INCLUDE) -o $@ $<
  63. #清除编译生成的各种文件
  64. clean:
  65. rm -rf $(TARGET).elf $(TARGET).bin $(TARGET).dis $(OBJS)
  66. #打印编译过程生成的变量
  67. print:
  68. @echo INCLUDE = $(INCLUDE)
  69. @echo SFILES = $(SFILES)
  70. @echo CFILES = $(CFILES)
  71. @echo SFILENDIR = $(SFILENDIR)
  72. @echo CFILENDIR = $(CFILENDIR)
  73. @echo SOBJS = $(SOBJS)
  74. @echo COBJS = $(COBJS)
  75. @echo OBJS = $(OBJS)

链接脚本imx6u.lds

  1. SECTIONS{
  2. . = 0x87800000;
  3. .text :
  4. {
  5. obj/start.o
  6. *(.text)
  7. }
  8. .rodata ALIGN(4) : {*(.rodata*)}
  9. .data ALIGN(4) : {*(.data)}
  10. __bss_start=.;
  11. .bss ALIGN(4) : {*(.bss) *(COMMON)}
  12. __bss_end=.;
  13. }

链接脚本的主要作用有定义链接起始地址、调整链接顺序(第一个要连接的文件必须是start.o)

.为定位计数器,默认定位计数器为0,给这个特殊符号赋值0x87800000,后面的链接起始地址就会是0x87800000

代码段可以分为text段、只读数据段、数据段和BSS段'

ALIGN(4)的作用是4字节对齐

BSS段(Block Started by Symbol)是程序数据段的一部分,用于存储未初始化的全局变量和静态变量。在程序启动时,BSS段会被清零,并且其大小会被计算到程序的总内存占用中,尽管它在磁盘上的表示可能非常小或甚至没有

GPIO输入输出配置的库函数

配置复用功能函数

  1. IOMUXC_SetPinMux(IOMUXC_GPIO1_IO03_GPIO1_IO03,0);

上面示例中的 IOMUXC_GPIO1_IO03_GPIO1_IO03是一个宏定义,如下:

上面的操作是我们通过传递参数,将对应模式的值放到我们的寄存器地址。也就是将0x5写到0x020E0068为地址的寄存器里,查看参考手册

就是向我们这个寄存器写入0x5,将其复用为GPIO1_IO03

** 配置电气属性函数**

  1. IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO03_GPIO1_IO03,0x10B0);

与我们的复用功能函数类似,也是通过传入参数到我们相关的配置寄存器地址中,如下:

为地址为0x020E02F4的配置寄存器写入0x10b0

通过查看参考手册进行对应的电气属性配置

写入0x10B0是配置为输出模式

写入0xF080是配置为输入模式,上拉,使能迟滞比较器

GPIO寄存器组

通过结构体指针操作寄存器组,进而配置GPIO为输入还是输出模式,1为输出模式。0为输入模式

标签: linux ubuntu

本文转载自: https://blog.csdn.net/weixin_74209413/article/details/143774170
版权归原作者 御风_21 所有, 如有侵权,请联系我们删除。

“Linux——GPIO输入输出裸机实验”的评论:

还没有评论