Subject: AVR assemble language
From: Rotary Engine
Date: 11/30/2011, 8:25 AM
To: AAA Put this in the To box


  I have about decided to do a single chip solution to
  the dwell ignition problem  because  potentially it is the
  cheapest way to do a stand alone ignition for use with a carb.
  The knowledge gained can then be used to do a variety of simple
  things including a trim table adjustment to the 555 fuel injection
  system using spread sheet data as suggested by Henry Nee.

  I will focus on assembly language as these are time critical jobs
  and with assembly language you always know how long
  it takes to do anything. If you keep the job  short and
  simple the software size will be manageable from many aspects.

  Further more I have considerable experience with assembly
  language much of which can be applied to the AVR instruction
  set.

  I realize that most of you will not be interested so you
  can delete the messages on the subject.

  Those that wish to follow along can make a folder and move
  the stuff over to that.

  Tom Walter, I think, was the first to mention the
  Arduino board as a good low cost and small AVR trainer that will
  do a variety of jobs. The advantage is it is wired
  for USB and there is programming software that runs
  on both Windows and Linux.

  There are a lot of people using this board around the world so there
  should eventually be a lot of asm code examples.

  The Arduino Mega 2560 is a small microcontroller board based on the
  ATmega2560.
  It has 54 digital input/output pins (of which 14 can be used as
  PWM outputs), 16 analog inputs, 4 UARTs (hardware serial ports), a 16
 MHz
  crystal oscillator, a USB connection, a power jack, an ICSP header, and
 a
  reset button. It contains everything needed to support the
  microcontroller;
  simply connect it to a computer with a USB cable.

  We will be using only a very few of these capabilities but the cost
  and size is so low it does not matter.

  AVRA is an assembler for Atmel AVR microcontrollers, and it is almost
  compatible with Atmel's own assembler AVRASM32.

  The initial version of AVRA was written by John Anders Haugum in 1999.
 He
  released all versions until v0.7. All later versions were released by
  Tobias
  Weber. And version 1.3.0 is released by Jerry Jacobs.


  Paul Lamar

  Runs on a Mac too.  This is the board we are using in the Mechatronics
  courses at the University of Utah.  Mostly for automated robots with
 lots
  of sensors.

  Chris Cosman

 Paul,

 The AT90USB Demo-Kit sells for 31.00 on Digikey and I think provides
 similar resources, plus has some external flash storage that might help
 for
 storing tables.  Check it out, as it could be a cheaper alternative.

 Thanks,
 Brannon

 That is a bargain. I had to call and confirm it was completely assembled.
 That beats the Arduino for our purposes. Thanks for finding that Brannon.
 I ordered one.

 Paul Lamar

 Paul,

 No problem, happy to help.  Let me know if you would like any help coding
 this up or if you'd like someone to review your code.  I've done several
 designs on these processors and one on this board in particular.

 One note, you might want to consider writing the majority in C, as you
 will
 be able to use the Atmel supplied libraries for USB communication, etc,
 and
 coding your time critical procedures in assembly.  Most compilers have
 statements that allow you to write in-line assembly.  Also, you can

 always
 generate the .lst file on compile and see what assembly is being
 generated
 for any code you do write in C.

 Thanks,
 Brannon

 Great Brannon!

 Good to hear it. Here is the problem.
 At 7500 RPM the engine makes one rev in 8 ms.

 The RX8 coil delays a fixed  2 ms after the crank sensor tells
 it to fire. This is called dwell.  In effect what this does is retard
 or reduce the advance near 90 degrees. That causes the spark to fire
 about 70 degrees AFTDC!!!!!! Of course losing power in the bargain and
 hurting the BSFC. (fuel burn).

 My suggestion is to measure the period of a give RPM and anticipate the

 advance
 required up to 2 ms at 7500 RPM for the next revolution. As you go
 through the
 rev range of course the adjustment changes. No adjustment at idle and a
 lot
 (2ms) at 7500 RPM.

 Any ideas? Do you have a scope you can test it with?

 CD's don't do this but they are a lot of bucks compared
 to the LS1 or RX8 coils with built in solid state switches.

 Paul Lamar


 What kind of help would you like on this project?  I think you ordered a
 different board, and it sounds like you are already coding things up.

 Let me know.

 Thanks,
 Brannon

 It had a lot of I/O on it in the form of input switches and ouput LED's
 and it was so cheap ($30) I could not resist. Just blink an LED when a
 switch
 is pushed and we will use that as a simple starting program.
 I'll explain it step by step for instruction and discussion.


 Paul Lamar


 Paul,

 Here's a simple routine that flashes an LED at Port B1.  If you send me
the
 output port that is going to the on-board LED, I can modify the code
 appropriately.  The LED flash frequency is also dependent on the micro
 clock frequency, and can be modified by adjusting the quantity
 LED_FLASHCOUNT found in LED.h.  I compiled it in AVR Studio 4 and had no
 issues.

 This is in C, and is well commented...let me know if this is the type of
 example you are looking for and I will expand it to flash the LED when a
 button is pushed.  Currently, it shows how to configure an output, and how
 to use an on-board timer to generate precise timing.  For the real app, I
 would probably use an interrupt, but as a first example that would
probably
 get a little complicated.

 Thanks,
 Brannon

 Can you do that in asm? Down the road when we get to time critical
 application we will need to do it in asm.

 Paul


Paul,

I agree that ASM will get you slightly faster code, dependent on the skill
of the coder, but I would not immediately discount C unless you can see on
a scope that it is too slow.  In most cases The generated ASM is plenty
fast.  For AVR processors, I have not had to use ASM except for controlling
digital communication timing when I have had to bit-bang a protocol.  Just
compile and check out the LST file to see what ASM is generated.

I understand from your posts that you are a strong advocate for coding in
ASM, but in my opinion it should only be used as necessary, as you gain
alot by using C in terms of readability, maintenance, being able to change
features, etc.

That's how we've done things with the med devices I've worked on for the
last ten years anyway.  Your call of course.

Thanks,
Brannon

C is great for a lot of things. IMHO it is not only about speed. When
controlling high speed mechanical
device it is essential to have precise timing accuracy. You don't get that
with C.
Print out the asm of your compile and send us that.

Paul Lamar

Sorry, but you can't draw a broad conclusion like that.  You have to look
at the speed and precision in which you want to operate, compare that to
the clock cycle of the microcontroller, and then determine where and when
ASM is appropriate.  Otherwise you are simply over-optimizing for a need
that may or may not even exist.

Both methods will provide deterministic code, which sounds like one of your
concerns.  The structure of the code is the major item that will determine
the timing accuracy.  As an example, the code that I sent will have a
timing variability based on where the main loop is in relation to timer 0
interrupt.  If this variability is unacceptable, pulling the flashing
routine out of the called function and placing it within the main loop
would reduce that variability (since calling a function takes about 20
lines of ASM, and those would be removed if the function call was removed).
Still don't need ASM.  Now, the actual setting of the bit will most likely
be done in two ASM instructions, whereas it could be done in one.  This is
a great place to do inline ASM, but only if it is really necessary, as one
ASM instruction, assuming two clock cycles for the execution, only takes
125ns.  Does your system require optimization in the 125ns ballpark?  If
so, what parts?

My point is that ASM is great, in the right situation.  Otherwise, it's
harder to write, more difficult to debug, and takes longer to develop.

Anyway, here's the LST file.

Thanks,
Brannon

All this to read a switch and turn on an LED in C?

Paul Lamar

----------------------------------------------------------------

LED.elf:     file format elf32-avr

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
 0 .text         0000017a  00000000  00000000  00000074  2**1
                 CONTENTS, ALLOC, LOAD, READONLY, CODE
 1 .bss          00000004  00800060  00800060  000001ee  2**0
                 ALLOC
 2 .debug_aranges 00000040  00000000  00000000  000001ee  2**0
                 CONTENTS, READONLY, DEBUGGING
 3 .debug_pubnames 00000072  00000000  00000000  0000022e  2**0
                 CONTENTS, READONLY, DEBUGGING
 4 .debug_info   00000150  00000000  00000000  000002a0  2**0
                 CONTENTS, READONLY, DEBUGGING
 5 .debug_abbrev 000000bd  00000000  00000000  000003f0  2**0
                 CONTENTS, READONLY, DEBUGGING
 6 .debug_line   0000018d  00000000  00000000  000004ad  2**0
                 CONTENTS, READONLY, DEBUGGING
 7 .debug_frame  00000070  00000000  00000000  0000063c  2**2
                 CONTENTS, READONLY, DEBUGGING
 8 .debug_str    000000db  00000000  00000000  000006ac  2**0
                 CONTENTS, READONLY, DEBUGGING

Disassembly of section .text:

00000000 <__vectors>:
  0:    09 c0           rjmp    .+18         ; 0x14 <__ctors_end>
  2:    16 c0           rjmp    .+44         ; 0x30 <__bad_interrupt>
  4:    15 c0           rjmp    .+42         ; 0x30 <__bad_interrupt>
  6:    14 c0           rjmp    .+40         ; 0x30 <__bad_interrupt>
  8:    13 c0           rjmp    .+38         ; 0x30 <__bad_interrupt>
  a:    12 c0           rjmp    .+36         ; 0x30 <__bad_interrupt>
  c:    11 c0           rjmp    .+34         ; 0x30 <__bad_interrupt>
  e:    10 c0           rjmp    .+32         ; 0x30 <__bad_interrupt>
 10:    0f c0           rjmp    .+30         ; 0x30 <__bad_interrupt>
 12:    0e c0           rjmp    .+28         ; 0x30 <__bad_interrupt>

00000014 <__ctors_end>:
 14:    11 24           eor    r1, r1
 16:    1f be           out    0x3f, r1    ; 63
 18:    cf e9           ldi    r28, 0x9F    ; 159
 1a:    cd bf           out    0x3d, r28    ; 61

0000001c <__do_clear_bss>:
 1c:    10 e0           ldi    r17, 0x00    ; 0
 1e:    a0 e6           ldi    r26, 0x60    ; 96
 20:    b0 e0           ldi    r27, 0x00    ; 0
 22:    01 c0           rjmp    .+2          ; 0x26 <.do_clear_bss_start>

00000024 <.do_clear_bss_loop>:
 24:    1d 92           st    X+, r1

00000026 <.do_clear_bss_start>:
 26:    a4 36           cpi    r26, 0x64    ; 100
 28:    b1 07           cpc    r27, r17
 2a:    e1 f7           brne    .-8          ; 0x24 <.do_clear_bss_loop>
 2c:    02 d0           rcall    .+4          ; 0x32 <main>
 2e:    a3 c0           rjmp    .+326        ; 0x176 <_exit>

00000030 <__bad_interrupt>:
 30:    e7 cf           rjmp    .-50         ; 0x0 <__vectors>

00000032 <main>:
//----------------------------------------------------------------------------//
/// MAIN Application Function
///
/// Timing Application Main Routine.
//----------------------------------------------------------------------------//
{
 32:    df 93           push    r29
 34:    cf 93           push    r28
 36:    cd b7           in    r28, 0x3d    ; 61
 38:    de b7           in    r29, 0x3e    ; 62
   // Initialization
   LED_HWInit();
 3a:    03 d0           rcall    .+6          ; 0x42 <LED_HWInit>
   LED_T0Init();
 3c:    17 d0           rcall    .+46         ; 0x6c <LED_T0Init>

   // Main Loop
   for(;;)
   {
       LED_FlashService();
 3e:    72 d0           rcall    .+228        ; 0x124 <LED_FlashService>
 40:    fe cf           rjmp    .-4          ; 0x3e <__SP_H__>

00000042 <LED_HWInit>:
///
/// PORTB = (XXXX XX0X)
/// DDRB  = (XXXX XX1X)
///
//----------------------------------------------------------------------------//
{
 42:    df 93           push    r29
 44:    cf 93           push    r28
 46:    cd b7           in    r28, 0x3d    ; 61
 48:    de b7           in    r29, 0x3e    ; 62
   PORTB &= ~(0x02);
 4a:    a8 e3           ldi    r26, 0x38    ; 56
 4c:    b0 e0           ldi    r27, 0x00    ; 0
 4e:    e8 e3           ldi    r30, 0x38    ; 56
 50:    f0 e0           ldi    r31, 0x00    ; 0
 52:    80 81           ld    r24, Z
 54:    8d 7f           andi    r24, 0xFD    ; 253
 56:    8c 93           st    X, r24

   DDRB  |=  (0x02);
 58:    a7 e3           ldi    r26, 0x37    ; 55
 5a:    b0 e0           ldi    r27, 0x00    ; 0
 5c:    e7 e3           ldi    r30, 0x37    ; 55
 5e:    f0 e0           ldi    r31, 0x00    ; 0
 60:    80 81           ld    r24, Z
 62:    82 60           ori    r24, 0x02    ; 2
 64:    8c 93           st    X, r24
}
 66:    cf 91           pop    r28
 68:    df 91           pop    r29
 6a:    08 95           ret

0000006c <LED_T0Init>:
/// - Force Output Compare A              = (  0) Clear for compatibility
/// - Force Output Compare B              = (  0) Clear for compatibility
/// - Clock Select                        = (010) clk(I/O)/8 (from prescalar)
///
//----------------------------------------------------------------------------//
{
 6c:    df 93           push    r29
 6e:    cf 93           push    r28
 70:    cd b7           in    r28, 0x3d    ; 61
 72:    de b7           in    r29, 0x3e    ; 62
   TCCR0A = (0 << COM0A1) |
 74:    ef e4           ldi    r30, 0x4F    ; 79
 76:    f0 e0           ldi    r31, 0x00    ; 0
 78:    10 82           st    Z, r1
            (0 << COM0B1) |
            (0 << COM0B0) |
            (0 << WGM01 ) |
            (0 << WGM00 );

   TCCR0B = (0 << FOC0A ) |
 7a:    e3 e5           ldi    r30, 0x53    ; 83
 7c:    f0 e0           ldi    r31, 0x00    ; 0
 7e:    82 e0           ldi    r24, 0x02    ; 2
 80:    80 83           st    Z, r24
            (0 << WGM02 ) |
            (0 << CS02  ) |
            (1 << CS01  ) |
            (0 << CS00  );

   TCNT0 = 0;
 82:    e2 e5           ldi    r30, 0x52    ; 82
 84:    f0 e0           ldi    r31, 0x00    ; 0
 86:    10 82           st    Z, r1
   OCR0A = 0;
 88:    e6 e5           ldi    r30, 0x56    ; 86
 8a:    f0 e0           ldi    r31, 0x00    ; 0
 8c:    10 82           st    Z, r1
   OCR0B = 0;
 8e:    e9 e4           ldi    r30, 0x49    ; 73
 90:    f0 e0           ldi    r31, 0x00    ; 0
 92:    10 82           st    Z, r1
}
 94:    cf 91           pop    r28
 96:    df 91           pop    r29
 98:    08 95           ret

0000009a <LED_ServTimer>:
///
/// @result int         1 - 1 second has just passed
///                     0 - otherwise
///
//----------------------------------------------------------------------------//
{
 9a:    df 93           push    r29
 9c:    cf 93           push    r28
 9e:    00 d0           rcall    .+0          ; 0xa0 <__stack+0x1>
 a0:    00 d0           rcall    .+0          ; 0xa2 <__stack+0x3>
 a2:    0f 92           push    r0
 a4:    cd b7           in    r28, 0x3d    ; 61
 a6:    de b7           in    r29, 0x3e    ; 62
   static unsigned int count = 0;

   if (TIFR0 & (1 << TOV0))
 a8:    e8 e5           ldi    r30, 0x58    ; 88
 aa:    f0 e0           ldi    r31, 0x00    ; 0
 ac:    80 81           ld    r24, Z
 ae:    88 2f           mov    r24, r24
 b0:    90 e0           ldi    r25, 0x00    ; 0
 b2:    82 70           andi    r24, 0x02    ; 2
 b4:    90 70           andi    r25, 0x00    ; 0
 b6:    00 97           sbiw    r24, 0x00    ; 0
 b8:    49 f1           breq    .+82         ; 0x10c <__stack+0x6d>
   {
       TIFR0 |= (1 << TOV0);  // clear TOV0 (set to clear)
 ba:    a8 e5           ldi    r26, 0x58    ; 88
 bc:    b0 e0           ldi    r27, 0x00    ; 0
 be:    e8 e5           ldi    r30, 0x58    ; 88
 c0:    f0 e0           ldi    r31, 0x00    ; 0
 c2:    80 81           ld    r24, Z
 c4:    82 60           ori    r24, 0x02    ; 2
 c6:    8c 93           st    X, r24

       if (LED_FLASHCOUNT == (count++))
 c8:    80 91 60 00     lds    r24, 0x0060
 cc:    90 91 61 00     lds    r25, 0x0061
 d0:    9d 83           std    Y+5, r25    ; 0x05
 d2:    8c 83           std    Y+4, r24    ; 0x04
 d4:    1b 82           std    Y+3, r1    ; 0x03
 d6:    8c 81           ldd    r24, Y+4    ; 0x04
 d8:    9d 81           ldd    r25, Y+5    ; 0x05
 da:    27 e0           ldi    r18, 0x07    ; 7
 dc:    80 3d           cpi    r24, 0xD0    ; 208
 de:    92 07           cpc    r25, r18
 e0:    11 f4           brne    .+4          ; 0xe6 <__stack+0x47>
 e2:    81 e0           ldi    r24, 0x01    ; 1
 e4:    8b 83           std    Y+3, r24    ; 0x03
 e6:    8c 81           ldd    r24, Y+4    ; 0x04
 e8:    9d 81           ldd    r25, Y+5    ; 0x05
 ea:    01 96           adiw    r24, 0x01    ; 1
 ec:    90 93 61 00     sts    0x0061, r25
 f0:    80 93 60 00     sts    0x0060, r24
 f4:    9b 81           ldd    r25, Y+3    ; 0x03
 f6:    99 23           and    r25, r25
 f8:    49 f0           breq    .+18         ; 0x10c <__stack+0x6d>
       {
           count = 0;
 fa:    10 92 61 00     sts    0x0061, r1
 fe:    10 92 60 00     sts    0x0060, r1

           return 1;
102:    81 e0           ldi    r24, 0x01    ; 1
104:    90 e0           ldi    r25, 0x00    ; 0
106:    9a 83           std    Y+2, r25    ; 0x02
108:    89 83           std    Y+1, r24    ; 0x01
10a:    02 c0           rjmp    .+4          ; 0x110 <__stack+0x71>
       }
   }

   return 0;
10c:    1a 82           std    Y+2, r1    ; 0x02
10e:    19 82           std    Y+1, r1    ; 0x01
110:    89 81           ldd    r24, Y+1    ; 0x01
112:    9a 81           ldd    r25, Y+2    ; 0x02
}
114:    0f 90           pop    r0
116:    0f 90           pop    r0
118:    0f 90           pop    r0
11a:    0f 90           pop    r0
11c:    0f 90           pop    r0
11e:    cf 91           pop    r28
120:    df 91           pop    r29
122:    08 95           ret

00000124 <LED_FlashService>:
///
/// @param      secFlag     denotes whether one second has passed.  This flag
///                         should be pulsed every second.
///
//----------------------------------------------------------------------------//
{
124:    df 93           push    r29
126:    cf 93           push    r28
128:    cd b7           in    r28, 0x3d    ; 61
12a:    de b7           in    r29, 0x3e    ; 62
    static unsigned int currentState = 0;

    if (LED_ServTimer())
12c:    b6 df           rcall    .-148        ; 0x9a <LED_ServTimer>
12e:    00 97           sbiw    r24, 0x00    ; 0
130:    f9 f0           breq    .+62         ; 0x170 <LED_FlashService+0x4c>
    {
        if (currentState)
132:    80 91 62 00     lds    r24, 0x0062
136:    90 91 63 00     lds    r25, 0x0063
13a:    00 97           sbiw    r24, 0x00    ; 0
13c:    61 f0           breq    .+24         ; 0x156 <LED_FlashService+0x32>
        {
            LED_Off();
13e:    a8 e3           ldi    r26, 0x38    ; 56
140:    b0 e0           ldi    r27, 0x00    ; 0
142:    e8 e3           ldi    r30, 0x38    ; 56
144:    f0 e0           ldi    r31, 0x00    ; 0
146:    80 81           ld    r24, Z
148:    82 60           ori    r24, 0x02    ; 2
14a:    8c 93           st    X, r24
            currentState = 0;
14c:    10 92 63 00     sts    0x0063, r1
150:    10 92 62 00     sts    0x0062, r1
154:    0d c0           rjmp    .+26         ; 0x170 <LED_FlashService+0x4c>
        }
        else
        {
            LED_On();
156:    a8 e3           ldi    r26, 0x38    ; 56
158:    b0 e0           ldi    r27, 0x00    ; 0
15a:    e8 e3           ldi    r30, 0x38    ; 56
15c:    f0 e0           ldi    r31, 0x00    ; 0
15e:    80 81           ld    r24, Z
160:    8d 7f           andi    r24, 0xFD    ; 253
162:    8c 93           st    X, r24
            currentState = 1;
164:    81 e0           ldi    r24, 0x01    ; 1
166:    90 e0           ldi    r25, 0x00    ; 0
168:    90 93 63 00     sts    0x0063, r25
16c:    80 93 62 00     sts    0x0062, r24
        }
    }
}
170:    cf 91           pop    r28
172:    df 91           pop    r29
174:    08 95           ret

00000176 <_exit>:
176:    f8 94           cli

00000178 <__stop_program>:
178:    ff cf           rjmp    .-2          ; 0x178 <__stop_program>

-- 
The Rotary Engine NewsLetter. Powered by Linux.
ACRE NL web site. http://www.rotaryeng.net
Youtube key word PaulLamar2
Copyright 1998-2011 All world wide rights reserved.