Hi,
I am trying to use the RTC of LPC2378 and the RTX kernel of KEIL.
The below is the code of one of my tasks.
void job3 (void) __task { while(1) { snprintf(FMTstring, 29, "%04d-%02d-%02d Y%03d-W%01d %02d:%02d:%02d\r", RTC_YEAR, RTC_MONTH, RTC_DOM, RTC_DOY, RTC_DOW, RTC_HOUR, RTC_MIN, RTC_SEC ); UART0sbWRITE( (BYTE *)FMTstring, 29 ); UART0sendKICK(); os_dly_wait (100); } }
I found that, I need to set the "Task stack size" to 348 bytes, otherwise I will get a stack overflow. Since I do not declare any variable in this task, why it needs so large stack?
"I went back to read some articles about Stack/Heap, seems that the parameters of a function call also consume the stack space."
More than that. When you call snprintf() that is a single function with the parameters that you supply. But snprintf() has a complex task to do, so snprintf() will perform its job by calling a large number of other functions, several of which may call yet other functions. Because of this, you need stack space for local variables, parameters and return addresses for all these function calls too, even if their calls are hidden in the run-time-library black-box.
Some RTL functions are cheap to call. Some are expensive. Formatted output are quite expensive functions to call, which is why I recommend that you keep down the number of threads that needs to use them, unless you have RAM enough to allocate big enough stacks to all your threads.
Hi Per,
Many thanks to your help.
-> which is why I recommend that you keep down -> the number of threads that needs to use them
I am not so sure about the meaning of "threads" here. Does "threads" mean the parameters of a function call? (Sorry for my English ability.)
According to the callgraph:
job3 (ARM, 100 bytes, Stack size 40 bytes, c-main.o(.text), UNUSED) [Calls] * >> os_dly_wait (via Veneer) * >> UART0sendKICK * >> UART0sbWRITE * >> __1snprintf (via Veneer) job2 (ARM, 20 bytes, Stack size 0 bytes, c-main.o(.text), UNUSED) job1 (ARM, 156 bytes, Stack size 16 bytes, c-main.o(.text), UNUSED) [Calls] * >> os_tsk_self (via Veneer) * >> os_tsk_create_user (via Veneer) * >> UART0sendKICK * >> UART0sbWRITE * >> UART0rbREAD * >> strlen (via Veneer) * >> __aeabi_memclr4
job3 only needs 100 bytes stack, but I have to set 348 bytes for it. After reading your reply, now I realize the cause.
Is there any documentation that can help me to totally understand the call-graph and the image-map?
__main (ARM, 8 bytes, Stack size 0 bytes, __main.o(!!!main)) [Stack] * Max Depth = 64 + Unknown Stack Size * Call Chain = __main â‡' __rt_entry â‡' __rt_lib_init â‡' _fp_init
What does the "Max Depth = 64 + Unknown Stack Size" mean?
And what does 'UNUSED' in "job3 (ARM, 100 bytes, del, del, UNUSED)" mean?
A thread is what your OS calls a task. It runs concurrently with other threads in shared memory, i.e. all threads has a common set of global variables. This is very light-weight, which is the reason why RTOS in embedded environments implements threads. On the other hand, it means that the developer must be very careful when accessing common variables so one thread doesn't overwrite the output of another thread, or reads data that has been only half-way updated.
Many thanks to your explanation.
Tasks/Threads of RTX kernel sounds different from what I heard about the threads on X86 platform. Looks like RTX's thread does not belong to any process.
Thread is also a mystery to me.
In this case, you don't have a GUI or command line to handle programs that ends or to send in parameters to main().
So in this case, you can see your application as a single process where the tasks are almost identical to the threads inside a process in Windows.