nanosleep() wait for at least 15 ms? - c

In order to make a good timing in an emulator, I have to wait for around 50 microseconds.
When I use nanosleep, for example with a duration of 10 microsecs, I measure a delay of 15 millisec ! I use mingw on windows with the following example code :
#include <stddef.h>
#include <time.h>
#include <stdio.h>
int main()
{
struct timespec startx, endx;
struct timespec req={0};
req.tv_sec=0;
req.tv_nsec=10000; // 10_000 ns = 10 microseconds
for (int i=0; i<10; i++)
{
clock_gettime(CLOCK_MONOTONIC, &startx);
nanosleep(&req, NULL);
clock_gettime(CLOCK_MONOTONIC, &endx);
if (endx.tv_sec-startx.tv_sec)
printf("%li microsecs\n",((endx.tv_nsec-startx.tv_nsec)/1000)+1000000);
else
printf("%li microsecs\n",(endx.tv_nsec-startx.tv_nsec)/1000);
}
return 0 ;
}
And the result is :
12528 microsecs
19495 microsecs
14890 microsecs
14229 microsecs
14657 microsecs
14824 microsecs
14724 microsecs
21074 microsecs
13697 microsecs
13893 microsecs
I guess I'm wrong somewhere....
If someone has an idea. I could also avoid the problem with a "do nop while (end-start) < 50usec"...
Thanks.

When I run the posted code through a compiler (gcc) the compiler outputs the following:
gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o"
untitled1.c: In function ‘main’:
untitled1.c:16:57: error: ‘err’ undeclared (first use in this function)
16 | if (nanosleep(&req, NULL)) printf("err : %i\n", err);
| ^~~
untitled1.c:16:57: note: each undeclared identifier is reported only once for each function it appears in
untitled1.c:18:18: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘__syscall_slong_t’ {aka ‘long int’} [-Wformat=]
18 | printf("%d microsecs %d\n",(endx.tv_nsec-startx.tv_nsec)/1000, endx.tv_sec-startx.tv_sec);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| int __syscall_slong_t {aka long int}
| %ld
untitled1.c:18:31: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘__time_t’ {aka ‘long int’} [-Wformat=]
18 | printf("%d microsecs %d\n",(endx.tv_nsec-startx.tv_nsec)/1000, endx.tv_sec-startx.tv_sec);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~~~~
| | |
| int __time_t {aka long int}
| %ld
Compilation failed.
When compiling, always enable the warnings, then fix those warnings.
to start, suggest casting the result of the call to time() to be a long int
as to your question:
context switches take time AND the cpu(s) are probably busy with other tasks AND the task scheduler only looks at the list of tasks ready to run periodically , so your request will not be immediately serviced.
to obtain a more accurate timing, do not depend on the OS. Rather use one of the hardware timers to produce a interrupt event when you want the elapsed time to expire. Then use an interrupt handler to handle the interrupt event from the hardware timer.

Related

C portable/cross-platform periodic timer (with millisecond resolution)?

I have been reading Signal Handler in a separate pthread using timer_create, and I decided to try implementing a C example for a periodic timer function based on the discussion there, and compiling it under MINGW64 for Windows.
It turns out, while MINGW64 can indeed emulate some aspects of POSIX under Windows, timer_create and sigevent are not part of that (/mingw64/include/signal.h does not contain declaration for sigevent - while MSYS2 /usr/include/signal.h, via /usr/include/sys/signal.h, does) - I get these errors:
test.c:153:1: error: unknown type name 'timer_t'; did you mean 'time_t'?
553 | timer_t timerId = 0;
| ^~~~~~~
| time_t
test.c: In function 'init_timer':
test.c:160:10: error: variable 'sev' has initializer but incomplete type
560 | struct sigevent sev = { 0 };
| ^~~~~~~~
test.c:160:27: warning: excess elements in struct initializer
560 | struct sigevent sev = { 0 };
| ^
test.c:160:27: note: (near initialization for 'sev')
test.c:160:19: error: storage size of 'sev' isn't known
560 | struct sigevent sev = { 0 };
| ^~~
test.c:170:22: error: 'SIGEV_THREAD' undeclared (first use in this function)
570 | sev.sigev_notify = SIGEV_THREAD;
| ^~~~~~~~~~~~
test.c:170:22: note: each undeclared identifier is reported only once for each function it appears in
test.c:174:9: warning: implicit declaration of function 'timer_create'; did you mean 'timerclear'? [-Wimplicit-function-declaration]
574 | res = timer_create(CLOCK_REALTIME, &sev, &timerId);
| ^~~~~~~~~~~~
| timerclear
test.c:180:9: warning: implicit declaration of function 'timer_settime'; did you mean 'timeGetTime'? [-Wimplicit-function-declaration]
580 | res = timer_settime(timerId, 0, &its, NULL);
| ^~~~~~~~~~~~~
| timeGetTime
test.c:160:19: warning: unused variable 'sev' [-Wunused-variable]
560 | struct sigevent sev = { 0 };
So, what I want to achieve, is a periodic timer callback of a function at a period of 10 ms (as tight as possible (*)), with C code that can compile with gcc under both MINGW64 and Linux.
Is it possible to achieve this - and if so, how? (maybe there is a library that facilitates this?)
(*) - in my experiments with MINGW64 builds on Windows 10, I've seen that nanosleep(&ts, &ts); in a while loop in main() with timestamp printouts, -- where ts = {.tv_sec = 0, .tv_nsec = 500 * 1000000} describes an interval of half a second, -- can measure anywhere between 505 and 520 ms; so I'm not sure how "tight" of a 10 ms period will be achievable - but I'd still love to know about options to implement a cross-platform periodic timer, even with a poorer timer resolution ...

How to pass string/array to function correctly? (stm32)

I'm not first and not last I mean)
And it's one more question about waring: assignment makes pointer from integer without a cast.
I've already read this and this and this and this and this and more and more.
I have NUCLEO-F070RB-STM32 devkit. And I want to send different messages on PC for debugging.
I use this construction:
uint8_t greeting[] = "Welcome to first circle of hell\n";
HAL_UART_Transmit(&huart2, greeting, sizeof(greeting)-1, 30);
//"sizeof(greeting)-1" cut "\0" from string
Here is a description:
/**
* #brief Send an amount of data in blocking mode.
* #note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* the sent data is handled as a set of u16. In this case, Size must indicate the number
* of u16 provided through pData.
* #note When UART parity is not enabled (PCE = 0), and Word Length is configured to 9 bits (M1-M0 = 01),
* address of user data buffer containing data to be sent, should be aligned on a half word frontier (16 bits)
* (as sent data will be handled using u16 pointer cast). Depending on compilation chain,
* use of specific alignment compilation directives or pragmas might be required
* to ensure proper alignment for pData.
* #param huart UART handle.
* #param pData Pointer to data buffer (u8 or u16 data elements).
* #param Size Amount of data elements (u8 or u16) to be sent.
* #param Timeout Timeout duration.
* #retval HAL status
*/
And all work perfectly.
But I want different message. I'm a good programmer.
uint8_t greeting[] = "Welcome to first circle of hell\n";
uint8_t str[] = "just for UART\r\n";
void send_to_uart (uint8_t);
void send_to_uart (uint8_t it_will_be_send)
{
HAL_UART_Transmit(&huart2, it_will_be_send, sizeof(it_will_be_send)-1, 30);
}
int main(void)
{
send_to_uart(greeting);
wile (1)
{
send_to_uart(str);
}
}
And I have a warning and have no data on my screen.
Bad bad bad programmer!
I understand that devil in pointers.
But can you explain slowly step by step for all newbies like me:
How to pass ...n arrays to functions. PLEEEAASEEE
P.S.
/* USER CODE BEGIN 0 */
void send_to_uart (uint8_t);
void send_to_uart (uint8_t it_will_be_send)
{
HAL_UART_Transmit(&huart2, it_will_be_send, sizeof(it_will_be_send)-1, 30);
}
/* USER CODE END 0 */
/**
* #brief The application entry point.
* #retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE BEGIN WHILE */
uint8_t greeting[] = "\nWelcome to first circle of hell\n";
uint8_t some_string[] = "some string to UART\r\n";
send_to_uart(greeting);
HAL_UART_Transmit(&huart2, greeting, sizeof(greeting)-1, 30);
while (1)
{
HAL_UART_Transmit(&huart2, "\nHAL some string to UART\n" , 25, 30);
send_to_uart(some_string);
HAL_UART_Transmit(&huart2, some_string, sizeof(some_string)-1, 30);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
make -j4 all
arm-none-eabi-gcc "../Core/Src/main.c" -mcpu=cortex-m0 -std=gnu11 -g3 -DDEBUG -DUSE_HAL_DRIVER -DSTM32F070xB -c -I../Core/Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc -I../Drivers/STM32F0xx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32F0xx/Include -I../Drivers/CMSIS/Include -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -MMD -MP -MF"Core/Src/main.d" -MT"Core/Src/main.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Core/Src/main.o"
../Core/Src/main.c: In function 'send_to_uart':
../Core/Src/main.c:67:29: warning: passing argument 2 of 'HAL_UART_Transmit' makes pointer from integer without a cast [-Wint-conversion]
67 | HAL_UART_Transmit(&huart2, it_will_be_send, sizeof(it_will_be_send)-1, 30);
| ^~~~~~~~~~~~~~~
| |
| uint8_t {aka unsigned char}
In file included from ../Core/Inc/stm32f0xx_hal_conf.h:288,
from ../Drivers/STM32F0xx_HAL_Driver/Inc/stm32f0xx_hal.h:30,
from ../Core/Inc/main.h:31,
from ../Core/Src/main.c:21:
../Drivers/STM32F0xx_HAL_Driver/Inc/stm32f0xx_hal_uart.h:1491:73: note: expected 'uint8_t *' {aka 'unsigned char *'} but argument is of type 'uint8_t' {aka 'unsigned char'}
1491 | HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
| ~~~~~~~~~^~~~~
../Core/Src/main.c: In function 'main':
../Core/Src/main.c:112:16: warning: passing argument 1 of 'send_to_uart' makes integer from pointer without a cast [-Wint-conversion]
112 | send_to_uart(greeting);
| ^~~~~~~~
| |
| uint8_t * {aka unsigned char *}
../Core/Src/main.c:65:28: note: expected 'uint8_t' {aka 'unsigned char'} but argument is of type 'uint8_t *' {aka 'unsigned char *'}
65 | void send_to_uart (uint8_t it_will_be_send)
| ~~~~~~~~^~~~~~~~~~~~~~~
../Core/Src/main.c:117:29: warning: pointer targets in passing argument 2 of 'HAL_UART_Transmit' differ in signedness [-Wpointer-sign]
117 | HAL_UART_Transmit(&huart2, "\nHAL some string to UART\n" , 25, 30);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| char *
In file included from ../Core/Inc/stm32f0xx_hal_conf.h:288,
from ../Drivers/STM32F0xx_HAL_Driver/Inc/stm32f0xx_hal.h:30,
from ../Core/Inc/main.h:31,
from ../Core/Src/main.c:21:
../Drivers/STM32F0xx_HAL_Driver/Inc/stm32f0xx_hal_uart.h:1491:73: note: expected 'uint8_t *' {aka 'unsigned char *'} but argument is of type 'char *'
1491 | HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);
| ~~~~~~~~~^~~~~
../Core/Src/main.c:118:15: warning: passing argument 1 of 'send_to_uart' makes integer from pointer without a cast [-Wint-conversion]
118 | send_to_uart(some_string);
| ^~~~~~~~~~~
| |
| uint8_t * {aka unsigned char *}
../Core/Src/main.c:65:28: note: expected 'uint8_t' {aka 'unsigned char'} but argument is of type 'uint8_t *' {aka 'unsigned char *'}
65 | void send_to_uart (uint8_t it_will_be_send)
| ~~~~~~~~^~~~~~~~~~~~~~~
arm-none-eabi-gcc -o "max6675_2.0.elf" #"objects.list" -mcpu=cortex-m0 -T"C:\stm32\cubeMX_workspace\max6675_2.0\STM32F070RBTX_FLASH.ld" --specs=nosys.specs -Wl,-Map="max6675_2.0.map" -Wl,--gc-sections -static --specs=nano.specs -mfloat-abi=soft -mthumb -Wl,--start-group -lc -lm -Wl,--end-group
Finished building target: max6675_2.0.elf
arm-none-eabi-objdump -h -S max6675_2.0.elf > "max6675_2.0.list"
arm-none-eabi-objcopy -O binary max6675_2.0.elf "max6675_2.0.bin"
arm-none-eabi-size max6675_2.0.elf
text data bss dec hex filename
8228 20 1804 10052 2744 max6675_2.0.elf
Finished building: default.size.stdout
Finished building: max6675_2.0.bin
Finished building: max6675_2.0.list
13:39:29 Build Finished. 0 errors, 4 warnings. (took 1s.941ms)
Look at this:
void send_to_uart (uint8_t);
So send_to_uart expect an argument of type uint8_t - fine.
Now look at this:
uint8_t greeting[] = "Welcome to first circle of hell\n";
int main(void)
{
send_to_uart(greeting); <--- What is greeting?
So is greeting a uint8_t ?
No - it's not. It's an array so you can't pass it to a function that expects a uint8_t
Try like:
for (int i = 0; i < strlen(greeting); ++i) send_to_uart(greeting[i]);

How to open file in C program?

The code here is a code from a website. Since I was facing an issue with my origin code, I ended up trying this implementation from a website. But turns out I have the same issue with this program too
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
FILE *fptr;
if ((fptr = fopen("D:\\TestFile\\test.txt","r")) == NULL){
printf("Error! opening file\n");
perror(fptr);
// Program exits if the file pointer returns NULL.
exit(1);
}
fscanf(fptr,"%d", &num);
printf("Value of n=%d\n", num);
printf("%s\n", fptr);
fclose(fptr);
return 0;
}
I am stuck with the if condition i.e., whatever I do I am not able to read the file except the root directory. Even though I specify the path, it still looks for the file under root directory.
I am not sure why it's not working, provided the same code works fine in Linux
I see 2 mistakes, the one related to perror mentioned in the comments, and the last printf. Now if the program is still not working, it could be interesting to check the error or to get the program output.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num;
FILE *fptr;
if ((fptr = fopen("D:\\TestFile\\test.txt","r")) == NULL){
// printf("Error! opening file\n");
// perror(fptr); // MISTAKE-1: perror parameter is a string
perror("Error! opening file");
// Program exits if the file pointer returns NULL.
exit(1);
}
fscanf(fptr,"%d", &num);
printf("Value of n=%d\n", num);
//printf("%s\n", fptr); // MISTAKE-2: fptr is not a string
fclose(fptr);
return 0;
}
the posted code does not cleanly compile!
Here is the results of compiling with many of the warnings enabled:
gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o"
untitled1.c: In function ‘main’:
untitled1.c:11:16: warning: passing argument 1 of ‘perror’ from incompatible pointer type [-Wincompatible-pointer-types]
11 | perror(fptr);
| ^~~~
| |
| FILE * {aka struct _IO_FILE *}
In file included from untitled1.c:1:
/usr/include/stdio.h:775:33: note: expected ‘const char *’ but argument is of type ‘FILE *’ {aka ‘struct _IO_FILE *’}
775 | extern void perror (const char *__s);
| ~~~~~~~~~~~~^~~
untitled1.c:19:13: warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘FILE *’ {aka ‘struct _IO_FILE *’} [-Wformat=]
19 | printf("%s\n", fptr);
| ~^ ~~~~
| | |
| | FILE * {aka struct _IO_FILE *}
| char *
Compilation finished successfully.
Note; the statement: Compilation finished successfully. just means the compiler applied some work around to each of the problems. It does NOT mean the correct code was produced.

How to make VSCODE show gcc output when compiling

I'm trying to edit my tasks.json and/or launch.json to output warnings gcc would usually show when compiling C code with -Wall and -Wextra flags using Run Without Debugging.
When using the the Run Without Debugging option in VSCODE it seems to compile the program using the flags set in my workspace tasks.json file but it doesn't show me the output of gcc.
There's a Task - build active file-tab in the terminal section but it just shows:
> Executing task: C/C++: gcc build active file <
Starting build...
Build finished successfully.
Terminal will be reused by tasks, press any key to close it.
Example code:
#include <stdio.h>
int main(void)
{
int ten = 10;
int two = 2;
printf("Doing it right:\t");
printf("%d minus %d is %d\n\n", ten, 2, ten - two);
printf("Doing it wrong:\t");
printf("%d minus %d is %d\n",ten); // Two arguments missing
return 0;
}
Example of the desired output upon compiling:
example.c: In function ‘main’:
example.c:13:23: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
13 | printf("%d minus %d is %d\n",ten); // Two arguments missing
| ~^
| |
| int
example.c:13:29: warning: format ‘%d’ expects a matching ‘int’ argument [-Wformat=]
13 | printf("%d minus %d is %d\n",ten); // Two arguments missing
| ~^
| |
| int

Why calling SetConsoleCtrlHandler() triggers a warning?

#include <windows.h>
BOOL MyCtrlHandler(DWORD ctrlType) {
return TRUE;
}
int main(void) {
SetConsoleCtrlHandler(MyCtrlHandler, TRUE);
return 0;
}
The function signature matches the doc:
The PHANDLER_ROUTINE type defines a pointer to this callback function. HandlerRoutine is a placeholder for the application-defined function name.
If I cross-compile it with MinGW in 64 bits, it works:
$ x86_64-w64-mingw32-gcc ctrl.c
$
But in 32 bits, I get a warning:
$ i686-w64-mingw32-gcc ctrl.c
ctrl.c: In function ‘main’:
ctrl.c:8:27: warning: passing argument 1 of ‘SetConsoleCtrlHandler’ from incompatible pointer type [-Wincompatible-pointer-types]
8 | SetConsoleCtrlHandler(MyCtrlHandler, TRUE);
| ^~~~~~~~~~~~~
| |
| BOOL (*)(DWORD) {aka int (*)(long unsigned int)}
In file included from /usr/share/mingw-w64/include/windows.h:74,
from ctrl.c:1:
/usr/share/mingw-w64/include/wincon.h:249:68: note: expected ‘PHANDLER_ROUTINE’ but argument is of type ‘BOOL (*)(DWORD)’ {aka ‘int (*)(long unsigned int)’}
249 | WINBASEAPI WINBOOL WINAPI SetConsoleCtrlHandler(PHANDLER_ROUTINE HandlerRoutine,WINBOOL Add);
|
$
I don't understand why, because MyCtrlHandler should have the same type as PHANDLER_ROUTINE.
The problem here is the difference between __cdecl and __stdcall. You must have lucked out with the default calling convention on your one successful attempt to compile. You need:
BOOL WINAPI MyCtrlHandler(DWORD ctrlType) {
return TRUE;
}

Resources