0

I am trying to create a generic cmake file for use with CLion and VSCode. The idea is to create one directory and within it a subdirectory per assignment (this is for my students). In the subdirectory they can create al kinds of C/C++/S sources. There is also a CMakeLists.txt that determines which additional libraries are included (and possibly compiled).

In the super or main directory there is a CMakeLists.txt as follows:

# @file     CMakeLists.txt
# @brief    Generic CMakeFile for ATXMega in VSCode and CLion
# @author   Nico Verduin
# @date     29-3-2023
#

cmake_minimum_required(VERSION 3.12)
set(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)

project(start_voorbeelden CXX C NONE)

# add our sub projects
add_subdirectory(blink)
#add_subdirectory(blink2)
#add_subdirectory(ucg_test)

Then comes a CMakeLists.txt in the subdirectory

#
# @file     CMakeLists.txt
# @brief    root CMakeList.txt for sub projects
# @author   Nico Verduin
# @date     29-3-2023
#
#import the standard cmake
set (USE_SPILIB 1)
#set (USE_UCGLIB 1)
 
include(../generic.cmake)

And last but not least the generic.cmake. This is where all te magic is supposed to happen.

#
# @file     generic.cmake
# @brief    Generic CMakeFile for ATXMega in VSCode and CLion
#           Needs to be imported into the root of the individual
#           sub projects
# @author   Nico Verduin
# @date     29-3-2023
#

# give the project the root folder name
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR FILENAME PROJECT_NAME)
message(STATUS "Current source dir = ${CMAKE_CURRENT_SOURCE_DIR}")

string(REPLACE " " "_" ProjectId ${PROJECT_NAME})
project(${PROJECT_NAME} C CXX NONE)

set(DEV_ROOT d:/vsavr8)
# avrdude
set(AVR_DUDE_EXECUTABLE ${DEV_ROOT}/tools/avrdude.exe)
# compiler path in root/gcc
set(COMPILE_PATH ${DEV_ROOT}/gcc/bin/)

# additional libraries
if(USE_SPILIB)
    set (SPILIB         "../spi/")
    message (STATUS "Including ${SPILIB}")
    include_directories(${SPILIB})
endif()

if(USE_UCGLIB)
    set (UCGLIB         "../ucglib/csrc/")
    set (UCG_CALLBACK   "../ucglib/callback/")
    message (STATUS "Including ${UCGLIB} and ${UCG_CALLBACK}")
    include_directories(${UCGLIB})
    include_directories(${UCG_CALLBACK})
endif()

# CPU to build for
set(TARGET_CPU ATxmega256A3U)

# our compilers
set (CMAKE_C_COMPILER ${COMPILE_PATH}avr-gcc.exe )
set (CMAKE_CXX_COMPILER ${COMPILE_PATH}avr-g++.exe )

#check if we can find the compilers
include(../CMakeVerifyCompiler.txt)

#list all search directories
message(STATUS "Included directories")
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
    message(STATUS "dir='${dir}'")
endforeach()

# compiler switches and definitions
# compiler switches and definitions
add_compile_definitions("__AVR_${TARGET_CPU}__")
add_compile_options("-O3")
add_compile_options(-fdata-sections)
add_compile_options(-ffunction-sections)
add_compile_options("-fpack-struct")
add_compile_options("-fshort-enums")
add_compile_options("-Wall")
add_compile_options("-Werror")
add_compile_options("-funsigned-char")
add_compile_options("-funsigned-bitfields")
add_compile_options("-c")
add_link_options(-Wl,--gc-sections)
add_link_options(-Wl,--print-memory-usage)
add_link_options(-Wl,--print-gc-sections)

# set verbose on
add_compile_options("-v")

# if you want to program in C++ or assembly that option is also added
# just the standard folders in the root
set(PROJECT_SOURCE_DIR  "*.c" "*.h" "*.cpp" "*.hpp" "*.s" )

# add additional library source folders
if (USE_SPILIB)
list( APPEND PROJECT_SOURCE_DIR "${SPILIB}*.c" "${SPILIB}*.h")
endif()

if (USE_UCGLIB)
    list( APPEND PROJECT_SOURCE_DIR "${UCGLIB}*.c" "${UCGLIB}*.h" "${UCG_CALLBACK}*.c" "${UCG_CALLBACK}*.h")
endif()

# get all the sources.
file(GLOB PROJECT_SRC CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR})
MESSAGE(${PROJECT_SRC})

# define our elf file
add_executable(${PROJECT_NAME}.elf
        ${PROJECT_SRC})

#### Uncomment this to see flashing process details
#set(FLASH_VERBOSE_FLAG "-v")
add_custom_target(FLASH_${PROJECT_NAME}
    ${AVR_DUDE_EXECUTABLE} -p x256a3u -P usb -c avrispmkII -b115200  ${FLASH_VERBOSE_FLAG} -U flash:w:${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf:a
    DEPENDS ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf
)

Unfortunately the magic is a little disappointing. If the program it very small it compiled fine. Then I added ucg lib (from olikraus). Now the flash file is bigger than the chip's flash (atxmega256a3u). So apparantly the flash file contained all code was included (about 1.3 MBytes).

I found on the web that I should add the compiler switches

add_compile_options(-fdata-sections)
add_compile_options(-ffunction-sections)

And in the linker part

add_link_options(-Wl,--gc-sections)

Now my flashfile is reduced to 24 bytes text. I don't think that is enough.

I took a smaller test (blink with some SPI functions) and added verbose to see what is coming out. this is the output

"C:\Program Files\JetBrains\CLion 2022.2.3\bin\cmake\win\bin\cmake.exe" --build D:\vsavr8\start_voorbeeld\cmake-build-debug --target blink.elf -- -j 6
Consolidate compiler generated dependencies of target blink.elf
[ 33%] Building C object blink/CMakeFiles/blink.elf.dir/blink.c.obj
Using built-in specs.
Reading specs from d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/device-specs/specs-avr2
COLLECT_GCC=d:\vsavr8\gcc\bin\avr-gcc.exe
Target: avr
Configured with: ../configure --prefix=/opt/avr-gcc-mingw32 --target=avr --enable-languages=c,c++ --disable-nls --disable-libssp --with-dwarf2 --host=x86_64-w64-mingw32 --build=x86_64-pc-linux-gnu : (reconfigured) ../configure --prefix=/opt/avr-gcc-mingw32 --target=avr --host=x86_64-w64-mingw32 --build=x86_64-pc-linux-gnu --enable-languages=c,c++ --disable-nls --disable-libssp --with-dwarf2 --with-newlib --disable-__cxa_atexit --disable-threads --disable-shared --enable-static --disable-sjlj-exceptions --enable-libstdcxx --enable-lto --disable-hosted-libstdcxx
Thread model: single
gcc version 9.2.0 (GCC) 
COLLECT_GCC_OPTIONS='-D' '__AVR_ATxmega256A3U__' '-I' 'D:\vsavr8\start_voorbeeld\blink\..\spi' '-g' '-O3' '-fdata-sections' '-ffunction-sections' '-fpack-struct' '-fshort-enums' '-Wall' '-Werror' '-funsigned-char' '-funsigned-bitfields' '-c' '-v' '-MD' '-MT' 'blink/CMakeFiles/blink.elf.dir/blink.c.obj' '-MF' 'CMakeFiles\blink.elf.dir\blink.c.obj.d' '-o' 'CMakeFiles\blink.elf.dir\blink.c.obj' '-c' '-specs=device-specs/specs-avr2'
 d:/vsavr8/gcc/bin/../libexec/gcc/avr/9.2.0/cc1.exe -quiet -v -I D:\vsavr8\start_voorbeeld\blink\..\spi -iprefix d:\vsavr8\gcc\bin\../lib/gcc/avr/9.2.0/ -MD CMakeFiles\blink.elf.dir\blink.c.d -MF CMakeFiles\blink.elf.dir\blink.c.obj.d -MT blink/CMakeFiles/blink.elf.dir/blink.c.obj -D __AVR_ATxmega256A3U__ D:\vsavr8\start_voorbeeld\blink\blink.c -mn-flash=6 -mskip-bug -quiet -dumpbase blink.c -auxbase-strip CMakeFiles\blink.elf.dir\blink.c.obj -g -O3 -Wall -Werror -version -fdata-sections -ffunction-sections -fpack-struct -fshort-enums -funsigned-char -funsigned-bitfields -o C:\Users\NICOVE~1\AppData\Local\Temp\ccyLTv7f.s
GNU C17 (GCC) version 9.2.0 (avr)
    compiled by GNU C version 7.3-win32 20180312, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "d:\vsavr8\gcc\bin\../lib/gcc/avr/9.2.0/../../../../avr/sys-include"
ignoring duplicate directory "d:/vsavr8/gcc/lib/gcc/../../lib/gcc/avr/9.2.0/include"
ignoring duplicate directory "d:/vsavr8/gcc/lib/gcc/../../lib/gcc/avr/9.2.0/include-fixed"
ignoring nonexistent directory "d:/vsavr8/gcc/lib/gcc/../../lib/gcc/avr/9.2.0/../../../../avr/sys-include"
ignoring duplicate directory "d:/vsavr8/gcc/lib/gcc/../../lib/gcc/avr/9.2.0/../../../../avr/include"
#include "..." search starts here:
#include <...> search starts here:
 D:\vsavr8\start_voorbeeld\blink\..\spi
 d:\vsavr8\gcc\bin\../lib/gcc/avr/9.2.0/include
 d:\vsavr8\gcc\bin\../lib/gcc/avr/9.2.0/include-fixed
 d:\vsavr8\gcc\bin\../lib/gcc/avr/9.2.0/../../../../avr/include
End of search list.
GNU C17 (GCC) version 9.2.0 (avr)
    compiled by GNU C version 7.3-win32 20180312, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: cf45033fcb74fa02d7459bd3a612262e
COLLECT_GCC_OPTIONS='-D' '__AVR_ATxmega256A3U__' '-I' 'D:\vsavr8\start_voorbeeld\blink\..\spi' '-g' '-O3' '-fdata-sections' '-ffunction-sections' '-fpack-struct' '-fshort-enums' '-Wall' '-Werror' '-funsigned-char' '-funsigned-bitfields' '-c' '-v' '-MD' '-MT' 'blink/CMakeFiles/blink.elf.dir/blink.c.obj' '-MF' 'CMakeFiles\blink.elf.dir\blink.c.obj.d' '-o' 'CMakeFiles\blink.elf.dir\blink.c.obj' '-c' '-specs=device-specs/specs-avr2'
 d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/as.exe -mmcu=avr2 -mgcc-isr -o CMakeFiles\blink.elf.dir\blink.c.obj C:\Users\NICOVE~1\AppData\Local\Temp\ccyLTv7f.s
COMPILER_PATH=d:/vsavr8/gcc/bin/../libexec/gcc/avr/9.2.0/;d:/vsavr8/gcc/bin/../libexec/gcc/;d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/
LIBRARY_PATH=d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/;d:/vsavr8/gcc/bin/../lib/gcc/;d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/lib/
COLLECT_GCC_OPTIONS='-D' '__AVR_ATxmega256A3U__' '-I' 'D:\vsavr8\start_voorbeeld\blink\..\spi' '-g' '-O3' '-fdata-sections' '-ffunction-sections' '-fpack-struct' '-fshort-enums' '-Wall' '-Werror' '-funsigned-char' '-funsigned-bitfields' '-c' '-v' '-MD' '-MT' 'blink/CMakeFiles/blink.elf.dir/blink.c.obj' '-MF' 'CMakeFiles\blink.elf.dir\blink.c.obj.d' '-o' 'CMakeFiles\blink.elf.dir\blink.c.obj' '-c' '-specs=device-specs/specs-avr2'
[ 66%] Linking C executable blink.elf
Memory region         Used Size  Region Size  %age Used
            text:          24 B         8 KB      0.29%
            data:          0 GB      65440 B      0.00%
          eeprom:          0 GB        64 KB      0.00%
            fuse:          0 GB         1 KB      0.00%
            lock:          0 GB         1 KB      0.00%
       signature:          0 GB         1 KB      0.00%
 user_signatures:          0 GB         1 KB      0.00%
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.text.spi_init' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.text.spi_transfer' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.text.spi_write' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.text.spi_read' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_DBLCLK_MASK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_SPEED_MASK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_MODE_MASK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_MASTER_MASK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_LSBFIRST_MASK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_SCK' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_MISO' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.rodata.__SPI_MOSI' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_info' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_abbrev' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_loc' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_aranges' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_ranges' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_line' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_str' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.comment' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_frame' in file 'CMakeFiles/blink.elf.dir/__/spi/spi.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.text.startup.main' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_info' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_abbrev' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_loc' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_aranges' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_ranges' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_line' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_str' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.comment' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
d:/vsavr8/gcc/bin/../lib/gcc/avr/9.2.0/../../../../avr/bin/ld.exe: removing unused section '.debug_frame' in file 'CMakeFiles/blink.elf.dir/blink.c.obj'
[100%] Built target blink.elf

Build finished

last but not least here is my example code:

blink.c

/**
 * @file blink.c
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2023-03-29
 *
 * @copyright Copyright (c) 2023
 *
 */
#define  F_CPU 2000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <spi.h>

/**
 * @brief
 * @return int
 */
int main() {

  spi_init();

  uint8_t x = 0;;
  spi_write(x);

  PORTC.DIRSET = PIN0_bm;       // bit 0 port C is set, it is an output

  while (1) {
    PORTC.OUTSET = PIN0_bm;     // bit 0 port C is high, led is on
    _delay_ms (500);
    PORTC.OUTCLR = PIN0_bm;     // bit 0 port C is low, led is off
    _delay_ms (950);
  }
}

spi.h and spi.c in a directory parallel to blink (called spi)

spi.h

#ifndef __SPI_H
#define __SPI_H

#include <inttypes.h>

#define SPI_SS_bm   0x10
#define SPI_MOSI_bm 0x20
#define SPI_MISO_bm 0x40
#define SPI_SCK_bm  0x80

#define FOO         0x00

// prototypes
void    spi_init(void);                   // init spi
uint8_t spi_transfer(uint8_t data);       // transfer data to slave
void    spi_write(uint8_t data);          // write (register?)
uint8_t spi_read(void);                   // read spi slave

#endif

spi.c

#include <inttypes.h>
#include <avr/io.h>
#include <spi_pins.h>
#include <spi.h>

// SPI on port D
#define __SPI_PORT PORTD
#define __SPI_DDR POR
const uint8_t __SPI_MOSI = 5;
const uint8_t __SPI_MISO = 6;
const uint8_t __SPI_SCK = 7;
const uint8_t __SPI_LSBFIRST_MASK = 0x01;
const uint8_t __SPI_MASTER_MASK = 0x01;
const uint8_t __SPI_MODE_MASK = 0x03;
const uint8_t __SPI_SPEED_MASK = 0x03;
const uint8_t __SPI_DBLCLK_MASK = 0x01;

//initialize the SPI bus
//  uint8_t lsbfirst - if 0: most significant bit is transmitted first
//  uint8_t master - if 1: use master mode, if 0: slave mode is used
//  uint8_t mode - sets the transfer mode:
//                 mode   leading clock edge   trailing clock edge
//                 -----------------------------------------------
//                 0      sample (rising)      setup  (falling)
//                 1      setup  (rising)      sample (falling)
//                 2      sample (falling)     setup  (rising)
//                 3      setup  (falling)     sample (rising)
//  uint8_t clkrate - spi bus clock rate, valid speeds are 0-3
//                    rate   speed
//                    ------------
//                    0      CPUCLK/4
//                    1      CPUCLK/16
//                    2      CPUCLK/64
//                    3      CPUCLK/128
//  uint8_t dblclk - if 1: doubles the SPI clock rate in master mode
//  EXAMPLE: spi_init(0, 1, 0, 3, 0)
void spi_init(void ) {

  // set IO ports
  PORTD.DIRSET = 1 << TFT_SCK | 1 << TFT_MOSI | 1 << TFT_CS;
  PORTD.DIRCLR = 1 << TFT_MISO;

  // deselect CS
  PORTD.OUTSET = 1 << TFT_CS;

  SPID.CTRL = SPI_ENABLE_bm |   // enable SPI
              SPI_MASTER_bm |   // Act as MAster
              SPI_CLK2X_bm  |   // double clock speed
              SPI_DORD_bm   |   // MSB first
              SPI_MODE_0_gc |   // SPI mode 0
              SPI_PRESCALER_DIV4_gc; // prescaling 4

}

/**
 * Transfer data over SPI
 * @param data
 * @return
 */
uint8_t spi_transfer(uint8_t data) {
  SPID.DATA = data;                       // fill SPI data register
  while (!(SPID.STATUS & (SPI_IF_bm)));   // wait until transferred
  return SPIC.DATA;                       // return sent data
}

/**
 * write data but do chip select first and deselect when sent
 * @param data
 */
void spi_write(uint8_t data) {
  PORTD.OUTCLR = 1 << TFT_CS;
  spi_transfer(data);
  PORTD.OUTSET = 1 << TFT_CS;
}

uint8_t spi_read(void){
  uint8_t data;

  PORTD.OUTCLR = 1 << TFT_CS;
  data = spi_transfer(FOO);
  PORTD.OUTSET = 1 << TFT_CS;

  return data;
}

The concept seems to work fine allowing students to create on directory per subject and then subdirectories per assignment. By making a generci cmake with the addational libraries they can focus on actual programming and not be disturbed by complicating stuff about the environment. And we are talking about students of who some are just learning to program for the first time of their lives.

All help will appreciated Regards Nico


Corrected files After input from @Tsyvarev the files are now as follows:

CMakeLists.txt

#
# @file     CMakeLists.txt
# @brief    Generic CMakeFile for ATXMega in VSCode and CLion
# @author   Nico Verduin
# @date     6-4-3-2023
#

cmake_minimum_required(VERSION 3.12)
set(CMAKE_SYSTEM_NAME Generic)
SET(CMAKE_SYSTEM_VERSION 1)

# get our avr toolchain lo ation
include(file_locations.cmake)

# CPU to build for
set(TARGET_CPU ATxmega256A3U)

# our compilers
set (CMAKE_C_COMPILER ${COMPILE_PATH}avr-gcc.exe )
set (CMAKE_CXX_COMPILER ${COMPILE_PATH}avr-g++.exe )
set (AVR_SIZE ${COMPILE_PATH}avr-size.exe )
set (AVR_OBJCOPY ${COMPILE_PATH}avr-objcopy.exe )

#check if we can find the compilers
include(CMakeVerifyCompiler.cmake)

# ser our compiler and link options
add_compile_definitions("__AVR_${TARGET_CPU}__")
add_compile_options("-Os")
add_compile_options(-fdata-sections)
add_compile_options(-ffunction-sections)
add_compile_options("-fpack-struct")
add_compile_options("-fshort-enums")
add_compile_options("-Wall")
add_compile_options("-Werror")
add_compile_options("-funsigned-char")
add_compile_options("-funsigned-bitfields")
add_compile_options("-mmcu=${TARGET_CPU}")
add_compile_options("-c")
add_link_options(-Wl,--gc-sections)
add_link_options(-mmcu=${TARGET_CPU})

# create our root project name
get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})

# this line is needed almost at the end of this CMakeLists.txt
project(start_voorbeeld CXX C NONE)

# add our sub projects
add_subdirectory(example_assignment)
add_subdirectory(blink)
add_subdirectory(ucg_test)

generic.cmake

#
# @file     generic.cmake
# @brief    Generic CMakeFile for ATXMega in VSCode and CLion
#           Needs to be imported into the root of the individual
#           sub projects
# @author   Nico Verduin
# @date     6-4-2023
#

# give the project the root folder name
cmake_path(GET CMAKE_CURRENT_SOURCE_DIR FILENAME PROJECT_NAME)

string(REPLACE " " "_" ProjectId ${PROJECT_NAME})
project(${PROJECT_NAME} C CXX NONE)

# additional optional libraries
# these are switched ON in the  CMakeLists.txt of a subdirectory
if(USE_SPILIB)
    set (SPILIB         "../spi/")
    include_directories(${SPILIB})
endif()

if(USE_UCGLIB)
    set (UCGLIB         "../ucglib/csrc/")
    set (UCG_CALLBACK   "../ucglib/callback/")
    include_directories(${UCGLIB})
    include_directories(${UCG_CALLBACK})
endif()

add_link_options("-Wl,--Map=${PROJECT_NAME}.map")

# if you want to program in C++ or assembly that option is also added
# just the standard folders in the root
set(PROJECT_SOURCE_DIR RECURSE "*.c" "*.h" "*.cpp" "*.hpp" "*.s" )

# add additional library source folders. Keep in mind that it does not look in lower
# directories
if (USE_SPILIB)
    list( APPEND  PROJECT_SOURCE_DIR "${SPILIB}*.c" "${SPILIB}*.h")
endif()

if (USE_UCGLIB)
    list( APPEND PROJECT_SOURCE_DIR "${UCGLIB}*.c" "${UCGLIB}*.h" "${UCG_CALLBACK}*.c" "${UCG_CALLBACK}*.h")
endif()

# get all the sources. including thous from sub directories
file(GLOB_RECURSE PROJECT_SRC CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR})

# Set to 1 in local CmakeLists.txt and will generate lots of output
if (VERBOSE)
    # print the memory used in the elf file. A bit useless as it contains
    # lots of info not flashed to the chip
    add_link_options(-Wl,--print-memory-usage)

    # outputs all the parts of .data and .text (mostly defined as .rodata)
    # that are remove due to --gc-sections option
    add_link_options(-Wl,--print-gc-sections)

    # show in detail every compile step
    add_compile_options("-v")

    # set verbose on during flash
    set(FLASH_VERBOSE_FLAG "-v")
endif()

# create our elf file
add_executable(${PROJECT_NAME}.elf
        ${PROJECT_SRC}
        )

# Clean up unused and info code y removing DEBUG info etc
add_custom_command(
        TARGET ${PROJECT_NAME}.elf
        POST_BUILD
        COMMAND ${AVR_OBJCOPY} --strip-all ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf
        # and show the size of our program. Change the -A to -B to get a one line size format
        # has no impact on execution
        COMMAND ${AVR_SIZE} -A ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf

)

add_custom_target(${PROJECT_NAME}_FLASH
        ${AVR_DUDE_EXECUTABLE} -p x256a3u -P usb -c avrispmkII -b115200  ${FLASH_VERBOSE_FLAG} -U flash:w:${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf:a
        DEPENDS ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.elf
)

Local CMakeLists.txt

#
# @file     CMakeLists.txt
# @brief    root CMakeList.txt for sub projects
# @author   Nico Verduin
# @date     29-3-2023
#

# set optional used libraries
set (USE_SPILIB 1)
set (USE_UCGLIB 1)

# If you want to see lots of verbose output from the compilers set VERBOSE to 1
set (VERBOSE)

# do not change this line
include(../generic.cmake)
Nico Verduin
  • 59
  • 1
  • 6
  • 1
    "This is where all te magic is supposed to happen." - This all "magic" about **setting a compiler** should be done in the [toolchain file](https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html#cross-compiling), which is processed at the time when `project()` call is processed. Setting a compiler after that call is wrong, see that my answer: https://stackoverflow.com/a/63944545/3440745 – Tsyvarev Apr 05 '23 at 16:18
  • Thank you for the comment and links. I will try to give it a shot this weekend. I still have a couple of months (this is for next year). Regards Nico – Nico Verduin Apr 06 '23 at 05:47
  • Although I made a lot of changens :) The solution given by @Tsyvarev was the correct one. – Nico Verduin Apr 09 '23 at 10:26

1 Answers1

0

Many (potential) problems here... Let's have a look at gcc's -v babbling. Unfortunately, we don't get to see the commands that make is spawning.

Don't -D __AVR_ATxmega256A3U__

This define is just a tiny little bit of what it means for avr-gcc to support ATxmega256A3U. Instead, use -mmcu=atxmega256a3u in all calls of avr-gcc / avr-g++ (compile, assemble and link). Ditch that -D __AVR_<device>__, it will come from the device-specs file.

You (inadvertently) compiled for device family avr2, not a single device. Outcome is that no start-up code is being linked, thus nothing calls main, thus --gc-sections will ditch everything below and including main. Again, the fix is to -mmcu=atxmega256a3u.

When you inspect the output of -v and find anything other than -mmcu=atxmega256a3u or -mmcu=avrxmega6, you have an error in your make process or option handling.

Where is compilation of blink.c? And link of blink.elf?

None of the calls is showing the compilaton of blink.c. This might be due to make's feature to only (re)compile when a target is older than the dependencies. For a complete compile and to verify all steps, better post output of -v after make clean or so.

Moreover, the -v doesn't contain the linker call that builds blink.elf from the object file blink.c.obj. As the latter is newer as the former, make should issue a command to link blink.elf. So something is broken with your cmake config?

Where is treatment of spi.c?

Same for the SPI module: No compile, no link. main uses SPI, but you won't get any "undefined reference" error from the linker because all code is dead, anyway (because nothing references main).

"Now the flash file is bigger than the chip's flash."

Three issues might be responsible here:

  • You effectively compiled for -mmcu=avr2, so there's no device properties of ATxmega256A3U anywhere.

  • You are using -O3 which unrolls loops and tries to inline functions no matter how much code size will increase. Use -Os or at least -O2 when possible.

  • You are using v9 which suffers from PR90706. This PR might lead to a code bloat of 10% or more depending on code. If possible, avoid any version from v9 up to and including v12.2. PR90706 is fixed in v12.3+. v8 and lower are not affected by this PR. Notice that to date, neither v12.3 nor v13 have been released.


Unrelated, but just in case:

  • GCC does not support configuration in the source tree. Better use a build directory outside the GCC source tree.

  • You used --with-newlib which is not supported by avr-gcc. The only supported libc implementaton is AVR-LibC.

emacs drives me nuts
  • 2,785
  • 13
  • 23
  • Thanks for the reply. A lot has changed since I started. By removing the -D define no errors came up. So that is gone. The avr2 has been resolved by using mmcu. As for the compiler version. I tested it now with several compiler with no difference. They all worked. Keep in mind that our students are programming (most of them) for the first time in their lives. So the intent was to avoid them having to think about makefiles etc. And we will find out next schoolyear. – Nico Verduin Apr 20 '23 at 06:40
  • I will see if I can make a zip file of the whole project file. That contains all the cmake files etc. And it has been tested on my old Macbook with OSX 13.6 (High Sierra) as well as Windows 10. – Nico Verduin Apr 20 '23 at 06:46
  • I put the repo [up here][1]. This is currently the latest version. Tested with VSCode and CLion Nico [1]: https://github.com/nicoverduin/xmega_voorbeelden_hva – Nico Verduin Apr 20 '23 at 07:09