1

I am using time() on an ARM micro-controller. The processor restarts as soon as it reaches this function.

What is strange is that when I am in debug mode the code works perfect but as soon as I want to apply it in standalone I encounter a reset.

Am I overlooking something? Is there a replacement for this function?

the part of code is like this

#include <sys/time.h>
#include <stdio.h>

void main (void)
{

   static time_t  rawtime = 0;

   rawtime = time (NULL);
}
Clifford
  • 88,407
  • 13
  • 85
  • 165
Ali
  • 91
  • 8
  • 3
    Just this code snippet doesn't tell us much. What's your compiler and debugger environment, build settings etc. One possible thing that could happen is that semihosting is used, which requires host/debugger to provide time in this case. – domen Mar 22 '19 at 10:45
  • `time()` should be declared in `` not in ``. – alk Mar 22 '19 at 10:51
  • Also: Are you sure your environment likes `void main(...` instead of `int main(...`. – alk Mar 22 '19 at 10:52
  • 2
    @alk pretty sure void main is correct for an embedded system, main is never supposed to return. And who should you return too? – Fredrik Mar 22 '19 at 10:54
  • 2
    Are you sure the system restarts when the `time()` call is executed and not after returning from `main()`? – Bodo Mar 22 '19 at 10:59
  • 5
    @Ali I don't see how this can work at all? This is an embedded system? Then time.h can't possibly work. You have to setup CPU timers which creates interrupts every 1ms (or other timebase), then keep track of the time yourself. – Fredrik Mar 22 '19 at 11:05
  • 3
    Well, you cant do this without operating system. On embedded you can only use function from your RTC lib. current time can be take only from RTC, time.h base on system operation clock. You should find some function to set RTC. RTC (if have battery) works even if processor dont run. – Igor Galczak Mar 22 '19 at 11:06
  • You need to clarify what hardware you have and if this is something with an OS or if it is bare metal MCU. In case of the latter, you have need external RTC clock hardware and integrate it yourself. "ARM" could mean anything. – Lundin Mar 22 '19 at 11:51
  • @Fredrik it would be a pretty bad bootstrap that cant handle a return from main for any definition of the word embedded. My phone runs embedded apps and they no doubt return from main. A typical mcu application yes unless that application is being used for development then there is no reason you cant return from main. Even the final application, no reason you shouldnt be able to, chip boots finds a fault in the board, system lights an led, puts a message on a display, returns from main. – old_timer Mar 22 '19 at 13:23
  • 1
    First off is the expectation that there is a time function, arm based mcus generally do not have any kind of a clock, they have timers so you can tell relative time from when you reset perhaps but no way to reach out to the world and find wall clock time. second bare metal means no os a lot of mcu code is bare metal, so C functions are not expected to be there as such a high percentage rely on system calls. so for any of this to work you have to replace all of that infrastructure and your program doesnt show how you did that. – old_timer Mar 22 '19 at 13:25
  • so it is likely the first comment, semihosting, is how it was working for you before. – old_timer Mar 22 '19 at 13:25
  • "in debug mode the code work perfect " is not objectively viewable with this code. Try `int main (void) { static time_t rawtime = 0; time(&rawtime); printf("%lld\n", (long long) rawtime); }`. – chux - Reinstate Monica Mar 22 '19 at 14:24
  • @chux : If the issue is that `time()` has not been re-targeted and is using semi-hosting in debug, then it is likely perhaps that `printf()` uses semi-hosting and will also fail. – Clifford Mar 23 '19 at 21:15
  • Why "" rather than ""? What toolchain (or whose C library) are you using? – Clifford Mar 23 '19 at 21:40
  • @Fredrik : "_time.h can't possibly work_" - not entirely true as described in my answer - a great deal of library and hardware initialisation occurs before `main()` is called, and this runtime-startup code is typically customised for the platform. Moreover it is possible to _initialise on first use_ in the `time()` function itself. Note also that only `time()` and `clock()` in time.h have hardware dependencies other functions in time.h are hardware independent and entirely portable. – Clifford Mar 23 '19 at 21:45
  • @IgorGalczak : A working `time()` implementation does not require an operating system - just an implementation. And a battery-backed RTC is not the only possible time source - it could be GNSS, LF radio time receiver or NTP for example. – Clifford Mar 23 '19 at 21:51
  • I am using XMC4500 and environment is DAvE from Infineon . https://en.wikipedia.org/wiki/DAvE_(Infineon) – Ali Mar 24 '19 at 12:40
  • and yes the semihosting seems to be the reason, why it is working in the debug mode! – Ali Mar 24 '19 at 12:43
  • @bodo sorry for making the confusion about the main() function. it is actually just a representation of how I call the time function not the actual application and I am sure that the restart happens direct after calling the time function because I have implemented an offline debug variable and it tells me that it is happening right there after the time(). – Ali Mar 24 '19 at 12:48
  • In that case you should not have wrapped it in a main function - that was misleading since the code you posted is not the code that is failing and would fail in the way you describe even without the call to time(). Rather then comment on it - which no one new to this question will ever read, edit the question to correct and probably avoid further down-votes. The actual problem is rather interesting, but no one will ever come to it through your description. – Clifford Mar 24 '19 at 17:00
  • Moreover _after_ time or _inside_ time? that part is critical. If it is after time() has returned, why are you blaming the time() function? Use your debugger rather than instrumenting the code - writing _more_ code to inspect code that is already broken is not a reliable debug method. We have to trust that your instrumentation to your broken code is not itself broken - in this case without sight of that instrumentation. – Clifford Mar 24 '19 at 17:03

2 Answers2

10

Is there a replacement for this function?

The available source of time is hardware dependent, and the library is hardware independent. As such you have to provide implementations for library functions with hardware dependencies yourself, or they may be included in a vendor provided board-support package (BSP) in some cases. The header time.h provides the standard declaration your implementation must conform to, while the library in this case provides a default implementation that is not fully functional.

If you are using armcc (as used in the Keil ARM MDK for example), then the default time() implementation uses semi-hosting. That is it obtains time from the development host rather then than the target hardware.

Semi-hosting will work only when debugging while connected to a debug host. However in that case time() should return -1 rather than a processor restart. This function is not the cause of the restart - you could demonstrate that by removing it, and the restart will still occur. The restart is simply that you explicitly return from main() - what else is the runtime supposed to do? It will either restart directly or it may enter a busy loop, where a watchdog timer expiry might restart it. It depends on your C run-time environment implementation. Moreover the behaviour may differ depending on whether the debugger is connected or not; it is possible to determine when the on-chip debug is active and to conditionally execute a break-point instruction for example to interrupt the debugger.

To have time() work correctly with your target hardware rather than use semi-hosting, you must re-implement it. It is defined as a weak-link and any implementation you provide will override the default, so somewhere in your project you must have a function:

#include <time.h>

time_t time( time_t* timep )
{
    int hour = 0 ;
    int minute = 0 ;
    int second = 0 ;
    int day_of_month = 0 ;
    int month = 0 ; 
    int year = 0 ;

    // Your code here to fill time/date from clock source
    ...

    // Normalise to time.h library epoch time_t (normally Unix epoch)
    struct tm timeinfo;
    timeinfo.tm_mon  = month - 1 ;   // check assumption here Jan = 0 in tm
    timeinfo.tm_mday = day_of_month ;
    timeinfo.tm_year = year + 100 ;  // check assumption here years start from 1900 in tm 
    timeinfo.tm_hour = hour ;
    timeinfo.tm_min  = minute;
    timeinfo.tm_sec  = second;

    // Convert to timestamp
    time_t t = mktime(&timeinfo);
    if( timep != NULL )
    {
        *timep = t ; 
    }

    return t; 
}

If your time source requires any kind of initialisation before it will work, you can do that in a number of ways, for example:

  • Place the initialisation code in the run-time start-up code that runs before main(). For example your start-up code may have a function called SysInit() or similar where you should do this.
  • Require the developer to perform necessary initialisation before time() is used.
  • Initialise on first use by modifying the time() function as below :

#include <time.h>
#include <stdbool.h>

time_t time( time_t* timep )
{
    static bool initialised = false ;
    if( !initialised )
    {
        initialised = true ;

        // your clock source initialisation here
        ...
    }

    ...

This last method is probably the simplest and least error prone and does not saddle the system with code that it might not need if the application does not use time().

Your example code includes stdio.h but does not use it, but note that the default stdio implementation similarly relies on semi-hosting, and may need re-targetting

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 1
    Thanks! Very good explanation of what is going on ! As you said in debug mode it is working because it obtains the time via semi-hosting from the development host. now I have re targeted the time function and it is working perfect. This main() is not the actual code. I have actually used the time() some weher in the middle of my firmware to obtain the time and pass it to FATFS. And as I observed exactly (with aid of messages shown on display) the restart is happening right after calling the time function. – Ali Mar 24 '19 at 13:07
  • 1
    @Ali "_messages shown on display_" may not be a reliable indicator of the point of failure since the display output may be buffered and asynchronous. Buffered display text may not be presented before the restart occurs. Moreover it is unhelpful to post code that does not truly represent the problem. The code shown may restart, but probably not for the same reason as the real code. I am willing to bet that given an infinite loop at the end of main, this example will not restart, indicating that time() may not be the problem - unless perhaps it asserts. – Clifford Mar 24 '19 at 13:47
  • 1
    @Ali You implied that you have debugger support. Why would you use unreliable display output over direct observation in the debugger? – Clifford Mar 24 '19 at 13:49
-2

First of all this isnt embedded code time.h and stdio.h are software libs. You should have some like this:

#include <arm/UART_some_lib.h>
#include <arm/RTC_some_lib.h>

static someStartupFunctions()
{
    RTC_setRTC(...);
}


int main(void)
{
    someStartupFunctions();

    while(1)
    {
     //Main code here

    }

    return 0;
}

BUT on arm can run operating system but there wont be embadded programing.

Igor Galczak
  • 142
  • 6
  • 1
    What makes you think an embedded system library cannot support both time.h or stdio.h? No OS is required. Moreover it does not follow that a system with an operating system cannot be an embedded system - that is nonsense. – Clifford Mar 23 '19 at 21:57