So we have prepared the code that we want to compile using SCons.
1. Command prompt
Since SCons will be invoked from the command line, it’s nice to have a batch file that will open the prompt with the necessary settings; so let’s create the following file in the project folder and call it shell.bat:
REM Add Python and tool-chain locations to system path set PYTHON_PATH=C:\Python27 set GNUARM_PATH=D:\APPLICATIONS\_DEVELOPMENT\_LANG\GNUARM\GNU Tools ARM Embedded\4.9 2014q4\bin set OPENOCD_PATH=D:\APPLICATIONS\_DEVELOPMENT\_LANG\GNUARM\OpenOCD\openocd-0.8.0\bin-x64 set PATH=%PYTHON_PATH%;%GNUARM_PATH%;%OPENOCD_PATH%;%PATH% start cmd.exe
Of course the specified paths must be substituted with correct ones. Now, if we double-click on the shell.bat file, a new command prompt will be opened.
2. The SCons script
Let’s then create a file in the project folder and call it SConstruct with the following contents:
# gnu arm toolchain must be already in system path import os env = Environment(ENV = os.environ) env['AR'] = 'arm-none-eabi-ar' env['AS'] = 'arm-none-eabi-as' env['CC'] = 'arm-none-eabi-gcc' env['CXX'] = 'arm-none-eabi-g++' env['LINK'] = 'arm-none-eabi-g++' # predefined is 'arm-none-eabi-gcc' env['RANLIB'] = 'arm-none-eabi-ranlib' env['OBJCOPY'] = 'arm-none-eabi-objcopy' env['PROGSUFFIX'] = '.elf' # include locations env['CPPPATH'] = [ '#Inc', '#Drivers/CMSIS/Include', '#Drivers/CMSIS/Device/ST/STM32F4xx/Include', '#Drivers/STM32F4xx_HAL_Driver/Inc', '#Drivers/STM32F4xx_HAL_Driver/Inc/Legacy', ] # compiler flags env.Append(CCFLAGS = [ '-mcpu=cortex-m4', '-mthumb', '-O2', '-fsigned-char', '-ffunction-sections', '-fdata-sections', '-std=gnu11', '-fmessage-length=0', '-mthumb-interwork', ]) # linker flags env.Append(LINKFLAGS = [ '-ffunction-sections', '-fdata-sections', '-TTrueSTUDIO/Discovery001 Configuration/STM32F407VG_FLASH.ld', '-Xlinker', '--gc-sections', '--specs=nano.specs', ]) # defines env.Append(CPPDEFINES = [ 'STM32F407xx', ]) # build everything prg = env.Program( target = 'main', source = [ 'Src/main.c', 'Src/stm32f4xx_hal_msp.c', 'Src/stm32f4xx_it.c', 'Src/sys/startup_stm32f4xx_fromCoocox.c', 'Drivers/CMSIS/Device/ST/STM32F4xx/Source/Templates/system_stm32f4xx.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_cortex.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_dma_ex.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ex.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_flash_ramfunc.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_gpio.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_pwr_ex.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_rcc_ex.c', 'Drivers/STM32F4xx_HAL_Driver/Src/stm32f4xx_hal_uart.c', ] ) # binary file builder def arm_generator(source, target, env, for_signature): return '$OBJCOPY -O binary %s %s'%(source[0], target[0]) env.Append(BUILDERS = { 'Objcopy': Builder( generator=arm_generator, suffix='.bin', src_suffix='.elf' ) }) env.Objcopy(prg)
This is our SCons configuration file. SCons experts will deservedly turn their nose up, because it’s super-simplified. SCons can do a lot more and better, but this script works and proves how it can be used to cross-compile for our target.
What the script does is very simple:
- In the first section it set the parameters that inform SCons about the toolchain we are using.
- Then the include libraries are added, together with compiler and linker flags.
- Finally all the sources are compiled and the final program is built. Afterwards the produced .elf file is converted in the binary form suitable for uploading to flash.
3. Building and uploading the project
In order to build the project, open a new command prompt by double cliccking on the previously created shell.bat file and type scons.
If everything works, at the end you should read something like “scons: done building targets.” and a couple of files should now be present in the project folder: main.elf and main.bin.
The second one can be uploaded to the MCU flash using the command:
openocd -f board/stm32f4discovery.cfg -c "init; reset halt; flash write_image erase main.bin 0x08000000; reset run; shutdown"
After some seconds, the board should start blinking, and if you connect to the USART2 port some chars are received.
Happy coding!