RT-Thread FAQ

Created at 2022-06-30 15:21:54


RT-Thread Community Developer Chuchu has organized a very detailed doc that explains many of the issues that new RT-Thread beginners may encounter during the very first development experience on RT-Thread. If you happen to have some technical issues and looking for someone to support you, this post could be a support foundation for you!
This post keeps updating.

> Basics

Q1. I download the SDK and it's working, the compiling is also doing good, however, I can't get the program to run, what's the problem?

If you're on the Keil + RT-Thread Env environment, the first thing you should do after downloading the source code is to menuconfig;

If you're using the RT-Studio IDE, you should open Settings before creating the project; Go through all the configuration items, cancel the irrelevant ones, and only leave the kernel.

First, ensure the minimum system can run, and use the lighting program to verify that the minimum system is running normally. Then add the features you need and the underlying peripherals, or something else.

Q2. I download the SDK and it's working, the compiling is also doing good, however, the program shows Hard Fault on Thread, what's the problem?

Same operations as above

Q3. I download the SDK and it's working, however, the compiling reports issue.

Same operations as above

> Kernel

Q1: How to appropriately define the RT_NAME_MAX

In principle, the little size of the RT_NAME_MAX, the less memory will be used. Take 100 kernel objects as an example, an object name occupies 8 bytes, a total of 800 bytes. The struct rt_object is the struct definition, it is followed by two rt_uint8_t variables.
RT_NAME_MAX can be defined as 2n + 2


Not turn on kernel debugging unless it's necessary for your situation.

Q3: How to appropriately define the thread stack size?

It has a lot to do with applications, and if it is only a minimal kernel system, idle threads, without enabling the interrupts and running the programs, 256 will be enough. If you're adding the program code, along with breaks and message mechanisms, it's better to put 1024.

Q4: How to quickly calculate the number returned by GET_PIN?

We know that the GPIO grouping of chips tends to start with PA, followed by PB PC PD PE... PZ. Usually, each set of ports is either 16bit or 8bit (corresponding to 16 IO and 8 IO, respectively). The simplified formula for GET_PIN is given below:

16bit is (X - A) * 16 + n

A10 is 10.
C9 is 2*16+9=41.
H1 is 7*16+1=113.

8bit is (X - A) * 8 + n

Q5: I don't understand the difference between hard timers, soft timers, and hardware timers.

The RT-Thread kernel defines a software timer, and unlike hardware timers, hardware timers require a timer peripheral, as well as various comparison, capture, and other functions. The software timer simply sets a time, and it executes the callback function that we set when it's timeout.

The software timer defined by RT-Thread is also subdivided into two types, "hard timer" and "soft timer", the former is to execute callback functions in SysTick interrupts, most of which are used for thread built-in timers, and the application layer can also be used, but always keep in mind that its callback functions are executed in interrupts.

The latter, which runs in a thread, can be used when the application layer does not have very high requirements for timing precision, but it should also be noted that the thread that defines the timer and executes the timer callback function are two different threads.

Q6. How much memory is appropriate to request for the Message Queue pool?

1rt_err_t rt_mq_init(rt_mq_t mq, const char *name, void *msgpool, 
2rt_size_t msg_size, rt_size_t pool_size, rt_uint8_t flag);
3rt_mq_t rt_mq_create(const char *name, rt_size_t msg_size, rt_size_t max_msgs, rt_uint8_t flag)

If you create a message queue with rt_mq_create, the message queue pool is automatically calculated based on the message body size msg_size and the maximum number that the message queue can hold max_msgs.

If you use rt_mq_init to initialize the message queue, the memory msgpool of the message queue pool needs to be provided by the user, in this case, you should pay attention to the message pool memory size pool_size. It can be calculated according to this formula:

(RT_ALIGN(msg_size, RT_ALIGN_SIZE) + sizeof(struct rt_mq_message*)) * max_msgs

msg_size is the message body size and max_msgs is the maximum message capacity in the message queue.

Q7. Notes for using a message queue

Although several APIs like rt_mq_send rt_mq_send_wait rt_mq_urgent and rt_mq_recv have size parameters, please strictly pass equal argument values according to the msg_size parameter values in rt_mq_init rt_mq_create. You should not change the value of the size parameter.

That's to say, don't use a message queue to send longer data directly.

Q8. INIT_xxx_EXPORT Macro Explanation

The first thing that RT-Thread impressed me is it has no initial configuration in the main function, it is a separate thread. Other threads are automatically started via INIT_APP_EXPORT.

RT-Thread defines a total of 6 startup processes,

 1/* board init routines will be called in board_init() function */
 2#define INIT_BOARD_EXPORT(fn)           INIT_EXPORT(fn, "1")
 4/* pre/device/component/env/app init routines will be called in init_thread */
 5/* components pre-initialization (pure software initilization) */
 6#define INIT_PREV_EXPORT(fn)            INIT_EXPORT(fn, "2")
 7/* device initialization */
 8#define INIT_DEVICE_EXPORT(fn)          INIT_EXPORT(fn, "3")
 9/* components initialization (dfs, lwip, ...) */
10#define INIT_COMPONENT_EXPORT(fn)       INIT_EXPORT(fn, "4")
11/* environment initialization (mount disk, ...) */
12#define INIT_ENV_EXPORT(fn)             INIT_EXPORT(fn, "5")
13/* appliation initialization (rtgui application etc ...) */
14#define INIT_APP_EXPORT(fn)             INIT_EXPORT(fn, "6")

INIT_BOARD_EXPORT runs before the task scheduler starts, and the only task scheduler is executed before it runs. Here is the peripheral initialization configuration process.

The remaining processes are executed by the main thread (on RT-Thread standard version, if the main thread is used) after the task scheduler starts.

These processes are not completely fixed, and some can be adjusted, for example, I used to advance the initialization of the LCD from DEVICE to BOARD, and make the initialization of emwin to PREV. Some message queues are also initialized during the ENV process.

In most cases, all of the defined initialization can be done in the above processes. However, it is also inevitable that there will be a possibility of conflict.

Check PR #5194 on RT-Thread Github Repository, it includes some links that also reported this issue, and many other developers ping their solutions there, it can be of your reference.

Personally, I think the startup orders are at the same level, and they have dependency and mutex between. In this case, you should adjust the code execution order, write the initialization process of dependency and mutex into the same function, and maintain its dependency on your own.

Q9. How to wake up a thread through rt_thread_suspend rt_thread_resume suspension

To be honest, I don't suggest you do this! On the RT-Thread, there are two possibilities that will happen if a thread jumps into the suspend state, one is that the time slice exhausts automatically give up CPU; One is to wait for resources to block and give up CPU. There is no complete and transparent way for two threads to know each other's current state.

Suppose thread A wants to explicitly suspend thread B, but A does not know whether B is currently giving up CPU while running, or waiting for resources to be suspended, or if resources are available while being woken up from the suspended state. Apparently, it is dangerous to hang other threads without knowing it.

The only thing that I can think of is that the thread B perform more tasks, and it will not take the initiative to give up CPU. Moreover, its thread priority is relatively low, and a high-priority thread A suspends B under certain conditions. But in this way thread B is bound to affect the idle thread.

In fact, this kind of scenario can be achieved by using the inter-thread synchronization mechanism, and thread B suspends itself by signaling to A; Thread A then wakes up thread B with another signal.

I feel I could find a way to use these two APIs directly, but one day, I notice that the RT-Thread's IPC was targeted. If it is suspended because of semaphores then it won't be woken up because of the mailbox. Because the time slice is exhausted, the suspended thread also does not need to think about what resources will be woken up. Suspend and wake are unique.

Q10. list_thread or ps cannot check the thread status?

  1. Thread errors on the Error column can not be of any reference, 0 is normal, and -2 indicates timeout, but when you execute rt_thread_mdelay it turns to -2. However, it does not mean that there is an error.
  2. The status column represents the current thread state. However, because the list_thread or ps commands are executed on the tshell thread, the tshell thread is definitely running; The idle thread cannot be suspended, it shows ready; Other threads may appear ready, but most of the time it is on suspend. However, this does not mean that other threads are suspended and not scheduled.

Q11. Can a timer perform long-term operations?

As mentioned above, there are three kinds of timers in RT-Thread, each with its own characteristics
Hardware timer: The callback function is in the interrupt, and it is not recommended to directly perform long-term operations.
Hard timer: Also executing callback functions in interrupts, it is not recommended to perform long-term operations directly.
Soft Timer: A soft timer that is executed by a timer thread that calls callback functions and has a theoretical basis for performing long-term operations. The timer thread is also a thread, it also has its own thread stack, priority, etc. If some operations are independent, putting them in a particular thread is the same as running on a timer thread.

However, the way the current timer thread handles soft timers is not suitable for performing long-running operations. Modifications are required to do so.

Note: The priority of the timer thread needs to be adjusted as needed; If there are multiple soft timers, the execution of the callback function will be relatively long, and there must be a possibility that a callback will be delayed, which is unavoidable.


0 Answer
There is no answer, come and add the answer

Write Your Answer

Log in to publish your answer.,Click here to log in.