As it has been asked in
another thread, I'm writing this as a quick/short tutorial for people who want to try programming their
Arduino Uno using FreePascal and Lazarus. The steps should work on Windows and Linux.
1. Make sure you are running up-to-date
Trunk versions of both FreePascal and Lazarus. There are several posts on this forum as well as Internet blogs about it, so make sure to check those. You should be having a fully working environment before proceeding and be comfortable configuring and rebuilding the trunk yourself.
2. On Windows, instead of
AVR Toolchain, you may want to just use
FPCBuild Binaries, which include AVR-related tools with prefix "avr-embedded-" (e.g. "avr-embedded-as.exe"). Make sure you have all these tools in some folder that you can easily remember.
On Linux, there is official
AVR Toolchain. If you happen to use Debian-based distribution, just use:
sudo apt-get install binutils-avr
3. Make sure to use latest version of
avrdude. On Windows, you can download it
from here. For Linux, you can pick the appropriate version from
this list. On Debian-based distribution, use:
sudo apt-get install avrdude
4. Compile trunk FreePascal for AVR target. On Windows, this is a sample batch script, which you may want to fine-tune yourself:
SET FPC_PATH=%CD%\3.0.0\bin\i386-win32
SET PPCBIN=%FPC_PATH%\fpc.exe
SET INSTALL_PATH=%CD%\Win32
SET PATH=%FPC_PATH%;%NDK_BIN%;%PATH%
make clean crossall crossinstall FPC=%PPCBIN% OS_TARGET=embedded CPU_TARGET=avr SUBARCH=avr5 INSTALL_PREFIX=%INSTALL_PATH% CROSSBINDIR=%GNU_BIN_PATH% BINUTILSPREFIX=avr-embedded- CROSSOPT="-O3 -XX -CX"
In above code, adjust the paths as needed. Pay special attention to "GNU_BIN_PATH", which should point to the path, where you downloaded FPCBuild binaries for AVR.
On Linux, you can use the following script (assumes FPC is installed in "/usr/local"):
#!/bin/sh
set -e
make clean crossall OS_TARGET=embedded CPU_TARGET=avr SUBARCH=avr5 BINUTILSPREFIX=avr- CROSSOPT="-O3 -XX -CX"
sudo make crossinstall OS_TARGET=embedded CPU_TARGET=avr SUBARCH=avr5
sudo ln -s -f /usr/local/lib/fpc/3.1.1/ppcrossavr /usr/local/bin/ppcrossavr
In above scripts, notice "avr5" subarch flag. This may be different for other Atmel chips, in FreePascal sources open to "/rtl/embedded/Makefile" to see what chip corresponds to each subarch. For Arduino Uno and ATMega328P, this is "avr5".
5. Edit "fpc.cfg" and on Windows add the following:
#ifdef embedded
-FD$GNU_BIN_PATH$
-OoFastMath
#-XX
-CX
-Oonostackframe
#ifdef avr
-XPavr-embedded-
#endif
#endif
Note that "GNU_BIN_PATH" should be set as a global environment variable pointing to AVR tools that you've installed in step 2.
On Linux, add something like this:
#IFDEF embedded
-OoFastMath
-XX
-CX
-OoNoStackFrame
#IFDEF cpuavr
-XPavr-
#ENDIF
#ENDIF
6. Open the attached example "Blinky" and try compiling it. If you have configured toolchains and built FreePascal for AVR target correctly, it should succeed. You should obtain files such as "Blinky.elf", "Blinky.hex" and "Blinky.bin". Either one of these files can be used for uploading to Arduino.
7. Upload the resulting executable to Arduino using its own bootloader and avrdude. The command would be something like:
sudo avrdude -v -patmega328p -carduino -P/dev/ttyACM0 -b115200 -D -Uflash:w:Blinky.hex:i
In above command, on Linux, "/dev/ttyACM0" is the path to mapped serial port after connecting Arduino, make sure to adjust it as needed. On Windows, it would probably be something like:
avrdude -v -patmega328p -carduino -P\\.\COM3 -b115200 -D -Uflash:w:Blinky.hex:i
If the operation is successful, the application should execute immediately and you should see internal LED blinking. If you have any problems with this, feel free to ask here.
Note that attached example accesses port bits directly, similar to C/C++ AVR samples. Currently, there is no higher-level framework, but
PXL on
GitHub is being ported. Meanwhile, you can just use code similar to
AVR C tutorials.
The following are some limitations on AVR target:
- In RTL, bit flags like "PA0", "PB3" are not defined. However, since these are just friendly names for bits, you can use something like "1 shl 2" (for PA2, PB2, PC2, etc..)
- Floating-point emulation doesn't seem to work yet, so you should stick to integers and/or fixed-point math.
- Classes don't seem to work either, currently compiler complains about something related to VMT. You can just stick to procedural approach with advanced records.
To figure out what Arduino pin corresponds to what port, you can use pinout diagram
from this post. Internal LED appears to be connected to pin 13 (PB5).