git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@752 35acf78f-673a-0410-8e92-d51de3d6d3f4
This commit is contained in:
parent
1c1d5129c5
commit
50bebb2976
13
docs/ch.txt
13
docs/ch.txt
|
@ -46,16 +46,10 @@
|
||||||
* - 128 priority levels.
|
* - 128 priority levels.
|
||||||
* - Multiple threads at the same priority level allowed.
|
* - Multiple threads at the same priority level allowed.
|
||||||
* - Round robin scheduling for threads at the same priority level.
|
* - Round robin scheduling for threads at the same priority level.
|
||||||
* - Unlimited number of threads.
|
* - Offers threads, virtual timers, semaphores, mutexes, condvars,
|
||||||
* - Unlimited number of virtual timers.
|
* event flags, messages, I/O queues.
|
||||||
* - Unlimited number of semaphores.
|
|
||||||
* - Unlimited number of mutexes.
|
|
||||||
* - Unlimited number of condvars.
|
|
||||||
* - Unlimited number of event sources.
|
|
||||||
* - Unlimited number of messages in queue.
|
|
||||||
* - Unlimited number of I/O queues.
|
|
||||||
* - No static setup at compile time, there is no need to configure a maximum
|
* - No static setup at compile time, there is no need to configure a maximum
|
||||||
* number of all the above resources.
|
* number of all the above objects.
|
||||||
* - No *need* for a memory allocator, all the kernel structures are static
|
* - No *need* for a memory allocator, all the kernel structures are static
|
||||||
* and declaratively allocated.
|
* and declaratively allocated.
|
||||||
* - Threads, Semaphores, Event Sources, Virtual Timers creation/deletion at
|
* - Threads, Semaphores, Event Sources, Virtual Timers creation/deletion at
|
||||||
|
@ -73,6 +67,7 @@
|
||||||
* .
|
* .
|
||||||
* <h2>Related pages</h2>
|
* <h2>Related pages</h2>
|
||||||
* - @subpage lic_faq
|
* - @subpage lic_faq
|
||||||
|
* - @subpage goals
|
||||||
* - @subpage concepts
|
* - @subpage concepts
|
||||||
* - @subpage articles
|
* - @subpage articles
|
||||||
* .
|
* .
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
* @page articles Articles
|
* @page articles Articles
|
||||||
* @{
|
* @{
|
||||||
* ChibiOS/RT Articles and Code Examples:
|
* ChibiOS/RT Articles and Code Examples:
|
||||||
* - @subpage article_portguide
|
* - @subpage article_mutual_exclusion
|
||||||
* - @subpage article_atomic
|
* - @subpage article_atomic
|
||||||
* - @subpage article_saveram
|
* - @subpage article_saveram
|
||||||
* - @subpage article_interrupts
|
* - @subpage article_interrupts
|
||||||
* - @subpage article_jitter
|
* - @subpage article_jitter
|
||||||
* - @subpage article_timing
|
* - @subpage article_timing
|
||||||
|
* - @subpage article_portguide
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page goals Project Goals
|
||||||
|
* @{
|
||||||
|
* <h2>Another RTOS?</h2>
|
||||||
|
* The first question to be answered is: there was really the need for YET
|
||||||
|
* ANOTHER RTOS?<br>
|
||||||
|
* My answer is yes because various reasons:
|
||||||
|
* - The ChibiOS/RT ancestor was created more than 15 years ago and while it
|
||||||
|
* had far less features than the current product it was complete and
|
||||||
|
* functioning. ChibiOS/RT is just a new (and silly) name given to
|
||||||
|
* something created when there were not many free RTOSes around (actually
|
||||||
|
* none, at least none in my knowledge, there was no widespread Internet
|
||||||
|
* at that time).
|
||||||
|
* - When, after a while, I needed a RTOS again, none of the existing FOSS
|
||||||
|
* projects met my expectations or my ideas of how a RTOS should be, not
|
||||||
|
* even close (see below). I decided that work on that old project was
|
||||||
|
* a better idea that contribute to, or fork, something else.
|
||||||
|
* - I wanted another toy.
|
||||||
|
* .
|
||||||
|
* <h2>Why is it different?</h2>
|
||||||
|
* In itself it implements ideas already seen in other projects but never
|
||||||
|
* all together in a single FOSS project. There are some basic choices in
|
||||||
|
* ChibiOS/RT (mostly derived by its ancestor):
|
||||||
|
*
|
||||||
|
* <h3>Static design</h3>
|
||||||
|
* Everything in the kernel is static, nowhere memory is allocated or freed,
|
||||||
|
* there are two allocator subsystems but those are options and not part of
|
||||||
|
* core OS. Safety is something you design in, not something you can add later.
|
||||||
|
*
|
||||||
|
* <h3>No fixed size tables or structures</h3>
|
||||||
|
* No tables to configure, no arrays that can be filled and overflow at
|
||||||
|
* runtime. Everything without practical upper bounds (except for resource
|
||||||
|
* limits and numerical upper bounds of course).
|
||||||
|
*
|
||||||
|
* <h3>No error conditions and no error checks</h3>
|
||||||
|
* All the API should not have error conditions, all the previous points are
|
||||||
|
* finalized to this objective. Everything you can invoke in the kernel is
|
||||||
|
* designed to not fail unless you pass garbage as parameters, stray pointers
|
||||||
|
* or such. Also the APIs are not slowed down by error checks, error checks
|
||||||
|
* exists but only when the debug switch is activated.<br>
|
||||||
|
* All the static core APIs always succeed if correct parameters are passed.
|
||||||
|
*
|
||||||
|
* <h3>Very simple APIs</h3>
|
||||||
|
* Every API should have the parameters you would expect for that function, no
|
||||||
|
* more no less. Each API should do a single thing with no options.
|
||||||
|
*
|
||||||
|
* <h3>Damn fast and compact</h3>
|
||||||
|
* Note first "fast" then "compact", the focus is on speed and execution
|
||||||
|
* efficiency rather than code size. This does not mean it is large, the OS
|
||||||
|
* with all the subsystems activated is well below 8KiB (32bit ARM code, the
|
||||||
|
* least space efficient) and can shrink down below 2KiB. It would be
|
||||||
|
* possible to make something smaller but:
|
||||||
|
* -# It would be pointless, it @a is already small.
|
||||||
|
* -# I would not sacrifice efficiency or features in order to save few bytes.
|
||||||
|
* .
|
||||||
|
* About the "fast" part, it is able to start/wait/exit more than <b>200,000
|
||||||
|
* threads per second</b> on a 72MHz STM32 (Cortex-M3). The Context Switch just
|
||||||
|
* takes <b>2.3 microseconds</b> on the same STM32. The numbers are not
|
||||||
|
* pulled out of thin air, it is the output of the included test suite.
|
||||||
|
*
|
||||||
|
* <h3>Tests and metrics</h3>
|
||||||
|
* I think it is nice to know how an OS is tested and how it performs before
|
||||||
|
* committing to use it. Test results on all the supported platforms and
|
||||||
|
* performance metrics are included in each ChibiOS/RT release. The test
|
||||||
|
* code is released as well, all the included demos are capable of executing
|
||||||
|
* the test suite and the OS benchmarks.
|
||||||
|
*/
|
||||||
|
/** @} */
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
/*
|
||||||
|
ChibiOS/RT - Copyright (C) 2006-2007 Giovanni Di Sirio.
|
||||||
|
|
||||||
|
This file is part of ChibiOS/RT.
|
||||||
|
|
||||||
|
ChibiOS/RT is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
ChibiOS/RT is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @page article_mutual_exclusion Mutual Exclusion guide
|
||||||
|
* @{
|
||||||
|
* The most common problem when writing multithreaded code is the
|
||||||
|
* synchronization on the shared resources/services.<br>
|
||||||
|
* ChibiOS/RT offers a rich variety of mechanisms that apparently solve the
|
||||||
|
* same problem. I wrote apparently because each mechanism has its pro and
|
||||||
|
* cons.
|
||||||
|
* This article will introduce the various mechanisms and the explain the
|
||||||
|
* right scenarios for each one.
|
||||||
|
*
|
||||||
|
* <h2>Basics</h2>
|
||||||
|
* Some of the concepts mentioned in this article can be found in the
|
||||||
|
* following Wikipedia articles:
|
||||||
|
* - <a href="http://en.wikipedia.org/wiki/Mutual_exclusion" target="_blank">
|
||||||
|
* Mutual Exclusion</a>
|
||||||
|
* - <a href="http://en.wikipedia.org/wiki/Priority_inversion" target="_blank">
|
||||||
|
* Priority Inversion</a>
|
||||||
|
* - <a href="http://en.wikipedia.org/wiki/Priority_inheritance"
|
||||||
|
* target="_blank">Priority Inheritance</a>
|
||||||
|
* - <a href="http://en.wikipedia.org/wiki/Priority_ceiling" target="_blank">
|
||||||
|
* Priority Ceiling</a>
|
||||||
|
* .
|
||||||
|
* <h2>Mutual exclusion by System Locks</h2>
|
||||||
|
* This is the lowest level mechanism, the system is locked by invoking the
|
||||||
|
* @p chSysLock() API and then unlocked by invoking @p chSysUnlock().<br>
|
||||||
|
* The implementation is architecture dependent but it is guaranteed to, at
|
||||||
|
* least, disable the interrupt sources with hardware priority below or equal
|
||||||
|
* the kernel level.
|
||||||
|
*
|
||||||
|
* <h3>Advantages</h3>
|
||||||
|
* - It is the lightest as execution time, often a lock or unlock becomes just a
|
||||||
|
* single inlined assembler instruction.
|
||||||
|
* - It ensures mutual exclusion among threads but also interrupt handling code.
|
||||||
|
* - The implementation would ensure mutual exclusion even on multicore
|
||||||
|
* architectures where multiple hardware threads are present.
|
||||||
|
* .
|
||||||
|
* <h3>Disadvantages</h3>
|
||||||
|
* - Disabling interrupts for a long period of time can deteriorate the overall
|
||||||
|
* system response time and/or introduce jitter.
|
||||||
|
* .
|
||||||
|
* <h3>When use Locks</h3>
|
||||||
|
* - When mutual exclusion with interrupt handlers is required.
|
||||||
|
* - When the operation within the lock zone is very simple and has finite
|
||||||
|
* time.
|
||||||
|
* .
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* @code
|
||||||
|
* ...
|
||||||
|
* chSysLock();
|
||||||
|
* /* Protected code */
|
||||||
|
* chSysUnlock();
|
||||||
|
* ...
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* <h2>Mutual exclusion by Semaphores</h2>
|
||||||
|
* In ChibiOS/RT the counting semaphores are mainly meant as a
|
||||||
|
* synchronization mechanism between interrupt handlers and high level code
|
||||||
|
* running at thread level. Usually a thread waits on a semaphore that is
|
||||||
|
* signaled asynchronously by an interrupt handler.<br>
|
||||||
|
* The semaphores can, however, be used as simple mutexes by initializing
|
||||||
|
* counter to one.
|
||||||
|
*
|
||||||
|
* <h3>Advantages</h3>
|
||||||
|
* - The semaphores code is "already there" if you use the I/O queues and
|
||||||
|
* you don't want to enable the mutexes too because space constraints.
|
||||||
|
* - Semaphores are lighter than mutexes because their queues are FIFO
|
||||||
|
* ordered and do not have any overhead caused by the priority inheritance
|
||||||
|
* algorithm.
|
||||||
|
* - A semaphore takes less RAM than a mutex (12 vs 16 bytes on 32 bit
|
||||||
|
* architectures).
|
||||||
|
* .
|
||||||
|
* <h3>Disadvantages</h3>
|
||||||
|
* - Semaphore queues are FIFO ordered by default, an option exist to make
|
||||||
|
* them priority ordered but this can impact I/O performance because
|
||||||
|
* semaphores are used in I/O queues.
|
||||||
|
* - Semaphores do not implement the priority inheritance algorithm so the
|
||||||
|
* priority inversion problem is not mitigated.
|
||||||
|
* .
|
||||||
|
* <h3>When use Semaphores</h3>
|
||||||
|
* - When you don't need queuing by priority nor the priority inheritance
|
||||||
|
* algorithm.
|
||||||
|
* - When RAM/ROM space is scarce.
|
||||||
|
* .
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* @code
|
||||||
|
* static Semaphore sem; /* Semaphore declaration */
|
||||||
|
* ...
|
||||||
|
* chSemInit(&sem, 1); /* Semaphore initialization before use */
|
||||||
|
* ...
|
||||||
|
* chSemWait(&sem);
|
||||||
|
* /* Protected code */
|
||||||
|
* chSemSignal(&sem);
|
||||||
|
* ...
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* <h2>Mutual exclusion by Mutexes</h2>
|
||||||
|
* The mutexes, also known as binary semaphores (we choose to not use this
|
||||||
|
* terminology to avoid confusion with counting semaphores), are the mechanism
|
||||||
|
* intended as general solution for the mutual exclusion problem.
|
||||||
|
*
|
||||||
|
* <h3>Advantages</h3>
|
||||||
|
* - Mutexes implement the Priority Inheritance algorithm that is an important
|
||||||
|
* tool in reducing jitter and improve overall system response time (it is
|
||||||
|
* not a magic solution, just a tool for the system designer).
|
||||||
|
* .
|
||||||
|
* <h3>Disadvantages</h3>
|
||||||
|
* - Heaviest among all the possible choices. The Priority Inheritance method
|
||||||
|
* is efficiently implemented but nothing is more efficient than no code at
|
||||||
|
* all.
|
||||||
|
* .
|
||||||
|
* <h3>When use Mutexes</h3>
|
||||||
|
* - When you are designing a very complex system with hard realtime
|
||||||
|
* requirements.
|
||||||
|
* .
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* @code
|
||||||
|
* static Mutex mtx; /* Mutex declaration */
|
||||||
|
* ...
|
||||||
|
* chMtxInit(&mtx); /* Mutex initialization before use */
|
||||||
|
* ...
|
||||||
|
* chMtxLock(&mtx);
|
||||||
|
* /* Protected code */
|
||||||
|
* chMtxUnlock();
|
||||||
|
* ...
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* <h2>Mutual exclusion by priority boost</h2>
|
||||||
|
* Another way to implement mutual exclusion is to boost the thread priority
|
||||||
|
* to a level higher than all of the threads competing for a certain resource.
|
||||||
|
* This solution effectively implements an Immediate Priority Ceiling
|
||||||
|
* algorithm.
|
||||||
|
*
|
||||||
|
* <h3>Advantages</h3>
|
||||||
|
* - Almost free as code size, you need no semaphores nor mutexes.
|
||||||
|
* - No RAM overhead.
|
||||||
|
* - Fast execution, priority change is a quick operation under ChibiOS/RT.
|
||||||
|
* - The priority ceiling protocol that can help mitigate the Priority
|
||||||
|
* Inversion problem.
|
||||||
|
* .
|
||||||
|
* <h3>Disadvantages</h3>
|
||||||
|
* - Makes the design more complicated because priorities must be assigned to
|
||||||
|
* not just threads but also assigned to the resources to be protected.
|
||||||
|
* - Locking a resource affects all the threads with lower priority even if
|
||||||
|
* not interested to the resource.
|
||||||
|
* - All the threads that can access the resource must have lower priority
|
||||||
|
* than the resource itself.
|
||||||
|
* - The mechanism is not easy to understand in the code unless it is clearly
|
||||||
|
* documented.
|
||||||
|
* - This method does not work in on multicore architectures where multiple
|
||||||
|
* hardware threads are present.
|
||||||
|
* - Only useful in very simple applications.
|
||||||
|
* .
|
||||||
|
* <h3>Example</h3>
|
||||||
|
* @code
|
||||||
|
* /* Priority assigned to the resource, threads must have lower
|
||||||
|
* priority than this.*/
|
||||||
|
* #define AAA_RESOURCE_PRIORITY NORMALPRIO+10
|
||||||
|
* ...
|
||||||
|
* /* Locks the resources AAA.*/
|
||||||
|
* tprio_t aaa_old_prio = chThdSetPriority(AAA_RESOURCE_PRIORITY);
|
||||||
|
* /* Accessing resource AAA */
|
||||||
|
* chThdSetPriority(aaa_old_prio); /* Unlocks AAA.*/
|
||||||
|
* ...
|
||||||
|
* @endcode
|
||||||
|
*
|
||||||
|
* <h2>Mutual exclusion by message passing</h2>
|
||||||
|
* Another method is to make a single dedicated thread execute the critical
|
||||||
|
* code and make it work as a messages server. The other threads can request
|
||||||
|
* the service to the server by sending a properly formatted message and
|
||||||
|
* then wait for the answer with the result.<br>
|
||||||
|
* This method is very useful when integrating into the system components not
|
||||||
|
* designed to be reentrant or to be executed in a multithreaded environment,
|
||||||
|
* as example a 3rd part file system or a networking protocol stack.
|
||||||
|
*
|
||||||
|
* <h3>Advantages</h3>
|
||||||
|
* - It is possible to encapsulate very complex logic without worry about
|
||||||
|
* about concurrent accesses.
|
||||||
|
* - If the encapsulate code uses a large stack area only the server thread
|
||||||
|
* have to allocate enough RAM, the client threads save RAM by just
|
||||||
|
* requesting the service to the server.
|
||||||
|
* - Clean system architecture.
|
||||||
|
* - This method also implements a form of Priority Ceiling. The ceiling is
|
||||||
|
* the priority of the server thread itself.
|
||||||
|
* .
|
||||||
|
* <h3>Disadvantages</h3>
|
||||||
|
* - More complex implementation, a protocol must be created between clients
|
||||||
|
* and server.
|
||||||
|
* - Two context switches are required for each request to the server (but
|
||||||
|
* ChibiOSRT is very efficient at that).
|
||||||
|
* - Requires a dedicated thread.
|
||||||
|
* .
|
||||||
|
*/
|
||||||
|
/** @} */
|
|
@ -108,6 +108,8 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
|
||||||
registers usage now the kernel is much smaller, faster and most OS APIs
|
registers usage now the kernel is much smaller, faster and most OS APIs
|
||||||
use less RAM in stack frames (note, this is an ARM7 thumb mode specific
|
use less RAM in stack frames (note, this is an ARM7 thumb mode specific
|
||||||
optimization).
|
optimization).
|
||||||
|
- CHANGE: Now the API chThdSetPriority() returns the old priority instead
|
||||||
|
of void.
|
||||||
- CHANGE: Modified the signature of the chMsgSendWithEvent() API, it now uses
|
- CHANGE: Modified the signature of the chMsgSendWithEvent() API, it now uses
|
||||||
a more efficient event signaling method.
|
a more efficient event signaling method.
|
||||||
- CHANGE: Removed the field p_tid from the Thread structure and the related
|
- CHANGE: Removed the field p_tid from the Thread structure and the related
|
||||||
|
|
|
@ -189,29 +189,34 @@ Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
|
||||||
#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS */
|
#endif /* CH_USE_DYNAMIC && CH_USE_WAITEXIT && CH_USE_MEMPOOLS */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Changes the running thread priority then reschedules if necessary.
|
* @brief Changes the running thread priority level then reschedules if
|
||||||
|
* necessary.
|
||||||
*
|
*
|
||||||
* @param newprio the new priority of the running thread
|
* @param newprio the new priority level of the running thread
|
||||||
|
* @return The old priority level.
|
||||||
|
* @note The function returns the real thread priority regardless of the
|
||||||
|
* actual priority that could be higher than the real priority because
|
||||||
|
* the priority inheritance mechanism.
|
||||||
*/
|
*/
|
||||||
void chThdSetPriority(tprio_t newprio) {
|
tprio_t chThdSetPriority(tprio_t newprio) {
|
||||||
|
tprio_t oldprio;
|
||||||
|
|
||||||
chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()");
|
chDbgAssert(newprio <= HIGHPRIO, "chthreads.c, chThdSetPriority()");
|
||||||
chSysLock();
|
chSysLock();
|
||||||
|
|
||||||
#if CH_USE_MUTEXES
|
#if CH_USE_MUTEXES
|
||||||
if (currp->p_prio != currp->p_realprio) {
|
oldprio = currp->p_realprio;
|
||||||
if (newprio > currp->p_prio)
|
if ((currp->p_prio == currp->p_realprio) || (newprio > currp->p_prio))
|
||||||
currp->p_prio = newprio;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
currp->p_prio = newprio;
|
currp->p_prio = newprio;
|
||||||
currp->p_realprio = newprio;
|
currp->p_realprio = newprio;
|
||||||
#else
|
#else
|
||||||
|
oldprio = currp->p_prio;
|
||||||
currp->p_prio = newprio;
|
currp->p_prio = newprio;
|
||||||
#endif
|
#endif
|
||||||
chSchRescheduleS();
|
chSchRescheduleS();
|
||||||
|
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
|
return oldprio;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -172,7 +172,7 @@ extern "C" {
|
||||||
Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
|
Thread *chThdCreateFromMemoryPool(MemoryPool *mp, tprio_t prio,
|
||||||
tfunc_t pf, void *arg);
|
tfunc_t pf, void *arg);
|
||||||
#endif
|
#endif
|
||||||
void chThdSetPriority(tprio_t newprio);
|
tprio_t chThdSetPriority(tprio_t newprio);
|
||||||
Thread *chThdResume(Thread *tp);
|
Thread *chThdResume(Thread *tp);
|
||||||
void chThdTerminate(Thread *tp);
|
void chThdTerminate(Thread *tp);
|
||||||
void chThdSleep(systime_t time);
|
void chThdSleep(systime_t time);
|
||||||
|
|
Loading…
Reference in New Issue