-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgeneric.mk
822 lines (718 loc) · 36.3 KB
/
generic.mk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
# Make code to all the different modules. Some things defined here are
# easy to override in modules, those section titles contain "(Overridable)".
# vim: foldmethod=marker
##### Make Settings and Sanity Measures {{{1
# This is sensible stuff for use but could confuse an experienced Make
# programmer, so it's out front here.
# Delete files produced by rules the commands of which return non-zero.
.DELETE_ON_ERROR:
# Don't let make parallelize anything.
.NOTPARALLEL:
# Disable old-fashioned suffix rules.
.SUFFIXES:
# Ensure that we can use bashisms.
SHELL = /bin/bash
# This Makefile requires that the -R/--no-builtin-variables and
# -r/--no-builtin-variables options be used. Implicit rules and default
# variables cause much more trouble and unreadability than they are worth.
ifeq ($(findstring r,$(MAKEFLAGS)),)
$(error This makefile requires use of the -r/--no-builtin-rules make option)
endif
ifeq ($(findstring R,$(MAKEFLAGS)),)
$(error This makefile requires use of the -R/--no-builtin-variables make \
option)
endif
# Avoid default goal confusion by essentially disabling default goals.
PRINT_DEFAULT_GOAL_TRAP_ERROR_MESSAGE := \
echo ; \
echo This build system doesn\'t support default goals, because they tend ; \
echo to cause confusion. Please explicitly specify a target. ; \
echo Useful targets:; \
echo ; \
echo ' *' some_file.o -- Compile some_file.c ; \
echo ' *' writeflash -- Compile, link, and upload current module test ; \
echo
.DEFAULT_GOAL = default_goal_trap
.PHONY: default_goal_trap
default_goal_trap:
@($(PRINT_DEFAULT_GOAL_TRAP_ERROR_MESSAGE) && false) 1>&2
# This function works almost exactly like the builtin shell command, except it
# stops everything with an error if the shell command given as its argument
# returns non-zero when executed. The other difference is that the output
# is passed through the strip make function (the shell function strips
# only the last trailing newline). In practice this doesn't matter much
# since the output is usually collapsed by the surroundeing make context
# to the same result produced by strip. WARNING: don't try to nest calls
# to this function.
SHELL_CHECKED = \
$(strip \
$(if $(shell (($1) 1>/tmp/SC_so) || echo 'non-empty'), \
$(error shell command '$1' failed. Its stderr should be above \
somewhere. Its stdout is available for review in '/tmp/SC_so'), \
$(shell cat /tmp/SC_so)))
##### Specs for Default Target Part (Overridable) {{{1
# Name for part being targetted, as known by the compiler and the uploader.
COMPILER_MCU ?= atmega328p
PROGRAMMER_MCU ?= m328p
# AVR libc uses this. Some people might prefer to put it in a header though.
CPU_FREQ_DEFINE ?= -DF_CPU=16000000
# This is used by the replace_bootloader target to determine which
# bootloader .hex file to use. Different Arduinos need different values:
# my Duemilanove uses ATmegaBOOT_168_atmega328.hex, which my Uno rev.3
# ships with optiboot_atmega328.hex for example. The default value of
# autoguess tried to make the determination automagically, but this can fail
# (in which case the guessing script will output some diagnostics).
ARDUINO_BOOTLOADER ?= autoguess
#ARDUINO_BOOTLOADER ?= optiboot_atmega328.hex
#ARDUINO_BOOTLOADER ?= ATmegaBOOT_168_atmega328.hex
# Target patters for which we presumably don't need a connected Arduino.
# Clients can augment this variable, but they have to do so before this file
# is processed (i.e. before the include statement that includes it, or with
# an environment variable setting). Note that using a command line setting
# won't work (even if it's an append), because setting make variables that
# way stomps settings that come from the Makefile or its included fragments.
# See comments near where the variable is referenced.
VALID_ARDUINOLESS_TARGET_PATTERNS += %.c %.o %.ee.hex %.hex %.out %.out.map
##### Program Name, Constituent Object Files (Overridable) {{{1
# This is the paragraph that determines which files are being built into what.
PROGNAME ?= program_to_upload
OBJS ?= $(patsubst %.c,%.o,$(wildcard *.c)) \
$(patsubst %.cpp,%.o,$(wildcard *.cpp))
HEADERS ?= $(wildcard *.h)
##### Upload Method (Overridable) {{{1
# Setting this to a non-empty value declares that there is no Arduino
# connected via USB (or if there is it should be ignored), so the normal
# probes for an Arduino on USB are disabled. This is useful if you're
# trying to program a bare chip using an AVRISPmkII.
NO_USB_ARDUINO_CONNECTION ?=
# This must be one of:
#
# arduino_bl Arduino bootloader over USB
# AVRISPmkII AVR ISP mkII programmer, overwriting any bootloader
#
# WARNING: the AVRISPmkII options will make your Arduino unprogrammable using
# the normal bootloader method (though you can recover: see the
# replace_bootloader target).
#
# Note that unless NO_USB_ARDUINO_CONNECTION is defined to a non-empty value,
# this build system still requires an Arduino to be connected over USB,
# it just doesn't use it for programming.
UPLOAD_METHOD ?= arduino_bl
# If this is set to true, then if the perl modules required to pulse the DTR
# line of the serial port aren't found or the DTR pulse code fails for some
# reason, it is not considered a fatal error (but the user will then have to
# push the reset button on the arduino immediately after the avrdude
# programming command goes off to program the device).
# FIXME: is this crud still required in the rev3 days? maybe should be true?
DTR_PULSE_NOT_REQUIRED ?= false
# Uploader program.
AVRDUDE ?= avrdude
# The programmer type being used as understood by avrdude. This should
# probably always be "arduino" when the UPLOAD_METHOD is arduino_bl, unless
# you've for some reason modified you avrdude.conf to include an alternate ID.
AVRDUDE_ARDUINO_PROGRAMMERID ?= arduino
# Location and characteristics of the Arduino on the USB. Note that this
# build system usually tries to find an Arduino even if the AVRISPmkII
# method is being used. If you don't want any of these checks to happen
# see the NO_USB_ARDUINO_CONNECTION variable above. The values that should
# be used here differ for different recent arduinos: for me at least, the
# Duemilanove needs /dev/ttyUSB0 and 57600 baud, the Uno /dev/ttyUSB0 and
# 115200 baud. For other setups or setups with multiple Arduinos hooked
# up, different device names might be required. The special value of
# 'autoguess' can be used to indicate that the build system should try to
# guess which values to use based on the device it finds connected (and
# output diagnostic messages if it can't guess).
ARDUINO_PORT ?= autoguess
#ARDUINO_PORT ?= /dev/ttyACM0
#ARDUINO_PORT ?= /dev/ttyUSB0
ARDUINO_BAUD ?= autoguess
#ARDUINO_BAUD ?= 115200
#ARDUINO_BAUD ?= 57600
# When using UPLOAD_METHOD = AVRISPmkII, this default argument value for the
# -P ("port") option to avrdude works nicely if there's only one AVRISPmkII
# attached. If there are multiple AVRISPmkII devices attached, you'll need
# to add a colon and a serial number to specify which one you want this
# build system to use. See the next few commented-out lines for a way to
# discover the serial numbers and use them to specify the correct programmer.
AVRISPMKII_PORT ?= usb
# Arrange for AVRISPMKII_PORT to be set like this instead of the above
# default setting for AVRISPMKII_PORT to cause the writeflash target (and
# others) to fail but output a list of the usb-connected AVRISPmkII devices.
# Look for lines like something like this:
#
# avrdude: usbdev_open(): Found AVRISP mkII, serno: 000200198321
# avrdude: usbdev_open(): Found AVRISP mkII, serno: 000200198577
#
# This works by using a "port" value that won't match anything, and squeaking
# a -v avrdude option in with it to cause avrdude to output diagnostics.
#AVRISPMKII_PORT ?= usb:xxx -v
# Once you know the serial number of the device you want to use you can use
# something like this:
#AVRISPMKII_PORT ?= usb:000200198321
##### Compilers, Assemblers, etc. (Overridable) {{{1
# Compilers. Note that some of these depend for overridability on the -R
# make option that this Makefile requires be used.
CC ?= avr-gcc
CXX ?= avr-g++
OBJCOPY ?= avr-objcopy
OBJDUMP ?= avr-objdump
SIZE ?= avr-size
# These programs could be useful, but I don't use them at the moment.
AVARICE ?=
AVRGDB ?=
##### Fuse Settings (Overridable) {{{1
# Fuse settings to be programmed, in the form of a list of setting for
# individual bits as they are named in for example the Mega328P datasheet.
# For example, setting this to 'BODLEVEL2=1 BODLEVEL1=0 BODLEVEL0=1'
# will enable brown out detection for a typical value of 2.7 V supply
# as described in the datasheet. Note that lock and fuse bits are always
# written a byte at a time: if any bits of a byte are specified, all should be
# (or else they will take their default values). Note also that in order
# for anything to be written to a fuse byte, at least one bit of that
# byte must be specified. Finally, note that the arduino uses a number
# of non-default lock and fuse settings: changing them may break things.
# On the other hand, if you want to use in-system programming to program
# a minimal system at a different clock rate, you'll need to learn about
# fuse settings. See the uses of this variable for more details.
LOCK_AND_FUSE_SETTINGS ?=
##### printf() Feature Support (Overridable) {{{1
# AVR libc provides minimal, standard, and (mostly) full-featured printf
# implementations, allowing you to trade features for small code size. See the
# discussion in
# http://www.nongnu.org/avr-libc/user-manual/group__avr__stdio.html for
# details. The default is to use the AVR libc default printf implementation,
# which supports most normal printf features except floating point support.
# Other possible values which individual modules may use are
# "-Wl,-u,vfprintf -lprintf_min" and "-Wl,-u,vfprintf -lprintf_flt -lm".
AVRLIBC_PRINTF_LDFLAGS ?=
##### Debugging and Versioning CPP Flags (Overridable) {{{1
# It's often convenient to compile code slightly differently when debugging
# will be done, this variable gets put in CPPFLAGS so you can set it to
# something like '-DDEBUG' then say '#ifdef DEBUG' in the code to do logging
# and such.
CPP_DEBUG_DEFINE_FLAGS ?=
# NOTE: See also CPP_GIT_DESCRIPTION_DEFINE_FLAGS. It's probably better
# for most purposes, though it has the disadvantage of producing a
# slightly longer string. Arrange for VERSION_CONTROL_COMMIT to be set
# at compile-time if possible. By default this is set such that if git
# rev-parse works in the build directory and the build directory is clean the
# CPP macro VERSION_CONTROL_COMMIT gets defined to the first 16 hex digits
# of the git commit pointed to by git HEAD, or is undefined otherwise.
# The version control commit can then be retrieved from the source as
# a string literal using EXPAND_AND_STRINGIFY (VERSION_CONTROL_COMMIT)
# (from util.h). Note that if VERSION_CONTROL_COMMIT is undefined, it will
# end up stringified as itself.
CPP_VERSION_CONTROL_COMMIT_DEFINE_FLAGS ?= \
`(git rev-parse 2>/dev/null) && \
(git status | grep -q 'nothing to commit, working directory clean') && \
echo -DVERSION_CONTROL_COMMIT=$$(git rev-parse --short=16 HEAD)`
# This is similar to CPP_VERSION_CONTROL_COMMIT_DEFINE_FLAGS, but it give uses
# the output of git-describe (in GIT_DESCRIPTION), which has the advantage
# of being tag-relative and always being defined even for untagged or dirty
# trees. Note that putting dirty trees on release hardware is particularly
# inadvisable, however, since those configurations aren't recoverable after
# the fact.
CPP_GIT_DESCRIPTION_DEFINE_FLAGS ?= \
-DGIT_DESCRIPTION=$$(git describe --dirty --tags --always)
##### Computed File Names and Settings {{{1
# Magical files that one doesn't see in non-microcontroller GCC development.
TRG = $(PROGNAME).out
DUMPTRG = $(PROGNAME).s
HEXROMTRG = $(PROGNAME).hex
HEXTRG = $(HEXROMTRG) $(PROGNAME).ee.hex
LSTFILES := $(patsubst %.o,%.c,$(OBJS))
GENASMFILES := $(patsubst %.o,%.s,$(OBJS))
# Automatic Determination of Arduino Parameters (Augmentable) {{{2
# In order to support building and linking of files when an Arduino is not
# connected, we avoid doing any of the autodetection work if we our goals
# clearly do not require communication with the Arduino. Note that this
# is conservative in the sense that if the user tries to build something
# that isn't explicitly included in our list of things that don't really
# need a connection, the autodetection code will go off and they will get
# the detection failure messages.
ARDUINOLESS_TARGET_WARNING_TEXT := \
If you should not need to be connected to an Arduino for the taget you are \
are building, consider adding a pattern to the \
VALID_ARDUINOLESS_TARGET_PATTERNS Make variable. \
\
If you are using an AVRISPmkII (UPLOAD_METHOD = AVRISPmkII), note that the \
autodetection code normally still requires the Arduino to be connected to \
the computer by USB. If you do not have a USB connection to the Arduino, \
you must define the NO_USB_ARDUINO_CONNECTION make variable to a non-empty \
value. Note that the Arduino hardware autodetection should work even if \
there is no Arduino bootloader on the chip.
ifneq ($(filter-out $(VALID_ARDUINOLESS_TARGET_PATTERNS),$(MAKECMDGOALS)),)
ifeq ($(NO_USB_ARDUINO_CONNECTION), )
ifeq ($(ARDUINO_PORT),autoguess)
ACTUAL_ARDUINO_PORT := \
$(call SHELL_CHECKED,./guess_arduino_attribute.perl --device)
ifeq ($(ACTUAL_ARDUINO_PORT),)
$(warning $(ARDUINOLESS_TARGET_WARNING_TEXT))
$(info )
$(error could not guess ARDUINO_PORT, see messages above)
endif
else
ACTUAL_ARDUINO_PORT := $(ARDUINO_PORT)
endif
ifeq ($(ARDUINO_BAUD),autoguess)
ACTUAL_ARDUINO_BAUD := \
$(call SHELL_CHECKED,./guess_arduino_attribute.perl --baud)
ifeq ($(ACTUAL_ARDUINO_BAUD),)
$(warning $(ARDUINOLESS_TARGET_WARNING_TEXT))
$(info )
$(error could not guess ARDUINO_BAUD, see messages above)
endif
else
ACTUAL_ARDUINO_BAUD := $(ARDUINO_BAUD)
endif
ifeq ($(ARDUINO_BOOTLOADER),autoguess)
ACTUAL_ARDUINO_BOOTLOADER := \
$(call SHELL_CHECKED,./guess_arduino_attribute.perl --bootloader)
ifeq ($(ACTUAL_ARDUINO_BOOTLOADER),)
$(warning $(ARDUINOLESS_TARGET_WARNING_TEXT))
$(info )
$(error could not guess ARDUINO_BOOTLOADER, see messages above)
endif
else
ACTUAL_ARDUINO_BOOTLOADER := $(ARDUINO_BOOTLOADER)
endif
else
ifeq ($(UPLOAD_METHOD),arduino_bl)
$(error The NO_USB_ARDUINO_CONNECTION Make variable is non-empty, but \
UPLOAD_METHOD is arduino_bl and at least one of the current \
make goals does not match any pattern in \
VALID_ARDUINOLESS_TARGET_PATTERNS )
endif
ifneq ($(filter replace_bootloader,$(MAKECMDGOALS)),)
$(error The NO_USB_ARDUINO_CONNECTION Make variable is non-empty, but \
replace_bootloader has been requested as a make goal. The \
replace_bootloader target needs to be able to find an Arduino \
on USB to determine which bootloader image is required for your \
hardware. )
endif
endif
endif
# }}}2
##### Build Settings and Flags (Augmentable) {{{1
HEXFORMAT := ihex
OPTLEVEL := s
# Language-independent diagnostic GCC flags. Clients can add their own.
# Note that order sometimes matters for compiler flags, so it could matter
# whether they do so before or after the include statement that includes
# this file.
#
# FIXME: this needs GCC 4.9. Enable it when that is common. Also add it
# to LDFLAGS or the command that invokes the linker if it's supported there.
#DIAGNOSTICS_FLAGS += -fdiagnostics-color=auto
# Clients can add their own CPPFLAGS. Note that order sometimes matters
# for compiler flags, so it could matter whether they do so before or after
# the include statement that includes this file.
CPPFLAGS += $(CPP_VERSION_CONTROL_COMMIT_DEFINE_FLAGS) \
$(CPP_GIT_DESCRIPTION_DEFINE_FLAGS) \
$(CPP_DEBUG_DEFINE_FLAGS) \
$(CPU_FREQ_DEFINE) \
-I.
# See comments near CPPFLAGS, above.
CFLAGS += -std=gnu11 -fshort-enums -mmcu=$(COMPILER_MCU) -O$(OPTLEVEL) \
-Werror -Wall -Wextra -Winline -Wmissing-prototypes \
-Wredundant-decls -Winit-self -Wstrict-prototypes
# There are a number of C compiler flags that the C++ compiler doesn't like, or
# that the standard arduino libs dont satisfy.
NONCXXFLAGS = -std=gnu11 \
-Wimplicit-int \
-Winline \
-Wmissing-prototypes \
-Wold-style-declaration \
-Wredundant-decls \
-Wstrict-prototypes \
# Support building C++ files. Currently this has mainly been used to ease
# the translation of Arduino modules away from C++, but maybe some people
# would like to use our interfaces from C++ for some reason. See also the
# comments near CPPFLAGS, above.
CXXFLAGS += $(filter-out $(NONCXXFLAGS), $(CFLAGS))
# WARNING: I don't think I've actually exercised the assembly parts of this
# build system myself at all. Not using assembly is sort of a project goal :)
ASMFLAGS := -I. -mmcu=$(COMPILER_MCU)-x assembler-with-cpp \
-Wa,-gstabs,-ahlms=$(firstword $(<:.S=.lst) $(<.s=.lst))
LDFLAGS := -mmcu=$(COMPILER_MCU) $(AVRLIBC_PRINTF_LDFLAGS) -lm \
-Wl,-Map,$(TRG).map
##### Rules {{{1
########## Interface Targets {{{2
# These are targets that users are likely to want to invoke directly (as
# arguments to make).
PRINT_ARDUINO_DTR_TOGGLE_WEIRDNESS_WARNING := \
echo "" ; \
echo "Couldn't pulse DTR or upload failed. Some possible reasons:" ; \
echo "" ; \
echo " * The Device::SerialPort perl module isn't installed, see the " ; \
echo " diagnostic output above for more details." ; \
echo "" ; \
echo " * You don't have write permission for the Arduino device file." ; \
echo " If you have a 'Permission denied' message above that refers to" ; \
echo " a file in /dev (perhaps /dev/ttyACM0 or /dev/ttyUSB0) this is " ; \
echo " likely the problem. Make sure the Arduino is plugged in, and " ; \
echo " then take a look at the mentioned file with 'ls -l' and see if" ; \
echo " there is a group you can add yourself to to get write" ; \
echo " permission (on debian I had to add myself to the 'dialout'" ; \
echo " group). Note that for group membership to take effect for you" ; \
echo " you may need to restart your system (or restart the Gnome" ; \
echo " Display Manager or somethimg) and login again. You can see" ; \
echo " what groups you're in with the 'groups' command." ; \
echo "" ; \
echo " * Your Arduino program is itself using the serial port, which" ; \
echo " prevents the programmer from working on my Arduino Uno rev. 3" ; \
echo " at least. Make sure that you do not have a screen session" ; \
echo " connected to the arduino, for example. If you get a message" ; \
echo " like \"Couldn't open /dev/ttyACM0: Device or resource busy\"" ; \
echo " this is a particularly likely explanation." ; \
echo "" ; \
echo " * You might need to press reset immediately after avrdude starts" ; \
echo " as required (with my Duemilanove anyway) if the above serial" ; \
echo " DTR pulse is not doing it (the DTR pulse does not seem to work" ; \
echo " if the arduino has been running for a while without being" ; \
echo " programmed, or if the program running on the arduino is using" ; \
echo " the serial line itself)." ; \
echo "" ; \
echo " * The bootloader has been nuked (by programming with the" ; \
echo " AVRISPmkII for example). See the replace_bootloader target in" ; \
echo " generic.mk." ; \
echo ""
PRINT_AVRISPMKII_PROGRAMMING_FAILED_MESSAGE := \
echo ; \
echo Programming failed. Is the AVRISPmkII hooked up? Does the Arduino ; \
echo have power? The AVRISPmkII does not power the Arduino, but you can ; \
echo just plug in the USB cable to power it and still use the AVRISPmkII ; \
echo for programming. ; \
echo
.PHONY: writeflash
writeflash: LOCK_AND_FUSE_AVRDUDE_OPTIONS := \
$(call SHELL_CHECKED,./lock_and_fuse_bits_to_avrdude_options.perl \
$(PROGRAMMER_MCU) $(LOCK_AND_FUSE_SETTINGS))
writeflash: $(HEXTRG) avrdude_version_check
ifeq ($(UPLOAD_METHOD), arduino_bl)
writeflash:
# First kill any screen session started from run_screen.mk.
screen -S $(SCREEN_SESSION_NAME) -X kill || true
# Give screen time to die, once I still had programming fail w/o this.
sleep 0.42 || sleep 1
$(PROBABLY_PULSE_DTR) || \
($(PRINT_ARDUINO_DTR_TOGGLE_WEIRDNESS_WARNING) && false) 1>&2
$(AVRDUDE) -c $(AVRDUDE_ARDUINO_PROGRAMMERID) \
-p $(PROGRAMMER_MCU) \
-P $(ACTUAL_ARDUINO_PORT) \
-b $(ACTUAL_ARDUINO_BAUD) \
-U flash:w:$(HEXROMTRG) \
$(LOCK_AND_FUSE_AVRDUDE_OPTIONS) || \
( $(PRINT_ARDUINO_DTR_TOGGLE_WEIRDNESS_WARNING) ; false ) 1>&2
# Sometimes the chip doesn't seem to reset after programming.
# Pulsing the DTR again here often seems to help wake it up. NOTE:
# this probably sort of races serial line use on the arduino itself,
# but it should pretty much always win :)
$(PROBABLY_PULSE_DTR) || \
($(PRINT_ARDUINO_DTR_TOGGLE_WEIRDNESS_WARNING) && false) 1>&2
else ifeq ($(UPLOAD_METHOD), AVRISPmkII)
writeflash: binaries_suid_root_stamp
$(AVRDUDE) -c avrispmkII \
-p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-U flash:w:$(HEXROMTRG) \
$(LOCK_AND_FUSE_AVRDUDE_OPTIONS) || \
( $(PRINT_AVRISPMKII_PROGRAMMING_FAILED_MESSAGE) && \
false ) 1>&2
else
$(error invalid UPLOAD_METHOD value '$(UPLOAD_METHOD)')
endif
# Support for writing an 8 byte signature to the start of the EEPROM memory
# using an AVRISPmkII. Either a random ID (from /dev/random) or a specific
# one (by setting Make variable NRID) can be set. This lets you easily
# donate some entropy from your linux box to your ATMega chip to give it a
# (hopefully unique) ID.
#
# The targets that write IDs require UPLOAD_METHOD to be AVRISPmkII, because
# I don't know how to program the EEPROM using the arduino bootloader
# upload method, assuming it's even supported. Note that it's fine to
# use bootloader programming for the program upload (writeflash target)
# while using the AVRISPmkII upload method for the targets that write IDs
# (see below).
#
# Unfortunately the UPLOAD_METHOD options used to upload the program code
# with the writeflash target differ in behavior with respect to the EEPROM:
#
# * The AVRISPmkII seems to always delete the entire EEPROM when the program
# memory space is written. So if you're using this programmer you'll
# probably want to create a spoofed version of the routine you use to
# read the ID during edit-compile-debug work (assuming you care if the
# ID stays the same), or possibly use the REUSE_EXISTING_RANDOM_ID
# feature (see below). When everything is done you can use the
# write_random_id_to_eeprom target to give your part a real ID.
#
# * The arduino_bl (bootloader over USB programming method) seems to leave
# the EEPROM alone. So you can use the write_random_id_to_eeprom target
# once to give your part an ID then reprogram as desired.
#
# This problem doesn't apply in reverse: you can write the EEPROM using
# the AVRISPmkII without disturbing the other memory types (program flash,
# lock and fuse bits, etc.) So you can write the ID after uploading the
# main program.
#
# See the cduino/random_id module for an example of how to read your random
# ID back out of the EEPROM from the ATMega side. Note in particular the
# possible endianness issues that exist when interpreting the ID as a uint64_t
# (or other integer) type.
#
# This isn't rolled into writeflash like the lock and fuse settings are
# because it's probably something we want to do only once and not change
# all the time.
#
# Random Id File
RIF = /tmp/generic.mk.random_id_file
# Dump the Id stored at the start of the first argument in human readable form.
DUMP_RANDOM_ID = \
od --format=x1 $(1) | cut -f 2-9 -d' ' | head -n 1 | perl -p -e 's/ //g'
.PHONY: new_random_id
new_random_id:
# Now that the write_non_random_id_to_eeprom target exists, this
# REUSE_EXISTING_RANDOM_ID functionality is probably not too useful.
# Because it's sometimes nice to be able to hard-wire things to use a
# particular id, we have this variable that can be defined non-empty to
# reuse an existing random id file. This is useful for example during
# testing when programming with the AVRISPmkII and you want to embed a
# known ID into your program code (because writing the program area blows
# away the EEPROM area forcing you to set the ID again afterwords).
ifndef REUSE_EXISTING_RANDOM_ID
dd if=/dev/random of=$(RIF) bs=1 count=8
else
test -r $(RIF) || \
( echo -e "\n"file $(RIF) not readable. Maybe you need to try \
without REUSE_EXISTING_RANDOM_ID first?"\n" 1>&2 && \
false )
endif
.PHONY: write_random_id_to_eeprom
# ID Report String
write_random_id_to_eeprom: IRS = \
"Wrote randomly generated 8 byte ID 0x"`$(call DUMP_RANDOM_ID, $(RIF))` \
"to start of chip EEPROM"
write_random_id_to_eeprom: avrdude_version_check new_random_id
ifeq ($(UPLOAD_METHOD), arduino_bl)
write_random_id_to_eeprom:
# I think most likely the bootloader just doesn't support this
@echo EEPROM writing using the $(UPLOAD_METHOD) upload method is not \
supported. If it can be done somehow please let me know! \
1>&2 && false
else ifeq ($(UPLOAD_METHOD), AVRISPmkII)
write_random_id_to_eeprom: binaries_suid_root_stamp
$(AVRDUDE) -c avrispmkII \
-p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-U eeprom:w:$(RIF):r
@echo $(IRS)
else
$(error invalid UPLOAD_METHOD value '$(UPLOAD_METHOD)')
endif
# This target gives a way of reading the ID back out of a device
.PHONY: read_id_from_eeprom
read_id_from_eeprom: IDF = /tmp/generic.mk.id_dump_file
read_id_from_eeprom:
ifeq ($(UPLOAD_METHOD), arduino_bl)
read_id_from_eeprom:
# I think most likely the bootloader just doesn't support this
@echo EEPROM reading using the $(UPLOAD_METHOD) upload method is not \
supported. If it can be done somehow please let me know! \
1>&2 && false
else ifeq ($(UPLOAD_METHOD), AVRISPmkII)
read_id_from_eeprom: binaries_suid_root_stamp
$(AVRDUDE) -c avrispmkII \
-p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-U eeprom:r:$(IDF):r
@echo -n "The ID at byte 0 of the EEPROM appears to be 0x"
@$(call DUMP_RANDOM_ID, $(RIF))
@echo "NOTE: due to endianness you'll need to reverse the bytes of a"
@echo "uint64_t literal value to get it to equal this (assuming you"
@echo "read the bytes of the ID starting from EEPROM byte 0)."
@echo
else
$(error invalid UPLOAD_METHOD value '$(UPLOAD_METHOD)')
endif
# This is the non-random ID value to be uploaded by the
# write_non_random_id_to_eeprom target.
NRID ?= 0x4242424242424242
NRIF = /tmp/generic.mk.non_random_id_file
.PHONY: write_non_random_id_to_eeprom
# ID Written String
write_non_random_id_to_eeprom: IWS = \
"Wrote 8 byte ID 0x$(NRID) to start of chip EEPROM"
ifeq ($(UPLOAD_METHOD), arduino_bl)
write_non_random_id_to_eeprom:
# I think most likely the bootloader just doesn't support this
@echo EEPROM writing using the $(UPLOAD_METHOD) upload method is not \
supported. If it can be done somehow please let me know! \
1>&2 && false
else ifeq ($(UPLOAD_METHOD), AVRISPmkII)
write_non_random_id_to_eeprom: binaries_suid_root_stamp
printf \
`echo $(NRID) | \
perl -pe 's/^0x//; s/([0-9A-Fa-f]{2})/\\\\x$$1/g;'` | \
dd of=$(NRIF) bs=1 count=8
$(AVRDUDE) -c avrispmkII \
-p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-U eeprom:w:$(NRIF):r
@echo $(IWS)
else
$(error invalid UPLOAD_METHOD value '$(UPLOAD_METHOD)')
endif
# This target is special: it uses an AVR ISPmkII and the bootloaded image
# that comes in the arduino download package and some magic goop copied here
# from arduino-1.0/hardware/arduino/bootloaders/atmega/Makefile to replace
# the bootloader and program the fuses as required for bootloading to work.
# The EEPROM is also erased. The intent is to put the chip back into a
# natural Arduino-ish state :) This is useful if we've managed to nuke the
# bootloader some way or other.
#
# FIXME: ATmegaBOOT_168_atmega328.hex seems unchanged in latest distribution,
# but we should autotrack
replace_bootloader: $(ACTUAL_ARDUINO_BOOTLOADER) binaries_suid_root_stamp
$(AVRDUDE) -c avrispmkII -p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-e -u \
`./lock_and_fuse_bits_to_avrdude_options.perl -- \
$(PROGRAMMER_MCU) \
BLB12=1 BLB11=1 BLB02=1 BLB01=1 LB2=1 LB1=1 \
BODLEVEL2=1 BODLEVEL1=0 BODLEVEL0=1 \
RSTDISBL=1 DWEN=1 SPIEN=0 WDTON=1 \
EESAVE=1 BOOTSZ1=0 BOOTSZ0=1 BOOTRST=0 \
CKDIV8=1 CKOUT=1 SUT1=1 SUT0=1 \
CKSEL3=1 CKSEL2=1 CKSEL1=1 CKSEL0=1` || \
( $(PRINT_AVRISPMKII_PROGRAMMING_FAILED_MESSAGE) && \
false ) 1>&2
$(AVRDUDE) -c avrispmkII -p $(PROGRAMMER_MCU) -P $(AVRISPMKII_PORT) \
-U flash:w:$< \
`./lock_and_fuse_bits_to_avrdude_options.perl -- \
$(PROGRAMMER_MCU) \
BLB12=0 BLB11=0 BLB02=1 BLB01=1 LB2=1 LB1=1`
COMPILE_C = $(CC) $(DIAGNOSTICS_FLAGS) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
# This is just like COMPILE_C, but we have an extra define that causes
# some printf-related macros to expand differently st we get the usual
# nice warnings about format-type mismatches, but don't get program memory
# strings. This way we can compile things twice: once to get sensible
# warnings (which we treat as errors probably), and then again to get actual
# RAM-efficient code.
COMPILE_C_FOR_PRINTF_WARNINGS = \
$(CC) $(DIAGNOSTICS_FLAGS) \
-DTRIGGER_PRINTF_WARNINGS \
$(CPPFLAGS) $(CFLAGS) -c $< -o $@
# FIXME: would we rather use a static pattern rule here? They are generally
# cleaner and result in much better error messages in some circumstances,
# but are also less well understood. This would take some thought as to
# which sorts of errors are more likely and how confusing the results are
# likely to be.
%.o: %.c
$(COMPILE_C_FOR_PRINTF_WARNINGS)
$(COMPILE_C)
COMPILE_CXX = $(CXX) $(DIAGNOSTICS_FLAGS) $(CPPFLAGS) $(CXXFLAGS) -c $< -o $@
# FIXME: see above fixme about static pattern rules.
%.o: %.cpp
$(COMPILE_CXX)
# Clean everything imaginable.
.PHONY: clean
clean:
rm -rf $(TRG) $(TRG).map $(DUMPTRG) $(PROGNAME).out $(PROGNAME).out.map
rm -rf $(OBJS)
rm -rf $(LST) $(GDBINITFILE)
rm -rf $(GENASMFILES)
rm -rf $(HEXTRG)
rm -rf *.deps
rm -rf binaries_suid_root_stamp
########## Supporting Targets (Implementation) {{{2
dependency_checks: avrdude_version_check \
avrgcc_check \
avrlibc_check
.PHONY: avrdude_version_check
avrdude_version_check: VERSION_CHECKER := \
perl -ne ' \
m/version (\d+\.\d+(?:\d+))/ and \
($$1 >= 5.10 \
or die "avrdude version 5.10 or later required (found version $$1)"); #'
avrdude_version_check:
avrdude -? 2>&1 | $(VERSION_CHECKER)
.PHONY: avrgcc_check
avrgcc_check:
@which fweg || \
( \
echo -e "\navr-gcc binary '$(CC)' not found\n" 1>&2 ; \
echo -e "Perhaps the CC make variable is set wrong, or perhaps no" ; \
echo -e "AVR GCC cross compiler is installed?\n" \
&& false \
)
.PHONY: avrlibc_check
avrlibc_check:
@echo I do not know offhand a reliable way to check for avrlibc
@echo availability...
# A bunch of stuff only works when suid root, this verifies the permissions.
# We are not trying to use avarice or avr-gdb at the moment, but if we were
# they would probably need this to talk over libusb as well.
binaries_suid_root_stamp: $(shell which $(AVRDUDE)) $(AVARICE) $(AVRGDB)
ls -l $$(which $(AVRDUDE)) | grep --quiet -- '^-rws' || \
( \
echo -e \\nError: $(AVRDUDE) binary is not suid root\\n 1>&2 && \
false )
# ls -l $$(which $(AVARICE)) | grep --quiet -- ' -rws' || \
# ( \
# echo -e \\nError: $(AVARICE) binary is not suid root\\n 1>&2 && \
# false )
# ls -l $$(which $(AVRGDB)) | grep --quiet -- ' -rws' || \
# ( \
# echo -e \\nError: $(AVRGDB) binary is not suid root\\n 1>&2 && \
# false )
touch $@
@echo -e \\ngood the binaries which need to be suid are\\n
# In case the user is confused about quoting.
ifeq ($(DTR_PULSE_NOT_REQUIRED),"true")
$(error "value of DTR_PULSE_NOT_REQUIRED shouldn't have quotes around it.")
endif
ifeq ($(DTR_PULSE_NOT_REQUIRED),'true')
$(error "value of DTR_PULSE_NOT_REQUIRED shouldn't have quotes around it.")
endif
# Arduino Duemilanove and newer allow you to pulse the DTR line to
# trigger a reset, after which the bootloaded takes over so a new sketch
# can be uploaded without having to putsh the reset button on the board.
# In theory. In practice it doesn't always work for me with this code at
# least. And I don't know how it interacts with serial line use exactly.
# One the duemilanove it seems to sort of work, with Uno rev. 3 avrdude
# seems to always fail. In case the user doesn't have the perl module
# we use for this and/or doesn't want to deal with it, they can set the
# DTR_PULSE_NOT_REQUIRED make variable to true.
PROBABLY_PULSE_DTR := perl -e ' \
eval "require Device::SerialPort;" or ( \
($$@ =~ m/^Can.t locate Device\/SerialPort/ or die $$@) and \
("$(DTR_PULSE_NOT_REQUIRED)" eq "true" and exit(0)) or ( \
print \
$$@. \
"\nDevice::SerialPort perl module not found. You will need to set". \
"\nDTR_PULSE_NOT_REQUIRED make variable to \"true\" and manually". \
"\npress the reset button on the arduino immediately after the". \
"\navrdude programming command goes off to successfully program the". \
"\nchip.\n\n" \
and exit(1) ) ); \
my $$port = Device::SerialPort->new("$(ACTUAL_ARDUINO_PORT)") \
or die "Cannot open $(ACTUAL_ARDUINO_PORT): $$!\n"; \
$$port->pulse_dtr_on(100);' || \
[ '$(DTR_PULSE_NOT_REQUIRED)' = true ]
# This target is just for testing out the PROBABLY_PULSE_DTR code.
test_probably_pulse_dtr:
$(PROBABLY_PULSE_DTR) || \
($(PRINT_ARDUINO_DTR_TOGGLE_WEIRDNESS_WARNING) && false) 1>&2
$(TRG): $(OBJS)
$(CC) $(LDFLAGS) -o $(TRG) $^
%.hex: %.out
$(OBJCOPY) -j .text -j .data -O $(HEXFORMAT) $< $@
%.ee.hex: %.out
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 \
-O $(HEXFORMAT) $< $@
# We use a general build-too-much strategy in which targets are considered
# out-of-date if any of these likely prerequisites have changed.
POSSIBLE_PREREQUISITES = $(HEADERS) Makefile generic.mk
# General build-too-much strategy.
$(OBJS): $(POSSIBLE_PREREQUISITES)
# This can be used to get a look at the assembly that will be produced from
# a given .c file. It might sometimes be useful to add -fverbose-asm after
# the -S switch as well, but I find its output noisy and it makes assembly
# files harder to compare.
%.s: %.c $(HEADERS) $(POSSIBLE_PREREQUISITES)
$(CC) -S $(CPPFLAGS) $(CFLAGS) $< -o $@