Decimal to binary conversion in ARM assembly
Here are a number of things that may help you improve your program.
Understand the calling convention
The procedure call standard for ARM says that the registers r0, r1, r2, and r3 can be used and not restored by a called function.  Further, if we don't alter lr, there's no need to preserve and then restore it.  These are all clues for making your program more efficient.
Know your instruction set
The code currently contains these lines:
    movs    r4, r4, lsr #1      @ divide by 2, set carry
    bcs     _odd                @ if carry set, remainder is 1
_even:
    mov     r5, #0              @ remainder of 0
    b       _toString
_odd:
    mov     r5, #1              @ remainder of 1
_toString:  
    add     r5, #48             @ convert

That is terribly inefficient.  We can simplify considerably:
    mov     r5, #48             @ start with ASCII '0'
    movs    r4, r4, lsr #1      @ divide by 2, set carry
    adc     r5, #0              @ add zero + carry
    

Minimize branching
The code ends with this curious combination:
    ble     _endloop
    b       _loop
_endloop:

First, the comment suggests that we're looking for exactly zero and so we should be looking only at the zero flag (beq or bne) rather than doing a signed comparison with ble.  Second, why not simply use a single instruction?
    beq     _loop

However, better, see the next suggestion.
Create reusable code
The code currently exits if the shifted value becomes zero.  That works, but only once.  In other words, if you use the routine to decode 255 and then again to decode the value 3, you will likely be surprised that your routine will falsely give the same binary string for both.  The problem is that it relies on the binStr buffer to always contain a string of zeroes.  A better approach is to explicitly set each byte of the buffer and instead use the counter you already have in r9.  This shortens the code and makes it reusable.
    subs    r9, r9, #1  
    bpl     _loop

Move loop invariants outside the loop
Every iteration through the loop we load the r1 register with the address of binStr even though r1 is never changed within the loop.  A more efficient approach would be to load r1 once outside the loop.
Document register usage
One of the keys to being a good assembly language programmer is to carefully manage register use.  The most basic requirement is to keep track of how you're using registers, and a good way to do that, both for yourself and future readers of the code is to document the use.  Based on the observations in the first suggestion above, here's what I used:
@ Register usage:  
@   r0 - passed value
@   r1 - pointer to current string digit
@   r2 - decrementing digit offset
@   r3 - the current digit

Results
Using all of these suggestions, the resulting routine is only nine instructions.
decToBin:
    ldr     r1, =binStr         @ output string location
    mov     r2, #7              @ start with the LSB 
_loop:
    mov     r3, #48             @ start with ASCII zero
    movs    r0, r0, lsr #1      @ divide by 2, set carry
    adc     r3, #0              @ add the extracted bit
    strb    r3, [r1, r2]        @ store remainder in string at pos in r9
    subs    r2, r2, #1          @ decrement counter
    bpl     _loop               @ end if it has gone negative
    bx      lr

Armed with these suggestions (pun intended!) see if you can perform a similar cleanup on the rest of the code.  In particular, there is a much more efficient way to check if the input value is in the appropriate range (hint: movs r1, r0, lsr #8).
Also, just for fun, this answer was composed and tested entirely on a Raspberry Pi running on battery power.
Other ideas
A more generally useful routine would have the caller pass a buffer pointer and buffer length into which the program would put its result rather than using a fixed location.  See if you can figure out how to modify the code to do that, and don't forget to place the terminating \0 character.