I'm currently messing around with an LPC 2378 which has an application board attached. On the fan there are several components, 2 of which are a fan and a heater.
If bits 6 and 7 of port 4 are connected to the fan (motor controller), the following code will turn on the fan:
FanOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x80
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
How can I rewrite this block of code to turn on a heater connected to bit 5 of port 4, (Setting the bit to 1 will turn it on, setting it to 0 will turn it off).
Edit after answered question:
;==============================================================================
; Turn Heater On
;==============================================================================
heaterOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x20
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Turn The Heater Off
;==============================================================================
heaterOff
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
AND r0, r0, #0xDF
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
As best as I understand the code, the fan is connected only to bit 7 (if bits are numerated from 0).
The following line is responsible for turning the fan-bit on:
ORR r0, r0, #0x80
You are setting all the bits that are 1 in the "mask" to 1. Since the mask is 0x80, that is 1000 0000 in binary, it only turns on bit 7.
Now, if you need to turn on the heater instead of the fan, and you have to set bit 5 instead of 7 (on the same port), you only need to change the mask in that line. New mask should be 0010 0000 binary, that is 0x20 in hexa, so the new code should be:
ORR r0, r0, #0x20
Also, if you want to turn the heater off at some point later, you do it by unsetting only bit 5, by anding with a mask that has 1s everywhere except on bit 5. If the mnemonic for bitwise and is BIC, the line would be:
BIC r0, r0, 0xDF
Now, I have not done any assembly in months but if I am not very mistaken, the code snippet you gave is actually a subroutine. You would call it from you main functionality with something like call to the FanOn address. And, to me, it seems that the subroutine is nice in a way that it preserves all the registers it uses, e.g. it pushes them to a stack in the first line and recovers them in the end.
So, to re-use the code, you could just write a new subroutine for turning the heater on, and one for turning each thing off if you want, and only change the label/subroutine name for each one, e.g. FanOff, HeaterOn...
Since all of them preserve all the registers, you can use them sequentially without worries.
The ORR instruction turns ON a bit, the #0x80 constant determines the bit(s) (in this case, only bit 7 is turned on). To turn OFF the bit, you will need an AND instruction and compute the appropriate mask (e.g., to turn OFF bit 7, you would AND with constant #0x7F). The appropriate constants for bit 5 are #0x20 and #0xDF.
Related
this works, but I have to do it using auto-indexing and I can not figure out that part.
writeloop:
cmp r0, #10
beq writedone
ldr r1, =array1
lsl r2, r0, #2
add r2, r1, r2
str r2, [r2]
add r0, r0, #1
b writeloop
and for data I have
.balign 4
array1: skip 40
What I had tried was this, and yes I know it is probably a poor attempt but I am new to this and do not understand
ldr r1, =array1
writeloop:
cmp r0, #10
beq writedone
ldr r2, [r1], #4
str r2, [r2]
add r0, r0, #1
b writeloop
It says segmentation fault when I try this. What is wrong? What I am thinking should happen is every time it loops through, it sets the element r2 it at = to the address of itself, and then increments to the next element and does the same thing
The ARM architechures gives several different address modes.
From ARM946E-S product overview and many other sources:
Load and store instructions have three primary addressing modes
- offset
- pre-indexed
- post-indexed.
They are formed by adding or subtracting an immediate or register-based offset to or from a base register. Register-based offsets can also be scaled with shift operations. Pre-indexed and post-indexed addressing modes update the base register with the base plus offset calculation. As the PC is a general purpose register, a 32‑bit value can be loaded directly into the PC to perform a jump to any address in the 4GB memory space.
As well, they support write back or updating of the register, hence the reason for pre-indexed and post-indexed. Post-index doesn't make much sense without write back.
Now to your issue, I believe that you want to write the values 0-9 to an array of ten words (length four bytes). Assuming this, you can use indexing and update the value via add. This leads to,
mov r0, #0 ; start value
ldr r1, =array1 ; array pointer
writeloop:
cmp r0, #10
beq writedone
str r0, [r1, r0, lsl #2] ; index with r1 base by r0 scaled by *4
add r0, r0, #1
b writeloop
writedone:
; code to jump somewhere else and not execute data.
.balign 4
array1: skip 40
For interest a more efficient loop can be done by counting and writing down,
mov r0, #9 ; start value
ldr r1, =array1 ; array pointer
writeloop:
str r0, [r1, r0, lsl #2] ; index with r1 base by r0 scaled by *4
subs r0, r0, #1
bne writeloop
Your original example was writing the pointer to the array; often referred to as 'value equals address'. If this is what you want,
ldr r0, =array_end ; finished?
ldr r1, =array1 ; array pointer
write_loop:
str r1, [r1], #4 ; add four and update after storing
cmp r0, r1
bne write_loop
; code to jump somewhere else and not execute data.
.balign 4
array1: skip 40
array_end:
I am working on making a bootloader for a side project.
I have read in a hex file, verified the checksum and stored everything in flash with a corresponding address with an offset of 0x4000. I am having issues jumping to my application. I have read, searched and tried alot of different things such as the code here.
http://www.keil.com/support/docs/3913.htm
my current code is this;
int binary_exec(void * Address){
int i;
__disable_irq();
// Disable IRQs
for (i = 0; i < 8; i ++) NVIC->ICER[i] = 0xFFFFFFFF;
// Clear pending IRQs
for (i = 0; i < 8; i ++) NVIC->ICPR[i] = 0xFFFFFFFF;
// -- Modify vector table location
// Barriars
__DSB();
__ISB();
// Change the vector table
SCB->VTOR = ((uint32_t)0x4000 & 0x1ffff80);
// Barriars
__DSB();
__ISB();
__enable_irq();
// -- Load Stack & PC
binExec(Address);
return 0;
}
__asm void binexec(uint32_t *address)
{
mov r1, r0
ldr r0, [r1, #4]
ldr sp, [r1]
blx r0"
}
This just jumps to a random location and does not do anything. I have manually added the address to the PC using keil's register window and it jumps straight to my application but I have not found a way to do it using code. Any ideas? Thank you in advance.
Also the second to last line of the hex file there is the start linear address record:
http://www.keil.com/support/docs/1584.htm
does anyone know what to do with this line?
Thank you,
Eric Micallef
This is what I am talking about can you show us some fragments that look like this, this is an entire application just doesnt do much...
20004000 <_start>:
20004000: 20008000
20004004: 20004049
20004008: 2000404f
2000400c: 2000404f
20004010: 2000404f
20004014: 2000404f
20004018: 2000404f
2000401c: 2000404f
20004020: 2000404f
20004024: 2000404f
20004028: 2000404f
2000402c: 2000404f
20004030: 2000404f
20004034: 2000404f
20004038: 2000404f
2000403c: 20004055
20004040: 2000404f
20004044: 2000404f
20004048 <reset>:
20004048: f000 f806 bl 20004058 <notmain>
2000404c: e7ff b.n 2000404e <hang>
2000404e <hang>:
2000404e: e7fe b.n 2000404e <hang>
20004050 <dummy>:
20004050: 4770 bx lr
...
20004054 <systick_handler>:
20004054: 4770 bx lr
20004056: bf00 nop
20004058 <notmain>:
20004058: b510 push {r4, lr}
2000405a: 2400 movs r4, #0
2000405c: 4620 mov r0, r4
2000405e: 3401 adds r4, #1
20004060: f7ff fff6 bl 20004050 <dummy>
20004064: 2c64 cmp r4, #100 ; 0x64
20004066: d1f9 bne.n 2000405c <notmain+0x4>
20004068: 2000 movs r0, #0
2000406a: bd10 pop {r4, pc}
offset 0x00 is the stack pointer
20004000: 20008000
offset 0x04 is the reset vector or the entry point to this program
20004004: 20004049
I filled in the unused ones so they land in an infinite loop
20004008: 2000404f
and tossed in a different one just to show
2000403c: 20004055
In this case the VTOR would be set to 0x2004000 I would read 0x20004049 from 0x20004004 and then BX to that address.
so my binexec would be fed the address 0x20004000 and I would do something like this
ldr r1,[r0]
mov sp,r1
ldr r2,[r0,#4]
bx r2
If I wanted to fake a reset into that code. a thumb approach with thumb2 I assume you can ldr sp,[r0], I dont hand code thumb2 so dont have those memorized, and there are different thumb2 sets of extensions, as well as different syntax options in gas.
Now if you were not going to support interrupts, or for other reasons (might carry some binary code in your flash that you want to perform better and you copy that from flash to ram then use it in ram) you could download to ram an application that simply has its first instruction at the entry point, no vector table:
20004000 <_start>:
20004000: f000 f804 bl 2000400c <notmain>
20004004: e7ff b.n 20004006 <hang>
20004006 <hang>:
20004006: e7fe b.n 20004006 <hang>
20004008 <dummy>:
20004008: 4770 bx lr
...
2000400c <notmain>:
2000400c: b510 push {r4, lr}
2000400e: 2400 movs r4, #0
20004010: 4620 mov r0, r4
20004012: 3401 adds r4, #1
20004014: f7ff fff8 bl 20004008 <dummy>
20004018: 2c64 cmp r4, #100 ; 0x64
2000401a: d1f9 bne.n 20004010 <notmain+0x4>
2000401c: 2000 movs r0, #0
2000401e: bd10 pop {r4, pc}
In this case it would need to be agreed that the downloaded program is built for 0x20004000, you would download the data to that address, but when you want to run it you would instead do this
.globl binexec
binexec:
bx r0
in C
binexec(0x20004000|1);
or
.globl binexec
binexec:
orr r0,#1
bx r0
just to be safe(r).
In both cases you need to build your binaries right if you want them to run, both have to be linked for the target address, in particular the vector table approach, thus the question, can you show us an example vector table from one of your downloaded, programs, even the first few words might suffice...
I am trying to boot a freertos app from UEFI on Qemu
When i run the app from uboot, using the below commands it runs without any errors
fatload mmc 0 80300000 rtosdemo.bin
go 0x80300000
An uefi application loads the elf file at 0x80300000 and then I tried two options.
My boot.s file is below
`start:
_start:
_mainCRTStartup:
ldr r0, .LC6
msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction */
mov sp, r0
sub r0, r0, #UND_STACK_SIZE
msr CPSR_c, #MODE_ABT|I_BIT|F_BIT /* Abort Mode */
mov sp, r0
...
`
Disassembly file
`
80300000 <_undf-0x20>:
80300000: ea001424 b 80305098 <start>
80300004: e59ff014 ldr pc, [pc, #20] ; 80300020 <_undf>
80300008: e59ff014 ldr pc, [pc, #20] ; 80300024 <_swi>
8030000c: e59ff014 ldr pc, [pc, #20] ; 80300028 <_pabt>
80300010: e59ff014 ldr pc, [pc, #20] ; 8030002c <_dabt>
...........
80305098 <start>:
80305098: e59f00f4 ldr r0, [pc, #244] ; 80305194 <endless_loop+0x18>
8030509c: e321f0db msr CPSR_c, #219 ; 0xdb
803050a0: e1a0d000 mov sp, r0
803050a4: e2400004 sub r0, r0, #4
`
use goto 0x80305098 which is the entry point addr specified in the elf file. Now it jumps to ldr r0, .. instruction but after that it just seems to be jumping some where in the middle of some function rather than stepping into msr instruction.
Since in uboot its jumping to 0x80300000, I tried by jumping to that addr, now it goes to instruction b 80305098 <start>, but after that instruction instead of jumping to 80305098 it just goes to the next instruction ldr pc, [pc, #20].
So any ideas on where I am going wrong?
EDIT:
I updated boot.s to
start:
_start:
_mainCRTStartup:
.thumb
thumb_entry_point:
blx arm_entry_point
.arm
arm_entry_point:
ldr r0, .LC6
msr CPSR_c, #MODE_UND|I_BIT|F_BIT /* Undefined Instruction Mode */
mov sp, r0
Now it works fine.
This is ARM code, but it sounds very much like it's being jumped to in Thumb state. The word e59f00f4 will be interpreted in Thumb as lsls r4, r6, #3; b 0x80304bde (if I've got my address maths right), which seems consistent with "jumping somewhere in the middle of some function". You can verify by checking bit 5 of the CPSR (assuming you're not in user mode) - if it's set, you've come in in Thumb state.
If that is the case, then the 'proper' solution probably involves making the UEFI loader application clever enough to do the right kind of interworking branch, but a quick and easy hack would be to place a shim somewhere just for the initial entry, something like:
.thumb
thumb_entry_point:
blx arm_entry_point
.arm
arm_entry_point:
b start
I need to optimize my mixing code in c for faster response time, so i decided to use inline assembly to do a mixing of two buffers into a new bigger buffer. Basically i have left and right channels separated and i want to put them together into a buffer. So i need to put 2 bytes from the left channel and then two bytes from the right channel and so on.
for this i decided to send my 3 pointers to my assembly code where i intend to copy memory pointed by the left channel pointer into R0 register and memory pointed by right channel pointer into R1 afterwards i intend to mix R0 and R1 into R3 and R4 to later save those registers to memory.(I intend to use other free registers to do same procedure and reduce processing time with pipelining)
So I have two registers R0 and R1 with data, and need to mix them into R3 and R4, and i need to end up is R3 = R0HI(high-part) + R1HI(high-part) and R4 = R0LO(low-part) + R1LO(low-part)
I can think of using a bitwise shifts, but my questions is if there is an easier way to do it like in intel x86 architecture where you could transfer the data into ax register and then us ah as high part and al as low part?
is my thinking right? is there a faster way to do this?
my actual (not working) code in the ndk
void mux(short *pLeftBuf, short *pRightBuf, short *pOutBuf, int vecsamps_stereo) {
int iterations = vecsamps_stereo / 4;
asm volatile(
"ldr r0, %[outbuf];"
"ldr r1, %[leftbuf];"
"ldr r2, %[rightbuf];"
"ldr r3, %[iter];"
"ldr r4, [r3];"
"mov r8, r4;"
"mov r9, r0;"
"mov r4, #0;"
"mov r10, r4;"
"loop:; "
"ldr r2, [r1];"
"ldr r3, [r2];"
"ldr r7, =0xffff;"
"mov r4, r2;"
"and r4, r4, r7;"
"mov r5, r3;"
"and r5, r5, r7;"
"lsl r5, r5, #16;"
"orr r4, r4, r5;"
"lsl r7, r7, #16;"
"mov r5, r2;"
"and r5, r5, r7;"
"mov r6, r3;"
"and r6, r6, r7;"
"lsr r6, r6, #16;"
"orr r5, r5, r6;"
"mov r6, r9;"
"str r4, [r6];"
"add r6, r6, #1;"
"str r5, [r6];"
"add r6, r6, #1;"
"mov r9, r6;"
"mov r4, r10;"
"add r4, r4, #1;"
"mov r10, r4;"
"cmp r4, r8;"
"blt loop"
:[outbuf] "=m" (pOutBuf)
:[leftbuf] "m" (pLeftBuf) ,[rightbuf] "m" (pRightBuf),[iter] "m" (pIter)
:"r0","r1","r2","r3","memory"
);
}
I may not be 100% clear on what you are trying to do, but it looks like you want:
R3[31:16] = R0[31:16], R3[15:0] = R1[31:16];
R4[31:16] = R0[15:0], R4[15:0] = R1[15:0];
and not the actual sum.
In this case, you should be able to accomplish this relatively efficiently with a spare register for a 16-bit mask. ARM assembly offers shifting of a second operand as a part of most arithmetic or logical instructions.
MOV R2, 0xffff ; load 16-bit mask into lower half of R2
AND R3, R2, R1, LSR #16 ; R3 = R2 & (R1 >> 16), or R3[15:0] = R1[31:16]
ORR R3, R3, R0, LSR #16 ; R3 = R3 | (R0 >> 16), or R3[31:16] = R0[31:16]
AND R4, R2, R1 ; R4 = R2 & R1, or R4[15:0] = R1[15:0]
ORR R4, R4, R0, LSL #16 ; R4 = R4 | (R1 << 16), or R4[31:16] = R0[15:0]
; repeat to taste
Another option is to load just the 16 bits at a time, but this may be lower performance if your buffers are in slow memory, and it may not work at all if it doesn't support access less than 32 bits. I'm not certain if the core will request the 32 bits and mask out what isn't needed or if it relies on the memory to handle the byte lanes.
; assume R2 contains CH1 pointer, R3 contains CH2 pointer,
; and R1 contains output ptr
LDRH R0, [R2] ; load first 16 bits pointed to by CH1 into R0
STRH R0, [R1] ; store those 16 bites back into *output
LDRH R0, [R3] ; load first 16 bits pointed to by CH2 into R0
STRH R0, [R1, #2]! ; store those 16 bites back into *(output+2),
; write output+2 to R1
; after "priming" we can now run the following for
; auto increment of pointers.
LDRH R0, [R2, #2]! ; R0 = *(CH1+2), CH1 += 2
STRH R0, [R1, #2]! ; *(Out+2) = R0, Out += 2
LDRH R0, [R3, #2]! ; R0 = *(CH2+2), CH1 += 2
STRH R0, [R1, #2]! ; *(Out+2) = R0, Out += 2
; Lather, rinse, repeat.
These two examples make use of some of the handy features of ARM assembly. The first example makes use of the built in shift available on most instructions, while the second makes use of sized load/store instructions as well as the write-back on these instructions. These should both be compatible with Cortex-M cores. If you do have a more advanced ARM, #Notlikethat's answer is more suitable.
In terms of code size, when you add the load and store to the first example, you end up executing two load instructions, the four logic instructions, and two stores for a total of eight instructions for mixing two samples. The second examples uses two loads and two stores for a total of four instructions when mixing one sample, or, well, eight instructions for mixing two.
You will probably find the first example works faster, as it has fewer memory accesses, and the number of stores can be reduced by using a STM store multiple instruction (ie STMIA OutputRegister!, {R3, R4}). In fact, the first example can be pipelined a bit by using eight registers. LDMIA can be used to load four 16 bit samples from a channel in one instruction, perform two sets of the four mixing instructions, and then store the four output registers in one STMIA instruction. This likely wouldn't offer much benefit in performance since it will likely interact with the memory in the same manner (STM and LDM just execute multiple LDRs and STRs), but if you are optimizing for minimal instructions, this would result in 11 instructions to mix four samples (compared to 16).
ARM registers are strictly 32-bit, however provided you're on a recent enough core (v6+, but not Thumb-only v7-M) there are a number of suitable instructions for dealing with halfwords (PKHBT, PKHTB), or arbitrary slices of registers (BFI, UBFX), not to mention crazy parallel add/subtract instructions that frighten me (available with saturating arithmetic which can be useful for audio, too)..
However, if your machine implements NEON instructions they would be the route to the optimal implementation since this is exactly the sort of thing they're designed for. Plus, they should be accessible through compiler intrinsics so you can use them directly in C code.
I'm currently writing some basic ARM assembler. The idea is to control a theoretical furnace and it's cooling/heating system on the LPC2378 development board with an application board attached.
I'm getting there as far as recognising input from the devices is concerned. However, i'm having trouble getting my loop right and I was hoping you guys may be able to point out why my loop is getting stuck, and even after button 1 has been pressed, the fan is not turning on. I previously had the fan working, but when I started trying to control the fan by the temperature of the heater it does not seem to ever start up, and the heater stays on, getting hotter and hotter without the fan to cool it down.
I'm guessing it could come down to the way i'm reading the temperature from the ADC controller.
Please don't hesitate to ask if you need any more information to answer the question.
;=========================================================================
; MotorControl_1
;
; BUT1 turns motor ON and BUT2 turns motor OFF
;
; No interrupt support (except for Reset) - as simple as it gets!
;
; WDH, November 2008
;==========================================================================
; Set-up interrupt vectors and stack support
$ LPC2378InterruptVectors.s
; After a reset exception, execution starts here - the processor is in ARM
; mode and supervisor state with interrupts disabled
SECTION .text:CODE:NOROOT(2)
REQUIRE __vector ; Forces reference to this symbol - required by linker
ARM
; __iar_program_start - defined start symbol.
__iar_program_start:
; Include lpc2378 IO register definitions
#include "iolpc2378.h"
; Include Olimex LPC-2378-STK IO definitions
#include "OlimexLPC2378BoardDefs.h"
; Main entry point - required by debugger
;=========================================================================
; main starts here
;=========================================================================
main
;=========================================================================
; Stack setup
;
; Stack pointer (r13 or SP) is assigned the highest address in a 32kB
; section of on-chip SRAM - assumes a FULL descending stack convention
;=========================================================================
ldr r13, = 0x40008000
ldr r2, = 0x000050 ;Load the delay value
ldr r3, = 0x028 ;Start set point at 40
ldr r4, = 0x000 ;Start temp difference as 0
; ldr r6, = 0x0f ;Temp High Value (15)
; ldr r7, = -0xF ;Set r7 to -15.
; Initialise IO
BL InitialiseARM_IO
BL InitialiseApplicationsBoard_IO
; Initialise the devices and display
BL FanOff
BL errorLedOff
BL systemLedOff
BL heaterOff
LoopStart
BL WaitBUT1
BL heaterOn
BL systemLedOn
BL readTemp
BL checkTemp
CMP r0, #5
BGT errorVal
SUBS r7, r6, r4 ;Performs r7 = r6 - r4 and sets condition register
BLT LoopStart ;Branches to label_bar if r7 < 0 (in which case r6 < r4)
BGT heaterOff
BGT errorLedOn
BGT FanOn
BGT LoopStart
BL WaitBUT2
BL FanOff
BL errorLedOff
BL systemLedOff
BL heaterOff
B LoopStart
;=========================================================================
; InitialiseARM_IO
;
; Initialise the ARM interface, as follows:
;
; Port0(13..14} GPIO Output to on-board LEDs
; bit 13: USB_LINK LED
; bit 14: USB_CONNECT LED
; Port0{18,29} GPIO Input from BUT1 and BUT2
; bit 18: BUT2 pressbutton input
; bit 29: BUT1 pressbutton input
; Port1{18,19} GPIO Inputs from joystick UP and DOWN
; bit 18: UP joystick inout
; bit 19: DOWN joystick input
;=========================================================================
InitialiseARM_IO
; Define data direction for LEDs - the LEDs are connected
; to P0.13 and P0.14
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
;LEDs on ARM board:
; Assign GPIO on P0.13 and P0.14
LDR R5, =PINSEL0 ; Address of PINSEL0
LDR R0, [R5] ; Read current PINSEL0
BIC R0, R0, #0x3C000000 ; Clear bits 26..29
STR R0, [R5] ; Put back in PINSEL0
; Configure output for P0.13 and P0.14
LDR R5, =IO0DIR ; Address of IO0DIR
LDR R0, [R5] ; Read current IO0DIR
ORR R0, R0, #0x6000 ; Set bits 13 and 14 - for P0.13 and P0.14
STR R0, [R5] ; Put back in IO0DIR
; Switches and Joystick inputs on ARM board
; Assign GPIO on P0.18 and P0.29
LDR R5, =PINSEL1 ; Address of PINSEL1
LDR R0, [R5] ; Read current PINSEL1
BIC R0, R0, #0x30 ; Clear bits 4..5
BIC R0, R0, #0x0c000000 ; Clear bits 26..27
STR R0, [R5] ; Put back in PINSEL0
; Configure input for P0.18 and P0.29
LDR R5, =IO0DIR ; Address of IO0DIR
LDR R0, [R5] ; Read current IO0DIR
BIC R0, R0, #0x20000000 ; Clear bits 18 and 29 - for P0.18 and P0.29
BIC R0, R0, #0x00040000
STR R0, [R5] ; Put back in IO0DIR
; Assign GPIO on P1.18 and P1.19
LDR R5, =PINSEL3 ; Address of PINSEL3
LDR R0, [R5] ; Read current PINSEL3
BIC R0, R0, #0xF0 ; Clear bits 4..7
STR R0, [R5] ; Put back in PINSEL3
; Configure input for P1.18 and P1.19
LDR R5, =IO1DIR ; Address of IO1DIR
LDR R0, [R5] ; Read current IO1DIR
BIC R0, R0, #0xc0000 ; Clear bits 18 and 19 - for P1.18 and P1.19
STR R0, [R5] ; Put back in IO1DIR
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; InitialiseApplicationsBoard_IO
;
; Initialise the interface to the Applications Board, as follows:
;
; Port4{0..7} GPIO Output to LEDs, Motor and Heater
; bits 0..4: Temperature error LED indicators
; bit 5: Heater control
; bits 6..7: Motor control
; Port4(8..15} GPIO Input from ADC
; bits 8..15: Inputs from Application Board ADC
;
;=========================================================================
InitialiseApplicationsBoard_IO
; Define data direction for LEDs - the LEDs are connected
; to P0.13 and P0.14
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
; Applications Board Interface via Port4
; Set FIO4MASK to allow access to all bits
LDR R5, =FIO4MASK ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
MOV R0, #0x0 ; Clear all bits of FIO4MASK
STR R0, [R5] ; Put back in IO4DIR
; Configure output for P4.0 to P4.7
LDR R5, =FIO4DIR ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
ORR R0, R0, #0xFF ; Set bits 0..7 - for P4.0 and P4.7
STR R0, [R5] ; Put back in IO4DIR
; Configure input for P4.8 to P4.15
LDR R5, =FIO4DIR ; Address of FIO4DIR
LDR R0, [R5] ; Read current IO4DIR
BIC R0, R0, #0xFF00 ; Clear bits 8..15 - for P4.8 and P4.15
STR R0, [R5] ; Put back in IO4DIR
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Wait for BUT1 to be pressed
;=========================================================================
WaitBUT1
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
WaitForBUT1Pressed
ldr r0, = IO0PIN ; Address of FIO0PIN register
ldr r1, [r0] ; Read FIO0PIN in to r1
ands r1, r1, # B1_MASK ; Mask out BUT1
beq BUT1Pressed ; Exit LED toggle loop if button is pressed
B WaitForBUT1Pressed
BUT1Pressed
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Wait for BUT2 to be pressed
;=========================================================================
WaitBUT2
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
WaitForBUT2Pressed
ldr r0, = IO0PIN ; Address of FIO0PIN register
ldr r1, [r0] ; Read FIO0PIN in to r1
ands r1, r1, # B2_MASK ; Mask out BUT1
beq BUT2Pressed ; Exit LED toggle loop if button is pressed
B WaitForBUT2Pressed
BUT2Pressed
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Turn Fan Motor ON
;=========================================================================
FanOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x80
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;=========================================================================
; Turn Fan Motor OFF
;=========================================================================
FanOff
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
BIC r0, r0, #0xc0
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Turn On Error LED
;==============================================================================
errorLedOn
STMFD r13!,{r0, r5,r14}
mov r0, # USB_LINK_LED_MASK
ldr r5, = IO0CLR
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Off Error LED
;==============================================================================
errorLedOff
STMFD r13!,{r0, r5,r14}
mov r0, # USB_LINK_LED_MASK
ldr r5, = IO0SET
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn On System LED
;==============================================================================
systemLedOn
STMFD r13!,{r0, r5,r14}
mov r0, # USB_CONNECT_LED_MASK
ldr r5, = IO0CLR
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Off System LED
;==============================================================================
systemLedOff
STMFD r13!,{r0, r5,r14}
mov r0, # USB_CONNECT_LED_MASK
ldr r5, = IO0SET
str r0, [r5]
LDMFD r13!,{r0, r5, r14}
mov pc, r14
;==============================================================================
; Turn Heater On
;==============================================================================
heaterOn
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
ORR r0, r0, #0x20
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Turn The Heater Off
;==============================================================================
heaterOff
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR R5, =FIO4PIN ; Address of FIO4PIN
LDR r0, [r5] ; Read current Port4
AND r0, r0, #0xDF
STR r0, [r5] ; Output
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Read Temperature
;==============================================================================
readTemp
STMFD r13!,{r0,r5,r14} ; Push r0, r5 and LR
LDR r0, =FIO4PIN
LDR r1, [r0]
LSR r1, r1, #8
AND r1, r1, #0xFF ; r1 now holds the temperature value
LDMFD r13!,{r0,r5,r14} ; Pop r0, r5 and LR
mov pc, r14 ; Put link register back into PC
;==============================================================================
; Implement Counter And Read Temperature
;==============================================================================
checkTemp
STMFD r13!,{r0, r14} ; Push PC, r0, Lr
LSR r1, r1, #8
LDR r0, [r2] ; Load delay value in r0.
SUB r0, r0, #0x01 ; Minus 1 from delay.
BEQ readTemp ; Branch if timer counted down.
errorVal
STMFD r13!,{r0, r14} ; Push PC, r0, Lr
SUB r1, r3, r6 ; Subtract set point from temperature, into r6
mov pc, r14 ; Put link register back into PC
END
It looks like you've confused BGT (branch if greater-than) with BLGT (branch and link if greater-than). In the middle of your main loop you have this:
BLT LoopStart ;Branches to label_bar if r7 < 0 (in which case r6 < r4)
BGT heaterOff
BGT errorLedOn
BGT FanOn
BGT LoopStart
If the condition is "greater-than", your code will branch to heaterOff and then when that function returns, it will exit the code entirely. The functions errorLedOn and FanOn can never execute.