ASM Newbie: weird initial results, what's going on?

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

Hi all,

I'm very new to programming AVR in assembler and my initial experiments have left me kind of confused. I've some some searching here and through google, but haven't been able to figure out what I've missed or done incorrectly.

First, the setup: I'm using an ATTiny25, programming with an adafruit usbtiny, and using the gcc toolchain since I'm using a mac. (So, I write some assembly.S, compile it with avr-gcc, extract a hex from the .o with avr-objcopy, and upload with avrdude.)

Now, the problem: this is pretty much a skeleton program that should toggle all output pins on and off with a nice, 50% duty cycle. But that's not what happens. Instead, the pins go high for about 5 microseconds, then stay low for about 120 microseconds (as eyeballed on my oscilloscope). Whaaaat?

Here's the code in its entirety:


.arch attiny25

#define __SFR_OFFSET 0

#include 

#define mp r16

0:
        rjmp    reset           ;reset vector                                                        
        rjmp    reset           ;1                                                                   
        rjmp    reset
        rjmp    reset
        rjmp    reset
        rjmp    reset
        rjmp    reset
        rjmp    reset
        rjmp    reset
        rjmp    reset           ;9                                                                   


reset:
        ldi     mp, RAMEND
        out     _SFR_IO_ADDR(SPL),mp
	
        ldi     mp, 0x3F
        out     DDRB, mp        ; all ports output                                                   

        out     PORTB, mp       ; all pins on                                                        

loop:
        ldi     mp,0x3F
        out	PINB,mp
        rjmp	loop

The fuse bits are all left at default, except I turned the clock/8 fuse off to see if it had any effect. (It did; everything sped up. Before the pins were going high for about 40us and staying low for almost 1ms).

If I comment out the #include and instead use register offsets for SPL/DDRB/PORTB/PINB directly from the datasheet, the behavior is the same, so that doesn't seem to be it.

I doubt it's a circuit thing, but for the sake of completeness: there is an LED +330ohm resistor attached to PB0, a .1uf cap decoupling Vcc to gnd, reset is held to +Vcc, and the power supply is a (supposedly) nice and even 3.3v from a sparkfun regulator kit.

If I change the main loop so that it reads like this:

loop:
ldi mp,0x3F
out PORTB, mp
forever:
rjmp forever

...the pins go high like they're supposed to and stay that way forever.

So what's wrong with the first code block? Any feedback MOST welcome.

Thanks,
Conor Peterson

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

There is more to go wrong in asm as you have to manage every little detail. May I make the suggestion that you learn to program the AVR using GCC. If you really want to use asm, you can still do that and you have the benefit of seeing the asm that GCC produces.

After 40 years of using asm on controllers that only had two or three working registers, I just can't be bothered keeping track of what happens in 32 registers.
Life is just too short for asm!

Charles Darwin, Lord Kelvin & Murphy are always lurking about!
Lee -.-
Riddle me this...How did the serpent move around before the fall?

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

I can't see why it doesn't work - writing to PINB is valid according to the ATTINY25 data sheet and will toggle the outputs.

I'm confused about gcc and your code being in ASM - so let's get real simple in ASM...

.arch attiny25 ;<- not sure what this does

0: ;<-normally would be .org 0
        rjmp    reset           ;reset vector
reset:
        ldi     r16, 0x3F
        out     DDRB, r16       ; all pins output
loop:
        ldi     r16,0x3F
        out     PORTB, r16      ;all pins high
        ldi     r16,0x00
        out     PORTB, r16      ;all pins low
        rjmp   loop 

What does that do?

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

That loop should take 4 clocks, so 4us at 1MHz and 500ns at 8MHz. I have no idea why your getting such high values or why it is not a square wave.

Regards,
Steve A.

The Board helps those that help themselves.

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

Hi guys,

Thanks for responding! I've got an update, but no solution yet.

Look at the disassembly, especially the last line, the rjmp:

(initial junk removed)
00000014 :
  14:	0f ed       	ldi	r16, 0xDF	; 223
  16:	0d bf       	out	0x3d, r16	; 61
  18:	0f e3       	ldi	r16, 0x3F	; 63
  1a:	07 bb       	out	0x17, r16	; 23
  1c:	08 bb       	out	0x18, r16	; 24

0000001e :
  1e:	0f e3       	ldi	r16, 0x3F	; 63
  20:	06 bb       	out	0x16, r16	; 22
  22:	00 c0       	rjmp	.+0      	; 0x24 

It looks like it's jumping to nowhere! So presumably the lonnnnng delay is caused by the PC falling off the end of the page.

Indeed, if I do this:

sbi PORTB,0
cbi PORTB,0
sbi PORTB,0
cbi PORTB,0

I get two spikes before the long delay.

So this is looking like a gcc problem.

MartinM57: I had to replace PORTB with 0x18 (and DDRB to 0x17) to get your simplification to compile. Here's the disassembly:

00000000 :
   0:	00 c0       	rjmp	.+0      	; 0x2 

00000002 :
   2:	0f e3       	ldi	r16, 0x3F	; 63
   4:	07 bb       	out	0x17, r16	; 23

00000006 :
   6:	0f e3       	ldi	r16, 0x3F	; 63
   8:	08 bb       	out	0x18, r16	; 24
   a:	00 e0       	ldi	r16, 0x00	; 0
   c:	08 bb       	out	0x18, r16	; 24
   e:	00 c0       	rjmp	.+0      	; 0x10 

It looks like it will have the same problem, unless I'm misunderstanding the rjmp instruction (which could very well be the case!). Unfortunately, I just left the studio, so testing it properly will have to wait 'till tomorrow.

For the time being, I'm going to focus my research on the avr-gcc end of things. When I figure this out, I'll be sure to post back here.

Thanks again everyone, and any further comments / speculation welcome.

[/b]

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

LDEVRIES wrote:
There is more to go wrong in asm as you have to manage every little detail. May I make the suggestion that you learn to program the AVR using GCC. If you really want to use asm, you can still do that and you have the benefit of seeing the asm that GCC produces.

After 40 years of using asm on controllers that only had two or three working registers, I just can't be bothered keeping track of what happens in 32 registers.
Life is just too short for asm!

I've never programmed anything in assembly before and learning this has been interesting and fun. I'll switch back to C if I have to, but I've always wanted to play a round of varsity football, you know? I'm an artist, not a professional, so the stakes are low and the enjoyment factor is still here. :)

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

Can you post your entire project please - especially the makefile (or the project files in the case of Studio).

As this looks like an avr-as rather than generic Asm issue I'll move this to the GCC forum.

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

Sure, thanks for moving this to the right forum. I've attached the file from my original post. I'm actually not using a makefile for this project, for now I'm just using shell scripts. My host computer is a MacBook with 10.6.4.

The exact lines I use to compile, generate the hex, and produce a disassembled file are:

avr-gcc -mmcu=attiny25 -Wa,-gstabs -I/usr/local/avr/include/ -c blinkasm.S
avr-objcopy -O ihex blinkasm.o blinkasm.hex
avr-objdump -d blinkasm.o > blinkasm.disasm

To upload:

avrdude -c usbtiny -p attiny25 -U flash:w:blinkasm.hex

My current thinking is that I have outdated/conflicting versions of the avr toolchain for mac:

conor ~/blinkasm $ avr-as --version
GNU assembler 2.17 + coff-avr-patch (20050630)
Copyright 2005 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.
This assembler was configured for a target of `avr'.

conor ~/blinkasm $ avr-gcc --version
avr-gcc (GCC) 4.1.1
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


conor ~/blinkasm $ avr-objdump --version
GNU objdump 2.17 + coff-avr-patch (20050630)
Copyright 2005 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.

Getting new versions of the avr toolchain via macports is the project of the morning.

One other thing -- could somebody school me on how rjmp works? It seems that, no matter what label I try to jump to, and regardless of where I place the rjmp, they always turn into "rjmp .+0" when I peek at the assembler output. Which, to me, means execution just moves to the next line. Am I just misunderstanding this instruction?

Attachment(s): 

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

Sure, thanks for moving this to the right forum. I've attached the file from my original post. I'm actually not using a makefile for this project, for now I'm just using shell scripts. My host computer is a MacBook with 10.6.4.

The exact lines I use to compile, generate the hex, and produce a disassembled file are:

avr-gcc -mmcu=attiny25 -Wa,-gstabs -I/usr/local/avr/include/ -c blinkasm.S
avr-objcopy -O ihex blinkasm.o blinkasm.hex
avr-objdump -d blinkasm.o > blinkasm.disasm

To upload:

avrdude -c usbtiny -p attiny25 -U flash:w:blinkasm.hex

My current thinking is that I have outdated/conflicting versions of the avr toolchain for mac:

conor ~/blinkasm $ avr-as --version
GNU assembler 2.17 + coff-avr-patch (20050630)
Copyright 2005 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.
This assembler was configured for a target of `avr'.

conor ~/blinkasm $ avr-gcc --version
avr-gcc (GCC) 4.1.1
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.


conor ~/blinkasm $ avr-objdump --version
GNU objdump 2.17 + coff-avr-patch (20050630)
Copyright 2005 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License.  This program has absolutely no warranty.

Getting new versions of the avr toolchain via macports is the project of the morning.

One other thing -- could somebody school me on how rjmp works? It seems that, no matter what label I try to jump to, and regardless of where I place the rjmp, they always turn into "rjmp .+0" when I peek at the assembler output. Which, to me, means execution just moves to the next line. Am I just misunderstanding this instruction?

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

Well, it wouldn't be an attachment if it didn't take two tries. It's also in the body of the original post, in case .gz is problematic for any of you.

Attachment(s): 

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

Quote:

I'm actually not using a makefile for this project

A very bad idea - there are too many subtleties it's too easy to overlook. It only takes about 5 minutes to download Mfile and use it to create a sensible Makefile which has many years of combined expert GCC user's experience ingrained in its template. If you use WinAVR it's even on your hard drive already.

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

No linker command = no 'fixed up' addresses, which is why all the rjmp .+0's. (You are going directly from object file to hex, skipping the linker).

Use the linker, or use a makefile as Cliff suggests.
(if I had a mac, I think I would attempt to use AVR Studio+WinAVR with something like VirtualBox)

I would also ditch the offset/sfr_io stuff with a couple macros-

.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

then use LOAD/STORE instead of in/out/lds/sts, and it also eliminates using the SFR macros.

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

curtvm: Indeed, that was the case! Thank you so much! Always use a makefile. :) I promised I'd post a follow up for any other newbies with similar issues, so here it is:

Unfortunately, I found it nearly impossible to get mfile working on my mac; mfile apparently depends on tixwish which isn't ported to macports, and to compile it, you need to track down the tcl/tk sources, which I found to be one step too far.

Instead, I stumbled upon Crosspack which contains up-to-date copies of the avr-toolchain, plus a command to generate makefiles and xcode templates. (!) And from there, creating/linking to assembler files is fairly simple. (Hints: if your assembler file is "lowlevel.S," make sure to add "lowlevel.o" to the main.hex dependencies in the makefile, or else your file won't be compiled; secondly, make sure to declare your asm routines .global and make corresponding extern entries in your c files to avoid linker errors.)

Thanks again everybody!