ソースを参照

Import lab files

DricomDragon 5 年 前
コミット
0aaf3cbd63
39 ファイル変更20913 行追加0 行削除
  1. 37 0
      dev-files/49-teensy.rules
  2. 17 0
      dev-files/archive_directory.py
  3. 29 0
      dev-files/build_all_header_file.py
  4. 58 0
      dev-files/build_base_header_file.py
  5. 22 0
      dev-files/build_grouped_sources.py
  6. 615 0
      dev-files/build_interrupt_handlers.py
  7. 32 0
      dev-files/build_objdump.py
  8. 397 0
      dev-files/code_builder.py
  9. 134 0
      dev-files/common_definitions.py
  10. 51 0
      dev-files/dev_platform.py
  11. 136 0
      dev-files/download_and_install_gccarm.py
  12. 115 0
      dev-files/interrupt_names_teensy_3_6.py
  13. 976 0
      dev-files/makefile.py
  14. 18 0
      dev-files/objdump.py.txt
  15. 169 0
      dev-files/teensy-3-6.ld
  16. 90 0
      dev-files/teensy_cli_loader_builder.py
  17. 1183 0
      dev-files/teensy_loader_cli.c
  18. 23 0
      dev-files/tool_directory.py
  19. 87 0
      dev-files/udev_on_linux.py
  20. 52 0
      dev-files/view-hex.py
  21. 23 0
      steps/-build-all.py
  22. 23 0
      steps/-clean-all.py
  23. 19 0
      steps/01-blink-led/1-build-as.py
  24. 30 0
      steps/01-blink-led/1-build.py
  25. 18 0
      steps/01-blink-led/1-verbose-build.py
  26. 18 0
      steps/01-blink-led/2-flash-via-usb.py
  27. 18 0
      steps/01-blink-led/2-hex-viewer.py
  28. 32 0
      steps/01-blink-led/clean.py
  29. 18 0
      steps/01-blink-led/display-obj-size.py
  30. 6 0
      steps/01-blink-led/makefile.json
  31. 800 0
      steps/01-blink-led/sources/cortex-m4-control-registers.h
  32. 53 0
      steps/01-blink-led/sources/reset-handler-sequential.s
  33. 26 0
      steps/01-blink-led/sources/setup-loop.cpp
  34. 9 0
      steps/01-blink-led/sources/setup-loop.h
  35. 531 0
      steps/01-blink-led/sources/start-teensy-3-6.cpp
  36. 25 0
      steps/01-blink-led/sources/start-teensy-3-6.h
  37. 14732 0
      steps/01-blink-led/sources/teensy-3-6-control-registers.h
  38. 274 0
      steps/01-blink-led/sources/teensy-3-6-interrupt-vectors.s
  39. 17 0
      steps/01-blink-led/sources/unused-interrupt.s

+ 37 - 0
dev-files/49-teensy.rules

@@ -0,0 +1,37 @@
+# UDEV Rules for Teensy boards, http://www.pjrc.com/teensy/
+#
+# The latest version of this file may be found at:
+#   http://www.pjrc.com/teensy/49-teensy.rules
+#
+# This file must be placed at:
+#
+# /etc/udev/rules.d/49-teensy.rules    (preferred location)
+#   or
+# /lib/udev/rules.d/49-teensy.rules    (req'd on some broken systems)
+#
+# To install, type this command in a terminal:
+#   sudo cp 49-teensy.rules /etc/udev/rules.d/49-teensy.rules
+#
+# After this file is installed, physically unplug and reconnect Teensy.
+#
+
+ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", ENV{ID_MM_DEVICE_IGNORE}="1"
+ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", ENV{MTP_NO_PROBE}="1"
+SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", MODE:="0666"
+KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="0478", MODE:="0666"
+
+# If you share your linux system with other users, or just don't like the
+# idea of write permission for everybody, you can replace MODE:="0666" with
+# OWNER:="yourusername" to create the device owned by you, or with
+# GROUP:="somegroupname" and mange access using standard unix groups.
+#
+#
+# If using USB Serial you get a new device each time (Ubuntu 9.10)
+# eg: /dev/ttyACM0, ttyACM1, ttyACM2, ttyACM3, ttyACM4, etc
+#    apt-get remove --purge modemmanager     (reboot may be necessary)
+#
+# Older modem proding (eg, Ubuntu 9.04) caused very slow serial device detection.
+# To fix, add this near top of /lib/udev/rules.d/77-nm-probe-modem-capabilities.rules
+#   SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789]?", GOTO="nm_modem_probe_end" 
+#
+

+ 17 - 0
dev-files/archive_directory.py

@@ -0,0 +1,17 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import os
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def createAndGetArchiveDirectory () :
+  ARCHIVE_DIR = os.path.abspath (os.path.dirname (__file__) + "/../archives")
+  if not os.path.exists (ARCHIVE_DIR):
+    os.mkdir (ARCHIVE_DIR)
+  return ARCHIVE_DIR
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+

+ 29 - 0
dev-files/build_all_header_file.py

@@ -0,0 +1,29 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import sys, os
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+separator = "//" + ("—" * 118) + "\n"
+#------------------------------ Destination file
+destinationFile = sys.argv [1]
+#------------------------------ Dependence file
+dependenceFile = sys.argv [2]
+#------------------------------ Header files
+dependenceString = ""
+s = "#pragma once\n\n"
+s += separator + "\n"
+for i in range (3, len (sys.argv)):
+  s += "#include \"" + os.path.basename (sys.argv [i]) + "\"\n"
+  dependenceString += " :" + sys.argv [i] + "\n\n"
+s += "\n" + separator
+#------------------------------ Write files
+f = open (destinationFile, "wt")
+f.write (s)
+f.close()
+f = open (dependenceFile, "wt")
+f.write (dependenceString)
+f.close()
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 58 - 0
dev-files/build_base_header_file.py

@@ -0,0 +1,58 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import sys, os
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+separator = "//" + ("—" * 118) + "\n"
+#------------------------------ Arg 1 is destination file
+destinationFile = sys.argv [1]
+#------------------------------ Arg 2 is processor frequency (in MHz)
+CPU_MHZ = sys.argv [2]
+#------------------------------ Arg 2 is task count ("*" is no task)
+TASK_COUNT = sys.argv [3]
+#------------------------------ Arg 3 is teensy name
+TEENSY_NAME = sys.argv [4]
+#------------------------------ Header files
+s = "#pragma once\n\n"
+s += separator + "\n"
+s += "#include <stdint.h>\n"
+s += "#include <stdlib.h>\n"
+s += "#include <string.h>\n"
+s += "\n"
+s += separator
+s += "//  TASK COUNT\n"
+s += separator + "\n"
+s += "static const uint32_t TASK_COUNT = " + TASK_COUNT + " ;\n\n"
+s += separator
+s += "//  DEV BOARD\n"
+s += separator + "\n"
+s += "#define " + TEENSY_NAME + "\n"
+s += "\n"
+s += separator
+s += "//  PROCESSOR FREQUENCY\n"
+s += separator + "\n"
+s += "#define CPU_MHZ (" + CPU_MHZ + ")\n\n"
+s += separator
+s += "//  FALLTHROUGH\n"
+s += separator + "\n"
+s += "#if __GNUC__ < 7\n"
+s += "  #define FALLTHROUGH\n"
+s += "#else\n"
+s += "  #define FALLTHROUGH __attribute__ ((fallthrough))\n"
+s += "#endif\n\n"
+s += separator
+s += "//   DIAGNOSTICS\n"
+s += separator + "\n"
+s += "#if __GNUC__ > 5\n"
+s += "  #pragma GCC diagnostic error \"-Wduplicated-branches\"\n"
+s += "  #pragma GCC diagnostic error \"-Wmisleading-indentation\"\n"
+s += "#endif\n\n"
+s += separator
+#------------------------------ Write destination file
+f = open (destinationFile, "wt")
+f.write (s)
+f.close()
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 22 - 0
dev-files/build_grouped_sources.py

@@ -0,0 +1,22 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+import sys, os
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+separator = "//" + ("—" * 118) + "\n"
+#------------------------------ Destination file
+destinationFile = sys.argv [1]
+# print ("Dest " + destinationFile)
+#------------------------------ Header files
+s = separator + "\n"
+for i in range (2, len (sys.argv)):
+  s += "#include \"" + sys.argv [i] + "\"\n"
+s += "\n" + separator
+#------------------------------ Write destination file
+f = open (destinationFile, "wt")
+f.write (s)
+f.close()
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 615 - 0
dev-files/build_interrupt_handlers.py

@@ -0,0 +1,615 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+import sys, interrupt_names_teensy_3_6
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def ENDC () :
+  return '\033[0m'
+
+#······················································································································*
+
+def RED () :
+  return '\033[91m'
+
+#······················································································································*
+
+def BOLD () :
+  return '\033[1m'
+
+#······················································································································*
+
+def BOLD_RED () :
+  return BOLD () + RED ()
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def asSeparator () :
+  return "@" + ("-" * 119) + "\n"
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def cppSeparator () :
+  return "//" + ("-" * 118) + "\n"
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateSVChandler ():
+  sFile = asSeparator ()
+  sFile += "@                 S V C    H A N D L E R    ( D O U B L E    S T A C K    M O D E )\n"
+  sFile += asSeparator ()
+  sFile += "@\n"
+  sFile += "@          PSP+32 -> |                            |\n"
+  sFile += "@                    |----------------------------| \\\n"
+  sFile += "@          PSP+28 -> | xPSR                       |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+24 -> | PC (after SVC instruction) |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+20 -> | LR                         |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+16 -> | R12                        |  |  Saved by interrupt response\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+12 -> | R3                         |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+8  -> | R2                         |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@          PSP+4  -> | R1                         |  |\n"
+  sFile += "@                    |----------------------------|  |\n"
+  sFile += "@     /--- PSP ----> | R0                         |  |\n"
+  sFile += "@     |              |----------------------------| /\n"
+  sFile += "@     |              |                            |\n"
+  sFile += "@     |\n"
+  sFile += "@     |                                          *---------------------*\n"
+  sFile += "@     |                                          | LR return code      | +36 [ 9]\n"
+  sFile += "@     |                                          *---------------------*\n"
+  sFile += "@     \----------------------------------------- | R13 (PSP)           | +32 [ 8]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R11                 | +28 [ 7]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R10                 | +24 [ 6]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R9                  | +20 [ 5]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R8                  | +16 [ 4]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R7                  | +12 [ 3]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R6                  | + 8 [ 2]\n"
+  sFile += "@                                                *---------------------*\n"
+  sFile += "@                                                | R5                  | + 4 [ 1]\n"
+  sFile += "@  *------------------------------------*        *---------------------*\n"
+  sFile += "@  | var.running.task.control.block.ptr +------> | R4                  | + 0 [ 0]\n"
+  sFile += "@  *------------------------------------*        *---------------------*\n"
+  sFile += "@\n"
+  sFile += asSeparator () + "\n"
+  sFile += "	.section	.bss.var.background.task.context, \"aw\", %nobits\n"
+  sFile += "  .align	  2\n\n"
+  sFile += "var.background.task.context:\n"
+  sFile += "  .space  4\n\n"
+  sFile += asSeparator () + "\n"
+  sFile += "	.section	.text.interrupt.SVC, \"ax\", %progbits\n\n"
+  sFile += "  .global interrupt.SVC\n"
+  sFile += "  .type interrupt.SVC, %function\n\n"
+  sFile += "interrupt.SVC:\n"
+  sFile += "@----------------------------------------- Save preserved registers\n"
+  sFile += "  push  {r4, lr}\n"
+  sFile += "@----------------------------------------- R4 <- thread SP\n"
+  sFile += "  mrs   r4, psp\n"
+  sFile += "@----------------------------------------- Restore R0, R1, R2 and R3 from saved stack\n"
+  sFile += "  ldmia r4!, {r0, r1, r2, r3}       @ R4 incremented by 16\n"
+  sFile += "@----------------------------------------- R4 <- Address of SVC instruction\n"
+  sFile += "  ldr   r4, [r4, #8]                @ 8 : 2 stacked registers before saved PC\n"
+  sFile += "@----------------------------------------- R12 <- bits 0-7 of SVC instruction\n"
+  sFile += "  ldrb  r12, [r4, #-2]              @ R12 is service call index\n"
+  sFile += "@----------------------------------------- R4 <- address of dispatcher table\n"
+  sFile += "  ldr   r4, =svc.dispatcher.table\n"
+  sFile += "@----------------------------------------- R12 <- address of routine to call\n"
+  sFile += "  ldr   r12, [r4, r12, lsl #2]      @ R12 = R4 + (R12 << 2)\n"
+  sFile += "@----------------------------------------- R4 <- calling task context\n"
+  sFile += "  ldr   r4, =var.running.task.control.block.ptr\n"
+  sFile += "  ldr   r4, [r4]\n"
+  sFile += "@----------------------------------------- Call service routine\n"
+  sFile += "  blx   r12                         @ R4:calling task context address\n"
+  sFile += "@--- Continues in sequence to handle.context.switch\n\n"
+  sFile += asSeparator ()
+  sFile += "@\n"
+  sFile += "@                 H A N D L E    C O N T E X T    S W I T C H    ( D O U B L E    S T A C K    M O D E )\n"
+  sFile += "@\n"
+  sFile += "@  On entry:\n"
+  sFile += "@    - R4 contains the runnning task save context address,\n"
+  sFile += "@    - R4 and LR of running task have been pushed on handler stack.\n"
+  sFile += "@\n"
+  sFile += asSeparator () + "\n"
+  sFile += "handle.context.switch:\n"
+  sFile += "@----------------------------------------- Select task to run\n"
+  sFile += "  bl    kernel.select.task.to.run\n"
+  sFile += "@----------------------------------------- R0 <- calling task context, R1 <- new task context\n"
+  sFile += "  ldr   r1, =var.running.task.control.block.ptr\n"
+  sFile += "  mov   r0, r4\n"
+  sFile += "  ldr   r1, [r1]\n"
+  sFile += "@----------------------------------------- Restore preserved registers\n"
+  sFile += "  pop   {r4, lr}\n"
+  sFile += "@----------------------------------------- Running task did change ?\n"
+  sFile += "  cmp   r0, r1  @ R0:calling task context, R1:new task context\n"
+  sFile += "  bne   running.state.did.change\n"
+  sFile += "  bx    lr  @ No change\n"
+  sFile += "@----------------------------------------- Save context of preempted task\n"
+  sFile += "running.state.did.change:\n"
+  sFile += "  mrs   r12, psp\n"
+  sFile += "  cbz   r0, save.background.task.context\n"
+  sFile += "@--- Save registers r4 to r11, PSP (stored in R12), LR\n"
+  sFile += "  stmia r0, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+  sFile += "  b     perform.restore.context\n"
+  sFile += "save.background.task.context:\n"
+  sFile += "  ldr   r2, =var.background.task.context\n"
+  sFile += "  str   r12, [r2]\n"
+  sFile += "@----------------------------------------- Restore context of activated task\n"
+  sFile += "perform.restore.context:\n"
+  sFile += "  cbz   r1, restore.background.task.context\n"
+  sFile += "  ldmia r1, {r4, r5, r6, r7, r8, r9, r10, r11, r12, lr}\n"
+  sFile += "  msr   psp, r12\n"
+  sFile += "  bx    lr\n"
+  sFile += "@----------------------------------------- Restore background task context\n"
+  sFile += "restore.background.task.context:\n"
+  sFile += "  ldr   r2, =var.background.task.context\n"
+  sFile += "  ldr   r2, [r2]\n"
+  sFile += "  msr   psp, r2\n"
+  sFile += "  bx    lr\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateBreakpointHandler () :
+  sFile = asSeparator ()
+  sFile += "@\n"
+  sFile += "@                 B K P T    H A N D L E R    ( D O U B L E    S T A C K    M O D E )\n"
+  sFile += "@\n"
+  sFile += asSeparator ()
+  sFile += "@\n"
+  sFile += "@                    |                            |\n"
+  sFile += "@          PSP+32 -> |----------------------------| \\\n"
+  sFile += "@                    | xPSR                       |  |\n"
+  sFile += "@          PSP+28 -> |----------------------------|  |\n"
+  sFile += "@                    | PC (BKPT instruction)      |  |\n"
+  sFile += "@          PSP+24 -> |----------------------------|  |\n"
+  sFile += "@                    | LR                         |  |\n"
+  sFile += "@          PSP+20 -> |----------------------------|  |\n"
+  sFile += "@                    | R12                        |  |  Saved by interrupt response\n"
+  sFile += "@          PSP+16 -> |----------------------------|  |\n"
+  sFile += "@                    | R3                         |  |\n"
+  sFile += "@          PSP+12 -> |----------------------------|  |\n"
+  sFile += "@                    | R2                         |  |\n"
+  sFile += "@          PSP+8  -> |----------------------------|  |\n"
+  sFile += "@                    | R1                         |  |\n"
+  sFile += "@          PSP+4  -> |----------------------------|  |\n"
+  sFile += "@                    | R0                         |  |\n"
+  sFile += "@          PSP    -> |----------------------------| /\n"
+  sFile += "@\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section  .text.interrupt.DebugMonitor, \"ax\", %progbits\n\n"
+  sFile += "  .global interrupt.DebugMonitor\n"
+  sFile += "  .type interrupt.DebugMonitor, %function\n\n"
+  sFile += "interrupt.DebugMonitor:\n"
+  sFile += "@--------------------- Save preserved registers\n"
+  sFile += "  push  {r5, lr}\n"
+  sFile += "@--------------------- R5 <- thread SP\n"
+  sFile += "  mrs   r5, psp\n"
+  sFile += "  ldmia r5, {r0, r1, r2, r3}\n"
+  sFile += "@--------------------- LR <- Address of BKPT instruction\n"
+  sFile += "  ldr   lr, [r5, #24]     @ 24 : 6 stacked registers before saved PC\n"
+  sFile += "@--------------------- Set return address to instruction following BKPT\n"
+  sFile += "@  adds  lr, #2\n"
+  sFile += "@  str   lr, [r5, #24]\n"
+  sFile += "@--------------------- R12 <- address of dispatcher\n"
+  sFile += "  ldr   r12, =section.dispatcher.table\n"
+  sFile += "@--------------------- LR <- bits 0-7 of BKPT instruction\n"
+  sFile += "  ldrb  lr, [lr, #-2]            @ LR is service call index\n"
+  sFile += "@--------------------- r12 <- address of routine to call\n"
+  sFile += "  ldr   r12, [r12, lr, lsl #2]   @ R12 = [R12 + LR * 4]\n"
+  sFile += "@--------------------- Call service routine\n"
+  sFile += "  blx   r12\n"
+  sFile += "@--------------------- Set return code (from R0 to R3) in stacked registers\n"
+  sFile += "  stmia r5!, {r0, r1, r2, r3}\n"
+  sFile += "@--------------------- Restore preserved registers, return from interrupt\n"
+  sFile += "  pop   {r5, pc}\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateBreakpointSection (sectionName, idx):
+  sFile  = asSeparator () + "\n"
+  sFile += "  .section .text." + section + ", \"ax\", %progbits\n"
+  sFile += "  .global " + section +"\n"
+  sFile += "  .align 1\n"
+  sFile += "  .type " + section +", %function\n\n"
+  sFile += section +":\n"
+  sFile += "  .fnstart\n"
+  sFile += "  mrs  r12, IPSR @ r12 <- 0x??????00 in thread mode, 0x??????nn, nn ≠ 0 in handler mode\n"
+  sFile += "  ands r12, #255\n"
+  sFile += "  bne  section." + section + " @ in handler mode, call implementation routine directly\n"
+  sFile += "  bkpt #" + str (idx) + "\n"
+  sFile += "  bx   lr\n\n"
+  sFile += ".Lfunc_end_" + section +":\n"
+  sFile += "  .size " + section +", .Lfunc_end_" + section +" - " + section +"\n"
+  sFile += "  .cantunwind\n"
+  sFile += "  .fnend\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateSoftwareInterruptandler () :
+  sFile = asSeparator ()
+  sFile += "@\n"
+  sFile += "@     SECTIONS: Software Interrupt Handler (two stack mode)\n"
+  sFile += "@\n"
+  sFile += asSeparator ()
+  sFile += "@\n"
+  sFile += "@                    |                            |\n"
+  sFile += "@          PSP+32 -> |----------------------------| \\\n"
+  sFile += "@                    | xPSR                       |  |\n"
+  sFile += "@          PSP+28 -> |----------------------------|  |\n"
+  sFile += "@                    | PC                         |  |\n"
+  sFile += "@          PSP+24 -> |----------------------------|  |\n"
+  sFile += "@                    | LR                         |  |\n"
+  sFile += "@          PSP+20 -> |----------------------------|  |\n"
+  sFile += "@                    | R12                        |  |  Saved by interrupt response\n"
+  sFile += "@          PSP+16 -> |----------------------------|  |\n"
+  sFile += "@                    | R3                         |  |\n"
+  sFile += "@          PSP+12 -> |----------------------------|  |\n"
+  sFile += "@                    | R2                         |  |\n"
+  sFile += "@          PSP+8  -> |----------------------------|  |\n"
+  sFile += "@                    | R1                         |  |\n"
+  sFile += "@          PSP+4  -> |----------------------------|  |\n"
+  sFile += "@                    | R0                         |  |\n"
+  sFile += "@          PSP    -> |----------------------------| /\n"
+  sFile += "@\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section  .text.interrupt.SWINT, \"ax\", %progbits\n\n"
+  sFile += "  .global interrupt.SWINT\n"
+  sFile += "  .type interrupt.SWINT, %function\n\n"
+  sFile += "interrupt.SWINT:\n"
+  sFile += "@--------------------- Save preserved registers\n"
+  sFile += "  push  {r5, lr}\n"
+  sFile += "@--------------------- R5 <- thread SP\n"
+  sFile += "  mrs   r5, psp\n"
+  sFile += "@--------------------- Restore R0, R1, R2 and R3 from saved stack\n"
+  sFile += "  ldmia r5, {r0, r1, r2, r3}\n"
+  sFile += "@--------------------- R12 <- Address section routine\n"
+  sFile += "  ldr   r12, [r5, #16]     @ 16 : 4 stacked registers before saved R12\n"
+  sFile += "@--------------------- Call section routine\n"
+  sFile += "  blx   r12\n"
+  sFile += "@--------------------- Set return code (from R0 to R3) in stacked registers\n"
+  sFile += "  stmia r5!, {r0, r1, r2, r3}    @ R5 is thread SP\n"
+  sFile += "@--------------------- Set R12 stacked register to 0\n"
+  sFile += "  mov   r0, #0\n"
+  sFile += "  str   r0, [r5]\n"
+  sFile += "@--------------------- Restore preserved registers, return from interrupt\n"
+  sFile += "  pop   {r5, pc}\n\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section  .text.direct.call.or.call.software.interrupt, \"ax\", %progbits\n\n"
+  sFile += "  .type direct.call.or.call.software.interrupt, %function\n\n"
+  sFile += "direct.call.or.call.software.interrupt: @ R12 contains the address of section implementation function\n"
+  sFile += "@--------------------- Save preserved registers\n"
+  sFile += "  push {r6, r7}\n"
+  sFile += "  mrs  r6, IPSR          @ IPSR[8...0] ≠ 0 in handler mode, = 0 in thread mode\n"
+  sFile += "  mov  r7, #511\n"
+  sFile += "  tst  r6, r7\n"
+  sFile += "  bne  direct.call\n"
+  sFile += "@--------------------- Software interrupt\n"
+  sFile += "  ldr  r6, = 0xE000EF00  @ Address of STIR control register\n"
+  sFile += "  movs r7, # (80 - 16)   @ Software Interrupt has number #80\n"
+  sFile += "  str  r7, [r6]          @ Generate Software Interrupt\n"
+  sFile += "@--------------------- Wait for the exception is carried out\n"
+  sFile += "wait.software.interrupt.done: @ R12 is reset by interrupt handler\n"
+  sFile += "  cmp  r12, #0\n"
+  sFile += "  bne  wait.software.interrupt.done\n"
+  sFile += "@--------------------- Restore preserved registers\n"
+  sFile += "  pop  {r6, r7}\n"
+  sFile += "  bx   lr\n"
+  sFile += "@--------------------- Direct call\n"
+  sFile += "direct.call:\n"
+  sFile += "  pop  {r6, r7}\n"
+  sFile += "  bx   r12              @ in handler mode, call implementation routine directly\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateSoftwareInterruptSection (sectionName, idx):
+  sFile  = asSeparator () + "\n"
+  sFile += "  .section .text." + sectionName + ", \"ax\", %progbits\n"
+  sFile += "  .global " + sectionName +"\n"
+  sFile += "  .align 1\n"
+  sFile += "  .type " + sectionName +", %function\n\n"
+  sFile += sectionName +":\n"
+  sFile += "  .fnstart\n"
+  sFile += "  ldr  r12, =section." + sectionName + "\n"
+  sFile += "  b    direct.call.or.call.software.interrupt\n\n"
+  sFile += ".Lfunc_end_" + sectionName +":\n"
+  sFile += "  .size " + sectionName +", .Lfunc_end_" + sectionName +" - " + sectionName +"\n"
+  sFile += "  .cantunwind\n"
+  sFile += "  .fnend\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateCppForBreakpointSection ():
+  s = "#include \"all-headers.h\"\n\n"
+  s += cppSeparator () + "\n"
+  s += "static void enableDebugMonitorInterruption (BOOT_MODE) {\n"
+  s += "//--- Enable DebugMonitor interrupt\n"
+  s += "  #define DEMCR (* ((volatile uint32_t *) 0xE000EDFC))\n"
+  s += "  DEMCR |= (1 << 16) ; // Set MON_EN\n"
+  s += "}\n\n"
+  s += cppSeparator () + "\n"
+  s += "MACRO_BOOT_ROUTINE (enableDebugMonitorInterruption) ;\n\n"
+  s += cppSeparator ()
+  return s
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateCppForSoftwareInterruptSection ():
+  s = "#include \"all-headers.h\"\n\n"
+  s += cppSeparator () + "\n"
+  s += "static void enableSoftwareInterrupt (BOOT_MODE) {\n"
+  s += "//--- Enable software interrupt\n"
+  s += "  NVIC_ENABLE_IRQ (ISRSlot::SWINT) ;\n"
+  s += "//--- Make STIR register accessible in unprivileged mode\n"
+  s += "  #define CCR (* ((volatile uint32_t *) 0xE000ED14))\n"
+  s += "  CCR |= (1 << 1) ;\n"
+  s += "}\n\n"
+  s += cppSeparator () + "\n"
+  s += "MACRO_BOOT_ROUTINE (enableSoftwareInterrupt) ;\n\n"
+  s += cppSeparator ()
+  return s
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def generateDisableInterruptSection (sectionName):
+  sFile  = asSeparator ()
+  sFile += "@   SECTION - " + sectionName + "\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section .text." + sectionName + ", \"ax\", %progbits\n"
+  sFile += "  .global " + sectionName +"\n"
+  sFile += "  .align 1\n"
+  sFile += "  .type " + sectionName +", %function\n\n"
+  sFile += sectionName +":\n"
+  sFile += "  .fnstart\n"
+  sFile += "@--- Save preserved registers\n"
+  sFile += "  push  {r6, lr}\n"
+  sFile += "@--- Save interrupt enabled state\n"
+  sFile += "  mrs   r6, PRIMASK\n"
+  sFile += "@--- Disable interrupt\n"
+  sFile += "  cpsid i\n"
+  sFile += "@--- Call section, interrupts disabled\n"
+  sFile += "  bl    section." + sectionName + "\n"
+  sFile += "@--- Restore interrupt state\n"
+  sFile += "  msr   PRIMASK, r6\n"
+  sFile += "@--- Restore preserved registers and return\n"
+  sFile += "  pop   {r6, pc}\n\n"
+  sFile += ".Lfunc_end_" + sectionName +":\n"
+  sFile += "  .size " + sectionName +", .Lfunc_end_" + sectionName +" - " + sectionName +"\n"
+  sFile += "  .cantunwind\n"
+  sFile += "  .fnend\n\n"
+  return sFile
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+#    ENTRY POINT
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#------------------------------ Interrupt dictionary
+interruptDictionary = interrupt_names_teensy_3_6.interruptNames ()
+# print "Dest " + destinationFile
+#------------------------------ Assembly destination file
+destinationCppFile = sys.argv [1]
+# print "Dest " + destinationAssemblerFile
+#------------------------------ Assembly destination file
+destinationAssemblerFile = sys.argv [2]
+# print "Dest " + destinationAssemblerFile
+#------------------------------ Service scheme
+serviceScheme = sys.argv [3]
+#------------------------------ Section scheme
+sectionScheme = sys.argv [4]
+#------------------------------ Header files
+headerFiles = []
+for i in range (5, len (sys.argv)):
+  headerFiles.append (sys.argv [i])
+#print headerFiles
+#------------------------------ Destination file string
+cppFile = ""
+sFile  = "  .syntax unified\n"
+sFile += "  .cpu cortex-m4\n"
+sFile += "  .thumb\n\n"
+#------------------------------ Explore header files
+interruptServiceList = []
+interruptSectionList = []
+boolServiceSet = set ()
+serviceList = []
+sectionList = []
+for header in headerFiles:
+  with open (header) as f:
+    for line in f:
+      splitStr = line.strip ().split ("//$interrupt-section ")
+      if len (splitStr) == 2 :
+        interruptName = splitStr [1].strip ()
+        if interruptName in interruptDictionary :
+          interruptSectionList.append (interruptName)
+          del interruptDictionary [interruptName]
+        else:
+          print (BOLD_RED () + "Error, interrupt '" + interruptName + "' does not exist, or is already assigned." + ENDC ())
+          sys.exit (1)
+      splitStr = line.strip ().split ("//$interrupt-service ")
+      if len (splitStr) == 2 :
+        interruptName = splitStr [1].strip ()
+        if interruptName in interruptDictionary :
+          interruptServiceList.append (interruptName)
+          del interruptDictionary [interruptName]
+        else:
+          print (BOLD_RED () + "Error, interrupt '" + interruptName + "' does not exist, or is already assigned." + ENDC ())
+          sys.exit (1)
+      splitStr = line.strip ().split ("//$service ")
+      if len (splitStr) == 2 :
+        serviceName = splitStr [1].strip ()
+        serviceList.append (serviceName)
+      splitStr = line.strip ().split ("//$bool-service ")
+      if len (splitStr) == 2 :
+        serviceName = splitStr [1].strip ()
+        serviceList.append (serviceName)
+        boolServiceSet.add (serviceName)
+      splitStr = line.strip ().split ("//$section ")
+      if len (splitStr) == 2 :
+        sectionName = splitStr [1].strip ()
+        sectionList.append (sectionName)
+#------------------------------ Has service ?
+if (len (serviceList) > 0) and (serviceScheme == "") :
+  print (BOLD_RED ()
+         + "As the project defines service(s), the makefile.json file should have a \"SERVICE-SCHEME\" "
+         + "entry (asoociated value: \"svc\")"
+         +  ENDC ())
+  sys.exit (1)
+#------------------------------ Has sections ?
+if (len (sectionList) > 0) and (sectionScheme == "") :
+  print (BOLD_RED ()
+         + "As the project defines section(s), the makefile.json file should have a \"SECTION-SCHEME\" "
+         + "entry (possible associated value: \"disableInterrupt\", \"bkpt\", \"swint\")"
+         +  ENDC ())
+  sys.exit (1)
+#------------------------------ Services
+if serviceScheme == "svc" :
+  sFile += generateSVChandler ()
+  del interruptDictionary ["SVC"]
+  sFile += asSeparator ()
+  sFile += "@   SERVICES\n"
+  idx = 1
+  for service in serviceList :
+    sFile += asSeparator () + "\n"
+    sFile += "  .section .text." + service + ", \"ax\", %progbits\n"
+    sFile += "  .global " + service +"\n"
+    sFile += "  .align 1\n"
+    sFile += "  .type " + service +", %function\n\n"
+    sFile += service +":\n"
+    sFile += "  .fnstart\n"
+    sFile += "  svc #" + str (idx) + "\n"
+    if service in boolServiceSet :
+      sFile += "  b   get.user.result\n\n"
+    else:
+      sFile += "  bx  lr\n\n"
+    sFile += ".Lfunc_end_" + service +":\n"
+    sFile += "  .size " + service +", .Lfunc_end_" + service +" - " + service +"\n"
+    sFile += "  .cantunwind\n"
+    sFile += "  .fnend\n\n"
+    idx += 1
+  sFile += asSeparator ()
+  sFile += "@    SERVICE DISPATCHER TABLE\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .align   2\n"
+  sFile += "  .global  svc.dispatcher.table\n\n"
+  sFile += "svc.dispatcher.table:\n"
+  sFile += "  .word start.phase2 @ 0\n"
+  idx = 1
+  for service in serviceList :
+    sFile += "  .word service." + service + " @ " + str (idx) + "\n"
+    idx += 1
+  sFile += "\n"
+#------------------------------ Generate section handler
+if sectionScheme == "bkpt" :
+  cppFile += generateCppForBreakpointSection ()
+  sFile += generateBreakpointHandler ()
+  del interruptDictionary ["DebugMonitor"]
+  sFile += asSeparator ()
+  sFile += "@   SECTIONS\n"
+  idx = 0
+  for section in sectionList :
+    sFile += generateBreakpointSection (section, idx)
+    idx += 1
+  sFile += asSeparator ()
+  sFile += "@    SECTION DISPATCHER TABLE\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .global section.dispatcher.table\n\n"
+  sFile += "section.dispatcher.table:\n"
+  idx = 0
+  for section in sectionList :
+    sFile += "  .word section." + section + " @ " + str (idx) + "\n"
+    idx += 1
+  sFile += "\n"
+elif sectionScheme == "swint" :
+  cppFile += generateCppForSoftwareInterruptSection ()
+  sFile += generateSoftwareInterruptandler ()
+  del interruptDictionary ["SWINT"]
+  sFile += asSeparator ()
+  sFile += "@   SECTIONS\n"
+  idx = 0
+  for section in sectionList :
+    sFile += generateSoftwareInterruptSection (section, idx)
+    idx += 1
+elif sectionScheme == "disableInterrupt" :
+  for section in sectionList :
+    sFile += generateDisableInterruptSection (section)
+elif len (sectionList) > 0 :
+  print (BOLD_RED ()
+         + "In the makefile.json file, the \"SECTION-SCHEME\" key has an invalid \"" + sectionScheme + "\" value; "
+         + "(possible value: \"disableInterrupt\", \"bkpt\", \"swint\")"
+         +  ENDC ())
+  sys.exit (1)
+#------------------------------ Interrupts as service
+for interruptServiceName in interruptServiceList :
+  sFile += asSeparator ()
+  sFile += "@   INTERRUPT - SERVICE: " + interruptServiceName + "\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section .text.interrupt." + interruptServiceName + ", \"ax\", %progbits\n\n"
+  sFile += "  .align  1\n"
+  sFile += "  .global interrupt." + interruptServiceName + "\n"
+  sFile += "  .type interrupt." + interruptServiceName + ", %function\n\n"
+  sFile += "interrupt." + interruptServiceName + ":\n"
+  sFile += "@----------------------------------------- Save preserved registers\n"
+  sFile += "  push  {r4, lr}\n"
+  sFile += "@----------------------------------------- Activity led On\n"
+  sFile += "  ldr   r0, =0x400FF084  @ Address of GPIOC_PSOR control register\n"
+  sFile += "  movs  r1, # (1 << 5)   @ Port D13 is PORTC:5\n"
+  sFile += "  str   r1, [r0]         @ turn on\n"
+  sFile += "@----------------------------------------- R4 <- running task context\n"
+  sFile += "  ldr   r4, =var.running.task.control.block.ptr\n"
+  sFile += "  ldr   r4, [r4]\n"
+  sFile += "@----------------------------------------- Call Interrupt handler\n"
+  sFile += "  bl    interrupt.service." + interruptServiceName + "\n"
+  sFile += "@----------------------------------------- Perform the context switch, if needed\n"
+  sFile += "  b     handle.context.switch\n\n"
+#------------------------------ Interrupts as section
+for interruptSectionName in interruptSectionList :
+  sFile += asSeparator ()
+  sFile += "@   INTERRUPT - SECTION: " + interruptSectionName + "\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section .text.interrupt." + interruptSectionName + ", \"ax\", %progbits\n\n"
+  sFile += "  .align  1\n"
+  sFile += "  .global interrupt." + interruptSectionName + "\n"
+  sFile += "  .type interrupt." + interruptSectionName + ", %function\n\n"
+  sFile += "interrupt." + interruptSectionName + ":\n"
+  sFile += "@----------------------------------------- Activity led On\n"
+  sFile += "  ldr   r0, =0x400FF084  @ Address of GPIOC_PSOR control register\n"
+  sFile += "  movs  r1, # (1 << 5)   @ Port D13 is PORTC:5\n"
+  sFile += "  str   r1, [r0]         @ turn on\n"
+  sFile += "@----------------------------------------- Goto interrupt function\n"
+  sFile += "  b     interrupt.section." + interruptSectionName + "\n\n"
+#------------------------------ Unused interrupts
+for unusedInterruptName in interruptDictionary.keys () :
+  sFile += asSeparator ()
+  sFile += "@   INTERRUPT - UNUSED: " + unusedInterruptName + "\n"
+  sFile += asSeparator () + "\n"
+  sFile += "  .section .text.interrupt." + unusedInterruptName + ", \"ax\", %progbits\n\n"
+  sFile += "  .align  1\n"
+  sFile += "  .type interrupt." + unusedInterruptName + ", %function\n"
+  sFile += "  .global interrupt." + unusedInterruptName + "\n\n"
+  sFile += "interrupt." + unusedInterruptName + ":\n"
+  sFile += "  movs r0, #" + str (interruptDictionary [unusedInterruptName]) + "\n"
+  sFile += "  b    unused.interrupt\n\n"
+#------------------------------ Write destination file
+sFile += asSeparator ()
+f = open (destinationAssemblerFile, "wt")
+f.write (sFile)
+f.close()
+f = open (destinationCppFile, "wt")
+f.write (cppFile)
+f.close()
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 32 - 0
dev-files/build_objdump.py

@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+import sys, os, stat
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+#    ENTRY POINT
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#------------------------------ objdump tool
+OBJDUMP_TOOL = sys.argv [1]
+#------------------------------ Source file
+SOURCE_NAME = sys.argv [2]
+#------------------------------ Destination file
+PYTHON_FILE_NAME = sys.argv [3]
+#------------------------------ script dir
+scriptDir = os.path.dirname (os.path.abspath (__file__))
+#------------------------------ Script source
+f = open (scriptDir + "/objdump.py.txt", "rt")
+s = f.read ()
+f.close()
+#------------------------------ Perform substitutions
+s = s.replace ("$OBJDUMP$", OBJDUMP_TOOL)
+s = s.replace ("$SOURCE$", SOURCE_NAME)
+#------------------------------ Destination file write
+f = open (PYTHON_FILE_NAME, "wt")
+f.write (s)
+f.close()
+os.chmod (PYTHON_FILE_NAME, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 397 - 0
dev-files/code_builder.py

@@ -0,0 +1,397 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import sys, os, subprocess, shutil, json
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import makefile
+import common_definitions
+import download_and_install_gccarm
+import teensy_cli_loader_builder
+import dev_platform
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   Run process and wait for termination                                                                               *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runProcess (command) :
+  returncode = subprocess.call (command)
+  if returncode != 0 :
+    print (makefile.BOLD_RED () + "Error " + str (returncode) + makefile.ENDC ())
+    sys.exit (returncode)
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   Run process, get output and wait for termination                                                                   *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runProcessAndGetOutput (command) :
+  result = ""
+  childProcess = subprocess.Popen (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+  while True:
+    out = childProcess.stdout.read(1)
+    if out == '' and childProcess.poll() != None:
+      break
+    if out != '':
+      result += out
+#--- Wait for subprocess termination
+  if childProcess.poll () == None :
+    childProcess.wait ()
+  if childProcess.returncode != 0 :
+    print (makefile.BOLD_RED () + "Error " + str (childProcess.returncode) + makefile.ENDC ())
+    sys.exit (childProcess.returncode)
+  return result
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   dictionaryFromJsonFile                                                                                             *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def dictionaryFromJsonFile (file) :
+  result = {}
+  if not os.path.exists (os.path.abspath (file)):
+    print (makefile.BOLD_RED () + "The '" + file + "' file does not exist" + makefile.ENDC ())
+    sys.exit (1)
+  try:
+    f = open (file, "r")
+    result = json.loads (f.read ())
+    f.close ()
+  except:
+    print (makefile.BOLD_RED () + "Syntax error in " + file + makefile.ENDC ())
+    sys.exit (1)
+  return result
+
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   buildCode                                                                                                          *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def buildCode (GOAL, projectDir, maxConcurrentJobs, showCommand):
+#--------------------------------------------------------------------------- Prepare
+  os.chdir (projectDir)
+  make = makefile.Make (GOAL)
+  make.mMacTextEditor = "TextWrangler" # "Atom"
+  allGoal = []
+#--------------------------------------------------------------------------- Install Linux UDEV rules ?
+  platform = dev_platform.getPlatform ()
+  if (platform == "linux") or (platform == "linux32") :
+    import udev_on_linux
+    udev_on_linux.installUDEVrulesOnLinux ()
+#--------------------------------------------------------------------------- Install compiler ?
+  BASE_NAME = "arm-none-eabi"
+  TOOL_DIR = download_and_install_gccarm.installGCCARMandGetToolDirectory ()
+  AS_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-as", "-mthumb", "-mcpu=cortex-m4"]
+  COMPILER_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-gcc", "-mthumb", "-mcpu=cortex-m4"]
+  LD_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-ld"]
+  LD_TOOL_WITH_OPTIONS = COMPILER_TOOL_WITH_OPTIONS
+  OBJCOPY_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-objcopy"]
+  DISPLAY_OBJ_SIZE_TOOL = [TOOL_DIR + "/bin/" + BASE_NAME + "-size"]
+  OBJDUMP_TOOL = TOOL_DIR + "/bin/" + BASE_NAME + "-objdump"
+#--------------------------------------------------------------------------- Install Teensy loader CLI ?
+  TEENSY_CLI_LOADER_PATH = teensy_cli_loader_builder.buildAndGetPath (TOOL_DIR + "/bin")
+#--------------------------------------------------------------------------- Analyze JSON file
+  print (makefile.BOLD_GREEN () + "--- Making " + projectDir + makefile.ENDC ())
+  dictionaire = dictionaryFromJsonFile (projectDir + "/makefile.json")
+#--- TEENSY
+  linkerScript = ""
+  teensyName = ""
+  if dictionaire.has_key ("TEENSY") :
+    TeensyKey = dictionaire ["TEENSY"]
+    if (TeensyKey == "3.1") or (TeensyKey == "3.2") :
+      teensyName = "TEENSY31"
+      linkerScript = "teensy-3-1.ld"
+    elif (TeensyKey == "3.5") :
+      teensyName = "TEENSY35"
+      linkerScript = "teensy-3-5.ld"
+    elif (TeensyKey == "3.6") :
+      teensyName = "TEENSY36"
+      linkerScript = "teensy-3-6.ld"
+    else:
+      make.enterError ('In the makefile.json file, the "TEENSY" key value is invalid (possible values: "3.1", "3.2", "3.5" or "3.6").')
+  else:
+    make.enterError ('The makefile.json file does not have a "TEENSY" key (possible values: "3.1", "3.2", "3.5" or "3.6").')
+#--- ASSERTION_GENERATION
+  ASSERTION_GENERATION = False
+  if dictionaire.has_key ("ASSERTION-GENERATION") and dictionaire ["ASSERTION-GENERATION"] :
+    ASSERTION_GENERATION = True
+#--- CPU_MHZ
+  CPU_MHZ = 0
+  if dictionaire.has_key ("CPU-MHZ") :
+    CPU_MHZ = dictionaire ["CPU-MHZ"]
+#--- SOURCE_FILE_DIRECTORIES
+  SOURCE_FILE_DIRECTORIES = []
+  if dictionaire.has_key ("SOURCE-DIR") :
+    SOURCE_FILE_DIRECTORIES = dictionaire ["SOURCE-DIR"]
+#--- GROUP_SOURCES
+  GROUP_SOURCES = False
+  if dictionaire.has_key ("GROUP-SOURCES") :
+    GROUP_SOURCES = dictionaire ["GROUP-SOURCES"]
+#--- TASK_COUNT
+  TASK_COUNT = "0" # Means TASK_COUNT is not defined by JSON file
+  if dictionaire.has_key ("TASK-COUNT") :
+    TASK_COUNT = str (dictionaire ["TASK-COUNT"])
+#--- LTO
+  usesLTO = False
+  if dictionaire.has_key ("LTO") and dictionaire ["LTO"] :
+    usesLTO = True
+#--- SERVICE
+  serviceScheme = ""
+  if dictionaire.has_key ("SERVICE-SCHEME") :
+    serviceScheme = dictionaire ["SERVICE-SCHEME"]
+#--- SECTION
+  sectionScheme = ""
+  if dictionaire.has_key ("SECTION-SCHEME") :
+    sectionScheme = dictionaire ["SECTION-SCHEME"]
+#--------------------------------------------------------------------------- Directories
+  BUILD_DIR = common_definitions.buildDirectory ()
+  GENERATED_SOURCE_DIR = common_definitions.generatedSourceDirectory ()
+  PRODUCT_DIR = common_definitions.productDirectory ()
+  ASBUILD_DIR = common_definitions.asDirectory ()
+#--------------------------------------------------------------------------- Build source lists
+  includeDirsInCompilerCommand = ["-I", GENERATED_SOURCE_DIR, "-I", projectDir]
+  H_SOURCE_LIST = []
+  CPP_SOURCE_LIST = []
+  S_SOURCE_LIST = []
+  for f in SOURCE_FILE_DIRECTORIES :
+    for root, dirs, files in os.walk (f) :
+      includeDirsInCompilerCommand += ["-I", root]
+      for name in files:
+        sourcePath = os.path.join (root, name)
+        (b, extension) = os.path.splitext (sourcePath)
+        if extension == ".cpp" :
+          CPP_SOURCE_LIST.append (sourcePath)
+        elif extension == ".h" :
+          H_SOURCE_LIST.append (sourcePath)
+        elif extension == ".s" :
+          S_SOURCE_LIST.append (sourcePath)
+        elif extension != "" : # Ceci permet d'ignorer les fichés cachés (dont les noms commencent par un point)
+          print (makefile.MAGENTA () + makefile.BOLD () + "Note: unhandled file " + sourcePath + makefile.ENDC ())
+#--------------------------------------------------------------------------- Build base header file
+  baseHeader_file = GENERATED_SOURCE_DIR + "/base.h"
+  H_SOURCE_LIST.insert (0, baseHeader_file)
+  rule = makefile.Rule ([baseHeader_file], "Build base header file")
+  rule.mOpenSourceOnError = False
+  rule.mDependences.append ("makefile.json")
+  rule.mCommand += ["../../dev-files/build_base_header_file.py", baseHeader_file, str (CPU_MHZ), TASK_COUNT, teensyName, "1" if ASSERTION_GENERATION else "0"]
+  rule.mPriority = -1
+  make.addRule (rule)
+#--------------------------------------------------------------------------- Build all header file
+  allHeadersSecondaryDependenceFile = BUILD_DIR + "/all-headers.dep"
+  allHeaders_file = GENERATED_SOURCE_DIR + "/all-headers.h"
+  rule = makefile.Rule ([allHeaders_file, allHeadersSecondaryDependenceFile], "Build all headers file")
+  rule.mOpenSourceOnError = False
+  rule.mDependences.append ("makefile.json")
+  rule.mDependences += H_SOURCE_LIST
+  rule.mCommand += ["../../dev-files/build_all_header_file.py", allHeaders_file, allHeadersSecondaryDependenceFile]
+  rule.mCommand += H_SOURCE_LIST
+  rule.enterSecondaryDependanceFile (allHeadersSecondaryDependenceFile, make)
+  rule.mPriority = -1
+  make.addRule (rule)
+#--------------------------------------------------------------------------- Build interrupt handler files
+  interruptHandlerSFile = GENERATED_SOURCE_DIR + "/interrupt-handlers.s"
+  interruptHandlerCppFile = GENERATED_SOURCE_DIR + "/interrupt-handler-helper.cpp"
+  S_SOURCE_LIST.append (interruptHandlerSFile)
+  CPP_SOURCE_LIST.append (interruptHandlerCppFile)
+  rule = makefile.Rule ([interruptHandlerSFile, interruptHandlerCppFile], "Build interrupt files")
+  rule.mOpenSourceOnError = False
+  rule.mDependences += H_SOURCE_LIST
+  rule.mDependences.append ("makefile.json")
+  rule.mDependences.append ("../../dev-files/build_interrupt_handlers.py")
+  rule.mCommand += ["../../dev-files/build_interrupt_handlers.py"]
+  rule.mCommand += [interruptHandlerCppFile]
+  rule.mCommand += [interruptHandlerSFile]
+  rule.mCommand += [serviceScheme]
+  rule.mCommand += [sectionScheme]
+  rule.mCommand += H_SOURCE_LIST
+  rule.mPriority = -1
+  make.addRule (rule)
+#--------------------------------------------------------------------------- Group sources ?
+  if GROUP_SOURCES :
+    allSourceFile = GENERATED_SOURCE_DIR + "/all-sources.cpp"
+    rule = makefile.Rule ([allSourceFile], "Group all sources")
+    rule.mOpenSourceOnError = False
+    rule.mDependences += CPP_SOURCE_LIST
+    rule.mDependences.append ("makefile.json")
+    rule.mCommand += ["../../dev-files/build_grouped_sources.py", allSourceFile]
+    rule.mCommand += CPP_SOURCE_LIST
+    rule.mPriority = -1
+    make.addRule (rule)
+    CPP_SOURCE_LIST = [allSourceFile]
+#--------------------------------------------------------------------------- Build makefile rules
+  objectFileList = []
+  asObjectFileList = []
+#--- CPP source files
+  for sourcePath in CPP_SOURCE_LIST :
+    source = os.path.basename (sourcePath)
+    objectFile = BUILD_DIR + "/" + source + ".o"
+    objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
+    asObjectFile = BUILD_DIR + "/" + source + ".s"
+  #--- Checking source
+    rule = makefile.Rule ([objectFileForChecking], "Checking " + source)
+    rule.mOpenSourceOnError = False
+    rule.mDependences.append (allHeaders_file)
+    rule.mDependences.append (sourcePath)
+    rule.mDependences.append ("makefile.json")
+    rule.enterSecondaryDependanceFile (objectFileForChecking + ".dep", make)
+    rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
+    rule.mCommand += common_definitions.checkModeOptions ()
+    rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
+    rule.mCommand += common_definitions.Cpp_actualOptions (False)
+    rule.mCommand += ["-c", sourcePath]
+    rule.mCommand += ["-o", objectFileForChecking]
+    rule.mCommand += ["-DSTATIC="]
+    rule.mCommand += includeDirsInCompilerCommand
+    rule.mCommand += ["-MD", "-MP", "-MF", objectFileForChecking + ".dep"]
+    make.addRule (rule)
+    rule.mPriority = -1
+    allGoal.append (objectFileForChecking)
+ #--- Compile source
+    rule = makefile.Rule ([objectFile], "Compiling " + source)
+    rule.mOpenSourceOnError = False
+    rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
+    rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
+    rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
+    rule.mCommand += ["-g"]
+    rule.mCommand += ["-c", sourcePath]
+    rule.mCommand += ["-o", objectFile]
+    rule.mCommand += ["-DSTATIC=static __attribute__((unused))"] if GROUP_SOURCES else ["-DSTATIC="]
+    rule.mCommand += includeDirsInCompilerCommand
+    rule.mCommand += ["-MD", "-MP", "-MF", objectFile + ".dep"]
+    rule.mDependences.append (allHeaders_file)
+    rule.mDependences.append (sourcePath)
+    rule.mDependences.append ("makefile.json")
+    rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
+    make.addRule (rule)
+    objectFileList.append (objectFile)
+  #--- objdump python source
+    objdumpPythonFile = BUILD_DIR + "/" + source + ".objdump.py"
+    rule = makefile.Rule ([objdumpPythonFile], "Building " + source + ".objdump.py")
+    rule.mDependences.append (objectFile)
+    rule.mDependences.append ("makefile.json")
+    rule.mCommand += ["../../dev-files/build_objdump.py", OBJDUMP_TOOL, source, objdumpPythonFile]
+    rule.mPriority = -1
+    make.addRule (rule)
+    allGoal.append (objdumpPythonFile)
+  #--- AS rule
+    rule = makefile.Rule ([asObjectFile], "Compiling -> s " + source)
+    rule.mOpenSourceOnError = False
+    rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
+    rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
+    rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
+    rule.mCommand += ["-S", sourcePath]
+    rule.mCommand += ["-o", asObjectFile]
+    rule.mCommand += ["-DSTATIC="]
+    rule.mCommand += includeDirsInCompilerCommand
+    rule.mCommand += ["-MD", "-MP", "-MF", asObjectFile + ".dep"]
+    rule.mDependences.append (sourcePath)
+    rule.mDependences.append (allHeaders_file)
+    rule.mDependences.append ("makefile.json")
+    rule.enterSecondaryDependanceFile (asObjectFile + ".dep", make)
+    make.addRule (rule)
+  #--- AS rule, getting output assembler file
+    listingFile = ASBUILD_DIR + "/" + source + ".s.list"
+    rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
+    rule.mOpenSourceOnError = False
+    rule.mCommand += AS_TOOL_WITH_OPTIONS
+    rule.mCommand += [asObjectFile]
+    rule.mCommand += ["-o", "/dev/null"]
+    rule.mCommand += ["-aln=" + listingFile]
+    rule.mDependences.append (asObjectFile)
+    rule.mDependences.append (allHeaders_file)
+    rule.mDependences.append ("makefile.json")
+    make.addRule (rule)
+    asObjectFileList.append (listingFile)
+#-- Add ARM S files
+  for sourcePath in S_SOURCE_LIST :
+    source = os.path.basename (sourcePath)
+    objectFile = BUILD_DIR + "/" + source + ".o"
+    objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
+    asObjectFile = ASBUILD_DIR + "/" + source + ".s"
+    if sourcePath != "" :
+      rule = makefile.Rule ([objectFile], "Assembling " + source)
+      rule.mOpenSourceOnError = False
+      rule.mCommand += AS_TOOL_WITH_OPTIONS
+      rule.mCommand += [sourcePath]
+      rule.mCommand += ["-o", objectFile]
+      rule.mCommand += includeDirsInCompilerCommand
+      rule.mCommand += ["--MD", objectFile + ".dep"]
+      rule.mDependences.append (sourcePath)
+      rule.mDependences.append ("makefile.json")
+      rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
+      make.addRule (rule)
+      objectFileList.append (objectFile)
+    #--- Add listing file
+      listingFile = ASBUILD_DIR + "/" + source + ".list"
+      rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
+      rule.mOpenSourceOnError = False
+      rule.mCommand += AS_TOOL_WITH_OPTIONS
+      rule.mCommand += [sourcePath]
+      rule.mCommand += ["-o", "/dev/null"]
+      rule.mCommand += ["-aln=" + listingFile]
+      rule.mDependences.append (sourcePath)
+      rule.mDependences.append ("makefile.json")
+      make.addRule (rule)
+      asObjectFileList.append (listingFile)
+#--------------------------------------------------------------------------- Link for internal flash
+  PRODUCT_INTERNAL_FLASH = PRODUCT_DIR + "/product"
+  LINKER_SCRIPT_INTERNAL_FLASH = "../../dev-files/" + linkerScript
+  allGoal.append (PRODUCT_INTERNAL_FLASH + ".elf")
+#--- Add link rule
+  rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".elf"], "Linking " + PRODUCT_INTERNAL_FLASH + ".elf")
+  rule.mDependences += objectFileList
+  rule.mDependences.append (LINKER_SCRIPT_INTERNAL_FLASH)
+  rule.mDependences.append ("makefile.json")
+  rule.mCommand += LD_TOOL_WITH_OPTIONS
+  rule.mCommand += objectFileList
+  rule.mCommand += ["-T" + LINKER_SCRIPT_INTERNAL_FLASH]
+  rule.mCommand.append ("-Wl,-Map=" + PRODUCT_INTERNAL_FLASH + ".map")
+  rule.mCommand += common_definitions.commonLinkerFlags (usesLTO)
+  rule.mCommand += ["-o", PRODUCT_INTERNAL_FLASH + ".elf"]
+  make.addRule (rule)
+#--- Add hex rule
+  allGoal.append (PRODUCT_INTERNAL_FLASH + ".hex")
+  rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".hex"], "Hexing " + PRODUCT_INTERNAL_FLASH + ".hex")
+  rule.mDependences.append (PRODUCT_INTERNAL_FLASH + ".elf")
+  rule.mDependences.append ("makefile.json")
+  rule.mCommand += OBJCOPY_TOOL_WITH_OPTIONS
+  rule.mCommand.append ("-O")
+  rule.mCommand.append ("ihex")
+  rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".elf")
+  rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".hex")
+  make.addRule (rule)
+#--------------------------------------------------------------------------- Goals
+  make.addGoal ("all", allGoal, "Build all")
+  make.addGoal ("run", allGoal, "Building all and run")
+  make.addGoal ("view-hex", allGoal, "Building all and show hex")
+  make.addGoal ("display-obj-size", allGoal, "Build binaries and display object sizes")
+  make.addGoal ("as", asObjectFileList, "Compile C and C++ to assembly")
+#--------------------------------------------------------------------------- Run jobs
+  #make.printRules ()
+  #make.checkRules ()
+#   make.writeRuleDependancesInDotFile ("dependances.dot")
+  make.runGoal (maxConcurrentJobs, showCommand)
+#--------------------------------------------------------------------------- Ok ?
+  make.printErrorCountAndExitOnError ()
+#---------------------------------------------------------------------------- "display-obj-size"
+  if GOAL == "display-obj-size" :
+    makefile.runCommand (DISPLAY_OBJ_SIZE_TOOL + objectFileList + ["-t"], "Display Object Size", False, showCommand)
+#---------------------------------------------------------------------------- "All" or "run"
+  if (GOAL == "all") or (GOAL == "run") or (GOAL == "view-hex") :
+    s = runProcessAndGetOutput (DISPLAY_OBJ_SIZE_TOOL + ["-t"] + [PRODUCT_INTERNAL_FLASH + ".elf"])
+    secondLine = s.split('\n')[1]
+    numbers = [int(s) for s in secondLine.split() if s.isdigit()]
+    print ("  ROM code:    " + str (numbers [0]) + " bytes")
+    print ("  ROM data:    " + str (numbers [1]) + " bytes")
+    print ("  RAM + STACK: " + str (numbers [2]) + " bytes")
+#----------------------------------------------- Run ?
+  if GOAL == "run":
+    FLASH_TEENSY = [TEENSY_CLI_LOADER_PATH, "-w", "-v", "-mmcu=TEENSY36"]
+    print (makefile.BOLD_BLUE () + "Loading Teensy..." + makefile.ENDC ())
+    runProcess (FLASH_TEENSY + [PRODUCT_INTERNAL_FLASH + ".hex"])
+    print (makefile.BOLD_GREEN () + "Success" + makefile.ENDC ())
+  elif GOAL == "view-hex":
+    print (makefile.BOLD_GREEN () + "View hex..." + makefile.ENDC ())
+    scriptDir = os.path.dirname (os.path.abspath (__file__))
+    runProcess (["python", scriptDir+ "/view-hex.py", PRODUCT_INTERNAL_FLASH + ".hex"])
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*

+ 134 - 0
dev-files/common_definitions.py

@@ -0,0 +1,134 @@
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def commonLinkerFlags (usesLTO) :
+  result = []
+  result.append ("-nostartfiles")
+  result.append ("-Wl,--fatal-warnings")
+  result.append ("-Wl,--warn-common")
+  result.append ("-Wl,--no-undefined")
+  if usesLTO :
+    result.append ("-flto")
+    result.append ("-ffat-lto-objects")
+    result.append ("-fuse-linker-plugin")
+  result.append ("-Wl,--cref")
+  result.append ("-Wl,-static")
+  result.append ("-Wl,--gc-sections")
+
+  result.append ("-Wl,--sort-common=descending")
+  result.append ("-Wl,--sort-section=alignment")
+#  result.append ("-Wl,--print-memory-usage")
+  result.append ("-Wl,--warn-section-align")
+  result.append ("-Wl,--warn-shared-textrel")
+  result.append ("-Wl,--warn-alternate-em")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def checkModeOptions () :
+  result = []
+  result.append ("-x")
+  result.append ("c++")
+  result.append ("-DCHECK_SOFTWARE_MODES")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def C_Cpp_optimizationOptions ():
+  result = []
+  result.append ("-Os")
+#  result.append ("-foptimize-register-move")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def C_Cpp_commonOptions (usesLTO):
+  result = []
+  result.append ("-Wall")
+  result.append ("-Wextra")
+  result.append ("-Werror")
+  result.append ("-Wreturn-type")
+  result.append ("-Wformat")
+  result.append ("-Wshadow")
+  result.append ("-Wsign-compare")
+  result.append ("-Wpointer-arith")
+  result.append ("-Wparentheses")
+  result.append ("-Wcast-align")
+  result.append ("-Wcast-qual")
+  result.append ("-Wwrite-strings")
+  result.append ("-Wswitch")
+  result.append ("-Wswitch-enum")
+  result.append ("-Wuninitialized")
+  result.append ("-Wsign-conversion")
+
+#--- Ordre de ne pas engendrer l'appel des destructeurs des variables globales C++
+# et donc d'utiliser des symboles tels que __cxa_exit, __lock___atexit_recursive_mutex, …
+  result.append ("-fno-use-cxa-atexit")
+
+#--- Engendrer fonctions et variables globales dans des sections spécifiques
+#    Ceci permet à l'éditeur de liens d'éliminer fonctions et variables inutilisées
+  result.append ("-ffunction-sections")
+  result.append ("-fdata-sections")
+
+#   result.append ("-fno-stack-protector") # CLANG
+#   result.append ("-fshort-enums") # CLANG
+  if usesLTO :
+    result.append ("-flto")
+    result.append ("-ffat-lto-objects")
+  result.append ("-Wno-unused-parameter")
+  result.append ("-Wshadow")
+#   result.append ("-Wduplicated-branches")
+#   result.append ("-Wmisleading-indentation")
+#  result.append ("-fomit-frame-pointer")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def C_actualOptions (usesLTO):
+  result = C_Cpp_commonOptions (usesLTO)
+  result.append ("-std=c99")
+  result.append ("-Wstrict-prototypes")
+  result.append ("-Wbad-function-cast")
+  result.append ("-Wmissing-declarations")
+  result.append ("-Wimplicit-function-declaration")
+  result.append ("-Wno-int-to-pointer-cast")
+  result.append ("-Wno-pointer-to-int-cast")
+  result.append ("-Wmissing-prototypes")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def Cpp_actualOptions (usesLTO):
+  result = C_Cpp_commonOptions (usesLTO)
+  result.append ("-std=c++14") # c++11 For forwarding enum declarations
+  result.append ("-fno-rtti")
+  result.append ("-fno-exceptions")
+  result.append ("-Woverloaded-virtual")
+  result.append ("-Weffc++")
+  result.append ("-fno-threadsafe-statics")
+  result.append ("-Wmissing-declarations")
+  result.append ("-Wsuggest-override")
+  return result
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def generatedSourceDirectory () :
+  return "zSOURCES"
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def buildDirectory () :
+  return "zBUILDS"
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def asDirectory () :
+  return "zASBUILDS"
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+def productDirectory ():
+  return "zPRODUCTS"
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 51 - 0
dev-files/dev_platform.py

@@ -0,0 +1,51 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import os, sys
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   FOR PRINTING IN COLOR
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class bcolors:
+    HEADER = '\033[95m'
+    BLUE = '\033[94m'
+    GREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+    BOLD_BLUE = '\033[1m' + '\033[94m'
+    BOLD_GREEN = '\033[1m' + '\033[92m'
+    BOLD_RED = '\033[1m' + '\033[91m'
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   PLATFORM
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def getPlatform () :
+#--- Determine platform
+  PLATFORM = ""
+  (SYSTEM_NAME, MODE_NAME, RELEASE, VERSION, MACHINE) = os.uname ()
+  #print "SYSTEM_NAME '" + SYSTEM_NAME + "'"
+  #print "MACHINE '" + MACHINE + "'"
+  if (MACHINE == "i386") & (SYSTEM_NAME == "Darwin") :
+    PLATFORM = "mac"
+  elif (MACHINE == "x86_64") & (SYSTEM_NAME == "Darwin") :
+    PLATFORM = "mac"
+  elif (MACHINE == "x86_64") & (SYSTEM_NAME == "Linux") :
+    PLATFORM = "linux"
+  elif (MACHINE == "i386") & (SYSTEM_NAME == "Linux") :
+    PLATFORM = "linux32"
+  elif (MACHINE == "i686") & (SYSTEM_NAME == "Linux") :
+    PLATFORM = "linux32"
+  else:
+    print (bcolors.BOLD_RED + "*** Unknown platform (SYSTEM_NAME = \"" + SYSTEM_NAME + "\", MACHINE = \"" + MACHINE + "\") ***" + bcolors.ENDC)
+    sys.exit (1) ;
+  return PLATFORM
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+

+ 136 - 0
dev-files/download_and_install_gccarm.py

@@ -0,0 +1,136 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import os, urllib, subprocess, sys
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import archive_directory
+import tool_directory
+import dev_platform
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   FOR PRINTING IN COLOR
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class bcolors:
+    HEADER = '\033[95m'
+    BLUE = '\033[94m'
+    GREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+    BOLD_BLUE = '\033[1m' + '\033[94m'
+    BOLD_GREEN = '\033[1m' + '\033[92m'
+    BOLD_RED = '\033[1m' + '\033[91m'
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   DISTRIBUTION GCC
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def distributionGCC () :
+  gcc = "gcc-arm-none-eabi-7-2017-q4-major"
+  if dev_platform.getPlatform () == "linux32" :
+    gcc = "gcc-arm-none-eabi-5_4-2016q3"
+  return gcc
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   ARCHIVE URL (from https://developer.arm.com/open-source/gnu-toolchain/gnu-rm)
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def compilerArchiveURL () :
+  baseURL = "https://developer.arm.com/-/media/Files/downloads/gnu-rm/"
+  PLATFORM = dev_platform.getPlatform ()
+  distribution = "7-2017q4/gcc-arm-none-eabi-7-2017-q4-major-" + PLATFORM + ".tar.bz2"
+  if dev_platform.getPlatform () == "linux32" :
+    distribution = "5_4-2016q3/gcc-arm-none-eabi-5_4-2016q3-20160926-linux.tar.bz2"
+  return baseURL + distribution
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   runCommand
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runCommand (cmd) :
+  str = "+"
+  for s in cmd:
+    str += " " + s
+  print bcolors.BOLD_BLUE + str + bcolors.ENDC
+  returncode = subprocess.call (cmd)
+  if returncode != 0 :
+    sys.exit (returncode)
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   ARCHIVE DOWNLOAD
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def downloadReportHook (a,b,fileSize):
+  # "," at the end of the line is important!
+  if fileSize < (1 << 10):
+    sizeString = str (fileSize)
+  else:
+    if fileSize < (1 << 20):
+      sizeString = str (fileSize >> 10) + "Ki"
+    else:
+      sizeString = str (fileSize >> 20) + "Mi"
+  print "% 3.1f%% of %sB\r" % (min(100.0, float(a * b) / fileSize * 100.0), sizeString),
+  sys.stdout.flush()
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def downloadArchive (archiveURL, archivePath):
+  print ("URL: "+ archiveURL)
+  print "Downloading..."
+  urllib.urlretrieve (archiveURL,  archivePath, downloadReportHook)
+  print ""
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#  Install GCC
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def install_gcc (INSTALL_DIR) :
+  print bcolors.BOLD_GREEN + "Install GCC tools..." + bcolors.ENDC
+  DISTRIBUTION = distributionGCC ()
+  #------------------------------------------------------------------ Archive dir
+  COMPILER_ARCHIVE_DIR = archive_directory.createAndGetArchiveDirectory ()
+  #------------------------------------------------------------------ Download
+  if not os.path.exists (COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2"):
+    url = compilerArchiveURL ()
+    runCommand (["rm", "-f", COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2.downloading"])
+    downloadArchive (url, COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2.downloading")
+    runCommand (["mv",
+                 COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2.downloading",
+                 COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2"
+                ])
+  #------------------------------------------------------------------ Install
+  if not os.path.exists (INSTALL_DIR):
+    os.mkdir (INSTALL_DIR)
+  if not os.path.exists (INSTALL_DIR + "/" + DISTRIBUTION):
+    runCommand (["cp", COMPILER_ARCHIVE_DIR + "/" + DISTRIBUTION + ".tar.bz2", INSTALL_DIR + "/" + DISTRIBUTION + ".tar.bz2"])
+    savedCurrentDir = os.getcwd ()
+    os.chdir (INSTALL_DIR)
+    print bcolors.BOLD_BLUE + "+ cd " + INSTALL_DIR + bcolors.ENDC
+    runCommand (["bunzip2", DISTRIBUTION + ".tar.bz2"])
+    runCommand (["tar", "xf", DISTRIBUTION + ".tar"])
+    runCommand (["rm", DISTRIBUTION + ".tar"])
+    os.chdir (savedCurrentDir)
+
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   GET GCC TOOL DIRECTORY
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def installGCCARMandGetToolDirectory () :
+#--- Absolute path of tool directory
+  TOOL_DIRECTORY = tool_directory.toolDirectory () + "/" + distributionGCC ()
+#--- Install tool ?
+  if not os.path.exists (TOOL_DIRECTORY) :
+    install_gcc (tool_directory.toolDirectory ())
+#--- Return tool directory
+  return TOOL_DIRECTORY
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+

+ 115 - 0
dev-files/interrupt_names_teensy_3_6.py

@@ -0,0 +1,115 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+def interruptNames () :
+  result = {}
+  result ["NMI"] = 2
+  result ["HardFault"] = 3
+  result ["MemManage"] = 4
+  result ["BusFault"] = 5
+  result ["UsageFault"] = 6
+  result ["SVC"] = 11
+  result ["DebugMonitor"] = 12
+  result ["PendSV"] = 14
+  result ["SysTick"] = 15
+  result ["DMA0_DMA16"] = 16
+  result ["DMA1_DMA17"] = 17
+  result ["DMA2_DMA18"] = 18
+  result ["DMA3_DMA19"] = 19
+  result ["DMA4_DMA20"] = 20
+  result ["DMA5_DMA21"] = 21
+  result ["DMA6_DMA22"] = 22
+  result ["DMA7_DMA23"] = 23
+  result ["DMA8_DMA24"] = 24
+  result ["DMA9_DMA25"] = 25
+  result ["DMA10_DMA26"] = 26
+  result ["DMA11_DMA27"] = 27
+  result ["DMA12_DMA28"] = 28
+  result ["DMA13_DMA29"] = 29
+  result ["DMA14_DMA30"] = 30
+  result ["DMA15_DMA31"] = 31
+  result ["DMA_Error"] = 32
+  result ["MCM"] = 33
+  result ["FTFE"] = 34
+  result ["Read_Collision"] = 35
+  result ["LVD_LVW"] = 36
+  result ["LLWU"] = 37
+  result ["WDOG_EWM"] = 38
+  result ["RNG"] = 39
+  result ["I2C0"] = 40
+  result ["I2C1"] = 41
+  result ["SPI0"] = 42
+  result ["SPI1"] = 43
+  result ["I2S0_Tx"] = 44
+  result ["I2S0_Rx"] = 45
+  result ["UART0_RX_TX"] = 47
+  result ["UART0_ERR"] = 48
+  result ["UART1_RX_TX"] = 49
+  result ["UART1_ERR"] = 50
+  result ["UART2_RX_TX"] = 51
+  result ["UART2_ERR"] = 52
+  result ["UART3_RX_TX"] = 53
+  result ["UART3_ERR"] = 54
+  result ["ADC0"] = 55
+  result ["CMP0"] = 56
+  result ["CMP1"] = 57
+  result ["FTM0"] = 58
+  result ["FTM1"] = 59
+  result ["FTM2"] = 60
+  result ["CMT"] = 61
+  result ["RTC"] = 62
+  result ["RTC_Seconds"] = 63
+  result ["PIT0"] = 64
+  result ["PIT1"] = 65
+  result ["PIT2"] = 66
+  result ["PIT3"] = 67
+  result ["PDB0"] = 68
+  result ["USB0"] = 69
+  result ["USBDCD"] = 70
+  result ["DAC0"] = 72
+  result ["MCG"] = 73
+  result ["LPTMR0"] = 74
+  result ["PORTA"] = 75
+  result ["PORTB"] = 76
+  result ["PORTC"] = 77
+  result ["PORTD"] = 78
+  result ["PORTE"] = 79
+  result ["SPI2"] = 81
+  result ["UART4_RX_TX"] = 82
+  result ["UART4_ERR"] = 83
+  result ["CMP2"] = 86
+  result ["FTM3"] = 87
+  result ["DAC1"] = 88
+  result ["ADC1"] = 89
+  result ["I2C2"] = 90
+  result ["CAN0_ORed_Message_buffer"] = 91
+  result ["CAN0_Bus_Off"] = 92
+  result ["CAN0_Error"] = 93
+  result ["CAN0_Tx_Warning"] = 94
+  result ["CAN0_Rx_Warning"] = 95
+  result ["CAN0_Wake_Up"] = 96
+  result ["SDHC"] = 97
+  result ["ENET_1588_Timer"] = 98
+  result ["ENET_Transmit"] = 99
+  result ["ENET_Receive"] = 100
+  result ["ENET_Error"] = 101
+  result ["LPUART0"] = 102
+  result ["TSI0"] = 103
+  result ["TPM1"] = 104
+  result ["TPM2"] = 105
+  result ["USBHSDCD"] = 106
+  result ["I2C3"] = 107
+  result ["CMP3"] = 108
+  result ["USBHS"] = 109
+  result ["CAN1_ORed_Message_buffer"] = 110
+  result ["CAN1_Bus_Off"] = 111
+  result ["CAN1_Error"] = 112
+  result ["CAN1_Tx_Warning"] = 113
+  result ["CAN1_Rx_Warning"] = 114
+  result ["CAN1_Wake_Up"] = 115
+  result ["SWINT"] = 64
+  return result
+
+#———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 976 - 0
dev-files/makefile.py

@@ -0,0 +1,976 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   Releases                                                                                                           *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+# 1.0: march 18th, 2015
+#        first release
+# 2.0: october 2th, 2015
+#        added several target definition for rules
+# 2.1: october 5th, 2015
+#        added checking routine formal argument run-time types
+# 2.2: october 24th, 2015
+#        changed subprocess.Popen to subprocess.call in runCommand
+#        added command tool checking using 'find_executable' function
+#        added optional argument to Make class initializer to log command utility tool path
+# 2.3: april 16th, 2016
+#        added advance percentage
+# 3.0: may 30th, 2016
+#        compatibility with Python 3:
+#             print xyz ---> print (xyz)
+#             change isinstance function arguments ---> function argumentIsString
+#             subprocess.call: add "universal_newlines=True" argument
+#             added test (job.mReturnCode != None) lines 727 and 739
+# 3.1: may 26th, 2018
+#        Added tolerance in secondary dependency file syntax:
+#
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+# http://www.diveintopython3.net/porting-code-to-python-3-with-2to3.html
+
+import subprocess, sys, os, copy
+import urllib, shutil, subprocess
+import platform, json, operator
+import threading, types, traceback
+
+if sys.version_info >= (2, 6) :
+  import multiprocessing
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   find_executable                                                                                                    *
+# From:                                                                                                                *
+# https://gist.github.com/4368898                                                                                      *
+# Public domain code by anatoly techtonik <techtonik@gmail.com>                                                        *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def find_executable(executable, path=None):
+    """Try to find 'executable' in the directories listed in 'path' (a
+    string listing directories separated by 'os.pathsep'; defaults to
+    os.environ['PATH']).  Returns the complete filename or None if not
+    found
+    """
+    if path is None:
+        path = os.environ['PATH']
+    paths = path.split(os.pathsep)
+    extlist = ['']
+    if os.name == 'os2':
+        (base, ext) = os.path.splitext(executable)
+        # executable files on OS/2 can have an arbitrary extension, but
+        # .exe is automatically appended if no dot is present in the name
+        if not ext:
+            executable = executable + ".exe"
+    elif sys.platform == 'win32':
+        pathext = os.environ['PATHEXT'].lower().split(os.pathsep)
+        (base, ext) = os.path.splitext(executable)
+        if ext.lower() not in pathext:
+            extlist = pathext
+    for ext in extlist:
+        execname = executable + ext
+        if os.path.isfile(execname):
+            return execname
+        else:
+            for p in paths:
+                f = os.path.join(p, execname)
+                if os.path.isfile(f):
+                    return f
+    else:
+        return None
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   processorCount                                                                                                     *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def processorCount () :
+  if sys.version_info >= (2, 6) :
+    coreCount = multiprocessing.cpu_count ()
+  else:
+    coreCount = 1
+  return coreCount
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   argumentIsString                                                                                                   *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def argumentIsString (argument) :
+  if sys.version_info < (3,0):
+    return isinstance (argument, types.StringTypes)
+  else:
+    return type (argument) is str
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   FOR PRINTING IN COLOR                                                                                              *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def BLACK () :
+  return '\033[90m'
+
+#······················································································································*
+
+def RED () :
+  return '\033[91m'
+
+#······················································································································*
+
+def GREEN () :
+  return '\033[92m'
+
+#······················································································································*
+
+def YELLOW () :
+  return '\033[93m'
+
+#······················································································································*
+
+def BLUE () :
+  return '\033[94m'
+
+#······················································································································*
+
+def MAGENTA () :
+  return '\033[95m'
+
+#······················································································································*
+
+def CYAN () :
+  return '\033[96m'
+
+#······················································································································*
+
+def WHITE () :
+  return '\033[97m'
+
+#······················································································································*
+
+def ENDC () :
+  return '\033[0m'
+
+#······················································································································*
+
+def BOLD () :
+  return '\033[1m'
+
+#······················································································································*
+
+def UNDERLINE () :
+  return '\033[4m'
+
+#······················································································································*
+
+def BLINK () :
+  return '\033[5m'
+
+#······················································································································*
+
+def BOLD_BLUE () :
+  return BOLD () + BLUE ()
+
+#······················································································································*
+
+def BOLD_GREEN () :
+  return BOLD () + GREEN ()
+
+#······················································································································*
+
+def BOLD_RED () :
+  return BOLD () + RED ()
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   runHiddenCommand                                                                                                   *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runHiddenCommand (cmd, logUtilityTool=False) :
+  executable = find_executable (cmd [0])
+  if executable == None:
+    print (BOLD_RED () + "*** Cannot find '" + cmd[0] + "' executable ***" + ENDC ())
+    sys.exit (1)
+  if logUtilityTool:
+    print ("Utility tool is '" + executable + "'")
+  result = ""
+  childProcess = subprocess.Popen (cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
+  while True:
+    line = childProcess.stdout.readline ()
+    if line != "":
+      result += line
+    else:
+      childProcess.wait ()
+      if childProcess.returncode != 0 :
+        sys.exit (childProcess.returncode)
+      return result
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   runCommand                                                                                                         *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runCommand (cmd, title, showCommand, logUtilityTool) :
+  if title != "":
+    print (BOLD_BLUE () + title + ENDC ())
+  if (title == "") or showCommand :
+    cmdAsString = ""
+    for s in cmd:
+      if (s == "") or (s.find (" ") >= 0):
+        cmdAsString += '"' + s + '" '
+      else:
+        cmdAsString += s + ' '
+    print (cmdAsString)
+  executable = find_executable (cmd [0])
+  if executable == None:
+    print (BOLD_RED () + "*** Cannot find '" + cmd[0] + "' executable ***" + ENDC ())
+    sys.exit (1)
+  if logUtilityTool:
+    print ("Utility tool is '" + executable + "'")
+  returncode = subprocess.call (cmd)
+  if returncode != 0 :
+    sys.exit (returncode)
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   runInThread                                                                                                        *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runInThread (job, displayLock, terminationSemaphore):
+  executable = find_executable (job.mCommand [0])
+  if executable == None:
+    print (BOLD_RED () + "*** Cannot find '" + job.mCommand[0] + "' executable ***" + ENDC ())
+    job.mReturnCode = 1
+    terminationSemaphore.release ()
+  else:
+    if job.mLogUtilityTool :
+      print ("Utility tool is '" + executable + "'")
+    childProcess = subprocess.Popen (job.mCommand, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True)
+    while True:
+      line = childProcess.stdout.readline ()
+      if line != "":
+        job.mOutputLines.append (line)
+        displayLock.acquire ()
+        sys.stdout.write (line) # Print without newline
+        displayLock.release ()
+      else:
+        childProcess.wait ()
+        job.mReturnCode = childProcess.returncode
+        terminationSemaphore.release ()
+        break
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   modificationDateForFile                                                                                            *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def modificationDateForFile (dateCacheDictionary, file):
+  absFilePath = os.path.abspath (file)
+  if absFilePath in dateCacheDictionary :
+    return dateCacheDictionary [absFilePath]
+  elif not os.path.exists (absFilePath):
+    date = sys.float_info.max # Very far in future
+    dateCacheDictionary [absFilePath] = date
+    return date
+  else:
+    date = os.path.getmtime (absFilePath)
+    dateCacheDictionary [absFilePath] = date
+    return date
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   class PostCommand                                                                                                  *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class PostCommand:
+  mCommand = []
+  mTitle = ""
+
+  #····················································································································*
+
+  def __init__ (self, title = ""):
+    self.mCommand = []
+    self.mTitle = title
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   class Job                                                                                                          *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class Job:
+  mTargets = []
+  mCommand = []
+  mTitle = ""
+  mRequiredFiles = []
+  mPostCommands = []
+  mReturnCode = None
+  mPriority = 0
+  mState = 0 # 0: waiting for execution
+  mOutputLines = []
+  mOpenSourceOnError = False # Do not try to open source file on error
+  mLogUtilityTool = False
+
+  #····················································································································*
+
+  def __init__ (self, targets, requiredFiles, command, postCommands, priority, title, openSourceOnError, logUtilityTool):
+    self.mTargets = copy.deepcopy (targets)
+    self.mCommand = copy.deepcopy (command)
+    self.mRequiredFiles = copy.deepcopy (requiredFiles)
+    self.mTitle = copy.deepcopy (title)
+    self.mPostCommands = copy.deepcopy (postCommands)
+    self.mPriority = priority
+    self.mOutputLines = []
+    self.mOpenSourceOnError = openSourceOnError
+    self.mLogUtilityTool = logUtilityTool
+
+  #····················································································································*
+
+  def run (self, displayLock, terminationSemaphore, showCommand, progressString):
+    displayLock.acquire ()
+    if self.mTitle != "":
+      print (progressString + BOLD_BLUE () + self.mTitle + ENDC ())
+    if (self.mTitle == "") or showCommand :
+      cmdAsString = ""
+      for s in self.mCommand:
+        if (s == "") or (s.find (" ") >= 0):
+          cmdAsString += '"' + s + '" '
+        else:
+          cmdAsString += s + ' '
+      print (progressString + cmdAsString)
+    displayLock.release ()
+    thread = threading.Thread (target=runInThread, args=(self, displayLock, terminationSemaphore))
+    thread.start()
+
+  #····················································································································*
+
+  def runPostCommand (self, displayLock, terminationSemaphore, showCommand):
+    postCommand = self.mPostCommands [0]
+    self.mCommand = postCommand.mCommand
+    displayLock.acquire ()
+    print (BOLD_BLUE () + postCommand.mTitle + ENDC ())
+    if showCommand:
+      cmdAsString = ""
+      for s in self.mCommand:
+        if (s == "") or (s.find (" ") >= 0):
+          cmdAsString += '"' + s + '" '
+        else:
+          cmdAsString += s + ' '
+      print (cmdAsString)
+    displayLock.release ()
+    thread = threading.Thread (target=runInThread, args=(self, displayLock, terminationSemaphore))
+    thread.start()
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   class Rule                                                                                                         *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class Rule:
+  mTargets = []
+  mDependences = []
+  mCommand = []
+  mSecondaryMostRecentModificationDate = 0.0 # Far in the past
+  mTitle = ""
+  mPostCommands = []
+  mPriority = 0
+  mDeleteTargetOnError = False # No operation on error
+  mCleanOperation = 0 # No operation on clean
+  mOpenSourceOnError = False # Do not try to open source file on error
+
+  #····················································································································*
+
+  def __init__ (self, targets, title = ""):
+    # print ("Rule '" + title + "'")
+    if not type (targets) is list:
+      print (BOLD_RED () + "*** Rule type instanciation: first argument 'targets' is not a list ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    else:
+      for aTarget in targets:
+        # print ("  Target '" + aTarget + "'")
+        if not argumentIsString (aTarget):
+          print (BOLD_RED () + "*** Rule type instanciation: an element of first argument 'targets' is not a string ***" + ENDC ())
+          traceback.print_stack ()
+          sys.exit (1)
+    if not argumentIsString (title):
+      print (BOLD_RED () + "*** Rule type instanciation: second argument 'title' is not a string ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    self.mTargets = copy.deepcopy (targets)
+    self.mDependences = []
+    self.mCommand = []
+    self.mSecondaryMostRecentModificationDate = 0.0
+    self.mPostCommands = []
+    self.mPriority = 0
+    self.mDeleteTargetOnError = False # No operation on error
+    self.mOpenSourceOnError = False # Do not try to open source file on error
+    self.mCleanOperation = 0 # No operation on clean
+    if title == "":
+      self.mTitle = "Building"
+      for s in targets:
+        self.mTitle += " " + s
+    else:
+      self.mTitle = copy.deepcopy (title)
+
+  #····················································································································*
+
+  def deleteTargetFileOnClean (self):
+    self.mCleanOperation = 1
+
+  #····················································································································*
+
+  def deleteTargetDirectoryOnClean (self):
+    self.mCleanOperation = 2
+
+  #····················································································································*
+
+  def enterSecondaryDependanceFile (self, secondaryDependanceFile, make):
+    if not argumentIsString (secondaryDependanceFile):
+      print (BOLD_RED () + "*** Rule.enterSecondaryDependanceFile: 'secondaryDependanceFile' argument is not a string ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    if make.mSelectedGoal != "clean":
+      filePath = os.path.abspath (secondaryDependanceFile)
+      if not os.path.exists (filePath):
+        self.mSecondaryMostRecentModificationDate = sys.float_info.max # Very far in future
+      else:
+        f = open (filePath, "r")
+        s = f.read ()
+        f.close ()
+        s = s.replace ("\\ ", "\x01") # Replace escaped spaces by \0x01
+        s = s.replace ("\\\n", "") # Suppress \ at the end of lines
+        liste = s.split ("\n\n")
+        # print ("DEP " + secondaryDependanceFile)
+        for s in liste:
+          # print ("S " + s)
+          components = s.split (':')
+          # print (str (len (components)))
+          #target = components [0].replace ("\x01", " ")
+          #print ("------- Optional dependency rules for target '" + target + "'")
+          #print ("Secondary target '" + target + "'")
+          if len (components) > 1 :
+            for src in components [1].split ():
+              secondarySource = src.replace ("\x01", " ")
+              # print ("  SECONDARY SOURCE  '" + secondarySource + "'")
+              modifDate = modificationDateForFile (make.mModificationDateDictionary, secondarySource)
+              if self.mSecondaryMostRecentModificationDate < modifDate :
+                self.mSecondaryMostRecentModificationDate = modifDate
+                #print (BOLD_BLUE () + str (modifDate) + ENDC ())
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   class Make                                                                                                         *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class Make:
+  mRuleList = []
+  mJobList = []
+  mErrorCount = 0
+  mModificationDateDictionary = {}
+  mGoals = {}
+  mSelectedGoal = ""
+  mLinuxTextEditor = ""
+  mMacTextEditor = ""
+  mSimulateClean = False
+  mLogUtilityTool = True
+  mShowProgressString = True
+
+  #····················································································································*
+
+  def __init__ (self, goal, logUtilityTool=False):
+    if not argumentIsString (goal):
+      print (BOLD_RED () + "*** Make instanciation: 'goal' argument is not a string ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    self.mRuleList = []
+    self.mJobList = []
+    self.mErrorCount = 0
+    self.mModificationDateDictionary = {}
+    self.mGoals = {}
+    self.mSelectedGoal = goal
+    self.mLinuxTextEditor = "gEdit"
+    self.mMacTextEditor = "TextEdit"
+    self.mLogUtilityTool = logUtilityTool
+
+  #····················································································································*
+
+  def doNotShowProgressString (self) :
+     self.mShowProgressString = False
+
+  #····················································································································*
+
+  def addRule (self, rule):
+    if not isinstance (rule, Rule):
+      print (BOLD_RED () + "*** Make.addRule: 'rule' argument is not an instance of Rule type ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    self.mRuleList.append (copy.deepcopy (rule))
+
+  #····················································································································*
+
+  def printRules (self):
+    print (BOLD_BLUE () + "--- Print " + str (len (self.mRuleList)) + " rule" + ("s" if len (self.mRuleList) > 1 else "") + " ---" + ENDC ())
+    for rule in self.mRuleList:
+      message = ""
+      for s in rule.mTargets:
+        message += " \"" + s + "\""
+      print (BOLD_GREEN () + "Target:" + message +  ENDC ())
+      for dep in rule.mDependences:
+        print ("  Dependence: \"" + dep + "\"")
+      s = "  Command: "
+      for cmd in rule.mCommand:
+        s += " \"" + cmd + "\""
+      print (s)
+      print ("  Title: \"" + rule.mTitle + "\"")
+      print ("  Delete target on error: " + ("yes" if rule.mDeleteTargetOnError else "no"))
+      cleanOp = "none"
+      if rule.mCleanOperation == 1:
+        cleanOp = "delete target file(s)"
+      elif rule.mCleanOperation == 2:
+        dirSet = set ()
+        for s in rule.mTargets:
+          path = os.path.dirname (s)
+          if path != "":
+            dirSet.add (path)
+        cleanOp = "delete target directory:"
+        for s in dirSet:
+          cleanOp += " \"" + s + "\""
+      print ("  Clean operation: " + cleanOp)
+      index = 0
+      for postCommand in rule.mPostCommands:
+         index = index + 1
+         s = "  Post command " + str (index) + ": "
+         for cmd in postCommand.mCommand:
+           s += " \"" + cmd + "\""
+         print (s)
+         print ("    Title: \"" + postCommand.mTitle + "\"")
+
+    print (BOLD_BLUE () + "--- End of print rule ---" + ENDC ())
+
+  #····················································································································*
+
+  def writeRuleDependancesInDotFile (self, dotFileName):
+    s = "digraph G {\n"
+    s += "  node [fontname=courier]\n"
+    arrowSet = set ()
+    for rule in self.mRuleList:
+      for target in rule.mTargets:
+        s += '  "' + target + '" [shape=rectangle]\n'
+        for dep in rule.mDependences:
+          arrowSet.add ('  "' + target + '" -> "' + dep + '"\n')
+    for arrow in arrowSet:
+      s += arrow
+    s += "}\n"
+    f = open (dotFileName, "w")
+    f.write (s)
+    f.close ()
+
+  #····················································································································*
+
+  def checkRules (self):
+    if self.mErrorCount == 0:
+      ruleList = copy.deepcopy (self.mRuleList)
+      index = 0
+      looping = True
+    #--- loop on rules
+      while looping:
+        looping = False
+        while index < len (ruleList):
+          aRule = ruleList [index]
+          index = index + 1
+        #--- Check dependance files have rule for building, or does exist
+          depIdx = 0
+          while depIdx < len (aRule.mDependences):
+            dep = aRule.mDependences [depIdx]
+            depIdx = depIdx + 1
+            hasBuildRule = False
+            for r in ruleList:
+              for target in r.mTargets:
+                if dep == target:
+                  hasBuildRule = True
+                  break
+            if not hasBuildRule:
+              looping = True
+              if not os.path.exists (os.path.abspath (dep)):
+                self.mErrorCount = self.mErrorCount + 1
+                print (BOLD_RED () + "Check rules error: '" + dep + "' does not exist, and there is no rule for building it." + ENDC ())
+              depIdx = depIdx - 1
+              aRule.mDependences.pop (depIdx)
+        #--- Rule with no dependances
+          if len (aRule.mDependences) == 0 :
+            looping = True
+            index = index - 1
+            ruleList.pop (index)
+            idx = 0
+            while idx < len (ruleList):
+              r = ruleList [idx]
+              idx = idx + 1
+              for target in aRule.mTargets:
+                while r.mDependences.count (target) > 0 :
+                  r.mDependences.remove (target)
+    #--- Error if rules remain
+      if len (ruleList) > 0:
+        self.mErrorCount = self.mErrorCount + 1
+        print (BOLD_RED () + "Check rules error; circulary dependances between:" + ENDC ())
+        for aRule in ruleList:
+          targetList = ""
+          for target in aRule.mTargets:
+            targetList += " '" + aRule.mTarget + "'"
+          print (BOLD_RED () + "  - " + targetList + ", depends from:" + ENDC ())
+          for dep in aRule.mDependences:
+            print (BOLD_RED () + "      '" + dep + "'" + ENDC ())
+
+  #····················································································································*
+
+  def existsJobForTarget (self, target):
+    for job in self.mJobList:
+      for aTarget in job.mTargets:
+        if aTarget == target:
+          return True
+    return False
+
+  #····················································································································*
+
+  def makeJob (self, target): # Return a bool indicating wheither the target should be built
+  #--- If there are errors, return immediatly
+    if self.mErrorCount != 0:
+      return False
+  #--- Target already in job list ?
+    if self.existsJobForTarget (target):
+      return True # yes, return target will be built
+  #--- Find a rule for making the target
+    absTarget = os.path.abspath (target)
+    rule = None
+    matchCount = 0
+    for r in self.mRuleList:
+      for aTarget in r.mTargets:
+        if target == aTarget:
+          matchCount = matchCount + 1
+          rule = r
+    if matchCount == 0:
+      absTarget = os.path.abspath (target)
+      if not os.path.exists (absTarget):
+        print (BOLD_RED () + "No rule for making '" + target + "'" + ENDC ())
+        self.mErrorCount = self.mErrorCount + 1
+      return False # Error or target exists, and no rule for building it
+    elif matchCount > 1:
+      print (BOLD_RED () + str (matchCount) + " rules for making '" + target + "'" + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+      return False # Error
+  #--- Target file does not exist, and 'rule' variable indicates how build it
+    appendToJobList = not os.path.exists (absTarget)
+  #--- Build primary dependences
+    jobDependenceFiles = []
+    for dependence in rule.mDependences:
+      willBeBuilt = self.makeJob (dependence)
+      if willBeBuilt:
+        jobDependenceFiles.append (dependence)
+        appendToJobList = True
+  #--- Check primary file modification dates
+    if not appendToJobList:
+      targetDateModification = os.path.getmtime (absTarget)
+      for source in rule.mDependences:
+        sourceDateModification = os.path.getmtime (source)
+        if targetDateModification < sourceDateModification:
+          appendToJobList = True
+          break
+  #--- Check for secondary dependancy files
+    if not appendToJobList:
+      targetDateModification = os.path.getmtime (absTarget)
+      if targetDateModification < rule.mSecondaryMostRecentModificationDate:
+        appendToJobList = True
+  #--- Append to job list
+    if appendToJobList:
+      self.mJobList.append (Job (
+        rule.mTargets,
+        jobDependenceFiles,
+        rule.mCommand,
+        rule.mPostCommands,
+        rule.mPriority,
+        rule.mTitle,
+        rule.mOpenSourceOnError,
+        self.mLogUtilityTool
+      ))
+  #--- Return
+    return appendToJobList
+
+  #····················································································································*
+  #Job state
+  # 0: waiting
+  # 1:running
+  # 2: waiting for executing post command
+  # 3:executing for executing post command
+  # 4: completed
+
+  def runJobs (self, maxConcurrentJobs, showCommand):
+    if self.mErrorCount == 0:
+      if len (self.mJobList) == 0:
+        print (BOLD_BLUE () + "Nothing to make." + ENDC ())
+      else:
+      #--- Sort jobs following their priorities
+        self.mJobList = sorted (self.mJobList, key=operator.attrgetter("mPriority"), reverse=True)
+      #--- Run
+        if maxConcurrentJobs <= 0:
+          maxConcurrentJobs = processorCount () - maxConcurrentJobs
+        jobCount = 0 ;
+        terminationSemaphore = threading.Semaphore (0)
+        displayLock = threading.Lock ()
+        loop = True
+        returnCode = 0
+        totalJobCount = float (len (self.mJobList))
+        launchedJobCount = 0.0
+        while loop:
+        #--- Launch jobs in parallel
+          for job in self.mJobList:
+            if (returnCode == 0) and (jobCount < maxConcurrentJobs):
+              if (job.mState == 0) and (len (job.mRequiredFiles) == 0):
+                #--- Create target directory if does not exist
+                for aTarget in job.mTargets:
+                  absTargetDirectory = os.path.dirname (os.path.abspath (aTarget))
+                  if not os.path.exists (absTargetDirectory):
+                    displayLock.acquire ()
+                    runCommand (
+                      ["mkdir", "-p", os.path.dirname (aTarget)], "Making \"" + os.path.dirname (aTarget) + "\" directory",
+                      showCommand,
+                      job.mLogUtilityTool
+                    )
+                    displayLock.release ()
+                #--- Progress string
+                launchedJobCount += 1.0
+                if self.mShowProgressString:
+                  progressString = "[{0:3d}%] ".format (int (100.0 * launchedJobCount / totalJobCount))
+                else:
+                  progressString = ""
+                #--- Run job
+                job.run (displayLock, terminationSemaphore, showCommand, progressString)
+                jobCount = jobCount + 1
+                job.mState = 1 # Means is running
+              elif job.mState == 2: # Waiting for executing post command
+                job.mReturnCode = None # Means post command not terminated
+                job.runPostCommand (displayLock, terminationSemaphore, showCommand)
+                jobCount = jobCount + 1
+                job.mState = 3 # Means post command is running
+        #--- Wait for a job termination
+          #print ("wait " + str (jobCount) + " " + str (len (self.mJobList)))
+          terminationSemaphore.acquire ()
+        #--- Checks for terminated jobs
+          index = 0
+          while index < len (self.mJobList):
+            job = self.mJobList [index]
+            index = index + 1
+            if (job.mState == 1) and (job.mReturnCode != None) and (job.mReturnCode == 0) : # Terminated without error
+              jobCount = jobCount - 1
+              for aTarget in job.mTargets:
+                if not os.path.exists (os.path.abspath (aTarget)): # Warning: target does not exist
+                  displayLock.acquire ()
+                  print (MAGENTA () + BOLD () + "Warning: target \"" + aTarget + "\" was not created by rule execution." + ENDC ())
+                  displayLock.release ()
+              if len (job.mPostCommands) > 0:
+                job.mState = 2 # Ready to execute next post command
+              else:
+                job.mState = 4 # Completed
+                index = index - 1 # For removing job from list
+            elif (job.mState == 1) and (job.mReturnCode != None) and (job.mReturnCode > 0) : # terminated with error : exit
+              jobCount = jobCount - 1
+              job.mState = 4 # Means Terminated
+              index = index - 1 # For removing job from list
+              if job.mOpenSourceOnError:
+                for line in job.mOutputLines:
+                  components = line.split (':')
+                  if (len (components) > 1) and os.path.exists (os.path.abspath (components [0])) :
+                    if sys.platform == "darwin":
+                      os.system ("open -a \"" + self.mMacTextEditor + "\" \"" + components [0] + "\"")
+                    elif sys.platform == "linux2":
+                      os.system ("\"" + self.mLinuxTextEditor + "\" \"" + components [0] + "\"")
+            elif (job.mState == 3) and (job.mReturnCode == 0): # post command is terminated without error
+              jobCount = jobCount - 1
+              job.mPostCommands.pop (0) # Remove completed post command
+              if len (job.mPostCommands) > 0:
+                job.mState = 2 # Ready to execute next post command
+              else:
+                job.mState = 4 # Completed
+                index = index - 1 # For removing job from list
+            elif (job.mState == 3) and (job.mReturnCode > 0): # post command is terminated with error
+              jobCount = jobCount - 1
+              job.mState = 4 # Completed
+              index = index - 1 # For removing job from list
+            elif job.mState == 4: # Completed: delete job
+              index = index - 1
+              self.mJobList.pop (index) # Remove terminated job
+              #displayLock.acquire ()
+              #print ("Completed '" + job.mTitle + "'")
+              #--- Remove dependences from this job
+              idx = 0
+              while idx < len (self.mJobList):
+                aJob = self.mJobList [idx]
+                idx = idx + 1
+                for aTarget in job.mTargets:
+                  while aJob.mRequiredFiles.count (aTarget) > 0 :
+                    aJob.mRequiredFiles.remove (aTarget)
+                  #print ("  Removed from '" + aJob.mTitle + "': " + str (len (aJob.mRequiredFiles)))
+              #displayLock.release ()
+              #--- Signal error ?
+              if (job.mReturnCode > 0) and (returnCode == 0):
+                self.mErrorCount = self.mErrorCount + 1
+                print (BOLD_RED () + "Return code: " + str (job.mReturnCode) + ENDC ())
+                if (returnCode == 0) and (jobCount > 0) :
+                  print ("Wait for job termination...")
+                returnCode = job.mReturnCode
+          loop = (len (self.mJobList) > 0) if (returnCode == 0) else (jobCount > 0)
+
+  #····················································································································*
+
+  def searchFileInRelativeDirectories (self, file, directoryList): # returns "" if not found, register error
+    matchCount = 0
+    result = ""
+    for sourceDir in directoryList:
+      sourcePath = sourceDir + "/" + file
+      if os.path.exists (os.path.abspath (sourcePath)):
+        matchCount = matchCount + 1
+        prefix = os.path.commonprefix ([os.getcwd (), sourcePath])
+        result = sourcePath [len (prefix):]
+        if result [0] == '/' :
+          result = result [1:]
+    if matchCount == 0:
+      print (BOLD_RED () + "Cannot find '" + file + "'" + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+    elif matchCount > 1:
+      print (BOLD_RED () + str (matchCount) + " source files for making '" + file + "'" + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+      result = ""
+    return result
+
+  #····················································································································*
+
+  def searchFileInDirectories (self, file, directoryList): # returns "" if not found, register error
+    matchCount = 0
+    result = ""
+    for sourceDir in directoryList:
+      sourcePath = sourceDir + "/" + file
+      if os.path.exists (os.path.abspath (sourcePath)):
+        matchCount = matchCount + 1
+        result = sourcePath
+    if matchCount == 0:
+      print (BOLD_RED () + "Cannot find '" + file + "'" + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+    elif matchCount > 1:
+      print (BOLD_RED () + str (matchCount) + " source files for making '" + file + "'" + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+      result = ""
+    return result
+
+  #····················································································································*
+
+  def addGoal (self, goal, targetList, message):
+    if not argumentIsString (goal):
+      print (BOLD_RED () + "*** Make.addGoal: 'goal' first argument is not a string ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    if not type (targetList) is list:
+      print (BOLD_RED () + "*** Make.addGoal: 'targetList' second argument is not a list ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    else:
+      for aTarget in targetList:
+        if not argumentIsString (aTarget):
+          print (BOLD_RED () + "*** Make.addGoal: an element of 'targetList' second argument 'targets' is not a string ***" + ENDC ())
+          traceback.print_stack ()
+          sys.exit (1)
+    if not argumentIsString (message):
+      print (BOLD_RED () + "*** Make.addGoal: 'message' third argument is not a string ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    if (goal in self.mGoals) or (goal == "clean") :
+      self.enterError ("The '" + goal + "' goal is already defined")
+    else:
+      self.mGoals [goal] = (targetList, message)
+    #print ('%s' % ', '.join(map(str, self.mGoals)))
+
+  #····················································································································*
+
+  def printGoals (self):
+    print (BOLD_BLUE () + "--- Print " + str (len (self.mGoals)) + " goal" + ("s" if len (self.mGoals) > 1 else "") + " ---" + ENDC ())
+    for goalKey in self.mGoals.keys ():
+      print (BOLD_GREEN () + "Goal: \"" + goalKey + "\"" + ENDC ())
+      (targetList, message) = self.mGoals [goalKey]
+      for target in targetList:
+        print ("  Target: \"" + target + "\"")
+      print ("  Message: \"" + message + "\"")
+
+    print (BOLD_BLUE () + "--- End of print goals ---" + ENDC ())
+
+  #····················································································································*
+
+  def runGoal (self, maxConcurrentJobs, showCommand):
+    if not isinstance (maxConcurrentJobs, int):
+      print (BOLD_RED () + "*** Make.runGoal: 'maxConcurrentJobs' first argument is not an integer ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    if not isinstance (showCommand, bool):
+      print (BOLD_RED () + "*** Make.runGoal: 'showCommand' second argument is not a boolean ***" + ENDC ())
+      traceback.print_stack ()
+      sys.exit (1)
+    if self.mSelectedGoal in self.mGoals :
+      (targetList, message) = self.mGoals [self.mSelectedGoal]
+      for target in targetList:
+        self.makeJob (target)
+      self.runJobs (maxConcurrentJobs, showCommand)
+      if self.mErrorCount > 0:
+        for rule in self.mRuleList:
+          for aTarget in rule.mTargets:
+            if rule.mDeleteTargetOnError and os.path.exists (os.path.abspath (aTarget)):
+              runCommand (["rm", aTarget], "Delete \"" + aTarget + "\" on error", showCommand, self.mLogUtilityTool)
+    elif self.mSelectedGoal == "clean" :
+      filesToRemoveList = []
+      directoriesToRemoveSet = set ()
+      for rule in self.mRuleList:
+        if rule.mCleanOperation == 1: # Delete target
+          for aTarget in rule.mTargets:
+            filesToRemoveList.append (aTarget)
+        elif rule.mCleanOperation == 2: # Delete target directories
+          for aTarget in rule.mTargets:
+            dirPath = os.path.dirname (aTarget)
+            if dirPath == "":
+              filesToRemoveList.append (aTarget)
+            else:
+              directoriesToRemoveSet.add (dirPath)
+      for dir in directoriesToRemoveSet:
+        if os.path.exists (os.path.abspath (dir)):
+          if self.mSimulateClean:
+            print (MAGENTA () + BOLD () + "Simulated clean command: " + ENDC () + "rm -fr '" + dir + "'")
+          else:
+            runCommand (["rm", "-fr", dir], "Removing \"" + dir + "\"", showCommand, self.mLogUtilityTool)
+      for file in filesToRemoveList:
+        if os.path.exists (os.path.abspath (file)):
+          if self.mSimulateClean:
+            print (MAGENTA () + BOLD () + "Simulated clean command: " + ENDC () + "rm -f '" + file + "'")
+          else:
+            runCommand (["rm", "-f", file], "Deleting \"" + file + "\"", showCommand, self.mLogUtilityTool)
+    else:
+      errorMessage = "The '" + self.mSelectedGoal + "' goal is not defined; defined goals:"
+      for key in self.mGoals:
+        (targetList, message) = self.mGoals [key]
+        errorMessage += "\n  '" + key + "': " + message
+      print (BOLD_RED () + errorMessage + ENDC ())
+      self.mErrorCount = self.mErrorCount + 1
+
+  #····················································································································*
+
+  def simulateClean (self):
+    self.mSimulateClean = True
+
+  #····················································································································*
+
+  def enterError (self, message):
+    print (BOLD_RED () + message + ENDC ())
+    self.mErrorCount = self.mErrorCount + 1
+
+  #····················································································································*
+
+  def printErrorCountAndExitOnError (self):
+    if self.mErrorCount == 1:
+      print (BOLD_RED () + "1 error." + ENDC ())
+      sys.exit (1)
+    elif self.mErrorCount > 1:
+      print (BOLD_RED () + str (self.mErrorCount) + " errors." + ENDC ())
+      sys.exit (1)
+
+  #····················································································································*
+
+  def printErrorCount (self):
+    if self.mErrorCount == 1:
+      print (BOLD_RED () + "1 error." + ENDC ())
+    elif self.mErrorCount > 1:
+      print (BOLD_RED () + str (self.mErrorCount) + " errors." + ENDC ())
+
+  #····················································································································*
+
+  def errorCount (self):
+    return self.mErrorCount
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*

+ 18 - 0
dev-files/objdump.py.txt

@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["$OBJDUMP$", "-S", "$SOURCE$.o"])
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 169 - 0
dev-files/teensy-3-6.ld

@@ -0,0 +1,169 @@
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                                   Memory                                                                           */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+MEMORY {
+  flash (rx) : ORIGIN = 0, LENGTH = 1024k
+  sram_low  (rwx) : ORIGIN = 0x1FFF0000, LENGTH = 64k
+  sram_high (rwx) : ORIGIN = 0x20000000, LENGTH = 192k
+}
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                             Discarded sections                                                                     */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+SECTIONS {
+  /DISCARD/ : {
+    *(.gnu.*) ;
+    *(.glue_7t);
+    *(.glue_7);
+    *(.ARM.*);
+    *(.comment);
+    *(.debug_frame);
+    *(.vfp11_veneer);
+    *(.v4_bx);
+    *(.iplt);
+    *(.rel.*);
+    *(.igot.plt);
+    *(rel.ARM.*);
+  }
+}
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                                Code                                                                                */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+SECTIONS {
+  .text : {
+  /*-------------------- Vectors */
+    __vectors_start = . ;
+    KEEP (*(isr.vectors)) ;
+    __vectors_end = . ;
+  /*-------------------- Flash magic values */
+    LONG (-1) ;
+    LONG (-1) ;
+    LONG (-1) ;
+    LONG (-2) ;
+  /*-------------------- Code */
+    __code_start = . ;
+    . = ALIGN(4) ;
+    *(.text*) ;
+    *(.text) ;
+    *(text) ;
+  /*-------------------- Boot routine array */
+    . = ALIGN (4) ;
+    __boot_routine_array_start = . ;
+    KEEP (*(boot.routine.array)) ;
+    . = ALIGN (4) ;
+    __boot_routine_array_end = . ;
+  /*-------------------- Global C++ object constructor call */
+    . = ALIGN (4) ;
+    __constructor_array_start = . ;
+    KEEP (*(.init_array)) ;
+    . = ALIGN (4) ;
+    __constructor_array_end = . ;
+  /*-------------------- Init routine array */
+    . = ALIGN (4) ;
+    __init_routine_array_start = . ;
+    KEEP (*(init.routine.array)) ;
+    . = ALIGN (4) ;
+    __init_routine_array_end = . ;
+  /*-------------------- Real time interrupt routine array */
+    . = ALIGN (4) ;
+    __real_time_interrupt_routine_array_start = . ;
+    KEEP (*(real.time.interrupt.routine.array)) ;
+    . = ALIGN (4) ;
+    __real_time_interrupt_routine_array_end = . ;
+  /*-------------------- ROM data */
+    . = ALIGN(4);
+    *(.rodata*);
+    . = ALIGN(4);
+  /*-------------------- End */
+    __code_end = . ;
+  } > flash
+}
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                          BSS (uninitialized data)                                                                  */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+SECTIONS {
+  .bss : {
+    . = ALIGN(4);
+    __bss_start = . ;
+    * (.bss*) ;
+    . = ALIGN(4);
+    * (COMMON) ;
+    . = ALIGN(4);
+    __bss_end = . ;
+  } > sram_low
+}
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                          Data (initialized data)                                                                   */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+SECTIONS {
+  .data : AT (__code_end) {
+    . = ALIGN (4) ;
+    __data_start = . ;
+    * (.data*) ;
+  /*-------------------- Teensy CAN 0 receive ports */
+    . = ALIGN (4) ;
+    __teensy_can0_receive_ports_array_start = . ;
+    * (teensy.CAN0.receive.ports.section) ;
+    . = ALIGN (4) ;
+    __teensy_can0_receive_ports_array_end = . ;
+  /*-------------------- Teensy CAN 1 receive ports */
+    . = ALIGN (4) ;
+    __teensy_can1_receive_ports_array_start = . ;
+    * (teensy.CAN1.receive.ports.section) ;
+    . = ALIGN (4) ;
+    __teensy_can1_receive_ports_array_end = . ;
+    . = ALIGN (4) ;
+    __data_end = . ;
+  } > sram_low
+}
+
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+__data_load_start = LOADADDR (.data) ;
+__data_load_end   = LOADADDR (.data) + SIZEOF (.data) ;
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                                System stack                                                                        */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+SECTIONS {
+  .system_stack :{
+    . = ALIGN (8) ;
+    __system_stack_start = . ;
+    . += 1024 ;
+    . = ALIGN (4) ;
+    __system_stack_end = . ;
+  } > sram_low
+}
+
+/*--------------------------------------------------------------------------------------------------------------------*/
+/*                                                                                                                    */
+/*                                    Heap                                                                            */
+/*                                                                                                                    */
+/*--------------------------------------------------------------------------------------------------------------------*/
+
+__heap_start = ORIGIN (sram_high) ;
+__heap_end = ORIGIN(sram_high) + LENGTH(sram_high) ;
+
+/*--------------------------------------------------------------------------------------------------------------------*/

+ 90 - 0
dev-files/teensy_cli_loader_builder.py

@@ -0,0 +1,90 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import os, urllib, subprocess, sys
+
+import archive_directory
+import dev_platform
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   Source file name                                                                                                   *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def fileBaseName () :
+  return "teensy_loader_cli"
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   FOR PRINTING IN COLOR                                                                                              *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+class bcolors:
+    HEADER = '\033[95m'
+    BLUE = '\033[94m'
+    GREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+    BOLD_BLUE = '\033[1m' + '\033[94m'
+    BOLD_GREEN = '\033[1m' + '\033[92m'
+    BOLD_RED = '\033[1m' + '\033[91m'
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   runCommand                                                                                                         *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def runCommand (cmd) :
+  str = "+"
+  for s in cmd:
+    str += " " + s
+  print (bcolors.BOLD_BLUE + str + bcolors.ENDC)
+  returncode = subprocess.call (cmd)
+  if returncode != 0 :
+    sys.exit (returncode)
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#  Install Teensy CLI Loader                                                                                           *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def installTeensyCLILoader (INSTALL_PATH) :
+  print (bcolors.BOLD_GREEN + "Install Teensy CLI Loader..." + bcolors.ENDC)
+  CURRENT_DIR = os.path.abspath (os.path.dirname (__file__))
+  PLATFORM = dev_platform.getPlatform ()
+  #------------------------------------------------------------------ Compile command
+  COMPILE_COMMAND = [
+    "gcc",
+    "-O2",
+    "-fomit-frame-pointer",
+    CURRENT_DIR + "/" + fileBaseName () + ".c",
+    "-o", INSTALL_PATH
+  ]
+  if PLATFORM == "mac" :
+    COMPILE_COMMAND += [
+      "-DUSE_APPLE_IOKIT",
+      "-framework", "Foundation",
+      "-framework", "IOKit",
+    ]
+  elif PLATFORM == "linux" :
+    COMPILE_COMMAND += ["-DUSE_LIBUSB", "-lusb"]
+  elif PLATFORM == "linux32" :
+    COMPILE_COMMAND += ["-DUSE_LIBUSB", "-lusb"]
+  #------------------------------------------------------------------ Compile
+  runCommand (COMPILE_COMMAND)
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   TOOL PATH                                                                                                          *
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def buildAndGetPath (TOOL_DIR) :
+  path = TOOL_DIR + "/" + fileBaseName ()
+#--- Install tool ?
+  if not os.path.exists (path) :
+    installTeensyCLILoader (path)
+#--- Return tool path
+  return path
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+

ファイルの差分が大きいため隠しています
+ 1183 - 0
dev-files/teensy_loader_cli.c


+ 23 - 0
dev-files/tool_directory.py

@@ -0,0 +1,23 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import os, urllib, subprocess, sys
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+import archive_directory
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+#   GET TOOL DIRECTORY
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+
+def toolDirectory () :
+#--- Absolute path of tool directory
+  DIRECTORY = os.path.expanduser ("~/treel-tools")
+#--- Return tool directory
+  return DIRECTORY
+
+#——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
+

+ 87 - 0
dev-files/udev_on_linux.py

@@ -0,0 +1,87 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#-----------------------------------------------------------------------------*
+
+import subprocess, sys, os, filecmp
+
+#-----------------------------------------------------------------------------*
+#   FOR PRINTING IN COLOR                                                     *
+#-----------------------------------------------------------------------------*
+
+class bcolors:
+    HEADER = '\033[95m'
+    BLUE = '\033[94m'
+    GREEN = '\033[92m'
+    WARNING = '\033[93m'
+    FAIL = '\033[91m'
+    ENDC = '\033[0m'
+    BOLD = '\033[1m'
+    UNDERLINE = '\033[4m'
+    BOLD_BLUE = '\033[1m' + '\033[94m'
+    BOLD_GREEN = '\033[1m' + '\033[92m'
+    BOLD_RED = '\033[1m' + '\033[91m'
+
+#-----------------------------------------------------------------------------*
+#   runCommand                                                                *
+#-----------------------------------------------------------------------------*
+
+def runCommand (cmd) :
+  str = "+"
+  for s in cmd:
+    str += " " + s
+  print (bcolors.BOLD_BLUE + str + bcolors.ENDC)
+  returncode = subprocess.call (cmd)
+  if returncode != 0 :
+    sys.exit (returncode)
+
+#-----------------------------------------------------------------------------*
+
+def udevPath ():
+  return "/etc/udev/rules.d"
+
+#-----------------------------------------------------------------------------*
+
+def udevFileForTeensy ():
+  return "49-teensy.rules"
+
+#-----------------------------------------------------------------------------*
+#   MAIN                                                                      *
+#-----------------------------------------------------------------------------*
+
+def installUDEVrulesOnLinux ():
+#------------------------------------------------------------------ Machine
+  (SYSTEM_NAME, MODE_NAME, RELEASE, VERSION, MACHINE) = os.uname ()
+  if SYSTEM_NAME != "Linux" :
+    print (bcolors.BOLD_RED + "This script is available only for Linux" + bcolors.ENDC)
+    sys.exit (1)
+#------------------------------------------------------------------ Get script absolute path
+  scriptDir = os.path.dirname (os.path.abspath (__file__))
+#------------------------------------------------------------------ Install udev file for Teensy
+  if not os.path.exists (udevPath () + "/" + udevFileForTeensy ()) :
+    runCommand (["sudo", "cp", scriptDir + "/" + udevFileForTeensy (), udevPath () + "/" + udevFileForTeensy ()])
+    runCommand (["sudo", "udevadm", "trigger"])
+  elif not filecmp.cmp (scriptDir + "/" + udevFileForTeensy (), udevPath () + "/" + udevFileForTeensy ()) :
+    runCommand (["sudo", "cp", scriptDir + "/" + udevFileForTeensy (), udevPath () + "/" + udevFileForTeensy ()])
+    runCommand (["sudo", "udevadm", "trigger"])
+#---
+
+#-----------------------------------------------------------------------------*
+#   MAIN                                                                      *
+#-----------------------------------------------------------------------------*
+
+def uninstallUDEVrulesOnLinux ():
+#------------------------------------------------------------------ Machine
+  (SYSTEM_NAME, MODE_NAME, RELEASE, VERSION, MACHINE) = os.uname ()
+  if SYSTEM_NAME != "Linux" :
+    print (bcolors.BOLD_RED + "This script is available only for Linux" + bcolors.ENDC)
+    sys.exit (1)
+#------------------------------------------------------------------ Uninstall
+  if os.path.exists (udevPath () + "/" + udevFileForTeensy ()) :
+    runCommand (["sudo", "rm", udevPath () + "/" + udevFileForTeensy ()])
+#------------------------------------------------------------------ Uninstall
+  if os.path.exists (udevPath () + "/" + udevFileForOpenOCD ()) :
+    runCommand (["sudo", "rm", udevPath () + "/" + udevFileForOpenOCD ()])
+
+#-----------------------------------------------------------------------------*
+

+ 52 - 0
dev-files/view-hex.py

@@ -0,0 +1,52 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+#  From: https://github.com/msolters/intel-hex-viewer
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys
+
+def parse_hex_line( line ):
+    if len( current_line ) == 0: return
+    bytecount = int( line[0:2], 16 )
+    address = int( line[2:6], 16 )
+    rec_type = int( line[6:8], 16 )
+
+    rec_output = str(hex(address)) + '\t(' + str(bytecount) + ')\t'
+    if rec_type == 0:
+        rec_output += '(data)'
+        rec_output += '\t\t' + line[8:(8+2*(bytecount))]
+    elif rec_type == 1:
+        rec_output += '(end of file)'
+    elif rec_type == 2:
+        rec_output += '(extended segment address)'
+    elif rec_type == 3:
+        rec_output += '(start segment address)'
+    elif rec_type == 4:
+        rec_output += '(extended linear address)'
+    elif rec_type == 5:
+        rec_output += '(start linear address)'
+    print (rec_output)
+
+#   (1) Open the Hex File
+hex_file_path = sys.argv[1]
+print ("Parsing " + hex_file_path)
+hex_file = open(hex_file_path, "rb")
+
+#   (2) Analyze the hex file line by line
+current_line = ""
+try:
+    byte = "1" # initial placeholder
+    while byte != "":
+        byte = hex_file.read(1)
+        if byte == ":":
+            #   (1) Parse the current line!
+            parse_hex_line( current_line )
+            #   (2) Reset the current line to build the next one!
+            current_line = ""
+        else:
+            current_line += byte
+    parse_hex_line( current_line )
+finally:
+    hex_file.close()

+ 23 - 0
steps/-build-all.py

@@ -0,0 +1,23 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#------------------------------------------------------------------------------*
+# https://docs.python.org/2/library/subprocess.html#module-subprocess
+
+import subprocess
+import sys
+import os
+
+#------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+#--- Enumerate directories
+for name in os.listdir (scriptDir):
+   fname = os.path.join (scriptDir, name, "1-build.py")
+   if os.path.isfile (fname) :
+     returncode = subprocess.call ([fname])
+     if returncode != 0 :
+       sys.exit (returncode)
+
+#------------------------------------------------------------------------------*

+ 23 - 0
steps/-clean-all.py

@@ -0,0 +1,23 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#------------------------------------------------------------------------------*
+# https://docs.python.org/2/library/subprocess.html#module-subprocess
+
+import subprocess
+import sys
+import os
+
+#------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+#--- Enumerate directories
+for name in os.listdir (scriptDir):
+   fname = os.path.join (scriptDir, name, "clean.py")
+   if os.path.isfile (fname) :
+     returncode = subprocess.call ([fname])
+     if returncode != 0 :
+       sys.exit (returncode)
+
+#------------------------------------------------------------------------------*

+ 19 - 0
steps/01-blink-led/1-build-as.py

@@ -0,0 +1,19 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["python", "1-build.py", "as", "0"])
+#--- Wait for subprocess termination
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 30 - 0
steps/01-blink-led/1-build.py

@@ -0,0 +1,30 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, json
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#----------------------------------------------------------------- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#----------------------------------------------------------------- Get max parallel jobs as first argument
+goal = "all"
+if len (sys.argv) > 1 :
+  goal = sys.argv [1]
+#----------------------------------------------------------------- Get max parallel jobs as first argument
+maxParallelJobs = 0 # 0 means use host processor count
+if len (sys.argv) > 2 :
+  maxParallelJobs = int (sys.argv [2])
+#----------------------------------------------------------------- Build
+jsonFilePath = os.path.abspath (scriptDir + "/makefile.json")
+f = open (jsonFilePath, "r")
+dictionary = json.loads (f.read ())
+f.close ()
+sys.path.append (scriptDir + "/../../dev-files")
+import code_builder
+code_builder.buildCode (goal, scriptDir, maxParallelJobs, maxParallelJobs == 1)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 18 - 0
steps/01-blink-led/1-verbose-build.py

@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["python", "1-build.py", "all", "1"])
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 18 - 0
steps/01-blink-led/2-flash-via-usb.py

@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["python", "1-build.py", "run"])
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 18 - 0
steps/01-blink-led/2-hex-viewer.py

@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["python", "1-build.py", "view-hex"])
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 32 - 0
steps/01-blink-led/clean.py

@@ -0,0 +1,32 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, shutil
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#----------------------------------------------------------------- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+#----------------------------------------------------------------- Import common definitions
+pythonScriptDir = scriptDir + "/../../dev-files"
+sys.path.append (pythonScriptDir)
+import common_definitions
+#-----------------------------------------------------------------
+GENERATED_SOURCE_DIR = scriptDir + "/" + common_definitions.generatedSourceDirectory ()
+if os.path.exists (GENERATED_SOURCE_DIR):
+  shutil.rmtree (GENERATED_SOURCE_DIR)
+BUILD_DIR = scriptDir + "/" + common_definitions.buildDirectory ()
+if os.path.exists (BUILD_DIR):
+  shutil.rmtree (BUILD_DIR)
+PRODUCT_DIR = scriptDir + "/" + common_definitions.productDirectory ()
+if os.path.exists (PRODUCT_DIR):
+  shutil.rmtree (PRODUCT_DIR)
+AS_DIR = scriptDir + "/" + common_definitions.asDirectory ()
+if os.path.exists (AS_DIR):
+  shutil.rmtree (AS_DIR)
+#---
+print ("Cleaning " + os.path.basename (scriptDir) + " done")
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 18 - 0
steps/01-blink-led/display-obj-size.py

@@ -0,0 +1,18 @@
+#! /usr/bin/env python
+# -*- coding: UTF-8 -*-
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+import sys, os, subprocess
+
+#----------------------------------------------------------------------------------------------------------------------*
+
+#--- Get script absolute path
+scriptDir = os.path.dirname (os.path.abspath (sys.argv [0]))
+os.chdir (scriptDir)
+#---
+returncode = subprocess.call (["python", "1-build.py", "display-obj-size", "1"])
+if returncode != 0 :
+  sys.exit (returncode)
+
+#----------------------------------------------------------------------------------------------------------------------*

+ 6 - 0
steps/01-blink-led/makefile.json

@@ -0,0 +1,6 @@
+{ "SOURCE-DIR" : ["sources"],
+
+  "TEENSY" : "3.6",
+
+  "CPU-MHZ" : 180
+}

+ 800 - 0
steps/01-blink-led/sources/cortex-m4-control-registers.h

@@ -0,0 +1,800 @@
+#pragma once
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#include <stdint.h>
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral NVIC
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- Interrupt Set-Enable Registers (idx = 0 ... 7)
+#define NVIC_ISER(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x00 + 4 * (idx))))
+
+//-------------------- Interrupt Clear-Enable Registers (idx = 0 ... 7)
+#define NVIC_ICER(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x80 + 4 * (idx))))
+
+//-------------------- Interrupt Set-Pending Registers (idx = 0 ... 7)
+#define NVIC_ISPR(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x100 + 4 * (idx))))
+
+//-------------------- Interrupt Clear-Pending Registers (idx = 0 ... 7)
+#define NVIC_ICPR(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x180 + 4 * (idx))))
+
+//-------------------- Interrupt Active Bit Register (idx = 0 ... 7)
+#define NVIC_IABR(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x200 + 4 * (idx))))
+
+//-------------------- Interrupt Priority Register (idx = 0 ... 59)
+#define NVIC_IPR(idx) (* ((const volatile uint32_t *) (0xE000E100 + 0x300 + 4 * (idx))))
+
+//-------------------- Software Trigger Interrupt Register
+#define NVIC_STIR (* ((volatile uint32_t *) (0xE000E100 + 0xE00)))
+
+  // Field (width: 9 bits): Interrupt ID of the interrupt to trigger, in the range 0-239.
+    inline uint32_t NVIC_STIR_INTID (const uint32_t inValue) { return (inValue & 511) << 0 ; }
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral SCB
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- Auxiliary Control Register
+#define SCB_ACTLR (* ((volatile uint32_t *) (0xE000E000 + 0x8)))
+
+  // Boolean field: Disables Interruption Folding
+    static const uint32_t SCB_ACTLR_DISFOLD = 1U << 2 ;
+
+  // Boolean field: Disabled FPU exception outputs
+    static const uint32_t SCB_ACTLR_PFEXCODIS = 1U << 10 ;
+
+  // Boolean field: Disables dynamic read allocate mode for Write-Back Write-Allocate memory regions:
+    static const uint32_t SCB_ACTLR_DISRAMODE = 1U << 11 ;
+
+  // Boolean field: Disables ITM and DWT ATB flush:
+    static const uint32_t SCB_ACTLR_DISITMATBFLUSH = 1U << 12 ;
+
+  // Boolean field: Disables the Branch Target Address Cache (BTAC).
+    static const uint32_t SCB_ACTLR_DISBTACREAD = 1U << 13 ;
+
+  // Boolean field: Disables the Branch Target Address Cache allocation.
+    static const uint32_t SCB_ACTLR_DISBTACALLOC = 1U << 14 ;
+
+  // Boolean field: Disables critical AXI Read-Under-Read.
+    static const uint32_t SCB_ACTLR_DISCRITAXIRUR = 1U << 15 ;
+
+  // Boolean field: Disables dual-issued direct branches.
+    static const uint32_t SCB_ACTLR_DISDI_DB = 1U << 16 ;
+
+  // Boolean field: Disables dual-issued indirect branches.
+    static const uint32_t SCB_ACTLR_DISDI_IB = 1U << 17 ;
+
+  // Boolean field: Disables dual-issued loads to PC.
+    static const uint32_t SCB_ACTLR_DISDI_LPC = 1U << 18 ;
+
+  // Boolean field: Disables integer MAC and MUL dual-issued instructions.
+    static const uint32_t SCB_ACTLR_DISDI_MAC_MUL = 1U << 19 ;
+
+  // Boolean field: Disables VFP dual-issued instruction.
+    static const uint32_t SCB_ACTLR_DISDI_VFP = 1U << 20 ;
+
+  // Boolean field: Disables direct branches instructions in channel 1.
+    static const uint32_t SCB_ACTLR_DISISSCH1_DB = 1U << 21 ;
+
+  // Boolean field: Disables indirect branches instructions in channel 1.
+    static const uint32_t SCB_ACTLR_DISISSCH1_IB = 1U << 22 ;
+
+  // Boolean field: Disables loads to PC instructions in channel 1.
+    static const uint32_t SCB_ACTLR_DISISSCH1_LPC = 1U << 23 ;
+
+  // Boolean field: Disables integer MAC and MUL instructions in channel 1.
+    static const uint32_t SCB_ACTLR_DISISSCH1_MAC_MUL = 1U << 24 ;
+
+  // Boolean field: Disables VFP instructions in channel 1
+    static const uint32_t SCB_ACTLR_DISISSCH1_VFP = 1U << 25 ;
+
+  // Boolean field: Disables dynamic allocation of ADD and SUB instructions:
+    static const uint32_t SCB_ACTLR_DISDYNADD = 1U << 26 ;
+
+//-------------------- CPUID Base Register
+#define SCB_CPUID (* ((const volatile uint32_t *) (0xE000E000 + 0xD00)))
+
+  // Field (width: 4 bits): Revision number, the p value in the rnpn product revision identifier.
+    inline uint32_t SCB_CPUID_Revision (const uint32_t inValue) { return (inValue & 15) << 0 ; }
+
+  // Field (width: 12 bits): Part number of the processor.
+    inline uint32_t SCB_CPUID_PartNo (const uint32_t inValue) { return (inValue & 4095) << 4 ; }
+
+  // Field (width: 4 bits): Reads as 0xF.
+    inline uint32_t SCB_CPUID_Constant (const uint32_t inValue) { return (inValue & 15) << 16 ; }
+
+  // Field (width: 4 bits): Variant number, the r value in the rnpn product revision identifier.
+    inline uint32_t SCB_CPUID_Variant (const uint32_t inValue) { return (inValue & 15) << 20 ; }
+
+  // Field (width: 8 bits): Implementer code.
+    inline uint32_t SCB_CPUID_Implementer (const uint32_t inValue) { return (inValue & 255) << 24 ; }
+
+//-------------------- Interrupt Control and State Register
+#define SCB_ICSR (* ((volatile uint32_t *) (0xE000E000 + 0xD04)))
+
+  // Field (width: 9 bits): Contains the active exception number.
+    inline uint32_t SCB_ICSR_VECTACTIVE (const uint32_t inValue) { return (inValue & 511) << 0 ; }
+
+  // Boolean field: Indicates whether there are preempted active exceptions.
+    static const uint32_t SCB_ICSR_RETTOBASE = 1U << 11 ;
+
+  // Field (width: 9 bits): Indicates the exception number of the highest priority pending enabled exception.
+    inline uint32_t SCB_ICSR_VECTPENDING (const uint32_t inValue) { return (inValue & 511) << 12 ; }
+
+  // Boolean field: Interrupt pending flag, excluding NMI and Faults
+    static const uint32_t SCB_ICSR_ISRPENDING = 1U << 22 ;
+
+  // Boolean field: SysTick exception clear-pending bit.
+    static const uint32_t SCB_ICSR_PENDSTCLR = 1U << 25 ;
+
+  // Boolean field: SysTick exception set-pending bit.
+    static const uint32_t SCB_ICSR_PENDSTSET = 1U << 26 ;
+
+  // Boolean field: PendSV clear-pending bit.
+    static const uint32_t SCB_ICSR_PENDSVCLR = 1U << 27 ;
+
+  // Boolean field: PendSV set-pending bit.
+    static const uint32_t SCB_ICSR_PENDSVSET = 1U << 28 ;
+
+  // Boolean field: NMI set-pending bit.
+    static const uint32_t SCB_ICSR_NMIPENDSET = 1U << 31 ;
+
+//-------------------- Vector Table Offset Register
+#define SCB_VTOR (* ((volatile uint32_t *) (0xE000E000 + 0xD08)))
+
+//-------------------- Application Interrupt and Reset Control Register
+#define SCB_AIRCR (* ((volatile uint32_t *) (0xE000E000 + 0xD0C)))
+
+  // Boolean field: System reset request bit setting is implementation defined.
+    static const uint32_t SCB_AIRCR_SYSRESETREQ = 1U << 2 ;
+
+  // Field (width: 3 bits): Interrupt priority grouping field. This field determines the split of group priority from subpriority.
+    inline uint32_t SCB_AIRCR_PRIGROUP (const uint32_t inValue) { return (inValue & 7) << 8 ; }
+
+  // Boolean field: Data endianness bit setting is implementation defined.
+    static const uint32_t SCB_AIRCR_ENDIANNESS = 1U << 15 ;
+
+  // Field (width: 16 bits): Register key. On write, write 0x5FA to VECTKEY, otherwise the write is ignored. Reads as 0xFA05
+    inline uint32_t SCB_AIRCR_VECTKEY (const uint32_t inValue) { return (inValue & 65535) << 16 ; }
+
+//-------------------- System Control Register
+#define SCB_SCR (* ((volatile uint32_t *) (0xE000E000 + 0xD10)))
+
+  // Boolean field: Indicates sleep-on-exit when returning from Handler mode to Thread mode
+    static const uint32_t SCB_SCR_SLEEPONEXIT = 1U << 1 ;
+
+  // Boolean field: Controls whether the processor uses sleep or deep sleep as its low-power mode
+    static const uint32_t SCB_SCR_SLEEPDEEP = 1U << 2 ;
+
+  // Boolean field: Send event on pending bit
+    static const uint32_t SCB_SCR_SEVONPEND = 1U << 4 ;
+
+//-------------------- Configuration and Control Register
+#define SCB_CCR (* ((volatile uint32_t *) (0xE000E000 + 0xD14)))
+
+  // Boolean field: Indicates how the processor enters Thread mode
+    static const uint32_t SCB_CCR_NONBASETHREADENA = 1U << 0 ;
+
+  // Boolean field: Enables unprivileged software access to the STIR
+    static const uint32_t SCB_CCR_USERSETMPEND = 1U << 1 ;
+
+  // Boolean field: Enables unalign access traps.
+    static const uint32_t SCB_CCR_UNALIGNED_TRP = 1U << 3 ;
+
+  // Boolean field: Enables faulting or halting when the processor executes an SDIF or UDIV instruction with a divisor of 0.
+    static const uint32_t SCB_CCR_DIV0_TRP = 1U << 4 ;
+
+  // Boolean field: Enables handlers with priority -1 or -2 to ignore data BusFaults caused by load and store instructions. This applies to the hard fault, NMI, and FAULTMASK escalated handlers.
+    static const uint32_t SCB_CCR_BFHFNMIGN = 1U << 8 ;
+
+  // Boolean field: Always reads-as-one. It indicates stack alignment on exception entry is 8-byte aligned.
+    static const uint32_t SCB_CCR_STKALIGN = 1U << 9 ;
+
+  // Boolean field: Enables L1 data cache.
+    static const uint32_t SCB_CCR_DC = 1U << 16 ;
+
+  // Boolean field: Enables L1 instruction cache.
+    static const uint32_t SCB_CCR_IC = 1U << 17 ;
+
+//-------------------- System Handler Priority Register 1
+#define SCB_SHPR1 (* ((volatile uint32_t *) (0xE000E000 + 0xD18)))
+
+  // Field (width: 8 bits): Priority of the system handler, MemManage
+    inline uint32_t SCB_SHPR1_PRI_4 (const uint32_t inValue) { return (inValue & 255) << 0 ; }
+
+  // Field (width: 8 bits): Priority of the system handler, BusFault
+    inline uint32_t SCB_SHPR1_PRI_5 (const uint32_t inValue) { return (inValue & 255) << 8 ; }
+
+  // Field (width: 8 bits): Priority of the system handler, UsageFault
+    inline uint32_t SCB_SHPR1_PRI_6 (const uint32_t inValue) { return (inValue & 255) << 16 ; }
+
+//-------------------- System Handler Priority Register 2
+#define SCB_SHPR2 (* ((volatile uint32_t *) (0xE000E000 + 0xD1C)))
+
+  // Field (width: 8 bits): Priority of the system handler, SVCall
+    inline uint32_t SCB_SHPR2_PRI_11 (const uint32_t inValue) { return (inValue & 255) << 24 ; }
+
+//-------------------- System Handler Priority Register 3
+#define SCB_SHPR3 (* ((volatile uint32_t *) (0xE000E000 + 0xD20)))
+
+  // Field (width: 8 bits): Priority of the system handler, PendSV
+    inline uint32_t SCB_SHPR3_PRI_14 (const uint32_t inValue) { return (inValue & 255) << 16 ; }
+
+  // Field (width: 8 bits): Priority of the system handler, SysTick
+    inline uint32_t SCB_SHPR3_PRI_15 (const uint32_t inValue) { return (inValue & 255) << 24 ; }
+
+//-------------------- System Handler Control and State Register
+#define SCB_SHCSR (* ((volatile uint32_t *) (0xE000E000 + 0xD24)))
+
+  // Boolean field: MemManage exception active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_MEMFAULTACT = 1U << 0 ;
+
+  // Boolean field: BusFault exception active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_BUSFAULTACT = 1U << 1 ;
+
+  // Boolean field: UsageFault exception active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_USGFAULTACT = 1U << 3 ;
+
+  // Boolean field: SVCall active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_SVCALLACT = 1U << 7 ;
+
+  // Boolean field: Debug Monitor active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_MONITORACT = 1U << 8 ;
+
+  // Boolean field: PendSV exception active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_PENDSVACT = 1U << 10 ;
+
+  // Boolean field: Systick exception active bit, reads as 1 if exception is active.
+    static const uint32_t SCB_SHCSR_SYSTICKACT = 1U << 11 ;
+
+  // Boolean field: UsageFault exception pending bit, reads as 1 if exception is pending
+    static const uint32_t SCB_SHCSR_USGFAULTPENDED = 1U << 12 ;
+
+  // Boolean field: MemManage exception pending bit, reads as 1 if exception is pending
+    static const uint32_t SCB_SHCSR_MEMFAULTPENDED = 1U << 13 ;
+
+  // Boolean field: BusFault exception pending bit, reads as 1 if exception is pending
+    static const uint32_t SCB_SHCSR_BUSFAULTPENDED = 1U << 14 ;
+
+  // Boolean field: SVCall pending bit, reads as 1 if exception is pending
+    static const uint32_t SCB_SHCSR_SVCALLPENDED = 1U << 15 ;
+
+  // Boolean field: MemManage enable bit, set to 1 to enable
+    static const uint32_t SCB_SHCSR_MEMFAULTENA = 1U << 16 ;
+
+  // Boolean field: BusFault enable bit, set to 1 to enable
+    static const uint32_t SCB_SHCSR_BUSFAULTENA = 1U << 17 ;
+
+  // Boolean field: UsageFault enable bit, set to 1 to enable
+    static const uint32_t SCB_SHCSR_USGFAULTENA = 1U << 18 ;
+
+//-------------------- MemManage Fault Status Register
+#define SCB_CFSR (* ((volatile uint8_t *) (0xE000E000 + 0xD28)))
+
+  // Boolean field: Instruction access violation flag
+    static const uint8_t SCB_CFSR_IACCVIOL = 1U << 0 ;
+
+  // Boolean field: Data access violation flag
+    static const uint8_t SCB_CFSR_DACCVIOL = 1U << 1 ;
+
+  // Boolean field: MemManage fault on unstacking for a return from exception
+    static const uint8_t SCB_CFSR_MUNSTKERR = 1U << 3 ;
+
+  // Boolean field: MemManage fault on stacking for exception entry
+    static const uint8_t SCB_CFSR_MSTKERR = 1U << 4 ;
+
+  // Boolean field: MemManage fault during floating-point lazy state preservation.
+    static const uint8_t SCB_CFSR_MLSPERR = 1U << 5 ;
+
+  // Boolean field: MemManage fault address register valid flag.
+    static const uint8_t SCB_CFSR_MMARVALID = 1U << 7 ;
+
+//-------------------- BusFault Status Register
+#define SCB_BFSR (* ((volatile uint8_t *) (0xE000E000 + 0xD29)))
+
+  // Boolean field: Instruction bus error
+    static const uint8_t SCB_BFSR_IBUSERR = 1U << 0 ;
+
+  // Boolean field: Precise data bus error
+    static const uint8_t SCB_BFSR_PRECISERR = 1U << 1 ;
+
+  // Boolean field: Precise data bus error
+    static const uint8_t SCB_BFSR_IMPRECISERR = 1U << 2 ;
+
+  // Boolean field: BusFault on unstacking for a return from exception.
+    static const uint8_t SCB_BFSR_UNSTKERR = 1U << 3 ;
+
+  // Boolean field: BusFault on stacking for exception entry.
+    static const uint8_t SCB_BFSR_STKERR = 1U << 4 ;
+
+  // Boolean field: BusFault on floating-point lazy state preservation.
+    static const uint8_t SCB_BFSR_LSPERR = 1U << 5 ;
+
+  // Boolean field: BusFault Address Register valid flag.
+    static const uint8_t SCB_BFSR_BFARVALID = 1U << 7 ;
+
+//-------------------- UsageFault Status Register
+#define SCB_UFSR (* ((volatile uint16_t *) (0xE000E000 + 0xD2A)))
+
+  // Boolean field: Undefined instruction UsageFault
+    static const uint16_t SCB_UFSR_UNDEFINSTR = 1U << 0 ;
+
+  // Boolean field: Invalid State UsageFault
+    static const uint16_t SCB_UFSR_INVSTATE = 1U << 1 ;
+
+  // Boolean field: Invalid PC load UsageFault, caused by an invalid PC load by EXC_RETURN
+    static const uint16_t SCB_UFSR_INVPC = 1U << 2 ;
+
+  // Boolean field: No coprocessor UsageFault
+    static const uint16_t SCB_UFSR_NOCP = 1U << 3 ;
+
+  // Boolean field: Unaligned access UsageFault
+    static const uint16_t SCB_UFSR_UNALIGNED = 1U << 8 ;
+
+  // Boolean field: Divide by zero UsageFault.
+    static const uint16_t SCB_UFSR_DIVBYZERO = 1U << 9 ;
+
+//-------------------- HardFault Status Register
+#define SCB_HFSR (* ((volatile uint32_t *) (0xE000E000 + 0xD2C)))
+
+  // Boolean field: Indicates a BusFault on a vector table read during exception processing.
+    static const uint32_t SCB_HFSR_VECTTBL = 1U << 1 ;
+
+  // Boolean field: Indicates a forced hard fault, generated by escalation of a fault with configurable priority that cannot be handled, either because of priority or because it is disabled.
+    static const uint32_t SCB_HFSR_FORCED = 1U << 30 ;
+
+  // Boolean field: Reserved for Debug use. When writing to the register, you must write 1 to this bit, otherwise behavior is UNPREDICTABLE.
+    static const uint32_t SCB_HFSR_DEBUGEVT = 1U << 31 ;
+
+//-------------------- MemManage Fault Address Register
+#define SCB_MMAR (* ((volatile uint32_t *) (0xE000E000 + 0xD34)))
+
+//-------------------- BusFault Address Register
+#define SCB_BFAR (* ((volatile uint32_t *) (0xE000E000 + 0xD38)))
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral SysTick
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- SysTick Control and Status Register
+#define SysTick_CSR (* ((volatile uint32_t *) (0xE000E010 + 0)))
+
+  // Boolean field: Enable SysTick Timer
+    static const uint32_t SysTick_CSR_ENABLE = 1U << 0 ;
+
+  // Boolean field: Generate Tick Interrupt
+    static const uint32_t SysTick_CSR_TICKINT = 1U << 1 ;
+
+  // Boolean field: Source to count from
+    static const uint32_t SysTick_CSR_CLKSOURCE = 1U << 2 ;
+
+  // Boolean field: SysTick counted to zero
+    static const uint32_t SysTick_CSR_COUNTFLAG = 1U << 16 ;
+
+//-------------------- SysTick Reload Value Register
+#define SysTick_RVR (* ((volatile uint32_t *) (0xE000E010 + 0x4)))
+
+  // Field (width: 24 bits): Value to auto reload SysTick after reaching zero
+    inline uint32_t SysTick_RVR_RELOAD (const uint32_t inValue) { return (inValue & 16777215) << 0 ; }
+
+//-------------------- SysTick Current Value Register
+#define SysTick_CVR (* ((volatile uint32_t *) (0xE000E010 + 0x8)))
+
+  // Field (width: 24 bits): Current value
+    inline uint32_t SysTick_CVR_CURRENT (const uint32_t inValue) { return (inValue & 16777215) << 0 ; }
+
+//-------------------- SysTick Calibration Value Register
+#define SysTick_CALIB (* ((const volatile uint32_t *) (0xE000E010 + 0xC)))
+
+  // Field (width: 24 bits): Reload value to use for 10ms timing
+    inline uint32_t SysTick_CALIB_TENMS (const uint32_t inValue) { return (inValue & 16777215) << 0 ; }
+
+  // Boolean field: Clock Skew
+    static const uint32_t SysTick_CALIB_SKEW = 1U << 30 ;
+
+  // Boolean field: No Ref
+    static const uint32_t SysTick_CALIB_NOREF = 1U << 31 ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral MPU
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- MPU Type Register
+#define MPU_TYPE (* ((const volatile uint32_t *) (0xE000ED90 + 0x0)))
+
+  // Boolean field: Indicates support for unified or separate instruction and data memory maps.
+    static const uint32_t MPU_TYPE_SEPARATE = 1U << 0 ;
+
+  // Field (width: 8 bits): Indicates the number of supported MPU data regions depending on your implementation.
+    inline uint32_t MPU_TYPE_DREGION (const uint32_t inValue) { return (inValue & 255) << 8 ; }
+
+  // Field (width: 8 bits): Indicates the number of supported MPU instruction regions. Always contains 0x0: the MPU memory map is unified and is described by the DREGION field.
+    inline uint32_t MPU_TYPE_IREGION (const uint32_t inValue) { return (inValue & 255) << 16 ; }
+
+//-------------------- MPU Control Register
+#define MPU_CTRL (* ((volatile uint32_t *) (0xE000ED90 + 0x4)))
+
+  // Boolean field: Enables the optional MPU.
+    static const uint32_t MPU_CTRL_ENABLE = 1U << 0 ;
+
+  // Boolean field: Enables the operation of MPU during hard fault, NMI, and FAULTMASK handlers.
+    static const uint32_t MPU_CTRL_HFNMIENA = 1U << 1 ;
+
+  // Boolean field: Enables privileged software access to the default memory map.
+    static const uint32_t MPU_CTRL_PRIVDEFENA = 1U << 2 ;
+
+//-------------------- MPU Region Number Register
+#define MPU_RNR (* ((volatile uint32_t *) (0xE000ED90 + 0x8)))
+
+  // Field (width: 8 bits): Indicates the MPU region referenced by the MPU_RBAR and MPU_RASR registers.
+    inline uint32_t MPU_RNR_REGION (const uint32_t inValue) { return (inValue & 255) << 0 ; }
+
+//-------------------- MPU Region Base Address Register
+#define MPU_RBAR (* ((volatile uint32_t *) (0xE000ED90 + 0xC)))
+
+  // Field (width: 4 bits): On Write, see the VALID field. On read, specifies the region number.
+    inline uint32_t MPU_RBAR_REGION (const uint32_t inValue) { return (inValue & 15) << 0 ; }
+
+  // Boolean field: MPU Region number valid bit. Depending on your implementation, this has the following effect: 0 - either updates the base address for the region specified by MPU_RNR or ignores the value of the REGION field. 1 - either updates the value of the MPU_RNR to the value of the REGION field or updates the base address for the region specified in the REGION field.
+    static const uint32_t MPU_RBAR_VALID = 1U << 4 ;
+
+  // Field (width: 27 bits): The ADDR field is bits[31:N] of the MPU_RBAR.
+    inline uint32_t MPU_RBAR_ADDR (const uint32_t inValue) { return (inValue & 134217727) << 5 ; }
+
+//-------------------- MPU Region Base Attribute and Size Register
+#define MPU_RASR (* ((volatile uint32_t *) (0xE000ED90 + 0x10)))
+
+  // Boolean field: Region enable bit.
+    static const uint32_t MPU_RASR_ENABLE = 1U << 0 ;
+
+  // Field (width: 5 bits): Specifies the size of the MPU protection region. Minimum value is 4. The Region size is defined as (Region size in bytes) = 2^(SIZE+1)
+    inline uint32_t MPU_RASR_SIZE (const uint32_t inValue) { return (inValue & 31) << 1 ; }
+
+  // Boolean field: Subregion disable bits
+    static const uint32_t MPU_RASR_SRD0 = 1U << 8 ;
+
+  // Boolean field: Subregion disable bits
+    static const uint32_t MPU_RASR_SRD1 = 1U << 9 ;
+
+  // Boolean field: Subregion disable bits
+    static const uint32_t MPU_RASR_SRD2 = 1U << 10 ;
+
+  // Boolean field: Subregion disable bits
+    static const uint32_t MPU_RASR_SRD3 = 1U << 11 ;
+
+  // Boolean field: Subregion disable bits
+    static const uint32_t MPU_RASR_SRD4 = 1U << 12 ;
+
+  // Boolean field: Subregion disable bits.
+    static const uint32_t MPU_RASR_SRD5 = 1U << 13 ;
+
+  // Boolean field: Subregion disable bits.
+    static const uint32_t MPU_RASR_SRD6 = 1U << 14 ;
+
+  // Boolean field: Subregion disable bits.
+    static const uint32_t MPU_RASR_SRD7 = 1U << 15 ;
+
+  // Boolean field: Memory access attribute.
+    static const uint32_t MPU_RASR_B = 1U << 16 ;
+
+  // Boolean field: Memory access attribute.
+    static const uint32_t MPU_RASR_C = 1U << 17 ;
+
+  // Boolean field: Shareable bit. Applies to Normal memory only.
+    static const uint32_t MPU_RASR_S = 1U << 18 ;
+
+  // Field (width: 3 bits): Memory access attribute.
+    inline uint32_t MPU_RASR_TEX (const uint32_t inValue) { return (inValue & 7) << 19 ; }
+
+  // Field (width: 3 bits): Access permission field
+    inline uint32_t MPU_RASR_AP (const uint32_t inValue) { return (inValue & 7) << 24 ; }
+
+  // Boolean field: Instruction access disable bit
+    static const uint32_t MPU_RASR_XN = 1U << 28 ;
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 1
+#define MPU_RBAR_A1 (* ((volatile uint32_t *) (0xE000ED90 + 0x14)))
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 1
+#define MPU_RASR_A1 (* ((volatile uint32_t *) (0xE000ED90 + 0x18)))
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 2
+#define MPU_RBAR_A2 (* ((volatile uint32_t *) (0xE000ED90 + 0x1C)))
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 2
+#define MPU_RASR_A2 (* ((volatile uint32_t *) (0xE000ED90 + 0x20)))
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 3
+#define MPU_RBAR_A3 (* ((volatile uint32_t *) (0xE000ED90 + 0x24)))
+
+//-------------------- Uses (MPU_RNR[7:2]<<2) + 3
+#define MPU_RASR_A3 (* ((volatile uint32_t *) (0xE000ED90 + 0x28)))
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral Debug
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- Debug Fault Status Register
+#define Debug_DFSR (* ((volatile uint32_t *) (0xE000ED00 + 0x30)))
+
+  // Boolean field: Halt request debug event.
+    static const uint32_t Debug_DFSR_HALTED = 1U << 0 ;
+
+  // Boolean field: BKPT instruction executed or breakpoint match in FPB.
+    static const uint32_t Debug_DFSR_BKPT = 1U << 1 ;
+
+  // Boolean field: Data Watchpoint and Trace trap. Indicates that the core halted due to at least one DWT trap event.
+    static const uint32_t Debug_DFSR_DWTTRAP = 1U << 2 ;
+
+  // Boolean field: Vector catch triggered. Corresponding FSR will contain the primary cause of the exception.
+    static const uint32_t Debug_DFSR_VCATCH = 1U << 3 ;
+
+  // Boolean field: An asynchronous exception generated due to the assertion of EDBGRQ.
+    static const uint32_t Debug_DFSR_EXTERNAL = 1U << 4 ;
+
+//-------------------- Debug Halting Control and Status Register (on read)
+#define Debug_DHCSR_RO (* ((const volatile uint32_t *) (0xE000ED00 + 0xF0)))
+
+  // Boolean field: Halting debug enable bit.
+    static const uint32_t Debug_DHCSR_RO_C_DEBUGGEN = 1U << 0 ;
+
+  // Boolean field: Processor halt bit.
+    static const uint32_t Debug_DHCSR_RO_C_HALT = 1U << 1 ;
+
+  // Boolean field: Processor step bit.
+    static const uint32_t Debug_DHCSR_RO_C_STEP = 1U << 2 ;
+
+  // Boolean field: When debug is enabled, the debugger can write to this bit to mask PendSV, SysTick and external configurable interrupts.
+    static const uint32_t Debug_DHCSR_RO_C_MASKINTS = 1U << 3 ;
+
+  // Boolean field: Allow imprecise entry to Debug state.
+    static const uint32_t Debug_DHCSR_RO_C_SNAPSTALL = 1U << 5 ;
+
+  // Boolean field: A handshake flag for transfers through the DCRDR.
+    static const uint32_t Debug_DHCSR_RO_S_REGRDY = 1U << 16 ;
+
+  // Boolean field: Indicates whether the processor is in Debug state.
+    static const uint32_t Debug_DHCSR_RO_S_HALT = 1U << 17 ;
+
+  // Boolean field: Indicates whether the processor is sleeping.
+    static const uint32_t Debug_DHCSR_RO_S_SLEEP = 1U << 18 ;
+
+  // Boolean field: Indicates whether the processor is locked up because of an unrecoverable exception.
+    static const uint32_t Debug_DHCSR_RO_S_LOCKUP = 1U << 19 ;
+
+  // Boolean field: Set to 1 every time the processor retires one or more instructions.
+    static const uint32_t Debug_DHCSR_RO_S_RETIRE_ST = 1U << 24 ;
+
+  // Boolean field: Indicates whether the processor has been reset since the last read of DHCSR.
+    static const uint32_t Debug_DHCSR_RO_S_RESET_ST = 1U << 25 ;
+
+//-------------------- Debug Halting Control and Status Register (on write)
+#define Debug_DHCSR_WO (* ((volatile uint32_t *) (0xE000ED00 + 0xF0)))
+
+  // Boolean field: Halting debug enable bit.
+    static const uint32_t Debug_DHCSR_WO_C_DEBUGGEN = 1U << 0 ;
+
+  // Boolean field: Processor halt bit.
+    static const uint32_t Debug_DHCSR_WO_C_HALT = 1U << 1 ;
+
+  // Boolean field: Processor step bit.
+    static const uint32_t Debug_DHCSR_WO_C_STEP = 1U << 2 ;
+
+  // Boolean field: When debug is enabled, the debugger can write to this bit to mask PendSV, SysTick and external configurable interrupts.
+    static const uint32_t Debug_DHCSR_WO_C_MASKINTS = 1U << 3 ;
+
+  // Boolean field: Allow imprecise entry to Debug state.
+    static const uint32_t Debug_DHCSR_WO_C_SNAPSTALL = 1U << 5 ;
+
+  // Field (width: 16 bits): Debug Key. The value 0xA05F must be written to enable write accesses to bits [15:0], otherwise the write access will be ignored.
+    inline uint32_t Debug_DHCSR_WO_S_RESET_ST (const uint32_t inValue) { return (inValue & 65535) << 16 ; }
+
+//-------------------- Debug Core Register Selector Register
+#define Debug_DCRSR (* ((volatile uint32_t *) (0xE000ED00 + 0xF4)))
+
+  // Field (width: 4 bits): Specifies the ARM core register, special-purpose register, or Floating-point extension register, to transfer.
+    inline uint32_t Debug_DCRSR_REGSEL (const uint32_t inValue) { return (inValue & 15) << 0 ; }
+
+  // Boolean field: Specifies the access type for the transfer.
+    static const uint32_t Debug_DCRSR_REGWnR = 1U << 16 ;
+
+//-------------------- Debug Core Register Data Register
+#define Debug_DCRDR (* ((volatile uint32_t *) (0xE000ED00 + 0xF8)))
+
+//-------------------- Debug Exception and Monitor Control Register
+#define Debug_DEMCR (* ((volatile uint32_t *) (0xE000ED00 + 0xFC)))
+
+  // Boolean field: Enable Reset Vector Catch. This causes a Local reset to halt a running system.
+    static const uint32_t Debug_DEMCR_VC_CORERESET = 1U << 0 ;
+
+  // Boolean field: Enable halting debug trap on a MemManage exception.
+    static const uint32_t Debug_DEMCR_VC_MMERR = 1U << 4 ;
+
+  // Boolean field: Enable halting debug trap on a UsageFault caused by an access to a Coprocessor.
+    static const uint32_t Debug_DEMCR_VC_NOCPERR = 1U << 5 ;
+
+  // Boolean field: Enable halting debug trap on a UsageFault exception caused by a checking error, for example an alignment check error.
+    static const uint32_t Debug_DEMCR_VC_CHKERR = 1U << 6 ;
+
+  // Boolean field: Enable halting debug trap on a UsageFault exception caused by a state information error, for example an Undefined instruction.
+    static const uint32_t Debug_DEMCR_VC_STATERR = 1U << 7 ;
+
+  // Boolean field: Enable halting debug trap on a BusFault exception.
+    static const uint32_t Debug_DEMCR_VC_BUSERR = 1U << 8 ;
+
+  // Boolean field: Enable halting debug trap on a fault occurring during exception entry or exception return.
+    static const uint32_t Debug_DEMCR_VC_INTERR = 1U << 9 ;
+
+  // Boolean field: Enable halting debug trap on HardFault exception.
+    static const uint32_t Debug_DEMCR_VC_HARDERR = 1U << 10 ;
+
+  // Boolean field: Enable the DebugMonitor exception.
+    static const uint32_t Debug_DEMCR_MON_EN = 1U << 16 ;
+
+  // Boolean field: Sets or clears the pending state of the DebugMonitor exception.
+    static const uint32_t Debug_DEMCR_MON_PEND = 1U << 17 ;
+
+  // Boolean field: When MON_EN is set to 0, this feature is disabled and the processor ignores MON_STEP. When MON_EN is set to 1, the meaning of MON_STEP is: 0 Do not step the processor, 1 Step the processor.
+    static const uint32_t Debug_DEMCR_MON_STEP = 1U << 18 ;
+
+  // Boolean field: DebugMonitor semaphore bit. The processor does not use this bit. The monitor software defines the meaning and use of this bit.
+    static const uint32_t Debug_DEMCR_MON_REQ = 1U << 19 ;
+
+  // Boolean field: Global enable for all DWT and ITM features.
+    static const uint32_t Debug_DEMCR_TRCENA = 1U << 24 ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral DWT
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- Control Register
+#define DWT_CTRL (* ((volatile uint32_t *) (0xE0001000 + 0)))
+
+  // Field (width: 4 bits): Number of comparators
+    inline uint32_t DWT_CTRL_NUMCOMP (const uint32_t inValue) { return (inValue & 15) << 28 ; }
+
+  // Boolean field: No trace sampling and exception tracing
+    static const uint32_t DWT_CTRL_NOTRCPKT = 1U << 27 ;
+
+  // Boolean field: No external match signals
+    static const uint32_t DWT_CTRL_NOEXTTRIG = 1U << 26 ;
+
+  // Boolean field: No cycle counter
+    static const uint32_t DWT_CTRL_NOCYCCNT = 1U << 25 ;
+
+  // Boolean field: No profiling counters
+    static const uint32_t DWT_CTRL_NOPRFCNT = 1U << 24 ;
+
+  // Boolean field: Reserved bit 23
+    static const uint32_t DWT_CTRL_Reserved_23 = 1U << 23 ;
+
+  // Boolean field: enable Cycle count event
+    static const uint32_t DWT_CTRL_CYCEVTENA = 1U << 22 ;
+
+  // Boolean field: enable Folded instruction count event
+    static const uint32_t DWT_CTRL_FOLDEVTENA = 1U << 21 ;
+
+  // Boolean field: enable Load Store Unit (LSU) count event
+    static const uint32_t DWT_CTRL_LSUEVTENA = 1U << 20 ;
+
+  // Boolean field: enable Sleep count event
+    static const uint32_t DWT_CTRL_SLEEPEVTENA = 1U << 19 ;
+
+  // Boolean field: enable interrupt overhead event
+    static const uint32_t DWT_CTRL_EXCEVTENA = 1U << 18 ;
+
+  // Boolean field: enable CPI count event
+    static const uint32_t DWT_CTRL_CPIEVTENA = 1U << 17 ;
+
+  // Boolean field: enable interrupt event tracing
+    static const uint32_t DWT_CTRL_EXCTRCENA = 1U << 16 ;
+
+  // Field (width: 3 bits): Reserved bits 13..15
+    inline uint32_t DWT_CTRL_Reserved_13_15 (const uint32_t inValue) { return (inValue & 7) << 13 ; }
+
+  // Boolean field: enable POSTCNT as timer for PC sample packets
+    static const uint32_t DWT_CTRL_PCSAMPLENA = 1U << 12 ;
+
+  // Field (width: 2 bits): ???
+    inline uint32_t DWT_CTRL_SYNCTAP (const uint32_t inValue) { return (inValue & 3) << 10 ; }
+
+  // Boolean field: ???
+    static const uint32_t DWT_CTRL_CYCTAP = 1U << 9 ;
+
+  // Field (width: 4 bits): ???
+    inline uint32_t DWT_CTRL_POSTINIT (const uint32_t inValue) { return (inValue & 15) << 5 ; }
+
+  // Field (width: 4 bits): ???
+    inline uint32_t DWT_CTRL_POSTPRESET (const uint32_t inValue) { return (inValue & 15) << 1 ; }
+
+  // Boolean field: enable cycle counter
+    static const uint32_t DWT_CTRL_CYCCNTENA = 1U << 0 ;
+
+//-------------------- Cycle Count Register
+#define DWT_CYCCNT (* ((volatile uint32_t *) (0xE0001000 + 4)))
+
+//-------------------- CPI Count Register
+#define DWT_CPICNT (* ((volatile uint32_t *) (0xE0001000 + 8)))
+
+//-------------------- Exception Overhead Count Register
+#define DWT_EXCCNT (* ((volatile uint32_t *) (0xE0001000 + 0xC)))
+
+//-------------------- Sleep Count Register
+#define DWT_SLEEPCNT (* ((volatile uint32_t *) (0xE0001000 + 0x10)))
+
+//-------------------- LSU Count Register
+#define DWT_LSUCNT (* ((volatile uint32_t *) (0xE0001000 + 0x14)))
+
+//-------------------- Folded-instruction Count Register
+#define DWT_FOLDCNT (* ((volatile uint32_t *) (0xE0001000 + 0x18)))
+
+//-------------------- Program Counter Sample Register
+#define DWT_PCSR (* ((const volatile uint32_t *) (0xE0001000 + 0x1C)))
+
+//-------------------- Comparator Register 0
+#define DWT_COMP0 (* ((volatile uint32_t *) (0xE0001000 + 0x20)))
+
+//-------------------- Mask Register 0
+#define DWT_MASK0 (* ((volatile uint32_t *) (0xE0001000 + 0x24)))
+
+//-------------------- Function Register 0
+#define DWT_FUNCTION0 (* ((volatile uint32_t *) (0xE0001000 + 0x28)))
+
+//-------------------- Comparator Register 1
+#define DWT_COMP1 (* ((volatile uint32_t *) (0xE0001000 + 0x30)))
+
+//-------------------- Mask Register 1
+#define DWT_MASK1 (* ((volatile uint32_t *) (0xE0001000 + 0x34)))
+
+//-------------------- Function Register 1
+#define DWT_FUNCTION1 (* ((volatile uint32_t *) (0xE0001000 + 0x38)))
+
+//-------------------- Comparator Register 2
+#define DWT_COMP2 (* ((volatile uint32_t *) (0xE0001000 + 0x40)))
+
+//-------------------- Mask Register 2
+#define DWT_MASK2 (* ((volatile uint32_t *) (0xE0001000 + 0x44)))
+
+//-------------------- Function Register 2
+#define DWT_FUNCTION2 (* ((volatile uint32_t *) (0xE0001000 + 0x48)))
+
+//-------------------- Comparator Register 3
+#define DWT_COMP3 (* ((volatile uint32_t *) (0xE0001000 + 0x50)))
+
+//-------------------- Mask Register 3
+#define DWT_MASK3 (* ((volatile uint32_t *) (0xE0001000 + 0x54)))
+
+//-------------------- Function Register 3
+#define DWT_FUNCTION3 (* ((volatile uint32_t *) (0xE0001000 + 0x58)))
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Peripheral SYST
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+//-------------------- SysTick Control and Status
+#define SYST_CSR (* ((volatile uint32_t *) (0xE000E000 + 0x10)))
+
+  // Boolean field: Enable the Counter
+    static const uint32_t SYST_CSR_ENABLE = 1U << 0 ;
+
+  // Boolean field: Enables SysTick exception request
+    static const uint32_t SYST_CSR_TICKINT = 1U << 1 ;
+
+  // Boolean field: Clock Source Selection
+    static const uint32_t SYST_CSR_CLKSOURCE = 1U << 2 ;
+
+  // Boolean field: Returns 1 if timer counted to 0 since last time this was read
+    static const uint32_t SYST_CSR_COUNTFLAG = 1U << 16 ;
+
+//-------------------- SysTick Reload Value Register
+#define SYST_RVR (* ((volatile uint32_t *) (0xE000E000 + 0x14)))
+
+//-------------------- SysTick Current Value Register
+#define SYST_CVR (* ((volatile uint32_t *) (0xE000E000 + 0x18)))
+
+//-------------------- SysTick Calibration Value Register
+#define SYST_CALIB (* ((const volatile uint32_t *) (0xE000E000 + 0x1C)))
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 53 - 0
steps/01-blink-led/sources/reset-handler-sequential.s

@@ -0,0 +1,53 @@
+	.syntax unified
+	.cpu cortex-m4
+	.thumb
+
+@----------------------------------------------------------------------------------------------------------------------*
+@                                                                                                                      *
+@                 R E S E T    H A N D L E R    ( D O U B L E    S T A C K    M O D E )                                *
+@                                                                                                                      *
+@----------------------------------------------------------------------------------------------------------------------*
+
+@--- This is stack for background task
+   BACKGROUND.STACK.SIZE = 512
+
+	.section	.bss.background.task.stack, "aw", %nobits
+  .align	  3   @ Stack should be aligned on a 8-byte boundary
+
+background.task.stack:
+  .space	BACKGROUND.STACK.SIZE
+
+@----------------------------------------------------------------------------------------------------------------------*
+@ See https://developer.arm.com/docs/dui0553/latest/2-the-cortex-m4-processor/21-programmers-model/213-core-registers
+
+	.section	".text.reset.handler", "ax", %progbits
+
+  .global reset.handler
+  .type reset.handler, %function
+
+reset.handler: @ Cortex M4 boots with interrupts enabled, in Thread mode
+@---------------------------------- Run boot, zero bss section, copy data section
+  bl    start.phase1
+@---------------------------------- Set PSP: this is stack for background task
+  ldr   r0,  =background.task.stack + BACKGROUND.STACK.SIZE
+  msr   psp, r0
+@---------------------------------- Set CONTROL register (see §B1.4.4)
+@ bit 0 : 0 -> Thread mode has privileged access, 1 -> Thread mode has unprivileged access
+@ bit 1 : 0 -> Use SP_main as the current stack, 1 -> In Thread mode, use SP_process as the current stack
+@ bit 2 : 0 -> FP extension not active, 1 -> FP extension is active
+  movs  r2, #2
+  msr   CONTROL, r2
+@--- Software must use an ISB barrier instruction to ensure a write to the CONTROL register
+@ takes effect before the next instruction is executed.
+  isb
+@---------------------------------- Run init routines, interrupt disabled
+  cpsid i              @ Disable interrupts
+  bl    start.phase2
+  cpsie i              @ Enable interrupts
+@---------------------------------- Run setup, loop
+  bl    setup.function
+background.task:
+  bl    loop.function
+  b     background.task
+
+@----------------------------------------------------------------------------------------------------------------------*

+ 26 - 0
steps/01-blink-led/sources/setup-loop.cpp

@@ -0,0 +1,26 @@
+#include "all-headers.h"
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Led L2 is connected to PORTD:7 (active high)
+
+void setup (void) {
+//--- Configure PTD7 as digital port (input or output)
+  PORTD_PCR (7) = PORT_PCR_MUX (1) ;
+//--- Configure PTD7 as digital output port (output level is low --> led is off)
+  GPIOD_PDDR |= (1 << 7) ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void loop (void) {
+//--- Drive PTD7 high --> led is on
+  GPIOD_PSOR = 1 << 7 ;
+//--- Wait...
+  for (volatile uint32_t i=0 ; i< 10 * 1000 * 1000 ; i++) {}
+//--- Drive PTD7 low --> led is off
+  GPIOD_PCOR = 1 << 7 ;
+//--- Wait...
+  for (volatile uint32_t i=0 ; i< 10 * 1000 * 1000 ; i++) {}
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 9 - 0
steps/01-blink-led/sources/setup-loop.h

@@ -0,0 +1,9 @@
+#pragma once
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void setup (void) asm ("setup.function") ;
+
+void loop (void) asm ("loop.function") ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 531 - 0
steps/01-blink-led/sources/start-teensy-3-6.cpp

@@ -0,0 +1,531 @@
+#include "all-headers.h"
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//   MICROCONTROLLER SERIAL NUMBER
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+static uint32_t gMicrocontrollerSerialNumber ;
+static uint32_t readMicrocontrollerSerialNumber (void) ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// CLOCK SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// The MCGCLOCKOUT frequency is given by (the 16 MHz quartz frequency is divided by 2 for the PPL)
+//  MCGCLOCKOUT = 16 MHz / 2 * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1)
+//
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// CPU CLOCK
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//  The CPU Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV1 + 1)
+//
+//  Here, CPU_MHZ is a given constant, so we only check that settings are correct by asserting:
+//     CPU_MHZ * (MCG:C5:PRDIV + 1) * (SIM:CLKDIV1:OUTDIV1 + 1) = (16 MHz / 2) * (MCG:C6:VDIV + 16)
+//
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// BUS (peripheral) CLOCK
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//  The peripheral Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV2 + 1)
+//
+//  Here, SIM:CLKDIV1:OUTDIV2 is a given constant, so we compute BUS_MHZ by:
+//     BUS_MHZ = (16 MHz / 2) * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV2 + 1)
+//
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Flexbus CLOCK
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//  The Flexbus Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV3 + 1)
+//
+//  Here, SIM:CLKDIV1:OUTDIV3 is a given constant, so we compute FLEXBUS_MHZ by:
+//     FLEXBUS_MHZ = (16 MHz / 2) * (MCG:C6:VDIV + 16) /(MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV3 + 1)
+//
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// Flash CLOCK
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//  The FLASH Clock is given by: MCGCLOCKOUT / (SIM:CLKDIV1:OUTDIV3 + 1)
+//
+//  Here, SIM:CLKDIV1:OUTDIV4 is a given constant, so we compute Flash Clock in kHz (result may not be integer):
+//     FLASH_KHZ = (16000 kHz / 2) * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) / (SIM:CLKDIV1:OUTDIV4 + 1)
+//
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// MICRO CONTROLLER REQUIREMENTS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// The clock dividers are programmed via the SIM module’s CLKDIV registers. Each divider is programmable from a
+// divide-by-1 through divide-by-16 setting. The following requirements must be met when configuring the clocks
+// for this device:
+// 1. The core and system clock frequencies must be 180 MHz or slower in HSRUN, 120 MHz or slower in RUN.
+// 2. The bus clock frequency must be programmed to 60 MHz or less in HSRUN or RUN, and an integer divide of the
+//      core clock. The core clock to bus clock ratio is limited to a max value of 8.
+// 3. The flash clock frequency must be programmed to 28 MHz or less, less than or equal to the bus clock, and an
+//      integer divide of the core clock. The core clock to flash clock ratio is limited to a max value of 8.
+// 4. The FlexBus clock frequency must be programmed to be less than or equal to the bus clock frequency. The
+//      FlexBus also has pad interface restrictions that limits the maximum frequency. For this device the FlexBus
+//      maximum frequency is 60 MHz. The core clock to FlexBus clock ratio is limited to a max value of 8.
+// 5. Since SDRAMC and FlexBus both use CLKOUT, the same restrictions apply to the SDRAM controller as stated
+//      for the FlexBus clock.
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SETTING SUMMARY
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// F_CPU   MCG_C5   MCG_C6   SIM_CLKDIV1   SIM_CLKDIV1   SIM_CLKDIV1   SIM_CLKDIV1   BUS_MHZ   FLEXBUS    FLASH
+// _MHZ    _PRDIV    _VDIV      _OUTDIV1      _OUTDIV2      _OUTDIV3      _OUTDIV4                _MHZ     _KHZ
+//  240         0       14             0             3             0             7       60        240   30 000
+//  216         0       11             0             1             0             7       54        216   27 000
+//  192         0        8             0             1             0             6       28        192   27 428
+//  180         1       29             0             1             0             6       60        180   25 714
+//  168         0        5             0             2             0             5       56        168   28 000
+//  144         0        2             0             1             0             4       28        144   28 800
+//  120         1       14             0             1             0             4       60        120   24 000
+//   96         1        8             0             1             0             2       24         96   24 000
+//   72         1        2             0             0             0             2       36         72   24 000
+//   48         1        8             1             1             1             3       48         48   24 000
+//   24         1        8             3             3             3             3       24         24   24 000
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// PRDIV SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 240
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 192
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 144
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#elif CPU_MHZ == 96
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_MCG_C5_PRDIV = 1 ;
+#else
+  #error "CPU_MHZ has an invalid value"
+  static const uint32_t K_MCG_C5_PRDIV = 0 ;
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// MCG:C6:VDIV SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_MCG_C6_VDIV = 0 ;
+#elif CPU_MHZ == 240
+  static const uint32_t K_MCG_C6_VDIV = 14 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_MCG_C6_VDIV = 11 ;
+#elif CPU_MHZ == 192
+  static const uint32_t K_MCG_C6_VDIV = 8 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_MCG_C6_VDIV = 29 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_MCG_C6_VDIV = 5 ;
+#elif CPU_MHZ == 144
+  static const uint32_t K_MCG_C6_VDIV = 2 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_MCG_C6_VDIV = 14 ;
+#elif CPU_MHZ == 96
+  static const uint32_t K_MCG_C6_VDIV = 8 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_MCG_C6_VDIV = 2 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_MCG_C6_VDIV = 8 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_MCG_C6_VDIV = 8 ;
+#else
+  #error "CPU_MHZ has an invalid value"
+  static const uint32_t K_MCG_C6_VDIV = 0 ;
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV1:OUTDIV1 SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 0 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 1 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 3 ;
+#else
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV1 = 0 ; // 0 for all other settings
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV1:OUTDIV2 SETTINGS (divisor for bus)
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 0 ;
+#elif CPU_MHZ == 240
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
+#elif CPU_MHZ == 192
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
+#elif CPU_MHZ == 144
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 2 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
+#elif CPU_MHZ == 96
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 1 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 3 ;
+#else
+  #error "CPU_MHZ has an invalid value"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV2 = 0 ;
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// BUS_MHZ
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+static const uint32_t BUS_MHZ = (16 / 2) * (K_MCG_C6_VDIV + 16) /(K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV2 + 1) ;
+
+//······················································································································
+
+uint32_t busMHZ (void) {
+  return BUS_MHZ ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV1:OUTDIV3 SETTINGS (divisor for Flexbus)
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 0 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 1 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 3 ;
+#else
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV3 = 0 ; // 0 for all other settings
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// FLEXBUS_MHZ
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+static const uint32_t FLEXBUS_MHZ = (16 / 2) * (K_MCG_C6_VDIV + 16) /(K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV3 + 1) ;
+
+//······················································································································
+
+uint32_t FlexBusMHZ (void) {
+  return FLEXBUS_MHZ ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV1:OUTDIV4 SETTINGS (divisor for Flash)
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 0 ;
+#elif CPU_MHZ == 240
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 7 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 7 ;
+#elif CPU_MHZ == 192
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 6 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 6 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 5 ;
+#elif CPU_MHZ == 144
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 4 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 4 ;
+#elif CPU_MHZ == 96
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 2 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 3 ;
+#else
+  #error "CPU_MHZ has an invalid value"
+  static const uint32_t K_SIM_CLKDIV1_OUTDIV4 = 0 ;
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// FLASH CLOCK (in kHz)
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+static const uint32_t FLASH_KHZ = (16000 / 2) * (K_MCG_C6_VDIV + 16) / (K_MCG_C5_PRDIV + 1) / (K_SIM_CLKDIV1_OUTDIV4 + 1) ;
+
+//······················································································································
+
+uint32_t FlashKHz (void) {
+  return FLASH_KHZ ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// USB CLOCK
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// The USB module SHOULD be driven by a 48 MHz clock.
+//
+// For all CPU frequencies (but 216 MHz and 180 MHz), this clock is derived from MCGPLLCLK; the MCGPLLCLK is
+// identical to MCGCLOCKOUT (as SIM_CLKDIV2_PLL_FLL_SEL=1). So:
+//   USB_CLOCK = MCGCLOCKOUT * (K_SIM_CLKDIV2_USBFRAC + 1) / (K_SIM_CLKDIV2_USBDIV + 1)
+// We check :
+//   48 MHz == 16 MHz / 2 * (MCG:C6:VDIV + 16) / (MCG:C5:PRDIV + 1) * (K_SIM_CLKDIV2_USBFRAC + 1) / (K_SIM_CLKDIV2_USBDIV + 1)
+// So:
+//   6 * (MCG:C5:PRDIV + 1) * (K_SIM_CLKDIV2_USBDIV + 1) == (MCG:C6:VDIV + 16) * (K_SIM_CLKDIV2_USBFRAC + 1)
+//
+// For 216 MHz and 180 MHz CPU frequencies, we use directly the built-in 48 MHz clock: SIM_CLKDIV2_PLL_FLL_SEL=3, with
+// di divisor (K_SIM_CLKDIV2_USBFRAC=0 and K_SIM_CLKDIV2_USBDIV=0).
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// USB SETTING SUMMARY
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// F_CPU   SIM_CLKDIV2   SIM_CLKDIV2   SIM_SOPT2_
+// _MHZ        _USBDIV      _USBFRAC    PLLFLLSEL
+//  240              4             0            1
+//  216              0             0            3
+//  192              3             0            1
+//  180              0             0            3
+//  168              6             1            1
+//  144              2             0            1
+//  120              4             1            1
+//   96              1             0            1
+//   72              2             1            1
+//   48              1             0            1
+//   24              1             0            1
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:SOPT2:PLLFLLSEL SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 0 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 3 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 3 ;
+#else
+  static const uint32_t K_SIM_SOPT2_PLLFLLSEL = 1 ; // For all other settings
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV2:USBFRAC SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV2_USBFRAC = 0 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_SIM_CLKDIV2_USBFRAC = 1 ;
+#else
+  static const uint32_t K_SIM_CLKDIV2_USBFRAC = 0 ; // For all other settings
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+// SIM:CLKDIV2:USBDIV SETTINGS
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#ifndef CPU_MHZ
+  #error "CPU_MHZ is not defined"
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
+#elif CPU_MHZ == 240
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 4 ;
+#elif CPU_MHZ == 216
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
+#elif CPU_MHZ == 192
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 3 ;
+#elif CPU_MHZ == 180
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
+#elif CPU_MHZ == 168
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 6 ;
+#elif CPU_MHZ == 144
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 2 ;
+#elif CPU_MHZ == 120
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 4 ;
+#elif CPU_MHZ == 96
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
+#elif CPU_MHZ == 72
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 2 ;
+#elif CPU_MHZ == 48
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
+#elif CPU_MHZ == 24
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 1 ;
+#else
+  #error "CPU_MHZ has an invalid value"
+  static const uint32_t K_SIM_CLKDIV2_USBDIV = 0 ;
+#endif
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//  BOOT ROUTINE
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void startPhase1 (void) {
+//--------------------------------------------------- Disable watchdog timer
+//--- These two instructions are required for unlocking watchdog timer
+  WDOG_UNLOCK = 0xC520 ;
+  WDOG_UNLOCK = 0xD928 ;
+//--- Disable watchdog timer
+  WDOG_STCTRLH = 0 ;
+//--------------------------------------------------- Enable clocks to always-used peripherals
+  SIM_SCGC3 = SIM_SCGC3_ADC1 | SIM_SCGC3_FTM2 | SIM_SCGC3_FTM3 ;
+  SIM_SCGC5 = SIM_SCGC5_PORTA | SIM_SCGC5_PORTB | SIM_SCGC5_PORTC | SIM_SCGC5_PORTD | SIM_SCGC5_PORTE ;    // clocks active to all GPIO
+  SIM_SCGC6 = SIM_SCGC6_RTC | SIM_SCGC6_FTM0 | SIM_SCGC6_FTM1 | SIM_SCGC6_ADC0 | SIM_SCGC6_FTF ;
+//  SCB_CPACR = 0x00F0_0000; // Enable floating point unit
+  LMEM_PCCCR = LMEM_PCCCR_GO | LMEM_PCCCR_INVW1 | LMEM_PCCCR_INVW0 | LMEM_PCCCR_ENWRBUF | LMEM_PCCCR_ENCACHE ;
+//--- If the RTC oscillator isn't enabled, get it started early
+	if ((RTC_CR & RTC_CR_OSCE) != 0) {
+		RTC_SR = 0;
+		RTC_CR = RTC_CR_SC16P | RTC_CR_SC4P | RTC_CR_OSCE;
+	}
+//--- Release I/O pins hold, if we woke up from VLLS mode
+	if (PMC_REGSC & PMC_REGSC_ACKISO) {
+    PMC_REGSC |= PMC_REGSC_ACKISO;
+  }
+//---------------------------------------------------
+//--- Since this is a write once register, make it visible to all F_CPU's
+//    so we can into other sleep modes in the future at any speed
+	SMC_PMPROT = SMC_PMPROT_AHSRUN | SMC_PMPROT_AVLP | SMC_PMPROT_ALLS | SMC_PMPROT_AVLLS;
+//--------------------------------------------------- PLL initialization (start in FEI mode)
+//--- Enable capacitors for crystal
+  OSC_CR = OSC_CR_SC8P | OSC_CR_SC2P | OSC_CR_ERCLKEN;
+//--- Enable osc, 8-32 MHz range, low power mode
+	MCG_C2 = MCG_C2_RANGE (2) | MCG_C2_EREFS;
+//--- Switch to crystal as clock source, FLL input = 16 MHz / 512
+	MCG_C1 =  MCG_C1_CLKS(2) | MCG_C1_FRDIV(4);
+//--- Wait for crystal oscillator to begin
+	while ((MCG_S & MCG_S_OSCINIT0) == 0) {}
+//--- Wait for FLL to use oscillator
+	while ((MCG_S & MCG_S_IREFST) != 0) {}
+//--- Wait for MCGOUT to use oscillator
+	while ((MCG_S & MCG_S_CLKST (3)) != MCG_S_CLKST(2)) {}
+//--- Now we're in FBE mode
+//------------------------------------ Read microcontroller serial number
+//   This SHOULD be done in normal mode (not in HSRUN mode)
+//   We cannot store result in RAM, BSS section will be cleared (see below)
+  const uint32_t serialNumber = readMicrocontrollerSerialNumber () ;
+//------------------------------------ Turn on the PLL
+  SMC_PMCTRL = SMC_PMCTRL_RUNM (3); // enter HSRUN mode
+	while (SMC_PMSTAT != SMC_PMPROT_AHSRUN) {} // wait for HSRUN
+//--- Configure CPU clock
+  MCG_C5 = K_MCG_C5_PRDIV ;
+  MCG_C6 = MCG_C6_PLLS | K_MCG_C6_VDIV ;
+//--- Wait for PLL to start using xtal as its input
+	while (!(MCG_S & MCG_S_PLLST)) {}
+//--- Wait for PLL to lock
+	while (!(MCG_S & MCG_S_LOCK0)) {}
+//------------------------------------ Now we're in PBE mode: program the clock dividers
+  SIM_CLKDIV1 =
+    SIM_CLKDIV1_OUTDIV1(K_SIM_CLKDIV1_OUTDIV1)
+  | SIM_CLKDIV1_OUTDIV2(K_SIM_CLKDIV1_OUTDIV2)
+  | SIM_CLKDIV1_OUTDIV3(K_SIM_CLKDIV1_OUTDIV3)
+  | SIM_CLKDIV1_OUTDIV4(K_SIM_CLKDIV1_OUTDIV4)
+  ;
+  SIM_CLKDIV2 =
+    SIM_CLKDIV2_USBDIV (K_SIM_CLKDIV2_USBDIV)
+  | K_SIM_CLKDIV2_USBFRAC
+  ;
+//--- Switch to PLL as clock source
+  MCG_C1 = MCG_C1_CLKS(0) | MCG_C1_FRDIV(4);
+//--- Wait for PLL clock to be used
+  while ((MCG_S & MCG_S_CLKST (3)) != MCG_S_CLKST(3)) {}
+//--- USB clock
+  SIM_SOPT2 =
+    SIM_SOPT2_USBSRC
+  | (K_SIM_SOPT2_PLLFLLSEL << 16)
+  | SIM_SOPT2_TRACECLKSEL
+  ;
+//------------------------------------ Clear '.bss' section
+  extern uint32_t __bss_start ;
+  extern const uint32_t __bss_end ;
+  uint32_t * p = & __bss_start ;
+  while (p != & __bss_end) {
+    * p = 0 ;
+    p ++ ;
+  }
+//------------------------------------ Copy .data section in RAM
+  extern uint32_t __data_start ;
+  extern const uint32_t __data_end ;
+  extern uint32_t __data_load_start ;
+  uint32_t * pSrc = & __data_load_start ;
+  uint32_t * pDest = & __data_start ;
+  while (pDest != & __data_end) {
+    * pDest = * pSrc ;
+    pDest ++ ;
+    pSrc ++ ;
+  }
+//------------------------------------ Now, we can store serial number
+  gMicrocontrollerSerialNumber = serialNumber ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+//   MICROCONTROLLER SERIAL NUMBER
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+static uint32_t readMicrocontrollerSerialNumber (void) {
+  while ((FTFE_FSTAT & FTFE_FSTAT_CCIF) == 0) {} // Wait
+  FTFE_FSTAT = FTFE_FSTAT_RDCOLERR | FTFE_FSTAT_ACCERR | FTFE_FSTAT_FPVIOL;
+//--- FTFE_FCCOB3 is a 8-bit register, followed by 3 other 8-bit registers, we write value by a single 32-bit access)
+  FTFE_FCCOB_0_3 = 0x41070000 ;
+  FTFE_FSTAT = FTFE_FSTAT_CCIF ;
+  while ((FTFE_FSTAT & FTFE_FSTAT_CCIF) == 0) {} // Wait
+//--- Read serial number (FTFE_FCCOBB is a 8-bit register, followed by 3 other 8-bit registers, we get the serial number with a single 32-bit access)
+  return FTFE_FCCOB_8_11 ;
+}
+
+//······················································································································
+
+uint32_t microcontrollerSerialNumber (void) {
+  return gMicrocontrollerSerialNumber ;
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void startPhase2 (void) {
+//------------------------------------ Aller exécuter les routines d'initialisation de la section boot.routine.array
+  extern void (* __boot_routine_array_start) (void) ;
+  extern void (* __boot_routine_array_end) (void) ;
+  void (* * ptr) (void) = & __boot_routine_array_start ;
+  while (ptr != & __boot_routine_array_end) {
+    (* ptr) () ;
+    ptr ++ ;
+  }
+//------------------------------------ Run C++ global variable constructors
+  extern void (* __constructor_array_start) (void) ;
+  extern void (* __constructor_array_end) (void) ;
+  ptr = & __constructor_array_start ;
+  while (ptr != & __constructor_array_end) {
+    (* ptr) () ;
+    ptr ++ ;
+  }
+//------------------------------------ Aller exécuter les routines d'initialisation de la section init.routine.array
+  extern void (* __init_routine_array_start) (void) ;
+  extern void (* __init_routine_array_end) (void) ;
+  ptr = & __init_routine_array_start ;
+  while (ptr != & __init_routine_array_end) {
+    (* ptr) () ;
+    ptr ++ ;
+  }
+}
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 25 - 0
steps/01-blink-led/sources/start-teensy-3-6.h

@@ -0,0 +1,25 @@
+#pragma once
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+#include <stdint.h>
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+uint32_t FlexBusMHZ (void) ;
+
+uint32_t busMHZ (void) ;
+
+uint32_t FlashKHz (void) ;
+
+uint32_t microcontrollerSerialNumber (void) ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void startPhase1 (void) asm ("start.phase1") ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+void startPhase2 (void) asm ("start.phase2") ;
+
+//——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

ファイルの差分が大きいため隠しています
+ 14732 - 0
steps/01-blink-led/sources/teensy-3-6-control-registers.h


+ 274 - 0
steps/01-blink-led/sources/teensy-3-6-interrupt-vectors.s

@@ -0,0 +1,274 @@
+@———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+@   INTERRUPT VECTORS
+@———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+	.syntax unified
+	.cpu cortex-m4
+	.thumb
+
+@———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+  .section isr.vectors, "a", %progbits
+
+@———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————
+
+  .word __system_stack_end
+@--- ARM Core System Handler Vectors
+  .word reset.handler @ 1
+  .word interrupt.NMI @ 2
+  .word interrupt.HardFault @ 3
+  .word interrupt.MemManage @ 4
+  .word interrupt.BusFault @ 5
+  .word interrupt.UsageFault @ 6
+  .word -1 @ 7, reserved
+  .word -1 @ 8, reserved
+  .word -1 @ 9, reserved
+  .word -1 @ 10, reserved
+  .word interrupt.SVC @ 11
+  .word interrupt.DebugMonitor @ 12
+  .word -1 @ 13, reserved
+  .word interrupt.PendSV @ 14
+  .word interrupt.SysTick @ 15
+@--- Non-Core Vectors
+  .word interrupt.DMA0_DMA16 @ 16
+  .word interrupt.DMA1_DMA17 @ 17
+  .word interrupt.DMA2_DMA18 @ 18
+  .word interrupt.DMA3_DMA19 @ 19
+  .word interrupt.DMA4_DMA20 @ 20
+  .word interrupt.DMA5_DMA21 @ 21
+  .word interrupt.DMA6_DMA22 @ 22
+  .word interrupt.DMA7_DMA23 @ 23
+  .word interrupt.DMA8_DMA24 @ 24
+  .word interrupt.DMA9_DMA25 @ 25
+  .word interrupt.DMA10_DMA26 @ 26
+  .word interrupt.DMA11_DMA27 @ 27
+  .word interrupt.DMA12_DMA28 @ 28
+  .word interrupt.DMA13_DMA29 @ 29
+  .word interrupt.DMA14_DMA30 @ 30
+  .word interrupt.DMA15_DMA31 @ 31
+  .word interrupt.DMA_Error @ 32
+  .word interrupt.MCM @ 33
+  .word interrupt.FTFE @ 34
+  .word interrupt.Read_Collision @ 35
+  .word interrupt.LVD_LVW @ 36
+  .word interrupt.LLWU @ 37
+  .word interrupt.WDOG_EWM @ 38
+  .word interrupt.RNG @ 39
+  .word interrupt.I2C0 @ 40
+  .word interrupt.I2C1 @ 41
+  .word interrupt.SPI0 @ 42
+  .word interrupt.SPI1 @ 43
+  .word interrupt.I2S0_Tx @ 44
+  .word interrupt.I2S0_Rx @ 45
+  .word -1 @ 46 (unused)
+  .word interrupt.UART0_RX_TX @ 47
+  .word interrupt.UART0_ERR @ 48
+  .word interrupt.UART1_RX_TX @ 49
+  .word interrupt.UART1_ERR @ 50
+  .word interrupt.UART2_RX_TX @ 51
+  .word interrupt.UART2_ERR @ 52
+  .word interrupt.UART3_RX_TX @ 53
+  .word interrupt.UART3_ERR @ 54
+  .word interrupt.ADC0 @ 55
+  .word interrupt.CMP0 @ 56
+  .word interrupt.CMP1 @ 57
+  .word interrupt.FTM0 @ 58
+  .word interrupt.FTM1 @ 59
+  .word interrupt.FTM2 @ 60
+  .word interrupt.CMT @ 61
+  .word interrupt.RTC @ 62
+  .word interrupt.RTC_Seconds @ 63
+  .word interrupt.PIT0 @ 64
+  .word interrupt.PIT1 @ 65
+  .word interrupt.PIT2 @ 66
+  .word interrupt.PIT3 @ 67
+  .word interrupt.PDB0 @ 68
+  .word interrupt.USB0 @ 69
+  .word interrupt.USBDCD @ 70
+  .word -1 @ 71 (unused)
+  .word interrupt.DAC0 @ 72
+  .word interrupt.MCG @ 73
+  .word interrupt.LPTMR0 @ 74
+  .word interrupt.PORTA @ 75
+  .word interrupt.PORTB @ 76
+  .word interrupt.PORTC @ 77
+  .word interrupt.PORTD @ 78
+  .word interrupt.PORTE @ 79
+  .word interrupt.SWINT @ 80
+  .word interrupt.SPI2 @ 81
+  .word interrupt.UART4_RX_TX @ 82
+  .word interrupt.UART4_ERR @ 83
+  .word -1 @ 84 (unused)
+  .word -1 @ 85 (unused)
+  .word interrupt.CMP2 @ 86
+  .word interrupt.FTM3 @ 87
+  .word interrupt.DAC1 @ 88
+  .word interrupt.ADC1 @ 89
+  .word interrupt.I2C2 @ 90
+  .word interrupt.CAN0_ORed_Message_buffer @ 91
+  .word interrupt.CAN0_Bus_Off @ 92
+  .word interrupt.CAN0_Error @ 93
+  .word interrupt.CAN0_Tx_Warning @ 94
+  .word interrupt.CAN0_Rx_Warning @ 95
+  .word interrupt.CAN0_Wake_Up @ 96
+  .word interrupt.SDHC @ 97
+  .word interrupt.ENET_1588_Timer @ 98
+  .word interrupt.ENET_Transmit @ 99
+  .word interrupt.ENET_Receive @ 100
+  .word interrupt.ENET_Error @ 101
+  .word interrupt.LPUART0 @ 102
+  .word interrupt.TSI0 @ 103
+  .word interrupt.TPM1 @ 104
+  .word interrupt.TPM2 @ 105
+  .word interrupt.USBHSDCD @ 106
+  .word interrupt.I2C3 @ 107
+  .word interrupt.CMP3 @ 108
+  .word interrupt.USBHS @ 109
+  .word interrupt.CAN1_ORed_Message_buffer @ 110
+  .word interrupt.CAN1_Bus_Off @ 111
+  .word interrupt.CAN1_Error @ 112
+  .word interrupt.CAN1_Tx_Warning @ 113
+  .word interrupt.CAN1_Rx_Warning @ 114
+  .word interrupt.CAN1_Wake_Up @ 115
+  .word -1 @ 116 (unused)
+  .word -1 @ 117 (unused)
+  .word -1 @ 118 (unused)
+  .word -1 @ 119 (unused)
+  .word -1 @ 120 (unused)
+  .word -1 @ 121 (unused)
+  .word -1 @ 122 (unused)
+  .word -1 @ 123 (unused)
+  .word -1 @ 124 (unused)
+  .word -1 @ 125 (unused)
+  .word -1 @ 126 (unused)
+  .word -1 @ 127 (unused)
+  .word -1 @ 128 (unused)
+  .word -1 @ 129 (unused)
+  .word -1 @ 130 (unused)
+  .word -1 @ 131 (unused)
+  .word -1 @ 132 (unused)
+  .word -1 @ 133 (unused)
+  .word -1 @ 134 (unused)
+  .word -1 @ 135 (unused)
+  .word -1 @ 136 (unused)
+  .word -1 @ 137 (unused)
+  .word -1 @ 138 (unused)
+  .word -1 @ 139 (unused)
+  .word -1 @ 140 (unused)
+  .word -1 @ 141 (unused)
+  .word -1 @ 142 (unused)
+  .word -1 @ 143 (unused)
+  .word -1 @ 144 (unused)
+  .word -1 @ 145 (unused)
+  .word -1 @ 146 (unused)
+  .word -1 @ 147 (unused)
+  .word -1 @ 148 (unused)
+  .word -1 @ 149 (unused)
+  .word -1 @ 150 (unused)
+  .word -1 @ 151 (unused)
+  .word -1 @ 152 (unused)
+  .word -1 @ 153 (unused)
+  .word -1 @ 154 (unused)
+  .word -1 @ 155 (unused)
+  .word -1 @ 156 (unused)
+  .word -1 @ 157 (unused)
+  .word -1 @ 158 (unused)
+  .word -1 @ 159 (unused)
+  .word -1 @ 160 (unused)
+  .word -1 @ 161 (unused)
+  .word -1 @ 162 (unused)
+  .word -1 @ 163 (unused)
+  .word -1 @ 164 (unused)
+  .word -1 @ 165 (unused)
+  .word -1 @ 166 (unused)
+  .word -1 @ 167 (unused)
+  .word -1 @ 168 (unused)
+  .word -1 @ 169 (unused)
+  .word -1 @ 170 (unused)
+  .word -1 @ 171 (unused)
+  .word -1 @ 172 (unused)
+  .word -1 @ 173 (unused)
+  .word -1 @ 174 (unused)
+  .word -1 @ 175 (unused)
+  .word -1 @ 176 (unused)
+  .word -1 @ 177 (unused)
+  .word -1 @ 178 (unused)
+  .word -1 @ 179 (unused)
+  .word -1 @ 180 (unused)
+  .word -1 @ 181 (unused)
+  .word -1 @ 182 (unused)
+  .word -1 @ 183 (unused)
+  .word -1 @ 184 (unused)
+  .word -1 @ 185 (unused)
+  .word -1 @ 186 (unused)
+  .word -1 @ 187 (unused)
+  .word -1 @ 188 (unused)
+  .word -1 @ 189 (unused)
+  .word -1 @ 190 (unused)
+  .word -1 @ 191 (unused)
+  .word -1 @ 192 (unused)
+  .word -1 @ 193 (unused)
+  .word -1 @ 194 (unused)
+  .word -1 @ 195 (unused)
+  .word -1 @ 196 (unused)
+  .word -1 @ 197 (unused)
+  .word -1 @ 198 (unused)
+  .word -1 @ 199 (unused)
+  .word -1 @ 200 (unused)
+  .word -1 @ 201 (unused)
+  .word -1 @ 202 (unused)
+  .word -1 @ 203 (unused)
+  .word -1 @ 204 (unused)
+  .word -1 @ 205 (unused)
+  .word -1 @ 206 (unused)
+  .word -1 @ 207 (unused)
+  .word -1 @ 208 (unused)
+  .word -1 @ 209 (unused)
+  .word -1 @ 210 (unused)
+  .word -1 @ 211 (unused)
+  .word -1 @ 212 (unused)
+  .word -1 @ 213 (unused)
+  .word -1 @ 214 (unused)
+  .word -1 @ 215 (unused)
+  .word -1 @ 216 (unused)
+  .word -1 @ 217 (unused)
+  .word -1 @ 218 (unused)
+  .word -1 @ 219 (unused)
+  .word -1 @ 220 (unused)
+  .word -1 @ 221 (unused)
+  .word -1 @ 222 (unused)
+  .word -1 @ 223 (unused)
+  .word -1 @ 224 (unused)
+  .word -1 @ 225 (unused)
+  .word -1 @ 226 (unused)
+  .word -1 @ 227 (unused)
+  .word -1 @ 228 (unused)
+  .word -1 @ 229 (unused)
+  .word -1 @ 230 (unused)
+  .word -1 @ 231 (unused)
+  .word -1 @ 232 (unused)
+  .word -1 @ 233 (unused)
+  .word -1 @ 234 (unused)
+  .word -1 @ 235 (unused)
+  .word -1 @ 236 (unused)
+  .word -1 @ 237 (unused)
+  .word -1 @ 238 (unused)
+  .word -1 @ 239 (unused)
+  .word -1 @ 240 (unused)
+  .word -1 @ 241 (unused)
+  .word -1 @ 242 (unused)
+  .word -1 @ 243 (unused)
+  .word -1 @ 244 (unused)
+  .word -1 @ 245 (unused)
+  .word -1 @ 246 (unused)
+  .word -1 @ 247 (unused)
+  .word -1 @ 248 (unused)
+  .word -1 @ 249 (unused)
+  .word -1 @ 250 (unused)
+  .word -1 @ 251 (unused)
+  .word -1 @ 252 (unused)
+  .word -1 @ 253 (unused)
+  .word -1 @ 254 (unused)
+  .word -1 @ 255 (unused)
+
+@———————————————————————————————————————————————————————————————————————————————————————————————————————————————————————

+ 17 - 0
steps/01-blink-led/sources/unused-interrupt.s

@@ -0,0 +1,17 @@
+	.syntax unified
+	.cpu cortex-m4
+	.thumb
+
+@-----------------------------------------------------------------------------------------------------------------------
+@   UNUSED INTERRUPT
+@-----------------------------------------------------------------------------------------------------------------------
+
+  .section .text.unused.interrupt, "ax", %progbits
+
+  .align  1
+  .global unused.interrupt
+
+unused.interrupt:
+  b    unused.interrupt
+
+@-----------------------------------------------------------------------------------------------------------------------