[001-Cortex_M3-GCC汇编] 第一个点灯程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/pengfei240/article/details/54693102

背景

使用Cortex-M3已经有一段时间了,大大小小也做过几个项目,可以说对这个系列的片子是有一定的了解。相对于以前的8位单片机来说,其存储空间,外设种类都有较大的提升,这对于产品的应用显得非常便利。最近,因为项目上的原因做了一些汇编工作,个人觉得如果想把Cortex-M3系列的芯片用好,汇编方面的理论知识还是需要学习和补充的,因此就有了写这一系列文档的动力,权当总结一下汇编的基础知识和实用样例。
本文重点不在于学习每一条汇编指令,而是通过使用汇编语言编写一个个简单实例使我们能对GCC汇编有一个基本的了解。

编译环境

主机环境: Ubuntu 16.04.1
目标板名称: TI DB-LM3S9B96
主芯片型号: TI LM3S9B96
交叉编译链: gcc-arm-none-eabi-5_4-2016q3
在另一篇文章 http://blog.csdn.net/pengfei240/article/details/52912833 中,已经详细描述了如何下载和制作交叉编译链,大家如果感兴趣可以参考下这篇文章。

工程目录

工程的结构按下面的目录形式进行组织:

  • 根目录以 asm 开始
  • source 为源码目录,该目录下每个例程为一个文件夹,分别以example1,example2…的形式进行组织
  • toolchain 为各个版本的交叉编译链存放的位置,其中软链接CrossCompile指向当前使用的交叉编译链
$ tree -L 2 asm
asm
├── source
│   └── example1
└── toolchain
    ├── CrossCompile -> gcc-arm-none-eabi-5_4-2016q3
    └── gcc-arm-none-eabi-5_4-2016q3

第一个点灯程序

硬件原理图

点灯程序原理图

由原理图可知,点灯方式为PF3端口设置为高电平。

源码

/*
*   example1
*
*   Description: It controls the port to turn on the LED.
*   Author: Peter Peng
*   Ver: 0.1
*/

    .equ STACK_BASE,            0x20000000
    .equ STACK_TOP,             0x400

    .equ SYSCTL_RCGC1_R,        0x400FE104
    .equ SYSCTL_RCGC2_R,        0x400FE108
    .equ GPIO_PORTF_AFSEL_R,    0x40025420
    .equ GPIO_PORTF_DIR_R,      0x40025400
    .equ GPIO_PORTF_DEN_R,      0x4002551C
    .equ GPIO_PORTF_DATA_R,     0x400253FC

    .equ SYSCTL_RCGC2_GPIOF,    0x00000020

    .text

    .thumb

    .syntax unified

    .global _start

_start:
    .word STACK_BASE + STACK_TOP        /* Top of Stack             */
    .word start                         /* Reset Handler            */
    .word NmiSR                         /* NMI Handler              */
    .word FaultISR                      /* Hard Fault Handler       */
    .word IntDefaultHandler             /* MPU Fault Handler        */
    .word IntDefaultHandler             /* Bus Fault Handler        */
    .word IntDefaultHandler             /* Usage Fault Handler      */
    .word 0                             /* Reserved                 */
    .word 0                             /* Reserved                 */
    .word 0                             /* Reserved                 */
    .word 0                             /* Reserved                 */
    .word IntDefaultHandler             /* SVCall Handler           */
    .word IntDefaultHandler             /* Debug Monitor Handler    */
    .word 0                             /* Reserved                 */
    .word IntDefaultHandler             /* PendSV Handler           */
    .word IntDefaultHandler             /* SysTick Handler          */
    .word IntDefaultHandler             /* GPIO Port A              */
    .word IntDefaultHandler             /* GPIO Port B              */
    .word IntDefaultHandler             /* GPIO Port C              */
    .word IntDefaultHandler             /* GPIO Port D              */
    .word IntDefaultHandler             /* GPIO Port E              */
    .word IntDefaultHandler             /* UART0                    */
    .word IntDefaultHandler             /* UART1                    */
    .word IntDefaultHandler             /* SSI                      */
    .word IntDefaultHandler             /* I2C                      */
    .word IntDefaultHandler             /* PWM Fault                */
    .word IntDefaultHandler             /* PWM Generator 0          */
    .word IntDefaultHandler             /* PWM Generator 1          */
    .word IntDefaultHandler             /* PWM Generator 2          */
    .word IntDefaultHandler             /* Quadrature Encoder       */
    .word IntDefaultHandler             /* ADC Sequence 0           */
    .word IntDefaultHandler             /* ADC Sequence 1           */
    .word IntDefaultHandler             /* ADC Sequence 2           */
    .word IntDefaultHandler             /* ADC Sequence 3           */
    .word IntDefaultHandler             /* Watchdog                 */
    .word IntDefaultHandler             /* Timer 0A                 */
    .word IntDefaultHandler             /* Timer 0B                 */
    .word IntDefaultHandler             /* Timer 1A                 */
    .word IntDefaultHandler             /* Timer 1B                 */
    .word IntDefaultHandler             /* Timer 2A                 */
    .word IntDefaultHandler             /* Timer 2B                 */
    .word IntDefaultHandler             /* Comp 0                   */
    .word IntDefaultHandler             /* Comp 1                   */
    .word IntDefaultHandler             /* Comp 2                   */
    .word IntDefaultHandler             /* System Control           */
    .word IntDefaultHandler             /* Flash Control            */
    .word IntDefaultHandler             /* GPIO Port F              */
    .word IntDefaultHandler             /* GPIO Port G              */
    .word IntDefaultHandler             /* GPIO Port H              */
    .word IntDefaultHandler             /* UART2 Rx and Tx          */
    .word IntDefaultHandler             /* SSI1 Rx and Tx           */
    .word IntDefaultHandler             /* Timer 3 subtimer A       */
    .word IntDefaultHandler             /* Timer 3 subtimer B       */
    .word IntDefaultHandler             /* I2C1 Master and Slave    */
    .word IntDefaultHandler             /* Quadrature Encoder 1     */
    .word IntDefaultHandler             /* CAN0                     */
    .word IntDefaultHandler             /* CAN1                     */
    .word IntDefaultHandler             /* CAN2                     */
    .word IntDefaultHandler             /* Ethernet                 */
    .word IntDefaultHandler             /* Hibernate                */
    .word IntDefaultHandler             /* USB0                     */
    .word IntDefaultHandler             /* PWM Generator 3          */
    .word IntDefaultHandler             /* uDMA Software Transfer   */
    .word IntDefaultHandler             /* uDMA Error               */
    .word IntDefaultHandler             /* ADC1 Sequence 0          */
    .word IntDefaultHandler             /* ADC1 Sequence 1          */
    .word IntDefaultHandler             /* ADC1 Sequence 2          */
    .word IntDefaultHandler             /* ADC1 Sequence 3          */
    .word IntDefaultHandler             /* I2S0                     */
    .word IntDefaultHandler             /* External Bus Interface 0 */
    .word IntDefaultHandler             /* GPIO Port J              */

    .thumb_func
start:

    /* SYSCTL_RCGC2_R |= SYSCTL_RCGC2_GPIOF */
    LDR R0, =SYSCTL_RCGC2_R
    LDR R1, [R0]
    ORR R1, #SYSCTL_RCGC2_GPIOF
    STR R1, [R0]

    NOP
    NOP

    /* GPIO_PORTF_AFSEL_R = 0x00000000 */
    MOV R0, #0x00
    LDR R1, =GPIO_PORTF_AFSEL_R
    STR R0, [R1]

    /* GPIO_PORTF_DIR_R = 0x00000008 */
    MOV R0, #0x08
    LDR R1, =GPIO_PORTF_DIR_R
    STR R0, [R1]

    /* GPIO_PORTF_DEN_R = 0x00000008 */
    LDR R1, =GPIO_PORTF_DEN_R
    STR R0, [R1]

    /* GPIO_PORTF_DATA_R = 0x00000008 */
    MOV R0, #0x08
    LDR R1, =GPIO_PORTF_DATA_R
    STR R0, [R1]

    b .

    .thumb_func
NmiSR:
    b .

    .thumb_func
FaultISR:
    b .

    .thumb_func
IntDefaultHandler:
    b .

    .end

源码解析

  • 注释: 以“//”、“/**/”和“#”标注的部分为注释语句
  • .equ: 将符号的值设置为表达式的值(相当于C语言的#define)
  • .text: 指定后续编译出来的内容放在代码段
  • .thumb: 同.code 16,告诉编译器后面的指令16bit对齐,即生成为Thumb指令
  • .syntax unified: 格式:syntax [unified | divided]。
    默认情况下[syntax divided],ARM和Thumb指令都有自己独立的语法;当使用统一语法时[syntax unified],ARM和Thumb使用相同的格式编写,由编译器将指令翻译为具体的ARM或Thumb指令
  • .global: 将符号导出给链接器
  • .word: 在当前位置放一个word型的值,在源码中,其实放置的就是各个中断处理程序的函数指针
  • 0x00复位向量: M3的0x00的位置放置的是MSP(堆栈指针)的初始值,在系统上电时,由硬件自动将该值加载到SP寄存器中。这一点是与其它芯片不太一致的地方
  • .thumb_func: 指示后面的符号是一个Thumb的函数。
    ARM 和 Thumb 指令集的动态切换,是通过 BX 指令使用一个寄存器名作为参数来完成,如果 LSB=1, 则进入 Thumb 指令处理模式;如果 LSB=0, 则进入 ARM 指令处理模式。但是,当使用.word形式放置函数指针时,链接器并不知道此处的LSB是多少(根本不知道放置的这个WORD是什么内容)。因此,需要使用.thumb_func来告知链接器,这儿的LSB=1(thumb指令集的函数指针)
  • .end: 表示汇编文件结束,将不再处理该指示符后的内容

start函数中实际就是几个寄存器(SysCtl和PortF)的赋值操作,代码中都有详细的注释,在这就不解释每一句汇编语法的含义了。

编译和下载

可以使用下面的四条命令来编译和调试程序,Makefile和Linker文件以后再实现:

# 编译
../../toolchain/CrossCompile/bin/arm-none-eabi-gcc -mcpu=cortex-m3 -c -mthumb -mthumb-interwork start.s

# 链接
../../toolchain/CrossCompile/bin/arm-none-eabi-ld -Ttext 0x0 -o start.out start.o

# objdump,如果需要调试可以使用该命令来反编译二进制文件
../../toolchain/CrossCompile/bin/arm-none-eabi-objdump -S start.out > start.dump

# ELF转换为bin文件,该bin文件就是我们下载需要的文件
../../toolchain/CrossCompile/bin/arm-none-eabi-objcopy -O binary start.out start.bin

最后在Windows上通过LM Flash Programmer软件将bin文件下载到目标板(Linux下的烧写工具以后再尝试),可以看见开发板上的LED灯被点亮。

猜你喜欢

转载自blog.csdn.net/pengfei240/article/details/54693102
今日推荐