roedler
roedler

Reputation: 49

cant use sleep() in embedded c for stm32

I try to learn embedded c for a stm32-microcontorller. I try to wirte a easy blink program, where i use the sleep()-function.

code:

/* Includes ------------------------------------------------------------------*/
#include <unistd.h>
#include "main.h"

int main(void)
{
  HAL_Init();

  while (1)
  { 
    HAL_GPIO_TogglePin(LD2_GPIO_Port,LD2_Pin);
    sleep(1);  // this line throws a error, when compiling
  }
}

the compiler gives me following error:

/usr/lib/gcc/arm-none-eabi/7.4.0/../../../../arm-none-eabi/bin/ld: CMakeFiles/untitled2.elf.dir/Src/main.c.obj: in function `main':
/home/heinrich/CLionProjects/untitled2/Src/main.c:106: undefined reference to `sleep'
collect2: error: ld returned 1 exit status
make[3]: *** [CMakeFiles/untitled2.elf.dir/build.make:391: untitled2.elf] Fehler 1
make[2]: *** [CMakeFiles/Makefile2:73: CMakeFiles/untitled2.elf.dir/all] Fehler 2
make[1]: *** [CMakeFiles/Makefile2:85: CMakeFiles/untitled2.elf.dir/rule] Fehler 2
make: *** [Makefile:118: untitled2.elf] Fehler 2

I think, the problem is a not-installed libary, but i installed everything in the fedora-repos for arm-gcc

OS: Fedora 30 IDE: CLion Toolchain: Arm-gcc-none-eabi

Upvotes: 3

Views: 11447

Answers (2)

Agnius Vasiliauskas
Agnius Vasiliauskas

Reputation: 11277

Micro-controller may not have standard library included, so in this case you must roll your own missing functions. For example sleep could be implemented like this:

void my_sleep(int secs) {
  #define STEPS_PER_SEC 650000000
  unsigned int i,s;
  for (s=0; s < secs; s++) {
    for (i=0; i < STEPS_PER_SEC; i++) {
       // skip CPU cycle or any other statement(s) for making loop 
       // untouched by C compiler code optimizations
       asm("nop");
    }
  }
}

int main() {
   my_sleep(1);
}

Btw constant STEPS_PER_SEC should be adjusted empirically according to your controller CPU specs and your compilation mode (optimizations On / Off, etc.).

Upvotes: 3

KamilCuk
KamilCuk

Reputation: 141493

You can't use POSIX functions on bare-metal target with arm-none-eabi-gcc compiler. There is no operating system. There is no sleep(), gettimeofday(), clock_gettime(), getpid(), fork(), stat(), open(), pthread_create() and many, many, many others C and posix and *unix specific functions. The declarations of these functions can be found in the standard headers, but linker will just give up with undefined reference error. You have to implement them yourself.

Your compiler arm-none-eabi-gcc by default uses newlib implementation of C standard library. It comes with an implementation of most basic and not operating system aware functions, like snprintf and mktime. For functions like printf or putc the callback _write() or _write_r() should be implemented for them to work. For malloc() to work you have to provide sbrk(). For most other functions, you have to implement them yourself.

The commonly used -specs=nosys.specs compiler option just specifies to use a "default" no-system implementation of some functions like fseek() or write() or sbrk(). Most of these functions just return -1 and set errno to ENOSYS, but are there, so that you can compile your program. The implementation can be found here.

If you happen to use stm32 hal library, you can initialize your systick interrupt for 1 ms and use the standard in stm32 world HAL_Delay() function and provide your own implementation of sleep():

unsigned int sleep(unsigned int seconds) {
   HAL_Delay(seconds * 1000);
   return 0;
}

The other way round is to use an operating system on your device that provides an implementation of these functions. For example there is RIOT OS that aims at providing POSIX compatibility and already provides many calls.

Upvotes: 8

Related Questions