I will try to give you an answer based on limited information, assuming:
- a simple, homegrown scheduler is used to call task1 and task2 based on a simple criterion
- task1 and task2 are executed to completion (i.e. do not crowd out each other)
- data is a byte stream (requires a slightly different implementation if you need packets)
What I usually try when designing embedded systems is to minimize the use of semaphores and simulate data flows without blocking. I will illustrate this below:
asynchronous (blocked) communication queues http://www.freeimagehosting.net/uploads/477741db06.gif ISRs can be separated from tasks using a FIFO streaming queue. An example can be found at http://msmvps.com/blogs/vandooren/archive/2007/01/05/creating-a-thread-safe-producer-consumer-queue-in-c-without-using-locks.aspx
Such an implementation (without locks) has no OS dependencies and should be trivially easy to support. It also gives a clear design to the consumer-producer, which is free from dead ends.
Assuming that tasks are started by the home planner, you can choose to check for events (non-empty fifo). that is, if (TRUE == fifo_filled (my_read_queue)) {call task 1}
Now about the synchronization of tasks1 and task2. If task1 simply creates data, the same mechanism can be used: if you have a queue (fifo) in which task1 can write data that can be read by task 2, then the tasks are deactivated. Again, this can be checked in your scheduler (if (TRUE == fifo_filled (task1_to_2_queue ()) {invoke task2)}
If you need more (i.e. if tasks are not completed before completion, but are crowded out), you will need some kind of mechanism for synchronization. Options include: - use an (free) operating system or a simple scheduler anyway - brew your own (my experience: should be done if it is as simple as a for loop and several if statements) - use a simple scheduler (much easier than full RTOS) - refactoring code for integrating task1 and task2 into one. In this case, you will effectively make a part of the scheduler of your application code.
Note. The example function that I used in this explanation (fifo_filled ()) is not part of the example code. It should return true if (read! = Write). In addition, the sample code uses global variables for reading and writing; you can either execute a function capable of processing several queues, or move the read / write and buffer variables to the structure, and refer to the structure in the parameters.
An alternative way is to create a critical partition using an interrupt. However, I try to limit this, as it often creates a strong system connection, and the code becomes more difficult to reuse.
Adriaan
source share