Branch(B) vs Branch With Link(BL)
The Cortex-M architecture supports two similar commands: B and BL. The branch command (B) allows the user to jump, or branch, to an instruction that does not immediately follow the current instruction. So what is missing from the branch instruction that is required to implement a function call? The answer to that is somewhat simple: functions can be called from numerous locations in an application, so the function cannot have a hard coded return address to a single memory location. A function needs to have the ability to return to an arbitrary address in the application.
In order for a function to return to an arbitrary address, the MCU needs to have a mechanism that saves the address of the instruction immediately after the function call. The BL command saves the address of the instruction immediately following the BL command into the Link Register (R14). By storing the address of the next instruction into the link register, a function can “return” by moving the contents of the LR back into the PC using the BX command.

In some situations, the function being executed may be at an address that is more than 16MBs from the address of the BL instruction. In this situation, you can use BLX, the register indirect version of Branch With Link.
Assembly Function Syntax
The code below demonstrates how to declare a function using assembly code. This example assumes that the function exists in a file that is separate from the main routine.
; Filename: ece353_main.s
; Author: ece353 staff
; Description:
export __main ; (1)
import testBit0 ; (2) Import address for 'testBit0'
import testBit10 ; (3) Import address for 'testBit10'
;**********************************************
; Indicate the following describes part
; of the application
;**********************************************
AREA |.text|, CODE, READONLY ;(4)
;**********************************************
; Code (FLASH) Segment
; main assembly program
;**********************************************
__main PROC ;(5)
; Initialize R0
MOV R0, #0x01
; Call the function
BL testBit0
; Load the address of testBit10
LDR R2, =(testBit10)
; If the function is more than 16MBs from the PC,
; use the register indirect version of BL
BLX R2
;Loop forever
B __main
ENDP ; (6)
ALIGN
END ; (7)
- Makes the address of __main available to code found in other files
- Imports the address of the function named testBit0
- Imports the address of the function named testBit10
- Indicates the resulting machine instructions are part of FLASH, or the code segment
- Gives a name of the function. This is a label that represents the address of the function. The PROC directive tells the assembler that this is a function call (more info).
- Tells the assembler where the end of the functions is located
- Tells the assembler that there are no additional instructions in the file.
Here is the Assembly source for the two functions that were called.
export testBit0
export testBit10
;**********************************************
; Indicate the following describes part
; of the application
;**********************************************
AREA |.text|, CODE, READONLY
;**********************************************
; function testBit0
;
; Description:
; Tests to see if bit 0 is a 1 or a 0.
;
; Paramters:
; R0 - Data being Examined
;
; Returns:
; Returns a 1 (True) in R1 if bit 0 is a 1.
; Returns a 0 (False)in R1 if bit 0 is a 0.
;
; NOTE: Not an EABI compliant routine!
;**********************************************
testBit0 PROC
TST R0, #0x01
MOVEQ R1, #0
MOVNE R1, #1
BX LR ; Return from the function
ENDP
;**********************************************
; function testBit10
;
; Description:
; Tests to see if bit 10 is a 1 or a 0.
;
; Paramters:
; R0 - Data being Examined
;
; Returns:
; Returns a 1 (True) in R1 if bit 10 is a 1.
; Returns a 0 (False)in R1 if bit 10 is a 0.
; NOTE: Not an EABI compliant routine!
;**********************************************
testBit10 PROC
TST R0, #0x400
MOVEQ R1, #0
MOVNE R1, #1
BX LR ; Return from the function
ENDP
END
Examining both of the functions above, we see that register R1 is modified to indicate if a particular bit in R0 is equal to 1. But what happens to the application if the main routine (__main) placed some type of meaningful data into R1 prior to calling either of these functions? The simple answer is that the data in R1 is lost and our application would not function correctly.