0

I'm programming an ATSAME70 and I'm trying to program a simple timer using the SysTick interrupt available in Cortex M MCUs, but I don't know what is going wrong.

If write this code in a simple main.cpp file:

// main.cpp

#include <cstdint>
#include "init.h"
#include "led.hpp"

volatile uint32_t g_ticks = 0;

extern "C" {
    void SysTick_Handler(void)
    {
        g_ticks++;
    }
}

class Timer
{
private:
    uint32_t start;

public:
    Timer() : start(g_ticks) {}
    float elapsed() const { return (g_ticks - start) / 1000.0f; }

};

int main()
{
    init();

    SysTick_Config(300000000 / 1000); /* Clock is running at 300 MHz */

    Timer t;
    while (t.elapsed() < 1.0f);

    Led::on();
    while (true);
}

It works, the led lights up properly after 1 second. But if I try to keep it clean and separate the program in the following files:

// timer.hpp

#include <cstdint>

class Timer
{
private:
    uint32_t start;

public:
    Timer();

    float elapsed() const;
};
// timer.cpp

#include "timer.hpp"

volatile uint32_t g_ticks = 0;

extern "C" {
    void SysTick_Handler(void)
    {
        g_ticks++;
    }
}

Timer::Timer() : start(g_ticks) {}

float Timer::elapsed() const
{
    return (g_ticks - start) / 1000.0f;
}
// main.cpp

#include <cstdint>
#include "init.h"
#include "led.hpp"
#include "timer.hpp"

int main()
{
    init();

    SysTick_Config(300000000 / 1000); /* Clock is running at 300 MHz */

    Timer t;
    while (t.elapsed() < 1.0f);

    Led::on();
    while (true);
}

It doesn't work anymore, the program reaches the first while loop and then it gets stuck there, I think g_ticks is being corrupted when I try to read it in t.elapsed() but I don't know what is happening. Does anybody know where I'm wrong?

init() is just a function in which I initialize all needed registers.

EDIT: here are the command lines used to generate the code:

$toolchain_path = "C:\Program Files (x86)\GNU Tools ARM Embedded\8 2018-q4-major\bin";
$link_file = "source\device\same70_flash.ld"

$c_files = "include\sensors\bmi088\bmi088.c " +
           ...
           "source\utils\syscalls.c";

$cpp_files = "source\device\init.cpp " +
             ...
             "source\main.cpp";
Invoke-Expression "& '$toolchain_path\arm-none-eabi-gcc.exe' -c -s -O3 -fdata-sections -ffunction-sections '-Wl,--gc-sections' '-Wl,--entry=Reset_Handler' -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 -Isource -Iinclude\CMSIS -D__SAME70N21__ $c_files --specs=nosys.specs"

foreach ($c_file in $c_files.split(" "))
{
    if ($objects) { $objects += " "; }
    $objects += ($c_file.split("\")[-1]).split(".")[0] + ".o";
}

Invoke-Expression "& '$toolchain_path\arm-none-eabi-ld.exe' -s --entry=Reset_Handler -r $objects -o drivers.o"
foreach ($object in $objects.split(" ")) { Remove-Item $object; }
Move-Item drivers.o bin\drivers.o -force

Invoke-Expression "& '$toolchain_path\arm-none-eabi-g++.exe' -s -O3 -fdata-sections -ffunction-sections '-Wl,--gc-sections' -mthumb -mcpu=cortex-m7 -mfloat-abi=hard -mfpu=fpv5-d16 '-Wl,--entry=Reset_Handler' -std=c++17 -Isource -Iinclude -Iinclude\CMSIS -D__SAME70N21__ bin/drivers.o $cpp_files --specs=nosys.specs -T $link_file -o bin\code.elf"
Invoke-Expression "& '$toolchain_path\arm-none-eabi-objcopy.exe' -O binary bin\code.elf bin\code.bin"

The script is written in powershell and I'll explain it a little bit. $c_files is just a string with every c file to be compiled separated by an space. $objects is an array of strings containing every file listed in $c_files but with the ".c" extension replaced by ".o". I've done this to link every c compiled file into "drivers.o". Finally, c++ code is compiled using this drivers.o as argument and then I generate the .bin file to upload it to the MCU.

The code is compiled using the latest GNU Arm Embedded toolchain. I must have made a mistake somewhere but I don't know where and I don't have a debugger to debug the code at runtime.

EDIT 2: Both variants work properly without optimizations. If I pass -O1 or higher as argument to the compiler the second variant stops working and I don't understand why.

David Bermejo
  • 125
  • 1
  • 6
  • Both codes looks equivalent. I think the error is outside the provided scope. Is g_ticks ticking at all? Try `if (g_ticks & 256) Led::on(); else Led::off();` – user5329483 Jul 27 '19 at 11:17
  • Do you compile and link both variants in the same way? Would you mind to show us your command lines? – the busybee Jul 28 '19 at 07:22
  • @user5329483 Yes, g_ticks is ticking. I've noticed that if I use the second version provided above it doesn't even call init() function so maybe compiled code gets corrupted somewhere? – David Bermejo Jul 28 '19 at 19:52
  • @thebusybee Yes, both variants are generated using the same script. I've edited the question and added the script used. – David Bermejo Jul 28 '19 at 20:12
  • With your **EDIT 2** I suspect that some function is discarded. Please see [-gc-sections discards used data](https://stackoverflow.com/questions/31521326/gc-sections-discards-used-data) whether it may help you. This is what I found there and what you could try: A crossref (`-Wl,-Map=output.map -Wl,--cref`) to compare non-optimized and optimized results. And `-Wl,-print-gc-sections` to see what's happening. – the busybee Jul 29 '19 at 08:37
  • Your statements "it doesn't even call init()" and "Yes, g_ticks is ticking" are a weird combination. I would try to remove as much as possible from init(). – user5329483 Jul 29 '19 at 16:41

0 Answers0