git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@346 35acf78f-673a-0410-8e92-d51de3d6d3f4

master
gdisirio 2008-07-22 09:55:51 +00:00
parent 71a1820c4a
commit 49c3629538
12 changed files with 1949 additions and 1867 deletions

View File

@ -24,6 +24,8 @@
#include "stm32_serial.h" #include "stm32_serial.h"
#include "stm32lib/stm32f10x_nvic.h" #include "stm32lib/stm32f10x_nvic.h"
#define USART_BITRATE (38400)
#ifdef USE_USART1 #ifdef USE_USART1
FullDuplexDriver COM1; FullDuplexDriver COM1;
static uint8_t ib1[SERIAL_BUFFERS_SIZE]; static uint8_t ib1[SERIAL_BUFFERS_SIZE];
@ -175,7 +177,7 @@ void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
#ifdef USE_USART1 #ifdef USE_USART1
chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1); chFDDInit(&COM1, ib1, sizeof ib1, NULL, ob1, sizeof ob1, OutNotify1);
RCC->APB2ENR |= 0x00004000; RCC->APB2ENR |= 0x00004000;
SetUSARTI(USART1, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); SetUSARTI(USART1, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0; GPIOA->CRH = (GPIOA->CRH & 0xFFFFF00F) | 0x000004B0;
NVICEnableVector(USART1_IRQChannel, prio1); NVICEnableVector(USART1_IRQChannel, prio1);
#endif #endif
@ -183,7 +185,7 @@ void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
#ifdef USE_USART2 #ifdef USE_USART2
chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2); chFDDInit(&COM2, ib2, sizeof ib2, NULL, ob2, sizeof ob2, OutNotify2);
RCC->APB1ENR |= 0x00020000; RCC->APB1ENR |= 0x00020000;
SetUSARTI(USART2, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); SetUSARTI(USART2, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00; GPIOA->CRL = (GPIOA->CRL & 0xFFFF00FF) | 0x00004B00;
NVICEnableVector(USART2_IRQChannel, prio2); NVICEnableVector(USART2_IRQChannel, prio2);
#endif #endif
@ -191,7 +193,7 @@ void InitSerial(uint32_t prio1, uint32_t prio2, uint32_t prio3) {
#ifdef USE_USART3 #ifdef USE_USART3
chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3); chFDDInit(&COM3, ib3, sizeof ib3, NULL, ob3, sizeof ob3, OutNotify3);
RCC->APB1ENR |= 0x00040000; RCC->APB1ENR |= 0x00040000;
SetUSARTI(USART3, 38400, 0, CR2_STOP1_BITS | CR2_LINEN, 0); SetUSARTI(USART3, USART_BITRATE, 0, CR2_STOP1_BITS | CR2_LINEN, 0);
GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00; GPIOB->CRH = (GPIOB->CRH & 0xFFFF00FF) | 0x00004B00;
NVICEnableVector(USART3_IRQChannel, prio3); NVICEnableVector(USART3_IRQChannel, prio3);
#endif #endif

View File

@ -49,6 +49,12 @@ void chSysHalt(void) {
} }
} }
/*
* Start a thread by invoking its work function.
*
* Start a thread by calling its work function. If the work function returns,
* call chThdExit and chSysHalt.
*/
__attribute__((naked, weak)) __attribute__((naked, weak))
void threadstart(void) { void threadstart(void) {
@ -80,7 +86,15 @@ void *retaddr;
*/ */
__attribute__((naked)) __attribute__((naked))
void SVCallVector(Thread *otp, Thread *ntp) { void SVCallVector(Thread *otp, Thread *ntp) {
/* { r0 = otp, r1 = ntp } */
/* get the BASEPRI in r3 */
/* get the PSP in r12 */
/* push the registers on the PSP stack */
/* stores the modified PSP into the thread context */
/* fetches the PSP position from the new thread context */
/* pop the registers from the PSP stack */
/* set the PSP from r12 */
/* set the BASEPRI from R3 */
#ifdef CH_CURRP_REGISTER_CACHE #ifdef CH_CURRP_REGISTER_CACHE
asm volatile ("mrs r3, BASEPRI \n\t" \ asm volatile ("mrs r3, BASEPRI \n\t" \
"mrs r12, PSP \n\t" \ "mrs r12, PSP \n\t" \
@ -135,6 +149,7 @@ void PendSVVector(void) {
(otp = currp)->p_ctx.r13 = sp_thd; (otp = currp)->p_ctx.r13 = sp_thd;
chSchReadyI(otp); chSchReadyI(otp);
(currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR; (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
/* set the round-robin time quantum */
rlist.r_preempt = CH_TIME_QUANTUM; rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_TRACE #ifdef CH_USE_TRACE
chDbgTrace(otp, currp); chDbgTrace(otp, currp);

View File

@ -66,6 +66,9 @@ typedef struct {
/* /*
* Platform dependent part of the \p chThdCreate() API. * Platform dependent part of the \p chThdCreate() API.
*
* The top of the workspace is used for the intctx datastructure.
*
*/ */
#define SETUP_CONTEXT(workspace, wsize, pf, arg) { \ #define SETUP_CONTEXT(workspace, wsize, pf, arg) { \
tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \ tp->p_ctx.r13 = (struct intctx *)((uint8_t *)workspace + \
@ -104,7 +107,10 @@ typedef struct {
INT_REQUIRED_STACK) INT_REQUIRED_STACK)
#define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2]; #define WorkingArea(s, n) uint32_t s[UserStackSize(n) >> 2];
/* called on each interrupt entry, currently nothing is done */
#define chSysIRQEnterI() #define chSysIRQEnterI()
/* called on each interrupt exit, pends a supervisor handler for
* execution after all higher priority interrupts; PendSVVector() */
#define chSysIRQExitI() { \ #define chSysIRQExitI() { \
SCB_ICSR = ICSR_PENDSVSET; \ SCB_ICSR = ICSR_PENDSVSET; \
} }

View File

@ -43,6 +43,7 @@ ResetHandler:
ldr r0, =__ram_end__ ldr r0, =__ram_end__
ldr r1, =__main_stack_size__ ldr r1, =__main_stack_size__
sub r0, r0, r1 sub r0, r0, r1
/* { r0 = main stack low address } */
msr PSP, r0 msr PSP, r0
// ldr r1, =__process_stack_size__ // ldr r1, =__process_stack_size__
// sub r0, r0, r1 // sub r0, r0, r1

View File

@ -74,6 +74,12 @@ Win32-MinGW - ChibiOS/RT simulator and demo into a WIN32 process,
*** Releases *** *** Releases ***
***************************************************************************** *****************************************************************************
*** 0.6.8 ***
- FIX: Fixed a bug in the priority inheritance mechanism, the bug was only a
problems when the CH_USE_MESSAGES_PRIORITY was enabled, this option is
disabled by default in ChibiOS/RT so it should not affect any user.
- Merged the documentation fixes submitted by Leon Woestenberg (thank you).
*** 0.6.7 *** *** 0.6.7 ***
- NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate() - NEW: New chThdCreateFast() API, it is a simplified form of chThdCreate()
that allows even faster threads creation. The new API does not support that allows even faster threads creation. The new API does not support

View File

@ -60,14 +60,19 @@ void chSysInit(void) {
} }
/** /**
* Preemption routine, this function must be called into an interrupt * Handles time ticks for round robin preemption and timer increments.
* handler invoked by a system timer. *
* The frequency of the timer determines the system tick granularity and, * Decrements the remaining time quantum of the running thread and preempts
* it when the quantum is used up. Increments system time and manages the
* timers.
*
* @note The frequency of the timer determines the system tick granularity and,
* together with the \p CH_TIME_QUANTUM macro, the round robin interval. * together with the \p CH_TIME_QUANTUM macro, the round robin interval.
*/ */
void chSysTimerHandlerI(void) { void chSysTimerHandlerI(void) {
/* running thread has not used up quantum yet? */
if (rlist.r_preempt > 0) if (rlist.r_preempt > 0)
/* decrement remaining quantum */
rlist.r_preempt--; rlist.r_preempt--;
#ifdef CH_USE_SYSTEMTIME #ifdef CH_USE_SYSTEMTIME
rlist.r_stime++; rlist.r_stime++;

View File

@ -51,34 +51,46 @@ void chMtxLock(Mutex *mp) {
/** /**
* Locks the specified mutex. * Locks the specified mutex.
*
* @param mp pointer to the \p Mutex structure * @param mp pointer to the \p Mutex structure
* @note This function must be called within a \p chSysLock() / \p chSysUnlock() * @note This function must be called within a \p chSysLock() / \p chSysUnlock()
* block. * block.
*/ */
void chMtxLockS(Mutex *mp) { void chMtxLockS(Mutex *mp) {
/* the mutex is already locked? */
if (mp->m_owner != NULL) { if (mp->m_owner != NULL) {
/* /*
* Inheritance, explores the thread-mutex dependances adjusting * Priority inheritance protocol; explores the thread-mutex dependencies
* the priority of all the affected threads. * boosting the priority of all the affected threads to equal the priority
* of the running thread requesting the mutex.
*/ */
Thread *tp = mp->m_owner; Thread *tp = mp->m_owner;
/* { tp is the thread currently owning the mutex } */
/* the running thread has higher priority than tp? */
while (tp->p_prio < currp->p_prio) { while (tp->p_prio < currp->p_prio) {
/* make priority of thread tp match the running thread's priority */
tp->p_prio = currp->p_prio; tp->p_prio = currp->p_prio;
/* /*
* The following states need priority queues reordering. * The following states need priority queues reordering.
*/ */
switch (tp->p_state) { switch (tp->p_state) {
/* thread tp is waiting on a mutex? */
case PRWTMTX: case PRWTMTX:
/* requeue tp with its new priority on the mutex wait queue */
prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue); prio_insert(dequeue(tp), &tp->p_wtmtxp->m_queue);
/* boost the owner of this mutex if needed */
tp = tp->p_wtmtxp->m_owner; tp = tp->p_wtmtxp->m_owner;
continue; continue;
#ifdef CH_USE_MESSAGES_PRIORITY #ifdef CH_USE_MESSAGES_PRIORITY
case PRSNDMSG: case PRSNDMSG:
if (tp->p_flags & P_MSGBYPRIO) if (tp->p_flags & P_MSGBYPRIO)
/* requeue tp with its new priority on (?) */
prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue); prio_insert(dequeue(tp), &tp->p_wtthdp->p_msgqueue);
break;
#endif #endif
/* thread tp is ready? */
case PRREADY: case PRREADY:
/* requeue tp with its new priority on the ready list */
chSchReadyI(dequeue(tp)); chSchReadyI(dequeue(tp));
} }
break; break;
@ -157,21 +169,26 @@ void chMtxUnlock(void) {
* If a thread is waiting on the mutex then the hard part begins. * If a thread is waiting on the mutex then the hard part begins.
*/ */
if (chMtxQueueNotEmptyS(mp)) { if (chMtxQueueNotEmptyS(mp)) {
/* get the highest priority thread waiting for the unlocked mutex */
Thread *tp = fifo_remove(&mp->m_queue); Thread *tp = fifo_remove(&mp->m_queue);
/* /*
* Recalculates the optimal thread priority by scanning the owned mutexes list. * Recalculates the optimal thread priority by scanning the owned mutexes list.
*/ */
tprio_t newprio = currp->p_realprio; tprio_t newprio = currp->p_realprio;
/* iterate mp over all the (other) mutexes the current thread still owns */
mp = currp->p_mtxlist; mp = currp->p_mtxlist;
while (mp != NULL) { while (mp != NULL) {
/* mutex mp has a higher priority thread pending? */
if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio)) if (chMtxQueueNotEmptyS(mp) && (mp->m_queue.p_next->p_prio > newprio))
/* boost current thread's priority to waiting thread */
newprio = mp->m_queue.p_next->p_prio; newprio = mp->m_queue.p_next->p_prio;
mp = mp->m_next; mp = mp->m_next;
} }
/* (possibly) boost the priority of the current thread */
currp->p_prio = newprio; currp->p_prio = newprio;
/* awaken the highest priority thread waiting for the unlocked mutex */
chSchWakeupS(tp, RDY_OK); chSchWakeupS(tp, RDY_OK);
} }
chSysUnlock(); chSysUnlock();
} }

View File

@ -44,6 +44,7 @@ void chSchInit(void) {
/** /**
* Inserts a thread in the Ready List. * Inserts a thread in the Ready List.
*
* @param tp the Thread to be made ready * @param tp the Thread to be made ready
* @return the Thread pointer * @return the Thread pointer
* @note The function must be called in the system mutex zone. * @note The function must be called in the system mutex zone.
@ -103,9 +104,12 @@ static void wakeup(void *p) {
} }
/** /**
* Puts the current thread to sleep into the specified state, the next highest * Put the current thread to sleep.
* priority thread becomes running. The thread is automatically awakened after *
* the specified time elapsed. * Puts the current thread to sleep into the specified state. The next highest
* priority thread becomes running. The thread put to sleep is awakened after
* the specified time has elapsed.
*
* @param newstate the new thread state * @param newstate the new thread state
* @param time the number of ticks before the operation timouts * @param time the number of ticks before the operation timouts
* @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs * @return the wakeup message, it is \p RDY_TIMEOUT if a timeout occurs
@ -124,8 +128,10 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
#endif /* CH_USE_VIRTUAL_TIMERS */ #endif /* CH_USE_VIRTUAL_TIMERS */
/** /**
* Wakeups a thread, the thread is inserted into the ready list or made * Wakes up a thread.
* running directly depending on its relative priority compared to the current *
* Wakes up a thread. The thread is inserted into the ready list or immediately
* made running depending on its relative priority compared to the current
* thread. * thread.
* @param ntp the Thread to be made ready * @param ntp the Thread to be made ready
* @param msg message to the awakened thread * @param msg message to the awakened thread
@ -135,11 +141,14 @@ msg_t chSchGoSleepTimeoutS(tstate_t newstate, systime_t time) {
* \p chSchRescheduleS() but much more efficient. * \p chSchRescheduleS() but much more efficient.
*/ */
void chSchWakeupS(Thread *ntp, msg_t msg) { void chSchWakeupS(Thread *ntp, msg_t msg) {
ntp->p_rdymsg = msg; ntp->p_rdymsg = msg;
/* the woken thread has equal or lower priority than the running thread? */
if (ntp->p_prio <= currp->p_prio) if (ntp->p_prio <= currp->p_prio)
/* put the woken thread on the ready queue */
chSchReadyI(ntp); chSchReadyI(ntp);
/* the woken thread has higher priority than the running thread */
else { else {
/* put the running thread on the ready queue */
Thread *otp = currp; Thread *otp = currp;
chSchReadyI(otp); chSchReadyI(otp);
(currp = ntp)->p_state = PRCURR; (currp = ntp)->p_state = PRCURR;
@ -147,46 +156,59 @@ void chSchWakeupS(Thread *ntp, msg_t msg) {
#ifdef CH_USE_TRACE #ifdef CH_USE_TRACE
chDbgTrace(otp, ntp); chDbgTrace(otp, ntp);
#endif #endif
/* switch the thread context */
chSysSwitchI(otp, ntp); chSysSwitchI(otp, ntp);
} }
} }
/** /**
* Performs a reschedulation. It is meant to be called if * Switch to the first thread on the runnable queue.
* \p chSchRescRequired() evaluates to \p TRUE. *
* Intended to be called if \p chSchRescRequired() evaluates to \p TRUE.
*/ */
void chSchDoRescheduleI(void) { void chSchDoRescheduleI(void) {
/* put the running thread on the ready queue */
Thread *otp = currp; Thread *otp = currp;
chSchReadyI(otp); chSchReadyI(otp);
/* pick the first thread from the ready queue */
(currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR; (currp = fifo_remove(&rlist.r_queue))->p_state = PRCURR;
rlist.r_preempt = CH_TIME_QUANTUM; rlist.r_preempt = CH_TIME_QUANTUM;
#ifdef CH_USE_TRACE #ifdef CH_USE_TRACE
chDbgTrace(otp, currp); chDbgTrace(otp, currp);
#endif #endif
/* switch thread context */
chSysSwitchI(otp, currp); chSysSwitchI(otp, currp);
} }
/** /**
* If a thread with an higher priority than the current thread is in the * Reschedule only if a higher priority thread is runnable.
* ready list then it becomes running. *
* If a thread with a higher priority than the current thread is in the
* ready list then make the higher priority thread running.
*
* @note The function must be called in the system mutex zone. * @note The function must be called in the system mutex zone.
*/ */
void chSchRescheduleS(void) { void chSchRescheduleS(void) {
/* first thread in the runnable queue has higher priority than the running
* thread? */
if (firstprio(&rlist.r_queue) > currp->p_prio) if (firstprio(&rlist.r_queue) > currp->p_prio)
chSchDoRescheduleI(); chSchDoRescheduleI();
} }
/** /**
* Evaluates if a reschedulation is required. * Evaluates if rescheduling is required.
*
* @return \p TRUE if there is a thread that should go in running state * @return \p TRUE if there is a thread that should go in running state
* immediatly else \p FALSE. * immediately else \p FALSE.
*/ */
bool_t chSchRescRequiredI(void) { bool_t chSchRescRequiredI(void) {
tprio_t p1 = firstprio(&rlist.r_queue); tprio_t p1 = firstprio(&rlist.r_queue);
tprio_t p2 = currp->p_prio; tprio_t p2 = currp->p_prio;
/* If the running thread has not reached its time quantum, reschedule only
* if the first thread on the ready queue has a higher priority.
* Otherwise, if the running thread has used up its time quantum, reschedule
* if the first thread on the ready queue has equal or higher priority.
*/
return rlist.r_preempt ? p1 > p2 : p1 >= p2; return rlist.r_preempt ? p1 > p2 : p1 >= p2;
} }

View File

@ -34,6 +34,7 @@ void init_thread(tprio_t prio, tmode_t mode, Thread *tp) {
tp->p_flags = mode; tp->p_flags = mode;
tp->p_prio = prio; tp->p_prio = prio;
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
/* realprio is the thread's own, non-inherited, priority */
tp->p_realprio = prio; tp->p_realprio = prio;
tp->p_mtxlist = NULL; tp->p_mtxlist = NULL;
#endif #endif
@ -89,6 +90,7 @@ static void memfill(uint8_t *p, uint32_t n, uint8_t v) {
*/ */
Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace, Thread *chThdCreate(tprio_t prio, tmode_t mode, void *workspace,
size_t wsize, tfunc_t pf, void *arg) { size_t wsize, tfunc_t pf, void *arg) {
/* thread structure is layed out in the lower part of the thread workspace */
Thread *tp = workspace; Thread *tp = workspace;
chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) && chDbgAssert((wsize >= UserStackSize(0)) && (prio <= HIGHPRIO) &&
@ -146,8 +148,9 @@ Thread *chThdCreateFast(tprio_t prio, void *workspace,
} }
/** /**
* Changes the thread priority, reschedules if necessary. * Changes the running thread priority, reschedules if necessary.
* @param newprio the new priority of the invoking thread *
* @param newprio the new priority of the running thread
*/ */
void chThdSetPriority(tprio_t newprio) { void chThdSetPriority(tprio_t newprio) {
@ -236,6 +239,7 @@ void chThdTerminate(Thread *tp) {
/** /**
* Terminates the current thread by specifying an exit status code. * Terminates the current thread by specifying an exit status code.
*
* @param msg the thread exit code. The code can be retrieved by using * @param msg the thread exit code. The code can be retrieved by using
* \p chThdWait(). * \p chThdWait().
*/ */
@ -258,6 +262,7 @@ void chThdExit(msg_t msg) {
/** /**
* Blocks the execution of the invoking thread until the specified thread * Blocks the execution of the invoking thread until the specified thread
* terminates then the exit code is returned. * terminates then the exit code is returned.
*
* @param tp the pointer to the thread * @param tp the pointer to the thread
* @return the exit code * @return the exit code
* @note The function is available only if the \p CH_USE_WAITEXIT * @note The function is available only if the \p CH_USE_WAITEXIT

View File

@ -27,11 +27,12 @@
/** Normal \p chSchReadyI() message. */ /** Normal \p chSchReadyI() message. */
#define RDY_OK 0 #define RDY_OK 0
/** Returned if the thread was made ready because a timeout.*/ /** Returned when the thread was made ready because of a timeout. */
#define RDY_TIMEOUT -1 #define RDY_TIMEOUT -1
/** Returned if the thread was made ready because a reset.*/ /** Returned when the thread was made ready because of a reset. */
#define RDY_RESET -2 #define RDY_RESET -2
/** The priority of the first thread on the given ready list. */
#define firstprio(rlp) ((rlp)->p_next->p_prio) #define firstprio(rlp) ((rlp)->p_next->p_prio)
/** /**
@ -42,6 +43,7 @@ typedef struct {
tprio_t r_prio; tprio_t r_prio;
cnt_t r_preempt; cnt_t r_preempt;
#ifndef CH_CURRP_REGISTER_CACHE #ifndef CH_CURRP_REGISTER_CACHE
/** the currently running thread */
Thread *r_current; Thread *r_current;
#endif #endif
#ifdef CH_USE_SYSTEMTIME #ifdef CH_USE_SYSTEMTIME

View File

@ -101,8 +101,9 @@ struct Thread {
eventmask_t p_epending; eventmask_t p_epending;
#endif #endif
#ifdef CH_USE_MUTEXES #ifdef CH_USE_MUTEXES
/** Owner mutexes list, \p NULL terminated.*/ /** List of mutexes owned by this thread, \p NULL terminated.*/
Mutex *p_mtxlist; Mutex *p_mtxlist;
/** Thread's own, non-inherited, priority */
tprio_t p_realprio; tprio_t p_realprio;
#endif #endif
}; };