assembly commands

Hi

Is it possible to insert assembly code within the C code ?
Elico

Is it possible to insert assembly code within the C code ?

Yes, but why would you want to?

Try it, see what happens. At the worst, the compiler will just complain about it.

In case I need fast and exact actions to be taken .

any tutor on this or examples ?

elico

http://www.nongnu.org/avr-libc/user-manual/inline_asm.html

elico:
In case I need fast and exact actions to be taken .

any tutor on this or examples ?

elico

You'll be hard pressed to beat the optimization strategies in the compiler itself; the number of people in the world that can do it is relatively small. You should first do everything you can to optimize your C code, after you have something working (do not "optimize as you go" - this can lead to bad things - up to and including making things slower!). Once you have it working, profile the code to find where your optimizations will do the best; typically these will be in your "inner loops".

There's little other need to be going down that low level, with the exception of learning purposes as well as possible need for direct port manipulation (realize also when you go down to that level, your code may be "stuck" with the processor in question, and may have to be ported should you move to a different ATMega; this is why the Arduino libraries are somewhat "inefficient", because they have a ton of conditionals in certain areas to allow support across the wide range of processors used).

I seem to recall a query like this in the past. And in the case at the time the person who wrote assembler code "for speed" wrote code that ran slower than the C code generated by the compiler.

Also you need to consider other issues, such as whether interrupts will occur, and what effect they will have.

In case I need ... exact actions to be taken .

Code written in C will give you exact actions. What did you mean exactly?

Thanks
Elico

Hi Nick, sometimes I see the port/pin manipulation done 'the fast way' compared to using digitalWrite() and like but not using the asm and commands in quotes route. It does get around CPU time saving and restoring registers but as has been shown it's not always completely safe either. That does leave me knowing there is room for streamlining what the IDE compiles but only with knowledge and caution.

Sure. Direct port manipulation can save time in time-critical applications. However fooling with assembler should only be done as a last resort.

Oh heck, I used C to do the port manipulations, just not the normal get at the port commands but direct register through address method. And still I am sure under the wrong conditions it could cause hard to debug problems.

/* blick-asm.pde
 *
 * Blink using inline assembler, from Arduino IDE.
 *
 * Turns on an LED on for one second, then off for one second, repeatedly.
 *
 * One of a series of "Blink" examples using various techniques.
 *   This praticular example uses inline assembler, and ignores the
 *   arduino functions and "background" tasks.
 *
 * The circuit:
 *     LED connected from digital pin 13 to ground, with suitable resistor.
 *
 *     Note: On most Arduino boards, there is already an LED on the board
 *     connected to pin 13, so you don't need any extra components for this example.
 *
 * Created Nov 2009, by Bill Westfield.
 *   Based on the blink.pde example distributer with the Arduino IDE,
 *      Created 1 June 2005 By David Cuartielles
 *        based on an orginal by H. Barragan for the Wiring i/o board
 */

#define LEDPORT PORTB    // Arduino pin 13 is bit 5 of port B
#define LEDPORT_DIR DDRB
#define LEDBIT 5

// The setup() method runs once, when the sketch starts
// For this example, we're going to put ALL of our code in setup, and
// never actually return...

void setup()   {

  asm volatile ("  sbi %[portdir], %[lbit]  \n"    // Set bit direction
      "3: "                                        // main loop label
      "   sbi %[port], %[lbit] \n"                 //  Turn on.
          /*
           * About the delay loop:
           *   The inner loop (dec, brne) is 3 cycles.
           *   For one second, we want 16million cycles, or 16000000/(3*256*256) loops.
           *   This is "about" 81.
           */
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"   // 100 * 256
      "1:"  // 1st delay loop label
      "        dec r16  \n"
      "        brne 1b  \n"
      "      dec r17    \n"
      "      brne 1b    \n"
      "    dec r18      \n"
      "    brne 1b      \n"
      
      "    cbi   %[port], %[lbit] \n"             // Turn off.
      
      "    clr r16  \n"
      "    clr r17  \n"
      "    ldi r18, 81  \n"
      "2:"  // 2nd delay loop label
      "        dec r16  \n"
      "        brne 2b  \n"
      "      dec r17    \n"
      "      brne 2b    \n"
      "    dec r18      \n"
      "    brne 2b      \n"
      
      "    rjmp 3b  \n"
      :
      : [portdir] "I" (_SFR_IO_ADDR(LEDPORT_DIR)),
        [port] "I" (_SFR_IO_ADDR(LEDPORT)),
	[lbit] "I" (LEDBIT)
      );
}

// Note that we never get to loop, since setup above loops forever.
void loop()                     
{
}

It seems reasonable to suit the solution to the problem context. I like C for portability, maintainability, and productivity reasons. This code took less than five minutes to code, and about eight minutes to comment. Timing is adequate for a visual indicator (-0 to +30 usec) and allows starting, stopping, and varying the blink rate. If I wanted to modify it (say, to have different "on" time than "off" time), I could probably add that in less than five minutes. It's not a work of art, but it gets the job done.

/*----------------------------------------------------------------------------*/
/* LED13 Blinker control - start/stop with adjustable blink rate              */
/*----------------------------------------------------------------------------*/
static time_t r13 = 0;                 /* r13 is on/off time                  */
static int  state = 0;                 /* s13 is blink state (0=off,1=on)     */
/*----------------------------------------------------------------------------*/
/* Blinker Task                                                               */
/*----------------------------------------------------------------------------*/
static void b13(void)
{  if (r13)                            /* If on/off time is zero, we're done  */
   {  digitalWrite(13,state=!state);   /* Invert the LED13 state              */
      after(r13,b13);                  /* Reschedule self according to rate   */
   }                                   /*  end: if rate is non-zero           */
   else state = 0;                     /* Reset state for next time           */
}                                      /*  end: b13()                         */
/*----------------------------------------------------------------------------*/
/* Routine to start/stop blinking LED on pin 13                               */
/*----------------------------------------------------------------------------*/
void blink13(time_t rate)
{  if (r13 = rate) b13();              /* Set rate, if nonzero start blinking */
}                                      /*  end: blink13()                     */
/*----------------------------------------------------------------------------*/

To me, a lot of writing tight asm was a matter of making the most of register to register operations. Much of the program structure resulted based on organizing and feeding data to the working algorithms.

Anyhow, if I arrange my operations in C or asm incorrectly there will be more register loading just due to the order I code my operations at least when usable registers are fewer than parameters and I dare say it's easier to keep track of register use with asm but do enough C and you won't be far off while keeping more hair and better eyesight.

Of course if you don't like asm on AVR's then spend some time with 6502's. ]:smiley:

OK, here's a reason to use asm,

ISR (WDT_vect, ISR_NAKED) {
  /////////////////////////////////////////////
  // DIY prologue so I know exactly where the
  // program counter and working registers are
  asm (
    "push r0\n"
    "in r0,0x3f\n"
    "push r0\npush r1\npush r2\npush r3\npush r4\n"
    "push r5\npush r6\npush r7\npush r8\npush r9\n"
    "push r10\npush r11\npush r12\npush r13\npush r14\n"
    "push r15\npush r16\npush r17\npush r18\npush r19\n"
    "push r20\npush r21\npush r22\npush r23\npush r24\n"
    "push r25\npush r26\npush r27\npush r28\npush r29\n"
    "push r30\npush r31\n"
  );  // 33 bytes on the stack

This is the prologue for an ISR in which I had to know exactly where each register was placed on the stack.

Why? It's a monitor program that displayed register contents.


Rob