Binary to ASCII converter
XOR instead of MOV
In your main subroutine, you move the value 0 into two registers.
A more efficient way to do that is to XOR the register with itself, like so:
xor r3, r3
Unnecessary branching
In your main subroutine, you branch over to the loop subroutine.
Since the loop subroutine is right beneath the main subroutine, you do not need a branch there since execution will just &quot;fall through&quot; to the loop subroutine.
Labels
I'm not sure how this works in ARM, but you seem to be using only global labels in your program, when there should be some local labels.
Local labels exist inside global labels, and they act kind of like a subroutine for a subroutine.
A change I might make is make the end_loop label a local label.
For more information on local labels, see here
For information on the syntax of a local label, see here
Disclaimer: I am not too familiar with ARM assembly, although I am familiar in other assemblies; some things I tell you might not work