NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Very simple assembly problem

August 02, 2009
by maas15
maas15's Avatar

So I'm trying to write a simple avr assembly program to turn the led on and off. There's like 20 million demos out there of people doing this. But I think my problem may be a hardware problem (as in I connected something wrong).

Anyway, I can get the led to turn on but not blink. If I make the Main section not be a loop, the led will flash briefly.

So anyway I'm trying to use Port B, so I have an led attached to pin 19 and another to pin 18. The other ends go to ground. Thats the way it should be, right? 19=PB5. Something like that. Anyway, I calculated that 28,000 NOPS should be a half second delay. The main program bit just turns the led on, waits half a sec (approximately) then turns it off, waits, then loops. The delay is two nested loops with 28 NOPs in the middle.

So what am I doing wrong? I calculated the correct delay so it wouldn't be a case of the lights blinking faster or slower than my ability (or patience) to view them.

So here's the program I'm trying to use: http://admiralsananda.net/private/blinken2.asm The forum was garbling it so I put it on one of my sites.

August 03, 2009
by maas15
maas15's Avatar

It's still rather frustrating, but after another day futzing with it I finally got one of the two leds (a red one :-p) to feebly blink in an approximation of what it should be doing. Except much dimmer.

But I'm calling it a success.

Encase anyone with the same problem wants to see whats different about the "working" version:

http://admiralsananda.net/private/blinken4.asm

Of course, virtually the same thing took all of 15 minutes in C:

http://admiralsananda.net/private/cblink.c

August 05, 2009
by BobaMosfet
BobaMosfet's Avatar

The clock rate for the ATMEGA168 is 14.74MHz-- that means it can execute atleast 14.74 MILLION Assembly instructions per second. 28,000 NOPs is equivalent to 0.00189 (1.9ms).

August 05, 2009
by wayward
wayward's Avatar

maas15, the frequency of the MCU's system clock is controlled by the internal or external oscillator used to drive it. The crystal that ships with NerdKits oscillates at 14.74MHz -- well within the range that ATmega168 works at when powered by +5V.

Since ATmega is a RISC family microcontroller, most of its instructions take one clock cycle to execute. See datasheet, chapter 31: "Instruction Set Summary", pp.347, for a list of instructions and their cycle times. NOP does take one cycle and your calculations, apart from missing the actual frequency of the crystal, were correct in that regard. :)

August 09, 2009
by Nerdful_com
Nerdful_com's Avatar

I made a binky LED, for your pin 19 you want something like this to compile (WinAVR has AVRdude that works great). Here's the source code for blinking/flashing a LED.

/* 
by www.nerdful.com
This code blinks an LED on then offevery 100ms.
This code will loop infinitely.
*/

#include <avr/io.h>
#include <avr/delay.h>
void sleep(uint8_t millisec)
{
while(millisec)
{
delay_ms(1);
millisec--;
}
}
main()
{
DDRB |=1<<PB5; //enable pin19
while(1)
{
PORTB &= ~(1<<PB5); //pin 19 on
sleep(100);
PORTB |=(1<<PB5); //pin 19 off
sleep(100);
}
}
August 09, 2009
by Nerdful_com
Nerdful_com's Avatar

Btw, the LED positive (longest wire) goes to the red + power rail and the -/gnd goes to the pin 19 to your MCU. When using PWM, then 2 dif MCU pins will get the + and - (pulse madulated speeds, forward and reversing), but this simple project is simple turning off and back on to make a flashing effect.

www.nerdful.com

August 10, 2009
by BobaMosfet
BobaMosfet's Avatar

wayward

If a NOP instruction takes one cycle (that is 1 Hertz), then 14.74M cycles can be executed in one second. So again, 28,000 NOPs is only 1.9ms. He won't even see it. Half a second would require something on the order of 7 MILLION NOPs to be issued.

Am I missing something?

August 10, 2009
by wayward
wayward's Avatar

BobaMosfet, no, you're spot on :) I just wanted to show that the idea he had throughout the calculations was good (one instruction = one cycle = 1/F [s]), but he probably used an incorrect starting frequency, and somehow ended up at 28 K instructions.

August 17, 2009
by sigkill0
sigkill0's Avatar

Hey BobaMosfet,

I followed the calculation you did for the 28,000 NOPS equaling a 1.9 ms delay. I think I'm missing something as the delay code in libnerdkits only has 9 NOPS for delaying 1 microsecond given the 14.74M clockspeed.

August 17, 2009
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi sigkill0,

Part of the delay is in executing the loop counter itself. We can look at the disassembled version of the delay_us function to see how it gets compiled into assembly instructions that are executed by the microcontroller. For example, running "make tempsensor.ass" in the tempsensor directory will generate assembly code that basically reads like this (cleaned up a bit):

delay_us:
1368    LDI R18, 0x00
136a    LDI R19, 0x00
136c    RJMP to 0x1384
136e    NOP
1370    NOP
1372    NOP
1374    NOP
1376    NOP
1378    NOP
137a    NOP
137c    NOP
137e    NOP
1380    SUBI R18, 0xFF
1382    SBCI R19, 0xFF
1384    CP R18, R24
1386    CPC R19, R25
1388    BRCS to 0x136E

The left column is the memory address in the flash memory, and the right side describes which instruction and its parameters. Then, you can look at the AVR instruction set and try to decode what's going on. I will admit that is not the most newbie-friendly technique, but it is a useful exercise in understanding how things are happening inside the microcontroller!

The first two LDI instructions are basically doing "uint16_t i=0" -- setting two bytes of registers to zero. Instructions 136e through 137e are the 9 NOP instructions. Instructions 1380 and 1382 are a subtraction and subtraction with carry -- which is really just a confusing way of doing "i++". Instructions 1384 and 1386 compare it the variable "i" (in registers R18 and R19) to the parameter (passed in via registers R24 and R25), which sets the carry flag "C" if the parameter is greater than the variable "i". Instruction 1388 is a branch to repeat the loop if the carry flag is set. Anyway, these instructions all take 1 cycle each, except for the BRCS instruction which takes 2 cycles when it branches, so in total, one cycle of the loop (instructions 136e through 1388) takes 15 cycles. (There are a few extra instructions at the beginning and end, but if the loop is run multiple times, only the 15 cycles are repeated.) At a crystal oscillator frequency of 14.7456 MHz, these cycles will take 15/14745600 = 1.017 microseconds, so the delay_us function is about 1.7% slow compared to nominal.

Hope that helps!

Mike

August 18, 2009
by sigkill0
sigkill0's Avatar

Mike,

Thanks makes perfect sense.

September 21, 2009
by maas15
maas15's Avatar

BobaMosfet: Shoot you're right. I think I was thinking MHz = ~1000Hz, but wolframalpha tells me that it's 1.474 * 10^7 Hz. Whoops. That explains all my trials that had the light stuck on permanently... I think the controller was doing exactly what I told it to do.

Dealing with such small bytes is driving me nuts! (Just an irrelevant aside).

Thanks to all for pointing out the exact problem.

September 21, 2009
by rusirius
rusirius's Avatar

"Dealing with such small bytes is driving me nuts! (Just an irrelevant aside)."

I suppose that's better than such small nuts driving you bytes...

Post a Reply

Please log in to post a reply.

Did you know that a microcontroller can measure an RC time constant? Learn more...