Hi,
is it possible to implement semaphores on a Arduino? Thanks in advance!
Best regards,
Michael
Hi,
is it possible to implement semaphores on a Arduino? Thanks in advance!
Best regards,
Michael
Yes. You can take a look at how FreeRTOS handles this subject, or if you're just worried about interrupts you can take various steps to protect your data so that it's interrupt-friendly.
Yes. You can take a look at how FreeRTOS handles this subject, or if you're just worried about interrupts you can take various steps to protect your data so that it's interrupt-friendly.
Thanks for the quick reply. At present my problem is that I send data over SPI to a another MCU. I have code in an ISR (timer overflow) which sends data to the MCU and code which sends data in the main loop over SPI to the MCU. At some point it looks like that one SPI write call overwrites the SPDR of the other SPI write call. Maybe you have an idea to solve that without semaphores.
Thanks!
#include <avr/interrupt.h>
// Set the timer frequency to 250 Khz
#define TIMER_CLOCK_FREQ 250000.0
// Master Output Slave Input
#define MOSI 11
// Master Input Slave Output
#define MISO 12
// Serial Clock
#define SCK 13
// Slave Select 1
#define SS1 2
// Slave Select 2
#define SS2 3
// Slave Select 3
#define SS3 8
// Slave Select 4
#define SS4 9
// Row 0
#define R0 4
// Row 1
#define R1 5
// Row 2
#define R2 6
// Row 3
#define R3 7
// Define the baudrate
#define BAUDRATE 9600
// The led register
byte leds[250];
//
byte clear;
//
int data = 0;
//
int size = 0;
//
#define INIT_TIMER_COUNT 6
//
#define RESET_TIMER TCNT2 = INIT_TIMER_COUNT
// ISR for Timer/Counter Overflow
ISR(TIMER2_OVF_vect){
//RESET_TIMER;
static int rowNumber = 1;
digitalWrite(SS1, LOW);
// Signalize through SPI that the next packet will be the row number
writeData(0xFF);
// Send the row number
writeData(rowNumber);
digitalWrite(SS1, HIGH);
digitalWrite(SS2, LOW);
// Signalize through SPI that the next packet will be the row number
writeData(0xFF);
// Send the row number
writeData(rowNumber);
digitalWrite(SS2, HIGH);
digitalWrite(R0, ((rowNumber & 0x01) ? LOW : HIGH));
digitalWrite(R1, ((rowNumber & 0x02) ? LOW : HIGH));
digitalWrite(R2, ((rowNumber & 0x04) ? LOW : HIGH));
digitalWrite(R3, ((rowNumber & 0x08) ? LOW : HIGH));
rowNumber = (rowNumber == 15) ? 1 : rowNumber + 1;
}
// Write bytewise data over SPI
char writeData(volatile unsigned char data){
// Start the transmission
SPDR = data;
// Wait till the end of the transmission
while(!(SPSR & (1 << SPIF))){};
// Return the received byte
return SPDR;
}
// Initialize serial connection and set pin modes
void setup(){
// Set the baudrate
Serial.begin(BAUDRATE);
// Set the pin modes
pinMode(MOSI, OUTPUT);
pinMode(MISO, INPUT);
pinMode(SCK, OUTPUT);
pinMode(SS1, OUTPUT);
pinMode(SS2, OUTPUT);
pinMode(SS3, OUTPUT);
pinMode(SS4, OUTPUT);
pinMode(R0, OUTPUT);
pinMode(R1, OUTPUT);
pinMode(R2, OUTPUT);
pinMode(R3, OUTPUT);
// Disable the slave devices
digitalWrite(SS1, HIGH);
digitalWrite(SS2, HIGH);
digitalWrite(SS3, HIGH);
digitalWrite(SS4, HIGH);
// Disable the rows
digitalWrite(R0, LOW);
digitalWrite(R1, LOW);
digitalWrite(R2, LOW);
digitalWrite(R3, LOW);
// Set the SPI Control Register SPCR to the value 01010000
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
// Overwrite previous junk with the SPI status register
clear = SPSR;
// Overwrite previous junk with the SPI data register
clear = SPDR;
// Timer 2 Settings: Timer Prescaler /64 , mode 0
// Timer clock = 16MHz/64 = 250 Khz
TCCR2A = 0;
//TCCR2B = (1 << CS22 | 0 << CS21 | 0 << CS20);
TCCR2B = (1 << CS22 | 1 << CS21 | 1 << CS20);
// Timer 2 Overflow Interrupt Enable
TIMSK2 = 1 << TOIE2;
}
void loop(){
static int i = 0;
digitalWrite(SS1, LOW);
writeData(0xEE);
writeData(i);
digitalWrite(SS1, HIGH);
digitalWrite(SS1, LOW);
writeData(0xFF);
writeData(0x00);
digitalWrite(SS1, HIGH);
Serial.println("ACK");
delay(1500);
i++;
if(i == 15){
i = 0;
}
}
There are several ways to deal with this.
A) Don't initiate an SPI transmission while one is in progress. When a transmission is in progress, the SPIF bit of the SPSR register is cleared. This bit will also be cleared before your program makes its first transmission, so you might need an extra variable to help you figure out when you're transmitting. This means that your writeData() method will need to start with a routine that waits for any existing transmission to finish (this is important since one could be in progress when your ISR calls writeData()).
B) Disable interrupts in your main loop while the SPI transmission is taking place, and re-enable them when it is finished. You can only use this option if your timer overflow period is longer than the time it will take for you to carry out your main loop transmission, otherwise you will miss overflow interrupts by doing this.
C) Don't perform an SPI transmission from your ISR. Instead, have it use global variables to queue a transmission that will then be carried out by the main loop. For example:
volatile unsigned char transmit = 0;
ISR(timer overflow)
{
transmit = 1;
}
void loop()
{
if (transmit)
{
transmit = 0;
initiate SPI transmission
}
...
}
Hi, another way is to have an small RTOS. We have ported FreeRTOS past year (2009), and it has Semaphores and MUTEX, you can look at these links:
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1256745982/0
The versión 0.1 Alpha (for the 0017 IDE) is available here:
http://www.multiplo.org/duinos/wiki/index.php?title=Main_Page
And there is a v0.2 Alpha which runs in 0018 at:
http://novell.chel.ru/get.php?file=DuinOS_v0.2_Alpha
We did not make the v0.2, but are working in the v0.3.
Regards,
Julián
Back to top