Cortex-M3寄存器組、彙編語言與C語言的接口介紹

學uCOS的任務切換時涉及到彙編代碼。爲了能理解彙編代碼,我在網上了解了Cortex-M3寄存器組、C與彙編的接口的知識,在這裏分享給大家。

先來介紹Cortex-M3寄存器組:

Cortex-M3擁有16個通用寄存器R0-R15。

R0-R12都是32位通用寄存器,用於數據操作。

R13是堆棧指針。在CM3處理器內核中共有兩個堆棧指針,於是也就支持兩個堆棧。當引用R13(SP)時,你引用到的是當前正在使用的那一個,另一個必須用特殊的指令來訪問。兩個堆棧指針分別是:

  1. 主堆棧指針(MSP):這是缺省的堆棧指針,它由OS內核、異常服務程序及需要特權訪問的應用程序代碼來使用。
  2. 進程堆棧指針(PSP):用於常規的應用程序代碼。

R14是連接寄存器(LR)。在函數調用時存儲返回的地址。

R15是程序計數器(PC)。指向當前程序的地址。如果修改它的值,就會改變程序的執行順序(很多高級操作都在這)。

接下來介紹彙編與C的接口:

讓C程序與彙編程序互相交互時,我們必須知道參數是如何傳遞的,以及值是如何返回的,這樣才能在主調函數與子程序之間協調工作。這些交互機制在ARM中有明確的規定,由文檔《ARM Architecture Procedure Call Standard(AAPCS,Ref5)》(我沒有看過)給出。雖然沒看官方的文檔,我還是在百度上看了一下C與彙編混合編程,並做以下總結:

1、發生函數調用時,入口參數依次通過R0-R3寄存器傳遞,其中R0傳遞第一個,R1傳遞第2個……,當超過4個參數時,其他參數通過棧傳遞。函數的返回值通過R0寄存器返回。在函數被調用前,R0-R3中的值會自動入棧。

2、R4-R11爲普通的通用寄存器,發生函數調用時,其中的數據不會自動入棧,如果被調函數需要使用這些寄存器,則需要由被調函數先將這些寄存器中數據入棧保存再使用這些寄存器。被調函數返回前,需要先將數據出棧回覆R4-R11的值,然後再返回主調函數。

3、R12(IP)可以記錄對子程序的調用。

R13-R15的作用在前一部分介紹過了,不再囉嗦。

最後,我用C和彙編寫了一個流水燈的程序,以此演示C語言調用匯編函數,其中LED亮滅的切換由彙編代碼實現。以下附上部分代碼:  代碼下載地址:https://download.csdn.net/download/qdchenxr/10887924

/******************led.h*******************/
#ifndef __LED_H
#define __LED_H  
#include "stm32f10x.h"

void LED_Init(void);//GPIO初始化
void LED_Change(unsigned char index);//彙編函數在C語言頭文件中的聲明
                            
#endif

 

/******************main.c*******************/
#include "delay.h"
#include "led.h"
 int main(void)
 {  
    unsigned char index=1;
    delay_init();      
    LED_Init();       
    while(1)
    {
        LED_Change(index);//調用匯編函數,傳遞一個參數
        index=!index;
        delay_ms(300);
    }
 }

 

/******************led.s*******************/
;全局函數
    EXPORT LED_Change           ;該文件定義的函數
;常量
GPIOB_BASE EQU 0x40010C00       ;GPIOB的基地址
GPIOB_BRR  EQU GPIOB_BASE+0x14  ;GPIOB_BRR寄存器的地址
GPIOB_BSRR EQU GPIOB_BASE+0x10  ;GPIOB_BSRR寄存器的地址   
GPIOE_BASE EQU 0x40011800       ;GPIOE的基地址
GPIOE_BRR  EQU GPIOE_BASE+0x14  ;GPIOE_BRR寄存器的地址
GPIOE_BSRR EQU GPIOE_BASE+0x10  ;GPIOE_BSRR寄存器的地址   
LED_LIGHT  EQU 0x0020
;代碼產生指令
    PRESERVE8
    THUMB
        
    AREA CODE, CODE, READONLY       
;LED切換函數
LED_Change
    CBZ R0, LED1_Light  ;一個參數由R0傳遞,判斷R0,如果值爲0就跳轉到LED1_Light
    
LED2_Light
;點亮LED2 
    LDR R1, =GPIOE_BRR  ;R1=GPIOE_BRR;//R1中存GPIOE_BRR寄存器的地址
    LDR R2, =LED_LIGHT  ;R2=0x0020;
    STR R2, [R1]         ;*R1=R2;
;熄滅LED1
    LDR R1, =GPIOB_BSRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
    BX LR               ;函數返回
    
LED1_Light
;點亮LED1 
    LDR R1, =GPIOB_BRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
;熄滅LED2
    LDR R1, =GPIOE_BSRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
    BX LR               ;函數返回

    NOP 
    END                 ;彙編文件結束

 效果如下:(轉成GIF後反了,不知道怎麼正過來)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章