Using SCons with GNU toolchain for ARM on Windows – part 3 : the SCons script

[part 1 part 2 part 3]

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!

Advertisements

4 thoughts on “Using SCons with GNU toolchain for ARM on Windows – part 3 : the SCons script

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s