Chapter 3. Getting Started

3.1. Creating The Project Directory

Create a directory named after your project. For our example, we'll call our project blink.

~$ mkdir blink
~$ cd blink	    
      

That's it. It's no harder than that. But to make this section more interesting, let's run dno in this directory:

blink$ dno
make: Nothing to be done for 'unknown'.
blink$
      

Here dno can't figure out what the right thing to do is, so does nothing. Which is the right thing to do.

3.2. Create An Initial Sketch

Let's create a copy of the much-used blink.ino sketch. You can use your favourite editor, or get it from github, or whatever. You could even copy and paste it from below:

/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduinos have an on-board LED you can control. On the UNO, MEGA and ZERO
  it is attached to digital pin 13, on MKR1000 on pin 6. LED_BUILTIN is set to
  the correct LED pin independent of which board is used.
  If you want to know what pin the on-board LED is connected to on your Arduino
  model, check the Technical Specs of your board at:
  https://www.arduino.cc/en/Main/Products

  modified 8 May 2014
  by Scott Fitzgerald
  modified 2 Sep 2016
  by Arturo Guadalupi
  modified 8 Sep 2016
  by Colby Newman

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Blink
*/

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}
      

Now our directory looks like this:

blink$ ls
blink.ino
blink$ 
      

Let's run dno again:

blink$ dno
Nothing to be done here (in /home/user/proj/blink).
Try dno ./BOARD_TYPE or dno tests
blink$ 
      

This tells us that dno does not know what sort of Arduino board to build for. You can get more information about this using dno info or dno help.

3.3. Select Our Board

We can tell dno what sort of board to build for by creating a BOARD_TYPE file. The simplest way to do this is using dno's BOARD_TYPE target.

To see what boards are available use dno show_boards.

Let's assume that we want to compile for a 3.3V Arduino pro mini. Using show_boards, we find that that the board name for this is pro, and that there are 4 cpu options:

blink$ dno show_boards BOARD=pro

    Supported ArduinoBoard and CPU Types
============================================================
pro                   Arduino Pro or Pro Mini
  16MHzatmega168        ATmega168 (5V, 16 MHz)
  8MHzatmega168         ATmega168 (3.3V, 8 MHz)
  16MHzatmega328        ATmega328P (5V, 16 MHz)
  8MHzatmega328         ATmega328P (3.3V, 8 MHz)
blink$
      

We create our BOARD_TYPE file as follows:

blink$ dno BOARD_TYPE BOARD=pro CPU=8MHzatmega328
  Creating BOARD_TYPE...
blink$ ls
blink.ino  BOARD_TYPE
blink$ 
      

We can see that dno has created a BOARD_TYPE file, which identifies the type of board that we are to compile for. Looking at it:

blink$ cat BOARD_TYPE
pro.8MHzatmega328
blink$ 
      

We see that it simply contains the board and cpu identification for our pro mini board.

3.4. Compiling/Building

Let's now run dno again and see what happens:

blink$ dno
  Creating BOARD_INFO...
  C++  [.] blink.ino
  AS  [core] wiring_pulse.S
  C  [core] wiring_shift.c
  C  [core] wiring_pulse.c
  C  [core] wiring_digital.c
  C  [core] wiring.c
  C  [core] wiring_analog.c
  C  [core] WInterrupts.c
  C  [core] hooks.c
  C++  [core] WString.cpp
  C++  [core] WMath.cpp
  C++  [core] USBCore.cpp
  C++  [core] Tone.cpp
  C++  [core] Stream.cpp
  C++  [core] Print.cpp
  C++  [core] PluggableUSB.cpp
  C++  [core] new.cpp
  C++  [core] main.cpp
  C++  [core] IPAddress.cpp
  C++  [core] HardwareSerial.cpp
  C++  [core] HardwareSerial3.cpp
  C++  [core] HardwareSerial2.cpp
  C++  [core] HardwareSerial1.cpp
  C++  [core] HardwareSerial0.cpp
  C++  [core] CDC.cpp
  C++  [core] abi.cpp
  AR [libcore] abi.o...
  LD blink.ino.o
  OBJCOPY (hex) blink.elf
blink$ ls -l
total 28
-rw-r--r-- 1 user user  1233 Jan  6 11:04 blink.ino
-rw-r--r-- 1 user user 12701 Jan  6 12:15 BOARD_INFO
-rw-r--r-- 1 user user    18 Jan  6 12:04 BOARD_TYPE
drwxr-xr-x 3 user user  4096 Jan  6 12:15 build
blink$ 
      

From dno's output we can see that BOARD_INFO was created, and then a bunch of compilation and other commands were executed. In addition to compiling the sketch blink.ino, the components of the core library were built, an archive file was built from those components (AR), the whole thing was linked together to create an executable (LD), and then, finally, a downloadable version of the executable was created (OBJCOPY).

Note thet the dno output shows a sanitised version of what is actually being done. This is mainly for aesthetic reasons: showing the full commands that are executed is pretty ugly. But if that's what you want, you can (as shown here) set VERBOSE on the command line:

blink$ dno VERBOSE=y
      

From our directory listing we can also see that a build directory was created. This is where all of our object, lib and executable files are created:

blink$ ls -l build
total 372
-rwxr-xr-x 1 user user  14108 Jan  6 12:15 blink.elf
-rw-r--r-- 1 user user   2615 Jan  6 12:15 blink.hex
-rw-r--r-- 1 user user   1104 Jan  6 12:15 blink.ino.d
-rw-r--r-- 1 user user   3860 Jan  6 12:15 blink.ino.o
drwxr-xr-x 2 user user   4096 Jan  6 12:15 libcore
-rw-r--r-- 1 user user 345554 Jan  6 12:15 libcore.a
blink$ ls build/libcore
abi.d		   HardwareSerial.o  Stream.d	       wiring.o
abi.o		   hooks.d	     Stream.o	       wiring_pulse.d
CDC.d		   hooks.o	     Tone.d	       wiring_pulse.o
CDC.o		   IPAddress.d	     Tone.o	       wiring_pulse.S.d
HardwareSerial0.d  IPAddress.o	     USBCore.d	       wiring_pulse.S.o
HardwareSerial0.o  main.d	     USBCore.o	       wiring_shift.d
HardwareSerial1.d  main.o	     WInterrupts.d     wiring_shift.o
HardwareSerial1.o  new.d	     WInterrupts.o     WMath.d
HardwareSerial2.d  new.o	     wiring_analog.d   WMath.o
HardwareSerial2.o  PluggableUSB.d    wiring_analog.o   WString.d
HardwareSerial3.d  PluggableUSB.o    wiring.d	       WString.o
HardwareSerial3.o  Print.d	     wiring_digital.d
HardwareSerial.d   Print.o	     wiring_digital.o
blink$ 
      

Note that once everything is built, dno will not rebuild it unless something changes:

blink$ dno
make: Nothing to be done for 'build'.
blink$
      

Note that the message says make:.... This is because dno is implemented using make.

3.5. Uploading To A Board

Now we need to connect our Arduino device to our computer. Typically, this is through a USB connection. Once done, we can verify that the device can be seen using dno devices:

blink$ dno devices
DEVICES: /dev/ttyUSB0
blink$
      

This shows that a serial device is connected to /dev/ttyUSB0. This is a good sign.

Now, as long as there is a single device connected, we should be able to upload our sketch:

blink$ dno upload
  Resetting device attached to (/dev/ttyUSB0)...
/usr/local/bin/dno do_upload
make[1]: Entering directory '.../proj/blink'
 
    Uploading blink.hex to /dev/ttyUSB0

avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: reading input file "build/blink.hex"
avrdude: writing flash (924 bytes):

Writing | ################################################## | 100% 0.51s

avrdude: 924 bytes of flash written
avrdude: verifying flash memory against build/blink.hex:
avrdude: load data flash data from input file build/blink.hex:
avrdude: input file build/blink.hex contains 924 bytes
avrdude: reading on-chip flash data:

Reading | ################################################## | 100% 0.43s

avrdude: verifying ...
avrdude: 924 bytes of flash verified

avrdude: safemode: Fuses OK (E:00, H:00, L:00)

avrdude done.  Thank you.

make[1]: Leaving directory '.../blink'
blink$ 	
      

Please note that the ridiculous verbosity of this is outside of dno's control.

3.6. In Summary

In summary, to create a brand new project, blink, from scratch, and upload it to an Arduino board takes only the following steps (dno output not shown):

~$ mkdir blink
~$ cd blink
blink$ [create blink.cpp using your favourite editor]
blink$ dno BOARD_TYPE BOARD=pro CPU=8MHzatmega328
[ . . . ]
blink$ dno
[ . . . ]
blink$ dno upload
[ . . . ]
      

It could hardly be more simple.

Note that if you were confident that blink.cpp would build without errors, you could even omit the build step: ie the step before the upload, as dno upload will automatically realise that compilation and linking is needed and will make it happen.