Help with asm loop

Go To Last Post
19 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm having a little trouble getting this loop to work. I've been reading the documentation over at avrbeginners.net and constructed this:

#include 

#define DDRD 0x11
#define PD0 0x12

.global main

main:       
            ldi         r16, 0x01   ; enable output on port D[0]
            out         DDRD, r16            

            in          r24, PD0    ; toggle LED
            ldi         r25, 0x01
            eor         r24, r25
            out         PD0, r24

            ldi         r30, 0      ; clear counting register
            
delay:
            nop
            nop
            nop
            nop
            nop
            inc         r30
            cpi         r30, 0xFF
            brne        delay       ; repeat until counter is 255
            rjmp        main

I'm not exactly sure where I went wrong here. I'm trying to loop through delay:, then return to main and xor the value of PD0. Can anyone point me in the right direction?

Last Edited: Fri. Dec 14, 2007 - 10:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, what does "went wrong" mean?

Most of us would prefer seeing DDRD, PORTD, etc. in the source. From what you posted, and not knowing which AVR model you are using, it is kind of hard to tell if 0x12 and 0x11 are correct.

But if this is indeed an LED that you are "watching", a short delay as your loop is doing will almost certainly show the LED as "on".

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

What assembler are you TRYING to use? Obvioulsy not the Studio assembler as the syntax is wrong for it.

How do you know it doesn't work? Have you tryed runing the code in the simulator?

Hints: tell the assembler whinch chip you are using.
Initialise the stack even if you don't need it now.
Don't use numbers for register names.
It is usually better in delay loops to start a register with a value and then decrement to 0. ie you won't need the cpi line.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

theusch wrote:
Well, what does "went wrong" mean?

Most of us would prefer seeing DDRD, PORTD, etc. in the source. From what you posted, and not knowing which AVR model you are using, it is kind of hard to tell if 0x12 and 0x11 are correct.

But if this is indeed an LED that you are "watching", a short delay as your loop is doing will almost certainly show the LED as "on".

Thanks, I updated the post to reflect DDRD and PD0; Anyway - sure enough - it just wasn't a long enough delay.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you meant PORTD, not PD0 (which is probably defined as 0, or maybe 1).

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:

It is usually better in delay loops to start a register with a value and then decrement to 0. ie you won't need the cpi line.

Thanks, I'll use that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Looks like you are still confused :) IF you are using Studio go into Help>AVR Tools user guide>STK500>Example Applications
There is a little program there that can shed some light.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Looks like you are still confused :) IF you are using Studio go into Help>AVR Tools user guide>STK500>Example Applications
There is a little program there that can shed some light.

I don't know what you mean by still confused... it's working now. The reason the ports were not defined is because I'm having problems getting __AVR_GCC__ to define the locations properly. I figured that's for another forum though.

Thanks again for your help

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And if you write in C, the code will become much nicer :)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

blader wrote:
And if you write in C, the code will become much nicer :)

Haha... I do that for a living, this is for fun =]

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well, I'm still a little afraid to give any advice after clawson's last advice :D, however:

If you still use gcc's assembler - you need to "fix up" IO addresses with _SFR_IO_ADDR().

I know you're a Linux user. Just try avra, it's almost compatible with Atmel's assembler. Still you need some **something**.inc. I'm sure you can acquire these files by launching AVR Studio setup under WINE.

If you're user of Ubuntu or other Debian-like Linuxes, you can tray

apt-get install **something**

Still your loop is too fast.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
I don't know what you mean by still confused... it's working now.
Then I'm confused :? I see that you are not using the Atmel assembler. Still don't you have to tell the assembler which chip you are using or do you plan to define ALL bits of the chip which are already defined in the chip's include file like DDRD etc.?

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Quote:
I don't know what you mean by still confused... it's working now.
Then I'm confused :? I see that you are not using the Atmel assembler. Still don't you have to tell the assembler which chip you are using or do you plan to define ALL bits of the chip which are already defined in the chip's include file like DDRD etc.?

The chip is defined as an argument to avr-gcc.. I don't plan on continuing to use the direct I/O addresses - it's just a quick way for me to get familiar with assembly before I tackle anything else.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Quote:
I don't know what you mean by still confused... it's working now.
Then I'm confused :? I see that you are not using the Atmel assembler. Still don't you have to tell the assembler which chip you are using or do you plan to define ALL bits of the chip which are already defined in the chip's include file like DDRD etc.?

John,

He's using avr-as rather than avrasm2. Just like the C compiler (which actually just converts C to avr-as source then assembles it anyway) the avr-as assembler is invoked from a Makefile and in that Makefile there's likely an "MCU=atmega16" or something that ultimately passes to the assembler as a "-mmcu=atmega16" command line option.

When using avr-as, just like when using avr-gcc all you need do in each source file is "#include " and then the -mmcu value that has been given will arrange for the right io???.h file to actually be used during the assembly.

As I told the lads in another post the only downside of using avr-as "in the raw" is that those .h files are really optimised for use in the C not the assembler so you cannot just use:

out PORTB, 23

but must use:

out _SFR_IO_ADDR(PORTB), 23

so that the correct 0x20 offset adjustments are made. To my mind this makes avr-as code look "messy" and if it were me I think I'd be tempted to use Atmel's xmlconvert.exe to convert the part description XML file to a raw header file with the absolute RAM addresses.

Oh an one other thing about avr-as compared to avrasm2 - it's a relocating/linking assembler, not an absolute assembler so there's no .org and you don't actually know at what address main: will be positioned. Oh and the entry point must be called "main:" because, like C, there's some code added before it gets to main: which just tries to link to a label of that name. The "pre-amble" does stuff like setting the stack before it reaches main: so there's no need for an avr-as program to do the out SPH/SPL thing at the top - that's implied already.

Being a linking assembler it is, of course, more powerful than avrasm2 and, for example, has absolutely no problem with linking to an existing library such as libm.a - so if you want sin()'s, cos()'s, tan()'s and even just floating point arithmetic in your Asm program you got them - just set up the call parms, call the library functions and then link to that libm.a maths library.

Equally you ccan write some of your subroutines in C and call them from the Asm main: function after having them compiled separately.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
avr-as assembler is invoked from a Makefile... etc. etc.

Well, OK people like to make life hard for themselves :lol:
But I guess if uidzer0 is not using Windows and Studio then this bit will just be a minor inconvenience..:lol:

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
To my mind this makes avr-as code look "messy" and if it were me I think I'd be tempted to use Atmel's xmlconvert.exe to convert the part description XML file to a raw header file with the absolute RAM addresses.
I'm not an assembly guy, but seeing as how over 50% of my bootloader was assembly, I decided to try avr-as. The _SFR_IO_ADDR/_SFR_MEM_ADDR is messy, so I just made a macro (was not able to get it done with a define macro for some reason)-
    .macro STORE addr,reg
        .if \addr < 0x60
            out \addr - 0x20,\reg
        .else
            sts \addr,\reg
        .endif
    .endm

    .macro LOAD reg,addr
        .if \addr < 0x60
            in \reg,\addr - 0x20
        .else
            lds \reg,\addr
        .endif
    .endm

which I'm sure is no different than anyone else's macros (well, except for the part where all io names will end up as mem addr, hence the -0x20). Although the 'in/out' will accept <0x20 in the macro, if I mistakenly do it the assembler will let me know (which I would want, as I don't want the macro to automatically make a lds/sts on a register address).

So the not-so-great-looking _SFR macros can be eliminated. I also have LOAD_S/STORE_S if I want to 'force' a lds/sts (not necessary, but now I should never see or use lds/sts/in/out in my code).

The nice thing about avr-as (at least when you are also using avr-gcc), is you can use the C preprocessor (#define/#if/etc), so you can keep previously made defines, use (some) existing header files, etc.

You 'real' asm guys- I don't know how you do it. I can almost handle asm on a 256 word app, but anything larger and I would give up hope of ever finishing anything. It is kind of fun though (up to a point).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
is you can use the C preprocessor (#define/#if/etc
You can use the C preprocessor with Studio assembler 2 :)

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey, I'm about 10 years behind the times, its just going to take me a while to catch up. I haven't even touched studio assembler 1, or even studio assembler 0 (I'm just thankful I'm not bank switching or sending everything through a w register).

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

js wrote:
Quote:
is you can use the C preprocessor (#define/#if/etc
You can use the C preprocessor with Studio assembler 2 :)

Except see recent thread in Studio forum where a bug/limitation in the avrasm2 C-pre-processor style #if/#define thing was found:

https://www.avrfreaks.net/index.p...

it's often safer to use a "real" C pre-processor and they don't come any more "real" than the one used in GCC

Cliff