Pages: [1]   Go Down
Author Topic: ChibiOS/RT RTOS trial port for Arduino  (Read 2899 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I have posted a port of ChibiOS/RT here http://code.google.com/p/beta-lib/downloads/list.  The file is ChibiOS20111027.zip.

There are five examples.  Three are small tests and two are serious data logging sketches.

I used timer 0 for the system timer so the OS tick time is 1024 usec or 976 Hz.

The fastest sketch for the Mega can log 976 samples per second to a csv file where each sample is the value of four analog pins.

Here is a description of the examples:
Quote
There are five examples in the ChibiOS/examples folder.

chBlinkPrint - A simple example of three threads. A high priority thread
               blinks an LED, a medium priority thread prints a counter
               every second, and the low priority idle loop increments the
               counter.

chContextTime - Test to determine context switch time with a semaphore.

chFastLogger - Data logger optimized for 328 Arduino.  Logs two analog pins
               every tick (1024 usec tick).

chJitter - Test of jitter in sleep for one tick.

chMegaLogger - Data logger optimized for Mega.  Logs four analog pins
               every tick (976 samples per sec, four values per sample)
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Great!
FYI - I am running ardu328p @7.37MHz, 57k6. When running chBlinkPrint the timing seems to be 2x slower (led blinks 2.5x per sec, each print 2secs) and the output is
0
490206
979938
1469669
1959827
..
When running chJitter I get constant 2286, 2322.
P.
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

pito,

I don't setup timer 0 for the system tick.  I just use the Arduino setup and the TIMER0_COMPA_vect ISR.

I didn't want to take another timer and the way timer 0 is setup for PWM I get a tick rate of
Code:
F_CPU/(64*256)

You could either change the PWM setup and edit the ISR or use another timer if you want a different tick rate.

I need to change the definition in chconf.h
Code:
#define CH_FREQUENCY  976
to
Code:
#define CH_FREQUENCY   (F_CPU/16384L)
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks, it blinks as advertised now  smiley.p
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Any hint how to determine the "200" stack size, ie.:
..static WORKING_AREA(waThread3, 200);
? p.
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Here is a link http://forum.chibios.org/phpbb/viewtopic.php?f=4&t=82.

I haven't tried it yet but plan to make a version for Arduino.
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

..interesting, but it is a postmortem check..
BTW - I removed the ATOMIC_BLOCK(ATOMIC_FORCEON) around count++ in chBlinkPrint. I have a third thread making an average and diff on the count var, and it seems it works. It is really necessary to do it atomic way? P.
Edit: it seems it shall be atomic as it starts to print garbage after a minute..
« Last Edit: October 28, 2011, 10:39:06 am by pito » Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

It almost must be a postmortem check.

Stack use depends on interrupts and how the compiler uses the stack.  A task can cause various interrupts.

When I build a system I use this kind of test to insure I have a safety margin but am not wasting memory.

For critical systems there are tools like this http://www.absint.com/stackanalyzer/.
« Last Edit: October 28, 2011, 11:07:04 am by fat16lib » Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I see.. Quite a difficult decision on stack sizes when using 328p and several tasks then..
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I enabled CH_DBG_FILL_THREADS in chconf.h and hacked the chBlinkPrint example to check the stack usage after it ran for a while.

The result is that ChibiOS allocates a minimal stack size of 69 bytes and the argument to WORKING_AREA is added.

For the LED blink thread 133 = (69 + 64) bytes were allocated and 102 bytes were unused for a max use of 31 bytes.

For the print thread 269 = (69 + 200) bytes were allocated and 198 were unused for a max use of 71 bytes.

Here is the hacked sketch, type any character to trigger the stack use print.
Code:
// Simple demo of three threads
// LED blink thread, print thread, and idle loop
#include <ChibiOS.h>
#include <util/atomic.h>
const uint8_t LED_PIN = 13;

volatile uint32_t count = 0;
//------------------------------------------------------------------------------
// thread 1 - high priority for blinking LED
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread1, 64);

static msg_t Thread1(void *arg) {
  pinMode(LED_PIN, OUTPUT);
  while (TRUE) {
    digitalWrite(LED_PIN, HIGH);
    chThdSleepMilliseconds(50);
    digitalWrite(LED_PIN, LOW);
    chThdSleepMilliseconds(150);
  }
  return 0;
}
//------------------------------------------------------------------------------
// thread 2 - print idle loop count every second
// 200 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread2, 200);

static msg_t Thread2(void *arg) {
  Serial.begin(9600);
  while (TRUE) {
    Serial.println(count);
    chThdSleepMilliseconds(1000);
  }
  return 0;
}
//------------------------------------------------------------------------------
void setup() {
  // initialize ChibiOS with interrupts disabled
  // ChibiOS will enable interrupts
  cli();
  halInit();
  chSysInit();
 
  // start blink thread
  chThdCreateStatic(waThread1, sizeof(waThread1),
    NORMALPRIO + 2, Thread1, NULL);
   
  // start print thread
  chThdCreateStatic(waThread2, sizeof(waThread2),
    NORMALPRIO + 1, Thread2, NULL);
}
//----------------------------------
size_t get_thd_free_stack(void *wsp, size_t size)
{
  size_t n = 0;
#if CH_DBG_FILL_THREADS
  uint8_t *startp = (uint8_t *)wsp + sizeof(Thread);
  uint8_t *endp = (uint8_t *)wsp + size;
  while (startp < endp)
    if(*startp++ == CH_STACK_FILL_VALUE) ++n;
#endif
  return n;
}
//----------------------------------------------------------------
void stackUse() {

  size_t n1 = get_thd_free_stack(waThread1, sizeof(waThread1));
  size_t n2 = get_thd_free_stack(waThread2, sizeof(waThread2));
  cli();
  Serial.print(sizeof(waThread1) - sizeof(Thread));
  Serial.write(',');
  Serial.println(n1);
  Serial.print(sizeof(waThread2) - sizeof(Thread)); 
  Serial.write(',');
  Serial.println(n2);
 
  while(1);
}
//------------------------------------------------------------------------------
// idle loop runs at NORMALPRIO
void loop() {
  // must insure increment is atomic
  // in case of context switch for print
  ATOMIC_BLOCK(ATOMIC_FORCEON) {
    count++;
  }
  if (Serial.available()) stackUse();
}
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

With
..  Serial.println(sizeof(waThread1) - sizeof(Thread) - n1); ...
gives (in my case, 3tasks):
allocated, used
=============
133,31
269,62
269,86

With smaller stacks:
allocated, used
=============
79,31
79,56
99,73
So not a predictable behaviour (or there are min and max I cannot catch)..
« Last Edit: October 28, 2011, 03:06:19 pm by pito » Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

The main reason for the variation is where the task is when an interrupt happens.  This adds the interrupt context to the stack.

I suspect you only have timer0 and Serial.  Serial probably only happens when you send the character to print the stats.

That just how it is with preemptive RTOSes.  You need to add a safety factor to the stack.

It's a lot better to have some measure of what is happening than guess.  Many embedded systems programmers use the stack fill trick.
Logged

Rapa Nui
Offline Offline
Edison Member
*
Karma: 52
Posts: 1990
Pukao hats cleaning services
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Would it be possible to use timer2 for os_ticks and during os_idle to go into extended standby mode?
Timer2 runs during that mode from xtal clk, can wake up the cpu when os_tick fires and it takes only 6clock cykles to wake up. So when scheduler sees there is nothing to do it can sleep for a while.. p.
Logged

0
Offline Offline
Edison Member
*
Karma: 44
Posts: 1471
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Timer2 works fine.  Just edit board.c to change boardInit() and CH_IRQ_HANDLER(TIMER0_COMPA_vect) to use timer2.

Also change
Code:
#define CH_FREQUENCY                    (F_CPU/16384L)
in chconf.h
Logged

Pages: [1]   Go Up
Jump to: