Recent

Author Topic: Confusing Arduino/AVR instructions & non-working 'Blinky'  (Read 2876 times)

botster

  • New Member
  • *
  • Posts: 18
Confusing Arduino/AVR instructions & non-working 'Blinky'
« on: February 26, 2017, 10:33:36 pm »
Hi folks,

My research on how to use Free Pascal to target the AVR (on my Arduino) led me to two main resources:
http://wiki.freepascal.org/AVR, and
FPC/Lazarus Arduino Tutorial

The information regarding building the cross compiler between those two resources is conflicting. The Wiki page says to use "make buildbase installbase ..." and the forum tutorial says, "make clean crossall crossinstall ..."

What's the difference?

Since I like simple, and since the Wiki page is dated later than the forum thread, I decided to try that method using v3.0.0 on Linux with the v3.1.1 fpc.zip trunk snapshot:

Code: [Select]
make buildbase installbase CPU_TARGET=avr OS_TARGET=embedded SUBARCH=avr5 CROSSINSTALL=1 INSTALL_PREFIX=~/opt/fpc NOGDB=1 PP=/usr/bin/fpc CROSSBINDIR=/opt/cross/bin BINUTILSPREFIX=avr-
That completed with no errors. But the Wiki instructions basically stop there. So, now what?

I found two directories in ~/opt/fpc: bin and lib. There was nothing in bin, but I found ppcrossavr in lib/fpc/3.1.1 along with a units directory.

Okay, so I downloaded and extracted Blinky.zip from the forum thread linked above. Then copied Blinky.lpr to ~/opt/fpc/lib/fpc/3.1.1 and, after some experimentation, finally got it to compile with:
Code: [Select]
./ppcrossavr Blinky.lpr -Tembedded -Pavr -MDelphi -Scghi -CX -O3 -Xs -XX -l -vewnhibq -Fiunits/avr-embedded/rtl -Fu. -FUunits/avr-embedded/rtl -Cpavr5 -Wpatmega328p -a -XPavr- -OoFastMath -OoNoStackFrame -XX -CX
And then uploaded it to my Arduino Uno with:
Code: [Select]
avrdude -v -patmega328p -carduino -P/dev/ttyUSB0 -b115200 -Uflash:w:blinky.hex:i
The Uno on-board LED blinked as it was being programmed and verified, and then, nothing. No blinking, visual silence.

I thought at first I may have 'bricked' my Arduino. But, an upload of a HEX file generated from C showed everything was good.

Looking at the assembly in the respective ELF files did me no good as assembly is like Greek to me. But it did give me an idea.

In Blinky.lpr, I replaced the two calls to the SomeDelay procedure with the For loop contained within that procedure and removed the procedure. I think this would be similar to inlining a procedure.

Now it works correctly: blink, blink, blink, ... (where ',' = normal pause and blink length is the same).

Then I tried actually inlining the procedure, ie. "procedure SomeDelay; inline;". That also works, but not correctly. The timing is obviously incorrect: blink blink, blink blink, blink blink, ... (short duration blinks).

Could someone help me understand why there is a difference between the procedures given on the Wiki and in the Tutorial, and why one would want to use one over the other?

And why does physically inlining the delay work while using a delay procedure does not? And why does declaring the procedure "inline" work but with incorrect timing?
« Last Edit: February 26, 2017, 10:40:05 pm by botster »
Lee

jmpessoa

  • Hero Member
  • *****
  • Posts: 1480
Re: Confusing Arduino/AVR instructions & non-working 'Blinky'
« Reply #1 on: February 26, 2017, 10:38:07 pm »


You can read [and try] about here   [initial works]:

https://github.com/jmpessoa/lazarduinomodulewizard 
Lamw: Lazarus Android Module Wizard
https://github.com/jmpessoa/lazandroidmodulewizard

botster

  • New Member
  • *
  • Posts: 18
Re: Confusing Arduino/AVR instructions & non-working 'Blinky'
« Reply #2 on: February 26, 2017, 11:47:03 pm »
After more thought and experimentation, I found that if I move the declaration for the loop index in the SomeDelay procedure to the top-level scope, it works.

In other words, from this:
Code: Pascal  [Select]
  1. program Blinky;
  2.  
  3. var
  4.   DelayVar: Integer = 0;
  5.  
  6. // This function simulates some kind of delay by looping.
  7. procedure SomeDelay;
  8.   I: LongInt;
  9. begin
  10.   for I := 0 to 400000 do
  11.     Dec(DelayVar);
  12. end;
  13.  
  14. ...
  15.  

To this:
Code: Pascal  [Select]
  1. program Blinky;
  2.  
  3. var
  4.   DelayVar: Integer = 0;
  5.   I: LongInt;
  6.  
  7. // This function simulates some kind of delay by looping.
  8. procedure SomeDelay;
  9. begin
  10.   for I := 0 to 400000 do
  11.     Dec(DelayVar);
  12. end;
  13.  
  14. ...
  15.  

Is this a bug? Or did I perhaps miss something in the compiler options? Or?


(Oh, and thanks for that @jmpessoa. It looks interesting. But it appears to be directed more toward those using Windows and the Lazarus IDE. I won't likely be using the IDE for my AVR work.)
« Last Edit: February 26, 2017, 11:50:33 pm by botster »
Lee

Cyrax

  • Hero Member
  • *****
  • Posts: 760
Re: Confusing Arduino/AVR instructions & non-working 'Blinky'
« Reply #3 on: February 27, 2017, 02:18:24 am »
Lazarus isn't limited for Windows only. You can use it in Linux, Mac and in other OS'es.

Code: Pascal  [Select]
  1. program Blinky;
  2.  
  3. var
  4.   DelayVar: Integer = 0;
  5.  
  6. // This function simulates some kind of delay by looping.
  7. procedure SomeDelay;
  8.   I: LongInt;
  9. begin
  10.   for I := 0 to 400000 do
  11.     Dec(DelayVar);
  12. end;
  13.  
  14. ...
  15.  

That example is wrong.

It should be like this:

Code: Pascal  [Select]
  1. program Blinky;
  2.  
  3. var
  4.   DelayVar: Integer = 0;
  5.  
  6. // This function simulates some kind of delay by looping.
  7. procedure SomeDelay;
  8. Var
  9.   I: LongInt;
  10. begin
  11.   for I := 0 to 400000 do
  12.     Dec(DelayVar);
  13. end;
  14.  
  15. ...
  16.  

botster

  • New Member
  • *
  • Posts: 18
Re: Confusing Arduino/AVR instructions & non-working 'Blinky'
« Reply #4 on: February 27, 2017, 05:44:53 am »
That example is wrong.

It should be like this:

Code: Pascal  [Select]
  1. program Blinky;
  2.  
  3. var
  4.   DelayVar: Integer = 0;
  5.  
  6. // This function simulates some kind of delay by looping.
  7. procedure SomeDelay;
  8. Var
  9.   I: LongInt;
  10. begin
  11.   for I := 0 to 400000 do
  12.     Dec(DelayVar);
  13. end;
  14.  
  15. ...
  16.  

Oops. When I was undoing the changes I made to get it to work, I neglected to undo the removal of the "var" keyword. Thus I incorrectly represented the example. Sorry for that.

With it coded as you stated, and as I should have stated, it does not work.

And, yes, I know Lazarus is not Windows-only.  :)  I am using it on Linux, but do not intend to do my AVR work in that IDE.
Lee

botster

  • New Member
  • *
  • Posts: 18
Re: Confusing Arduino/AVR instructions & non-working 'Blinky'
« Reply #5 on: February 28, 2017, 01:37:34 am »
In the "Inline assembler" section at AVR_Programming, in the code for the "Wait" unit, there is a comment next to the ("Wait10m") Procedure's local variable "tmpByte: byte;" that says:
Quote
In Inline assembler local variables are accesed by the instructions LDD and STD, global variables are accessed by LDS and STS.

But in the assembler code output by "avr-objdump -d blinky.elf" for the example that uses the delay procedure with a local variable and does not work, it appears the local variable is being access by LDS, contrary to the above quote:
Code: [Select]
000000c2 <PsBLINKY_ss_SOMEDELAY>:
  c2: 61 2d        mov r22, r1
  c4: 51 2d        mov r21, r1
  c6: 21 2d        mov r18, r1
  c8: 31 2d        mov r19, r1
  ca: 61 50        subi r22, 0x01 ; 1
  cc: 51 09        sbc r21, r1
  ce: 21 09        sbc r18, r1
  d0: 31 09        sbc r19, r1
  d2: a1 e0        ldi r26, 0x01 ; 1
  d4: 4a 2f        mov r20, r26
  d6: 64 0f        add r22, r20
  d8: 51 1d        adc r21, r1
  da: 21 1d        adc r18, r1
  dc: 31 1d        adc r19, r1
  de: 70 91 00 01 lds r23, 0x0100 ; 0x800100 <__data_start>
  e2: 40 91 01 01 lds r20, 0x0101 ; 0x800101 <__data_start+0x1>
  e6: 71 50        subi r23, 0x01 ; 1
  e8: 41 09        sbc r20, r1
  ea: 70 93 00 01 sts 0x0100, r23 ; 0x800100 <__data_start>
  ee: 40 93 01 01 sts 0x0101, r20 ; 0x800101 <__data_start+0x1>
  f2: a0 e2        ldi r26, 0x20 ; 32
  f4: 7a 2f        mov r23, r26
  f6: a1 ea        ldi r26, 0xA1 ; 161
  f8: 8a 2f        mov r24, r26
  fa: a7 e0        ldi r26, 0x07 ; 7
  fc: 9a 2f        mov r25, r26
  fe: 41 2d        mov r20, r1
 100: 67 17        cp r22, r23
 102: 58 07        cpc r21, r24
 104: 29 07        cpc r18, r25
 106: 34 07        cpc r19, r20
 108: 24 f3        brlt .-56      ; 0xd2 <PsBLINKY_ss_SOMEDELAY+0x10>
 10a: 08 95        ret


Could this be the problem?

And, does anyone know why there is a difference between the procedures given on the Wiki and in the Tutorial, and why one would want to use one over the other?
Lee