SConstruct.py - Build all libraries and examples over many chips¶
This file contains all that a SConstruct file normally contains.
In order to use CodeChat, however, all Python files must end with
a .py
extension. So, SConstuct simply executes this file.
This file provides an automated build process for the ref index “libraries” included in this collection. To use:
- Install SCons.
- Install the Microchip compiler. Make sure your path includes the directories in which the compiler binaries exist.
- From the command line, change to the directory in which this file lies.
- Execute
SCons
, which builds everything. Optionally use runscons.bat to filter through the resulting warnings.The build process can be modified by passing options to SCons. See
SCons --help
for options specific to this build andSCons -H
for generic SCons options.
The generated build targets follow the naming convention:
[bootloader/esos]_hardware platform_mcu_[clock/nofloat]
This module perfoms builds over a variety of CPUs and configurations. The files listed below specify a set of targets used in each of these builds.
The overall structure of this file is:
import os
import psutil
Make sure SCons is recent enough.
EnsureSConsVersion(2, 0)
Create a Microchip XC16 Construction Environment¶
Define command-line options to set bootloader. The Environment below depends on opts, so this must go here instead of with the rest of the Command-line options.
opts = Variables()
opts.Add(EnumVariable('BOOTLDR', 'Determines bootloader type', 'msu',
allowed_values=('msu', 'none')))
Create the environment.
env = Environment(
Force SCons to set up with gnu tools to start with reasonable defaults. Note: using platform = ‘posix’ causes SCons to try to call fork() when executing programs (such as compilers), which errors out on Windows.
tools = ['gcc', 'gnulink', 'ar', 'zip', 'packaging'],
options = opts,
CPPPATH = 'lib/include',
CC = 'xc16-gcc',
LIBPATH = '.',
AR = 'xc16-ar',
LINK = 'xc16-gcc',
Copied and cobbled together from SConsToolscc.py with mods
CCCOM = '$CC -c -o $TARGET $CFLAGS $CCFLAGS $CPPFLAGS $_CPPDEFFLAGS $_CPPINCFLAGS $SOURCES',
CCCCOMSTR = 'Compiling $SOURCES',
The warnings provide some lint-like checking. Omitted options: -Wstrict-prototypes -Wold-style-definition complains about void foo(), which should be void foo(void), but isn’t worth the work to change.
CCFLAGS = '-mcpu=${MCU} -O1 -msmart-io=1 -omf=elf -Wall -Wextra -Wdeclaration-after-statement -Wlong-long -fdiagnostics-show-option',
LINKFLAGS = '-mcpu=${MCU} -omf=elf -Wl,--heap=100,$LINKERSCRIPT,--stack=16,--check-sections,--data-init,--pack-data,--handles,--isr,--no-gc-sections,--fill-upper=0,--stackguard=16,--no-force-link,--smart-io,--no-cpp',
LINKERSCRIPT = '--script="lib/lkr/p${MCU}_bootldr.gld"',
ARFLAGS = 'rcs',
ARSTR = 'Create static library: $TARGET',
OBJSUFFIX = '.o',
PROGSUFFIX = '.elf',
Copy the host envrionment variables for our scons environment so scons can find the build tools and related env vars.
ENV = os.environ,
)
Create a bin2hex builder¶
Add the bin2hex function to the environment as a new builder This functions converts a binary (.elf or .cof) file to a hex file.
def bin2hex(
The name of the .elf/.cof file to be converted.
binName,
An Environment in which to build these sources.
buildEnvironment,
A string to serve as an alias for this build.
aliasString):
f = os.path.splitext(binName)[0]
myHex = buildEnvironment.Hex(f, f)
Add this hex file to a convenient alias
buildEnvironment.Alias(aliasString, myHex)
b2h = Builder(
action = 'xc16-bin2hex $SOURCE -a -omf=elf',
suffix = 'hex',
src_suffix = 'elf')
env.Append(BUILDERS = {'Hex' : b2h})
Command-line options¶
adjust our default environment based on user command-line requests
dict = env.Dictionary()
if dict['BOOTLDR'] != 'msu':
env.Replace(LINKERSCRIPT = '--script="p${MCU}.gld"')
By default, run number_of_cpus*4 jobs at once. This only works if the –no-cpp option is passed to the linker; otherwise, the linker produces a temporary file in the root build directory, which gets overwritten and confused when multiple builds run. There’s some nice examples and explanation for this in the SCons user guide.
Some results from running on my 8-core PC:, gathered from the Total build time returned by the –debug=time scons command-line option:
-j | Time (sec) | Time (hh:mm:ss) | Speedup |
---|---|---|---|
32 | 303 | 0:05:03 | 11.66006601 |
16 | 348.7 | 0:05:49 | 10.13191855 |
8 | 510.9 | 0:08:31 | 6.915247602 |
4 | 916 | 0:15:16 | 3.8569869 |
2 | 1777 | 0:29:37 | 1.98818233 |
1 | 3533 | 0:58:53 | 1 |
env.SetOption('num_jobs', psutil.cpu_count()*4)
print("Running with -j %d." % GetOption('num_jobs'))
generate some command line help for our custom options
Help(opts.GenerateHelpText(env))
Help("""Additional targets:
template-build: Build all .c/.h files which are produced by templates.
zipit: Build an archive for distributing end-user library contents.
bootloader: Build the bootloader binaries only.""")
A DEBUG STATEMENT to see what the scons build envrionment (env) has defined
#print env.Dump()
Definition of targets¶
First, set up for defining targets.
Inform SCons about the dependencies in the template-based files
SConscript('templates/SConscript.py', 'env')
Create a target which zips up library files. Only built it if explicitly requested on the command line.
if 'zipit' in COMMAND_LINE_TARGETS:
zip_file = 'build/pic24_code_examples.zip'
hg_dir = 'build/pic24lib_all'
env.Command(zip_file, '', [
Clone the repo to create a clean distribution.
Delete(hg_dir, must_exist = 0),
'hg clone . ' + hg_dir,
Copy over hex files from the build.
Copy(hg_dir + '/hex', 'hex'),
Perform zip in clean clone.
'scons -C ' + hg_dir + ' -f SCons_zipit.py', ])
env.Alias('zipit', zip_file)
Only build this if it’s explicitly requested. Since the dependencies of ‘’ are wrong, force a build using AlwaysBuild.
env.AlwaysBuild(zip_file)
Library builds¶
Call SCons_build.py - Build all libraries and examples with a specific buildTargets value. It create a variant build
named hardware_platform _ MCU _ clock
.
def buildTargetsSConscript(
A list of library targets to build, as defined in SCons_build.py - Build all libraries and examples.
buildTargets,
The Environment to use for building. Use env.Clone(MCU='blah', CPPDEFINES='blah'
to choose a MCU, clock, and hardware platform as desired.
env,
A string giving the name of the hardware platform.
hardware_platform,
The same of the clock chosen, or of some special build option (such as nofloat).
extra_defines = ''):
Build a variant directory name, based on the hardware platform, MCU, and extra defines (if any)
vdir = 'build/' + '_'.join([hardware_platform, env['MCU']])
if extra_defines:
vdir += '_' + extra_defines
SConscript('SCons_build.py', exports = 'buildTargets env bin2hex',
variant_dir = vdir)
Build over various MCUs¶
Build small, non-DMA on the PIC24HJ32GP202
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap11', 'chap12'],
env.Clone(MCU='24HJ64GP202'), 'default')
Build everything on the PIC24FJ64GA002
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap11', 'chap12',
'chap15'],
env.Clone(MCU='24FJ64GA002'), 'default')
Build small, non-DMA on the dsPIC33FJ32GP202
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap11', 'chap12'],
env.Clone(MCU='33FJ64GP202'), 'default')
Minimally test the 24F16KA102. It has hardmapped UART pins.
buildTargetsSConscript(['reset', 'echo'],
env.Clone(MCU='24F32KA302', CPPDEFINES='HARDWARE_PLATFORM=HARDMAPPED_UART'), 'hardmappedUART')
Build the PIC24HJ64GP502-compatible directories.
buildTargetsSConscript(['chap11', 'chap13', 'chap15'],
env.Clone(MCU='24HJ64GP502'), 'default')
Same as above, but for a dsPIC
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap11', 'chap12',
'chap13', 'chap15'],
env.Clone(MCU='33FJ128GP802'), 'default')
Same as above, but for the dsPIC33EP128GP502
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap12',
'chap13', 'chap15'],
env.Clone(MCU='33EP128GP502'), 'default')
Build some for the PIC24E device
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap11', 'chap12'],
env.Clone(MCU='24EP64GP202'), 'default')
Build over various hardware platforms¶
Same as above, but for the dsPIC33EP128GP502 on a MicroStickII target
buildTargetsSConscript(['chap08', 'chap09', 'chap10', 'chap12',
'chap13', 'chap15'],
env.Clone(MCU='33EP128GP502', CPPDEFINES='HARDWARE_PLATFORM=MICROSTICK2'), 'microstick2')
Build some selected chapter applications for the chip used on the Fall 2013 Embedded systems board
buildTargetsSConscript(['chap08', 'chap09', 'chap13'],
env.Clone(MCU='33EP128GP504', CPPDEFINES='HARDWARE_PLATFORM=EMBEDDED_C1'), 'embeddedC1')
Build some selected chapter applications for the CAN2 rev.F14 board used in ECE4723 Embedded Systems
buildTargetsSConscript(['chap08', 'chap09'],
env.Clone(MCU='33EP512GP806', CPPDEFINES='HARDWARE_PLATFORM=EMBEDDED_F14'), 'embeddedF14')
Build for the explorer board
buildTargetsSConscript(['explorer'],
env.Clone(MCU='24FJ128GA010', CPPDEFINES='HARDWARE_PLATFORM=EXPLORER16_100P'), 'explorer16100p')
buildTargetsSConscript(['explorer'],
env.Clone(MCU='24HJ256GP610', CPPDEFINES='HARDWARE_PLATFORM=EXPLORER16_100P'), 'explorer16100p')
Build reset on other supported platforms
buildTargetsSConscript(['reset'],
env.Clone(MCU='24FJ64GA002', CPPDEFINES='HARDWARE_PLATFORM=STARTER_BOARD_28P'), 'starterboard28p')
buildTargetsSConscript(['reset'],
env.Clone(MCU='33FJ128GP204', CPPDEFINES='HARDWARE_PLATFORM=DANGEROUS_WEB'), 'dangerousweb')
Build over various clocks¶
Build reset with various clock options on all processors
for clock in ['SIM_CLOCK', 'FRCPLL_FCY16MHz', 'FRC_FCY4MHz',
'PRI_NO_PLL_7372KHzCrystal', 'PRIPLL_8MHzCrystal_16MHzFCY']:
buildTargetsSConscript(['reset'],
env.Clone(MCU='24FJ64GA002', CPPDEFINES='CLOCK_CONFIG=' + clock), 'default', clock)
buildTargetsSConscript(['reset'],
env.Clone(MCU='24FJ64GA102', CPPDEFINES='CLOCK_CONFIG=' + clock), 'default', clock)
buildTargetsSConscript(['reset'],
env.Clone(MCU='24F32KA302', CPPDEFINES=['CLOCK_CONFIG=' + clock, 'HARDWARE_PLATFORM=HARDMAPPED_UART']), 'harmappedUART', clock)
for clock in ['SIM_CLOCK', 'PRI_NO_PLL_7372KHzCrystal', 'FRC_FCY3685KHz',
'FRCPLL_FCY40MHz', 'PRIPLL_7372KHzCrystal_40MHzFCY', 'PRIPLL_8MHzCrystal_40MHzFCY']:
buildTargetsSConscript(['reset'],
env.Clone(MCU='24HJ32GP202', CPPDEFINES='CLOCK_CONFIG=' + clock), 'default', clock)
buildTargetsSConscript(['reset'],
env.Clone(MCU='33FJ128GP802', CPPDEFINES='CLOCK_CONFIG=' + clock), 'default', clock)
Misc builds¶
Do a no-float build of reset
buildTargetsSConscript(['reset'],
env.Clone(MCU='24HJ32GP202', CPPDEFINES='_NOFLOAT'), 'default', 'nofloat')
Bootloader builds¶
Call SCons_bootloader.py - Build the bootloader with a specific Environment. It creates a variant build
named default_bootloader _ MCU
.
def buildTargetsBootloader(
The build environment to use. Typically env
, though a env.Clone
can be used to configure env.
env,
The MCU to build the bootloader for.
mcu,
The DEFINEd name of the target platform
hardware_platform = 'DEFAULT_DESIGN',
The string to use in the target build directory name
hardware_alias = 'default'):
Create an environment for building the bootloader: 1. Define the MCU and the target hardware platform
env = env.Clone(MCU = mcu, HW = hardware_alias)
- Use the custom bootloader linker script.
env.Replace(
LINKERSCRIPT = '--script=bootloader/pic24_dspic33_bootloader.X/lkr/p${MCU}.gld',
)
env.Append(CPPDEFINES = ['BOOTLOADER', 'HARDWARE_PLATFORM=' + hardware_platform])
Now, invoke a variant build using this environment.
SConscript('SCons_bootloader.py', exports = 'env bin2hex',
variant_dir = 'build/bootloader_' + hardware_alias + '_' + mcu)
Build the bootloader for a variety of common MCUs that can have UART in the “default” location, e.g. RB10=MCUrx and RB11=MCUtx
for mcu in ('24FJ32GA002',
'24FJ64GA002',
'24FJ32GA102',
'24FJ64GA102',
'24FJ64GB002',
'24FJ64GB004',
'24HJ12GP202',
'24HJ32GP202',
'24HJ64GP502',
'24HJ128GP502',
'24EP64GP202',
'33FJ32GP202',
'33FJ128GP802',
'33EP128GP502',
'33EP128GP504',
):
buildTargetsBootloader(env, mcu)
Build the bootloader for MCUs with a hardmapped UART.
for mcu in ('24F32KA302',):
buildTargetsBootloader(env, mcu,
hardware_platform='HARDMAPPED_UART',
hardware_alias='hardmappedUART')
Build bootloader for MCUs on specific hardware platforms
buildTargetsBootloader(env,
mcu='33EP128GP504',
hardware_platform='EMBEDDED_C1',
hardware_alias='embeddedC1')
buildTargetsBootloader(env,
mcu='33EP512GP806',
hardware_platform='EMBEDDED_F14',
hardware_alias='embeddedF14')
buildTargetsBootloader(env,
mcu='33EP128GP502',
hardware_platform='MICROSTICK2',
hardware_alias='microstick2')
ESOS builds¶
def buildTargetsEsos(env, mcu, hardware_platform = 'DEFAULT_DESIGN', hardware_alias = 'default'):
Create an environment for building ESOS.
env = env.Clone(MCU = mcu)
env.Append(CPPDEFINES = ['BUILT_ON_ESOS', 'HARDWARE_PLATFORM=' + hardware_platform],
CPPPATH = ['esos/include', 'esos/include/pic24'])
Now, invoke a variant build using this environment.
SConscript('SCons_esos.py', exports = 'env bin2hex',
variant_dir = 'build/esos_' + hardware_alias + '_' + mcu)
Build ESOS over a variety of chips that can have UART in the “default” location, e.g. RB10=MCUrx and RB11=MCUtx
for mcu in (
'24HJ64GP202',
'24FJ64GA002',
'24HJ128GP502',
'24EP64GP202',
'33FJ64GP202',
'33FJ128GP802',
'33EP128GP502',
'33EP128GP504',
):
buildTargetsEsos(env, mcu)
buildTargetsEsos(env, mcu='33EP128GP504', hardware_platform='EMBEDDED_C1', hardware_alias='embeddedC1')
buildTargetsEsos(env, mcu='33EP512GP806', hardware_platform='EMBEDDED_F14', hardware_alias='embeddedF14')
buildTargetsEsos(env, mcu='33EP128GP502', hardware_platform='MICROSTICK2', hardware_alias='microstick2')