Data share between tasks – beginner

Hi, Im running freeRTOS on AVR mega 2560. I have two tasks A and B and also global data structure lets name it G: A – periodic (50 Hz) and responsible for reading data form sensor through I2C and performing some algorithm. It uses configuration stored in G. void controltask(void * pvParameters) { TickTypet xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); while (1) { vTaskDelayUntil(&xLastWakeTime, (CONTROLPERIODMS / portTICKRATEMS)); // Read sensor // Calibrate readings using data stored in G // Perform algo using data stored in G } } B – is responsible for communication through serial port with a PC application. Reception of each byte is done in the ISR. After receiving complete packet it`s processed in this task. Any other requests form PC between processing and trasmitting response are rejected. Some requests are read/write operations on struct G. Accessing G can occur anytime. void seriallinktask(void * pvParameters) { while(1) { if(readytoprocess == 1) { readytoprocess = 0; // Read form / write to data in G structure // Prepare response // Transmitt response (handeled in tx ISR) } } } Since these two tasks use global struct G it needs to be protected by a semaphore, mutex or copied into queue. I do not know which one should be used here. Semaphore or mutex uses block time – how many ticks should wait for access. In the task A I do not want to wait for the semaphore or mutex to be obtained. It should be executed without any delay. Because it could happen that after giving the sem/mutex by task A task B takes this sem/mutex just before task A. Context switch is done and task A leaves empty handed. if(pdTRUE == xSemaphoreTake(sem, 0)) <– oops task B as the sem/mutex { // Read sensor // Calibrate readings using data stored in G // Perform algo xSemaphoreGive(sem); } Now the only solution that is working is to combine these two tasks into one like so: void controlandserialtask(void * pvParameters) { TickTypet xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); while (1) { vTaskDelayUntil(&xLastWakeTime, (CONTROLPERIODMS / portTICKRATEMS)); // Read sensor // Calibrate readings using data stored in G // Perform algo using data stored in G
    // Read form / write to data in G structure
    // Prepare response
    // Transmitt response (handeled in tx ISR)
}
} But this limits serial throughput heavily. The other way I think is to use queues somehow. Can anyone help me how to solve the problem of sharing the data between tasks A and B without delaying execution of task A ? Sorry for my english 🙂

Data share between tasks – beginner

The answer will depend on what is in the global data structure, and whether all the members of the data structure must be updated atomically (without interruption). In the simplest case, if one task only ever reads, and all reads are atomic as far as the application is concerned, you will not have to provide any mutual exclusion. For example, if the structure was as follows: struct aStruct { uint8t Member1; uint8t Member2; }; In this case utin8_t can be read and written by the AVR atomically as they are 8-bits and the AVR is an 8-bit device. If it also doesn’t matter if A reads Member1, then B updates Member2, then A reads Member2 (so Member1 and Member2 have changed relative to each other between A reading them) – then no mutual exclusion will be required. In the other extreme case, if the structure was something like this: struct aStruct { uint32t Member1; uint32t Member2; }; So the structure members cannot be accessed atomically on an 8-bit device because they are themselves 32-bit…and if it matters if Member2 is updated between A reading Member1 and Member2, then you are going to have to use mutual exclusion on all accesses. The mutual exclusion primitive to use depends on the size of the structure and/or the time taken to read from it. On an AVR interrupt service routines will not need to provide mutual exclusion. In tasks, if accessing the struct is quick, then mutual exclusion can be provided using a simple critical section: uint32_t Member1Copy, Member2Copy; /* Take consistent (uninterrupted) copies of the structure members. */ taskENTER_CRITICAL(); Member1Copy = MyStruct.Member1; Member2Copy = MyStruct.Member2; taskEXIT_CRITICAL(); If the structure is larger or takes longer to access, then you will have to do something else so as not to leave interrupts disabled for too long. Note you cannot use a mutex in an interrupt though. Regards.

Data share between tasks – beginner

Good to realize that you might need to protect the concurrent accesses. First note, that not all possibly concurrent accesses need protection. If the read is a single atomic read, then it doesn’t need to be protected, as well as if the write is a single atomic write, and the read side only reads each value once, then there is no need for protection, as the atomisity itself is enough protection. Assuming we still need to protect the structure, then we can look at the possible methods. 1) The queue. This works if you want to do something like alternate who has the access, but given your description that isn’t what you need, A queue can be used to simulate a semaphore (and FreeRTOS does this internally), but it is better to use the natural primitive then to simulate it. 2) Semaphore vs Mutex. Both work mostly the same. You can take it before access, and give it back after, and achieve your exclusive access. The Mutex (short for Mutual Exlcustion) is the more natural primitive, being basically a semaphore with a few extra restrictions/features aimed at mutual exclusion, the biggest in my opinion is priority inheritance to break priority inversion. If you really only have two tasks this won’t be a problem. Your big question seems to be, how can task A wait for the synchronization primitive but not fall behind its needed schedule? The key here is that tasks (Task B in particular here) should hold onto the data buffer for as short of a time as possible, normally by building up the list of changes to be made before acquiring access to the structure (or at the very minimum having gathered all needed data before acquiring access), or copying the needed information out to local variables. That way if B starts an update just before Task A needs to start, when task A needs to get the structure, it will find it in use, momentarily block, task B will then QUICKY finish and release the buffer, and A will resume with just a very short delay. Note that task A shouldn’t get the struct until AFTER it has read the data (and thus is ready to use it), and task B shouldn’t get the struct until it has a command to update it. Note that by A not waiting for the semaphore until after it has the data, then the timing of getting the data won’t be affected by the possibly short delay if B is updating. If you really can get the access time down to just a few cycles (a quick copy in or out), then the other option for synchronization is a critical section. This is a lot “lighter weight” than a semaphore/mutex, with the slight cost of delaying interrupts (which is why it should only be used if very quick).

Data share between tasks – beginner

I think that critical sections will do the trick here and also wont mess up much with latency. Ive got to access about 64 bytes maximum. Thank you very much for your advices. Best regards.