Assembly LED code

12 Feb 2012

Hi,

I am not sure if what I am asking will be just too much out of the MBED community as my understanding of assembly language for the MBED is rudimentary. What I have been trying to look for is a beginners tutorial in how a pure assembly program is written to make an LED flash on the MBED 1768 board with if possible step by step explanation of what each line does and what memory addresses are used and where are the LED output addresses.

I tried to debug the simple DigitalOut myled(LED1) program available here but I don't understand how the code finds the physical output registers to make the LED flash.

If the code in assembly is too long a am happy with a partial hint on how the C++ or ASM program finds the outputs.

Many Thanks.

Replies

13 Feb 2012

You'll find the addresses in the LPC headers. Create a project,click on imported mbed library and open it on right side

16 Feb 2012

Thanks for the hint, I am starting to understand more on it reading the LPC1768 Manual, but not quite there yet.

So GPIO for LED 1 is the GPIO starting 0x2009C020 and looking at some assembler code there is also some address 0x040000, which I presume it is BIT 18 for P1[18]

The part I still don't fully understand is how both of these addresses are linked, could any of you guys explain to me how from address 0x2009C020 we reach P1[18]

Thanks again.

16 Feb 2012

Did you see the example at http://mbed.org/cookbook/Assembly-Language

16 Feb 2012

Yes I did, I have never really attempted assembly coding since a brief time back in the 90's with the Amiga Computer. Trying to fully understand how addressing works to such a low level is a slight challenge for me but slowly I am getting there while reading through the manuals and ARM tutorials.

Thanks

16 Feb 2012

There are several ways to write to port pins from assembler:

You can create a mask for the selected pin and use the 'set' and 'reset' registers

or

You can write some binary value directly to the output register.

Note all port registers are in principle 32 bits but you can address them 8, 16 and 32 bits at a time creating very flexible ways of driving the port pins (and very fast too if needed) It will take some studying, not only to understand the IO system but also how all addressing modes of the ARM CPU work. If you do not need the absolute maximum speed I would stick to C, in one of my own projects I deliberately used some assembler to get the 'promised' 120 nsec response to an interrupt and to keep my interrupt routine under 1 usec in total. It takes a lot of tweaking to get assembler routines right and for the rest of the code I used standard C and mbed libraries.

If you want to learn more about the inner stuff of the mbed's CPU get a copy of the UM10360 LPC17xx manual and also take a peek at:

http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337e/index.html

Prepare for some heavy reading though :)

16 Feb 2012

Here is some example on how to write a value directly to the port pins:

save this part as asmtest.s

Code

    AREA asm_func, CODE, READONLY
    
; Export my asm function location so that C compiler can find it and link
    EXPORT speed_check
    
    ALIGN


speed_check

    ; setup a pointer to the base address of port 1
    LDR     R1,=0x2009c020      ; pointer to base of port1 

loop
    LDR     R3,=0x00000000      ; set LED 1 off (all bits 'zero')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
 
    LDR     R3,=0x00040000      ; set LED 1 on (bit 18 aka P1.18 is 'one')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
           
    B       loop                ; branch to loop (endless loop!)
    
    ALIGN
    END

and the calling C code (main.c):

Code

#include "mbed.h"

DigitalOut myled(LED1);
extern "C" void speed_check();

int main() {
    
    speed_check();  // execute assembler routine

    // this part is never reached
    while(1) {
    }
}

The result of this little program is that LED1 is switched on and off as fast as possible resulting in multi MHZ blinking speed. The effect is that you will see the LED light up at half brightness.

Note, this code resets all bits on port1 to zero regardless of the internal function. Normally you would use the special set and clear registers with a mask to not disturb the other port pins.

16 Feb 2012

Wow, Thanks for this.

I will study the code along with the recommendations you also gave on the link for the Cortex M3.

Most grateful for this.

thanks,

18 Feb 2012

Code

	GLOBAL __main
	AREA main, CODE, READONLY
	EXPORT __main
	EXPORT __use_two_region_memory
__use_two_region_memory EQU 0
	EXPORT SystemInit
	ENTRY
; Dummy System Init routine
SystemInit
	BX		LR
; ASM setup above to keep Keil tools happy - starts at label __main
; (for version 4.21 - might need minor changes for another version)
;
; Simulate C arg in R0, a Call to my_asm, and then loop forever
__main
	LDR		R0,=0
	BL		my_asm
	LDR		R0,=1
	BL		my_asm
	B		__main
; Assembly code to test below:

    AREA asm_func, CODE, READONLY
    
; Export my asm function location so that C compiler can find it and link
    EXPORT my_asm
    
    ALIGN


my_asm

    ; setup a pointer to the base address of port 1
    LDR     R1,=0x2009c020      ; pointer to base of port1 

loop
    LDR     R3,=0x00000000      ; set LED 1 off (all bits 'zero')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
 
    LDR     R3,=0x00040000      ; set LED 1 on (bit 18 aka P1.18 is 'one')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
           
    B       loop                ; branch to loop (endless loop!)
    
    ALIGN
    END

So I configured the Keil compiler as shown on the tutorial to make me a .bin file as pure to assembly language as possible without using C, the code compiles and and the debug seems to give me the impression that the code works as it should be but when I run it on the MBED hardware I get no LED1 light.

What have missed?

19 Feb 2012

The C line:

Code

DigitalOut myled(LED1);

initializes the port pins. In your code the port pin is not initialized as output.

Add a line like this before the loop and after the LDR R1

Code

my_asm

    ; setup a pointer to the base address of port 1
    LDR     R1,=0x2009c020      ; pointer to base of port1 

    LDR     R3,=0x00040000      ; set LED 1 port pin to output
    STR     R3,[R1,#0x00]       ; set direction bits (base+0x00)

loop
    LDR     R3,=0x00000000      ; set LED 1 off (all bits 'zero')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
 
    LDR     R3,=0x00040000      ; set LED 1 on (bit 18 aka P1.18 is 'one')
    STR     R3,[R1,#0x14]       ; set outputs directly (base+0x14)
           
    B       loop                ; branch to loop (endless loop!)
    
    ALIGN
    END

20 Feb 2012

Thank you again.

Please log in to post a reply.