Correct, the priorities are fixed.
The AVR and MSP430 ports are untested, I am grateful for any feedback you can provide. I will look at that issue.
Giovanni
[FUN] Preliminary results
- Giovanni
- Site Admin
- Posts: 14455
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: [FUN] Preliminary results
It appears there is an inconsistency in how nilSchGoSleepTimeoutS is used. In some places the second argument is used as an interval and other places as the system time.
nilThdSleepUntilS is defined this way and assumes the second argument of nilSchGoSleepTimeoutS is the system time:
nilSemWaitTimeoutS assumes the second argument of nilSchGoSleepTimeoutS is an interval and has this call:
The nilSchGoSleepTimeoutS code assumes the second argument is a time but tests it as if it is an interval.
I discovered this when I found that on AVR with a 16-bit systime_t there was a problem with rollover while ChibiOS/RT works fine.
The problem is that nilThdSleep can result in a call to nilSchGoSleepTimeoutS with TIME_INFINITE even though the argument to nilThdSleep is small.
I am trying to modify Nil RTOS so nilSchGoSleepTimeoutS treats its second argument as an interval.
nilThdSleepUntilS is defined this way and assumes the second argument of nilSchGoSleepTimeoutS is the system time:
Code: Select all
#define nilThdSleepUntilS(time) nilSchGoSleepTimeoutS(nil.currp, (time))
nilSemWaitTimeoutS assumes the second argument of nilSchGoSleepTimeoutS is an interval and has this call:
Code: Select all
return nilSchGoSleepTimeoutS((void *)sp, time);
The nilSchGoSleepTimeoutS code assumes the second argument is a time but tests it as if it is an interval.
Code: Select all
otp->timeout = (bool_t)(time != TIME_INFINITE);
I discovered this when I found that on AVR with a 16-bit systime_t there was a problem with rollover while ChibiOS/RT works fine.
The problem is that nilThdSleep can result in a call to nilSchGoSleepTimeoutS with TIME_INFINITE even though the argument to nilThdSleep is small.
I am trying to modify Nil RTOS so nilSchGoSleepTimeoutS treats its second argument as an interval.
- Giovanni
- Site Admin
- Posts: 14455
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: [FUN] Preliminary results
Hi,
Thanks for all the findings, I never went beyond the first tests with Nil, I really need to allocate some time to it because it is a small thing that I really like conceptually.
Giovanni
Thanks for all the findings, I never went beyond the first tests with Nil, I really need to allocate some time to it because it is a small thing that I really like conceptually.
Giovanni
- Giovanni
- Site Admin
- Posts: 14455
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: [FUN] Preliminary results
wgreiman wrote:I have been playing with nil on an Arduino. It appears that nil doesn't do a reschedule in nilSysTimerHandler.
I was running two periodic threads, thread1 with a short period and thread2 with a long period. Thread1 was first in the task table but it was not rescheduled when its sleep period expired.
I added the following lines after the do-while loop in nilSysTimerHandler and it seems to work but may not be the correct solution.Code: Select all
nilSysLockFromIsr();
nilSchRescheduleS();
nilSysUnlockFromIsr();
I am assuming nil is intended to have a fixed priority preemptive scheduler with thread priority determined by position in the task table.
I looked into this, nilSysTimerHandler () does not reschedule because it must be called from an ISR that uses the ISR wrapper macros, the call to nilSchRescheduleS() is performed by the epilogue macro. It is just like in ChibiOS.
Giovanni
- Giovanni
- Site Admin
- Posts: 14455
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: [FUN] Preliminary results
I committed a fix for the problems with sleep functions, I could change it some more after deciding how to proceed with Nil.
Giovanni
Giovanni
Re: [FUN] Preliminary results
Giovanni,
Thanks for the sleep fixes.
I have now a preliminary version of an Arduino library using Nil RTOS. I have written a number of demonstration and test programs.
I am very excited about Nil as a first RTOS for Arduino users. I have ported ChibiOS/RT and FreeRTOS to Arduino and a number of people are using these ports. ChibiOS/RT is great on Arduino Due with SAM3X8E and Teensy 3.0 with MK20DX128.
Nil RTOS is simple and small and I plan on writing a detailed tutorial to help new Adruino users.
Here is a demo, a tutorial blink, for AVR Arduinos.
This program uses 2150 bytes of flash on an ATmega328 with the Arduino system and Nil RTOS.
The Arduino environment is not very flexible so I have modified the the thread definition macros and the NilSystem type so you don't need to define NIL_CFG_NUM_THREADS in nilconf.h. Here is the table end macro:
I have found several problems but have temporary fixes. The biggest problem is with semaphore timeout. The counter doesn't get incremented on timeout and the wrong status is returned. I will collect these and post them later.
Thanks for the sleep fixes.
I have now a preliminary version of an Arduino library using Nil RTOS. I have written a number of demonstration and test programs.
I am very excited about Nil as a first RTOS for Arduino users. I have ported ChibiOS/RT and FreeRTOS to Arduino and a number of people are using these ports. ChibiOS/RT is great on Arduino Due with SAM3X8E and Teensy 3.0 with MK20DX128.
Nil RTOS is simple and small and I plan on writing a detailed tutorial to help new Adruino users.
Here is a demo, a tutorial blink, for AVR Arduinos.
Code: Select all
/*
* Example to demonstrate thread definition, semaphores, and thread sleep.
*/
#include <NilRTOS.h>
// The LED is attached to pin 13 on Arduino.
const uint8_t LED_PIN = 13;
// Declare a semaphore with an inital counter value of zero.
SEMAPHORE_DECL(sem, 0);
//------------------------------------------------------------------------------
/*
* Thread 1, turn the LED off when signalled by thread 2.
*/
// Declare a stack with 128 bytes beyond context switch and interrupt needs.
NIL_WORKING_AREA(waThread1, 128);
// Declare thread function for thread 1.
NIL_THREAD(Thread1, arg) {
while (TRUE) {
// Wait for signal from thread 2.
nilSemWait(&sem);
// Turn LED off.
digitalWrite(LED_PIN, LOW);
}
}
//------------------------------------------------------------------------------
/*
* Thread 2, turn the LED on and signal thread 1 to turn the LED off.
*/
// Declare a stack with 128 bytes beyond context switch and interrupt needs.
NIL_WORKING_AREA(waThread2, 128);
// Declare thread function for thread 2.
NIL_THREAD(Thread2, arg) {
pinMode(LED_PIN, OUTPUT);
while (TRUE) {
// Turn LED on.
digitalWrite(LED_PIN, HIGH);
// Sleep for 200 milliseconds.
nilThdSleepMilliseconds(200);
// Signal thread 1 to turn LED off.
nilSemSignal(&sem);
// Sleep for 200 milliseconds.
nilThdSleepMilliseconds(200);
}
}
//------------------------------------------------------------------------------
/*
* Threads static table, one entry per thread. A thread's priority is
* determined by its position in the table with highest priority first.
*
* These threads start with a null argument. A thread's name may also
* be null to save RAM since the name is currently not used.
*/
NIL_THREADS_TABLE_BEGIN()
NIL_THREADS_TABLE_ENTRY("thread1", Thread1, NULL, waThread1, sizeof(waThread1))
NIL_THREADS_TABLE_ENTRY("thread2", Thread2, NULL, waThread2, sizeof(waThread2))
NIL_THREADS_TABLE_END()
//------------------------------------------------------------------------------
void setup() {
// Start Nil RTOS.
nilBegin();
}
//------------------------------------------------------------------------------
// Loop is the idle thread. The idle thread must not invoke any
// kernel primitive able to change its state to not runnable.
void loop() {
// Not used.
}
This program uses 2150 bytes of flash on an ATmega328 with the Arduino system and Nil RTOS.
The Arduino environment is not very flexible so I have modified the the thread definition macros and the NilSystem type so you don't need to define NIL_CFG_NUM_THREADS in nilconf.h. Here is the table end macro:
Code: Select all
/**
* @brief End of user threads table.
*/
#if WHG_MOD
#define NIL_THREADS_TABLE_END() \
{"idle", 0, NULL, NULL, 0} \
}; \
static Thread nil_threads[sizeof(nil_thd_configs)/sizeof(ThreadConfig)]; \
NilSystem nil = {0, 0, 0, nil_threads, \
&nil_threads[sizeof(nil_thd_configs)/sizeof(ThreadConfig) - 1]}; \
const uint8_t nil_thd_count = sizeof(nil_thd_configs)/sizeof(ThreadConfig) - 1;
#else /* WHG_MOD */
#define NIL_THREADS_TABLE_END() \
{"idle", 0, NULL, NULL, 0} \
};
#endif /* WHG_MOD */
I have found several problems but have temporary fixes. The biggest problem is with semaphore timeout. The counter doesn't get incremented on timeout and the wrong status is returned. I will collect these and post them later.
- Giovanni
- Site Admin
- Posts: 14455
- Joined: Wed May 27, 2009 8:48 am
- Location: Salerno, Italy
- Has thanked: 1076 times
- Been thanked: 922 times
- Contact:
Re: [FUN] Preliminary results
Hi,
I was aware of your libraries for Arduino, good job in making ChibiOS (and FreeRTOS) more accessible.
About nil, it definitely needs a test suite like the ChibiOS one, I need to decide what to do with this new toy. Thanks for all the problems you are reporting, I will try to fix everything ASAP.
Giovanni
I was aware of your libraries for Arduino, good job in making ChibiOS (and FreeRTOS) more accessible.
About nil, it definitely needs a test suite like the ChibiOS one, I need to decide what to do with this new toy. Thanks for all the problems you are reporting, I will try to fix everything ASAP.
Giovanni
Re: [FUN] Preliminary results
Here are some patches I made to nil to fix what I think are bugs. These are temporary fixes, I know there are better ways to fix these problems.
The patches are between an "#if WHG_PATCH" and an "#endif". Ignore "#if WHG_MOD", these are changes to support porting to an Arduino library.
A patch in nilSysTimerHandler for nilSemWait time out:
Patches in nilSchGoSleepTimeoutS to to return the correct wakeup.msg and prevent sleep in the idle thread:
Patches in nilSemWaitTimeoutS to fix semaphore problems:
A patch in nil.h for nilThdSleep:
The patches are between an "#if WHG_PATCH" and an "#endif". Ignore "#if WHG_MOD", these are changes to support porting to an Arduino library.
A patch in nilSysTimerHandler for nilSemWait time out:
Code: Select all
void nilSysTimerHandler(void) {
Thread *tp;
systime_t time;
time = ++nil.systime;
tp = &nil.threads[0];
do {
nilSysLockFromIsr();
if (tp->timeout && (tp->wakeup.time == time)) {
#if WHG_PATCH
nilDbgAssert(tp->waitobj.p != NULL,
"nilSysTimerHandler(), #1", "");
/* Could add a field to Thread structure to indicate waitobj type. */
if (tp->waitobj.thdp < nil.threads || tp->waitobj.thdp > nil.idlep) {
/* Handle nilSemWaitTimeout. */
tp->wakeup.msg = NIL_MSG_TMO;
tp->waitobj.semp->cnt++;
} else {
/* Do nothing for nilThdSleep */
}
#else /* WHG_PATCH */
nilDbgAssert(tp->waitobj.p == NULL,
"nilSysTimerHandlerI(), #1", "");
#endif /* WHG_PATCH */
nilSchReadyI(tp);
}
nilSysUnlockFromIsr();
tp++;
#if WHG_MOD
} while (tp < nil.idlep);
#else /* WHG_MOD */
} while (tp < &nil.threads[NIL_CFG_NUM_THREADS]);
#endif /* WHG_MOD */
Patches in nilSchGoSleepTimeoutS to to return the correct wakeup.msg and prevent sleep in the idle thread:
Code: Select all
msg_t nilSchGoSleepTimeoutS(void *waitobj, bool_t timeout, systime_t time) {
Thread *ntp, *otp = nil.currp;
#if WHG_PATCH
nilDbgAssert(otp < nil.idlep, "nilSchGoSleepTimeoutS(), #1", "");
/* Idle thread can't sleep, need better solution. (Bill Greiman)*/
while (otp == nil.idlep) {}
#endif /* WHG_PATCH */
/* Timeout settings.*/
otp->timeout = timeout;
otp->wakeup.time = time;
/* Storing the wait object for the current thread.*/
otp->waitobj.p = waitobj;
/* Scanning the whole threads array.*/
ntp = nil.threads;
while (TRUE) {
/* Is this thread ready to execute?*/
if (ntp->waitobj.p == NULL) {
nil.currp = nil.nextp = ntp;
port_switch(ntp, otp);
#if WHG_PATCH
return otp->wakeup.msg;
#else /* WHG_PATCH */
return ntp->wakeup.msg;
#endif /* WHG_PATCH */
}
/* Points to the next thread in lowering priority order.*/
ntp++;
#if WHG_MOD
nilDbgAssert(ntp <= nil.idlep,
"nilSchGoSleepTimeoutS(), #2", "");
#else /* WHG_MOD */
nilDbgAssert(ntp <= &nil.threads[NIL_CFG_NUM_THREADS],
"nilSchGoSleepTimeoutS(), #1", "");
#endif /* WHG_MOD */
}
}
Patches in nilSemWaitTimeoutS to fix semaphore problems:
Code: Select all
msg_t nilSemWaitTimeoutS(Semaphore *sp, systime_t time) {
/* Note, the semaphore counter is a volatile variable so accesses are
manually optimized.*/
#if WHG_PATCH
cnt_t cnt = sp->cnt - 1;
if (cnt >= 0) {
sp->cnt = cnt;
return NIL_MSG_OK;
}
if (TIME_IMMEDIATE == time) {
return NIL_MSG_TMO;
}
sp->cnt = cnt;
return nilSchGoSleepTimeoutS((void *)sp,
time != TIME_INFINITE,
nilTimeNow() + time);
#else /* WHG_PATCH */
cnt_t cnt = sp->cnt;
if ((cnt <= 0) && (TIME_IMMEDIATE != time)) {
sp->cnt = cnt - 1;
return nilSchGoSleepTimeoutS((void *)sp,
time != TIME_INFINITE,
nilTimeNow() - time);
}
return NIL_MSG_TMO;
#endif /* WHG_PATCH */
}
A patch in nil.h for nilThdSleep:
Code: Select all
#if WHG_PATCH
#define nilThdSleepS(time) \
nilSchGoSleepTimeoutS(nil.currp, TRUE, nilTimeNow() + time)
#else /* WHG_PATCH */
#define nilThdSleepS(time) \
nilSchGoSleepTimeoutS(nil.currp, TRUE, nilTimeNow() - time)
#endif /* WHG_PATCH */
Re: [FUN] Preliminary results
I think there needs to be two macros that return nil.systime, nilTimeNow() and nilTimeNowS().
For the 8-bit AVR, fetching the 16-bit time isn't atomic when interrupts are enabled.
The following function didn't work correctly until I added nilSysLock() and nilSysUnlock().
For the 8-bit AVR, fetching the 16-bit time isn't atomic when interrupts are enabled.
The following function didn't work correctly until I added nilSysLock() and nilSysUnlock().
Code: Select all
/**
* @brief Delay the invoking thread for the specified time.
*
* @param[in] time the delay in system ticks.
*
* @note This function does not sleep and will block all lower
* priority threads. This function should only be used
* in the idle thread.
* @api
*/
void nilThdDelay(systime_t time) {
systime_t t;
nilSysLock();
systime_t t0 = nilTimeNow();
nilSysUnlock();
do {
nilSysLock();
t = nilTimeNow();
nilSysUnlock();
} while ((t - t0) < time);
}
Who is online
Users browsing this forum: No registered users and 14 guests