Synchronization between two tasks

Actually, this is a design issue for firmware in the embedded system. I have two ISRs (of the same priority) performed independently. These ISRs are triggered when h / w generates data. I need a mechanism that needs to be installed to synchronize between task1 and task2. task 2 should be aware of the specific values ​​calculated in task 1, which should then be taken into account when calculating certain values ​​in task 2. I have no OS primitives to use, i.e. there is no operating system in the system. Task1 is executed in the context of ISR1 and task2 in the context of ISR2. The processor we use is the STMicroelectronics 32 controller

EDIT: Additional Information The processor connects to specific IP addresses that cause interrupts when they are ready to transfer data. These IP addresses act as a Battery type for these input streaming frames.

+3
synchronization embedded firmware
source share
4 answers

I would not do heavy processing in the context of an interrupt, just read the data and set the flag.

Flags can then be checked in a simple scheduler in the main loop to complete tasks as needed. Thus, tasks cannot interrupt each other and cannot see the inconsistent conclusion of another task.

A task can also set such a flag to activate another task. For example. Task1 can activate Task2 because Task2 needs the values ​​from Task1.

For data that is read in the ISR, you need a buffer. Depending on the time of your input, which may be a ring buffer or a double buffer.

+4
source share
  • Disable interrupts before reading or writing shared values
  • Enable interrupts after reading or writing for shared values
+2
source share

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.

+2
source share

I come to this from the point of view of no OS, there is no real structure other than C, and registers, etc. How I would do this is to have a state variable for each ISR that can be seen by other ISRs. Then, when you enter ISR1, you simply check the status of the ISR2 task and work as needed. Then, ISR2 is called and checks its status and the status of ISR1 and works as it sees fit. I would use ENUM in the header file to list the states for clarity (INIT, WAITONDATA, etc.), and then switch to ISR to process each state. Then you only need to make sure that the data that needs to be shared can be seen by both ISRs and installed.

Of course, as others have said, you do not want to do a lot of calculations in the ISR. You just want to set the flag that an event has occurred or some data is present, and then process the data in the main loop. Then your system does not block for too long to process the ISR. You do this in the same way - a state variable that can be seen in the main loop (or at least the function that you call to process data from the main loop) and ISR. Change its state in the ISR and check this state in the main loop function. Do chores as needed.

Remember, if you update variables in the ISR, they must be defined as volatile!

volatile uint8 state = INIT;

eg.

+2
source share

All Articles