PaulStoffregen
Well-known member
When using ChibiOS, is there any library that supports multiple threads accessing a SD card?
When using ChibiOS, is there any library that supports multiple threads accessing a SD card?
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.
This method is very useful when integrating into the system components not designed to be reentrant or to be executed in a multithreaded environment, for example a 3rd part file system or a networking protocol stack.
// Example to demonstrate thread definition, semaphores, and thread sleep.
#include <ChibiOS_ARM.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.
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread1, 64);
static msg_t Thread1(void *arg) {
while (!chThdShouldTerminate()) {
// Wait for signal from thread 2.
chSemWait(&sem);
// Turn LED off.
digitalWrite(LED_PIN, LOW);
}
return 0;
}
//------------------------------------------------------------------------------
// Thread 2, turn the LED on and signal thread 1 to turn the LED off.
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread2, 64);
static msg_t Thread2(void *arg) {
pinMode(LED_PIN, OUTPUT);
while (1) {
digitalWrite(LED_PIN, HIGH);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
// Signal thread 1 to turn LED off.
chSemSignal(&sem);
// Sleep for 200 milliseconds.
chThdSleepMilliseconds(200);
}
return 0;
}
//------------------------------------------------------------------------------
void setup() {
chBegin(chSetup);
// chBegin never returns, main thread continues with mainThread()
while(1) {
}
}
//------------------------------------------------------------------------------
// main thread runs at NORMALPRIO
void chSetup() {
// start blink thread
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO + 2, Thread1, NULL);
chThdCreateStatic(waThread2, sizeof(waThread2),
NORMALPRIO + 1, Thread2, NULL);
}
//------------------------------------------------------------------------------
void loop() {
// not used
}
// Connect a scope to pin 13
// Measure difference in time between first pulse with no context switch
// and second pulse started in thread 2 and ended in thread 1.
// Difference should be about 15-16 usec on a 16 MHz 328 Arduino.
#include <ChibiOS_ARM.h>
const uint8_t LED_PIN = 13;
// Semaphore to trigger context switch
Semaphore sem;
//------------------------------------------------------------------------------
// thread 1 - high priority thread to set pin low
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread1, 64);
static msg_t Thread1(void *arg) {
while (TRUE) {
chSemWait(&sem);
digitalWrite(LED_PIN, LOW);
}
return 0;
}
//------------------------------------------------------------------------------
// thread 2 - lower priority thread to toggle LED and trigger thread 1
// 64 byte stack beyond task switch and interrupt needs
static WORKING_AREA(waThread2, 64);
static msg_t Thread2(void *arg) {
pinMode(LED_PIN, OUTPUT);
while (TRUE) {
// first pulse to get time with no context switch
digitalWrite(LED_PIN, HIGH);
digitalWrite(LED_PIN, LOW);
// start second pulse
digitalWrite(LED_PIN, HIGH);
// trigger context switch for task that ends pulse
chSemSignal(&sem);
// sleep until next tick (1024 microseconds tick on Arduino)
chThdSleep(1);
}
return 0;
}
//------------------------------------------------------------------------------
void setup() {
chBegin(chSetup);
while (1) {}
}
//------------------------------------------------------------------------------
void chSetup() {
// initialize semaphore
chSemInit(&sem, 0);
// start high priority thread
chThdCreateStatic(waThread1, sizeof(waThread1),
NORMALPRIO+2, Thread1, NULL);
// start lower priority thread
chThdCreateStatic(waThread2, sizeof(waThread2),
NORMALPRIO+1, Thread2, NULL);
}
//------------------------------------------------------------------------------
void loop() {
// not used
}
// Example of how a handler task can be triggered from an ISR
// by using a binary semaphore.
#include <ChibiOS_ARM.h>
// pins to generate interrupts - these pins must be connected with a wire
const uint8_t INPUT_PIN = 2;
const uint8_t OUTPUT_PIN = 3;
// initialize semaphore as taken
BSEMAPHORE_DECL(isrSem, 1);
// ISR entry time
volatile uint32_t tIsr = 0;
//------------------------------------------------------------------------------
// Fake ISR, normally
// void isrFcn() {
// would be replaced by somthing like
// CH_IRQ_HANDLER(INT0_vect) {
//
void isrFcn() {
// on ARM CH_IRQ_PROLOGUE is void
CH_IRQ_PROLOGUE();
/* IRQ handling code, preemptable if the architecture supports it.*/
// Only ISR processing is to save time
tIsr = micros();
chSysLockFromIsr();
/* Invocation of some I-Class system APIs, never preemptable.*/
// signal handler task
chBSemSignalI(&isrSem);
chSysUnlockFromIsr();
/* More IRQ handling code, again preemptable.*/
// Perform rescheduling if required.
CH_IRQ_EPILOGUE();
}
//------------------------------------------------------------------------------
// handler task for interrupt
static WORKING_AREA(waThd1, 200);
msg_t handler(void *arg) {
while (1) {
// wait for event
chBSemWait(&isrSem);
// print elapsed time
uint32_t t = micros();
Serial.print("Handler: ");
Serial.println(t - tIsr);
}
}
//------------------------------------------------------------------------------
void setup() {
Serial.begin(9600);
while (!Serial) {}
// setup and check pins
pinMode(INPUT_PIN, INPUT);
pinMode(OUTPUT_PIN, OUTPUT);
digitalWrite(OUTPUT_PIN, HIGH);
bool shouldBeTrue = digitalRead(INPUT_PIN);
digitalWrite(OUTPUT_PIN, LOW);
if (digitalRead(INPUT_PIN) || !shouldBeTrue) {
Serial.print("pin ");
Serial.print(INPUT_PIN);
Serial.print(" must be connected to pin ");
Serial.println(OUTPUT_PIN);
while (1) {}
}
// Start ChibiOS
chBegin(mainThread);
while (1) {}
}
//------------------------------------------------------------------------------
void mainThread() {
// start handler task
chThdCreateStatic(waThd1, sizeof(waThd1), NORMALPRIO + 1, handler, NULL);
// attach interrupt function
attachInterrupt(INPUT_PIN, isrFcn, RISING);
while (1) {
// cause an interrupt - normally done by external event
Serial.println("High");
digitalWrite(OUTPUT_PIN, HIGH);
Serial.println("Low");
digitalWrite(OUTPUT_PIN, LOW);
Serial.println();
chThdSleepMilliseconds(1000);
}
}
//------------------------------------------------------------------------------
void loop() {
// not used
}
High
Handler: 4
Low
But the real question to me, is how. Do you really want a full OS, with protected device drivers, that user level programs communicate with through queues... This may solve some of these issues, but you may just end up going to a small Linux...
//------------------------------------------------------------------------------
/** fill heap on Teensy */
/*
void startup_early_hook() {
uint32_t* end = &_estack - 100;
uint32_t* p = &_ebss;
while (p < end) *p++ = MEMORY_FILL_PATTERN;
}
*/
It reason is more general. You don't know why an application uses an interrupt. Maybe the interrupt was caused by a pin change and knowing the time of the event as accurately as possible is important. The SPI part may access a sensor where time is not as important.
Looks like I removed this code.
It is at about line 72 of ChibiOS_ARM.c
Code:void startup_early_hook() { uint32_t* end = &_estack - 100; uint32_t* p = &_ebss; while (p < end) *p++ = MEMORY_FILL_PATTERN; } */
It originally was used for debug of stack problems but is not needed and causes a crash in recent versions of Teensy 3 software.
IMHO this is because in recent Teensyduino versions, startup_early_hook disables the Watchdog timer.
At least a few people wanted to use the watchdog timer, but couldn't because it was being disabled before they could configure it. Freescale has a configure-only-once approach, so the old way was effectively locking people out from using the watchdog.
PaulStoffregen
Is ChibiOS GPLv3 licensed?
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013,2014 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/>.
*/