0
votes

I have recently been provided this task in a module in which we are working with Arduinos. The previous tasks we had were in C however when it comes to this I have simply no idea what to do or even how to start in that case. We have also not been provided with any type of lectures or etc to cover this. Can anyone help or just get the ball rolling a little bit so I can understand it better? Thank you.

The first bit of code that I have to edit is below:

"delay_ms%=:    nop                 ; code to replace  nop  \n"
"delay_100us%=: nop                 ; code to replace  nop  \n"
"delay_1us%=:   nop                 ; code to replace nop  \n"
"               sbiw r30,1          ; decrement ms count (r31:r30)\n"
"               brne delay_ms%=     ; loop to delay_ms while > 0  \n"
"               ret                 ; return from subroutine      \n"

and then the rest of the code is this:

" blink%=:                               ; start of blink code    \n"
//
// turn onboard LED on
//   
"               ldi  r18,0x20            ; bit 5 (pin 13) = high  \n"
"               out  5,r18               ; output to port B       \n"
//
// delay by value in millisecs variable
 //
"               lds  r30,millisecs      ; r30 = hi byte           \n"
"               lds  r31,millisecs + 1  ; r31 = lo byte           \n"
"               call delay_ms%=         ; call millisec delay sub \n"
 //
 // turn onboard LED off
 // 
  "               ldi  r18,0x00           ; value for all LEDs off  \n"
   "               out  5,r18              ; output to port B        \n"
 //
 // delay by value in millisecs variable
 //
 "               lds  r30,millisecs      ; r30 = hi byte           \n"
 "               lds  r31,millisecs + 1  ; r31 = lo byte           \n"
 "               call delay_ms%=         ; call millisec delay sub \n"

 ::: "r16", "r17", "r18", "r30", "r31");    // clobbered registers

 //-------------------------------------------------------------------------     -------
 // calculate the execution time of the blink routine, and print details 
 long endtime = millis();                  // make a note of the end time
 float ms = endtime-starttime;             // calculate the interval
 float expected = 2 * millisecs;           // expected delay is millisecs *      2 (2 delays in blink)
 float overheads = 17;                     // overheads due to the timing
 expected = expected + overheads;   
 float error_percent = 100.0*(ms-expected)/expected;
 Serial.print("delay="); Serial.print(ms); Serial.print("ms  "); 
 Serial.print("error: ");
 if(error_percent>0)
 Serial.print("+");
 Serial.print(error_percent);Serial.println("%");
 }

The instruction set is here: http://www.atmel.com/images/Atmel-0856-AVR-Instruction-Set-Manual.pdf

1

1 Answers

1
votes

The quoted strings are assembly code inside a asm() call that you left off. When compiled, the strings will be converted literally into the relevant assembly instructions.

A name with a colon : after it is called a label, and a function call is just a jump to label. You can also jump within a function with a branch instruction such as brne, branch if the previous result was not 0.

The asm() call indicates that registers "r16", "r17", "r18", "r30", "r31" are all used, but the blink code seems to only use "r18", "r30", "r31". This means you are intended to use "r16" and "r17" in your delay code.

The delay code so far is just a loop that counts down the value in the double register r31:r30

"delay_ms%=:    nop                 ; code to replace  nop  \n"
"               sbiw r30,1          ; decrement ms count (r31:r30)\n"
"               brne delay_ms%=     ; loop to delay_ms while > 0  \n"
"               ret                 ; return from subroutine      \n"

It branches back to the top of the loop until the count reaches 0, when it returns.

You need to insert some code inside that loop that counts down a loop of your own that takes 1 millisecond. You will need to know the clock speed to determine the number. Use r17:r16 for the count, similarly to how the delay count is set, except you will use ldi, load immediate.

"delay_ms%=:    ldi ...             ; set up r17 and r16 in a few instructions \n"
"delay_1us%=:   sbiw r16,1          ; decrement count n"
"               brne delay_1us%=  ; loop to  while > 0  \n"
"               sbiw r30,1          ; decrement ms count (r31:r30)\n"
"               brne delay_ms%=     ; loop to delay_ms while > 0  \n"
"               ret                 ; return from subroutine      \n"