Sharing a variable within main program with another module
Sharing a variable within main program with another module
How can I share a variable in the "Main" program with another module? Using the "Flashform" example how can I share a varibale in "main.cpp" with "formcode.cpp"? Thanks Ron
Re: Sharing a variable within main program with another module
Where is this example "Flashform" you are talking about at ?
-
- Posts: 513
- Joined: Sat Apr 26, 2008 7:14 am
Re: Sharing a variable within main program with another module
The following techniques are often used for sharing variables not only between two tasks, but also between a task and an ISR. In order of simplicity
1) Write the variable in ONLY one task, but read (but never modify) it in other tasks. In this case, you could substitute an ISR for either the reading or writing task. For this to work, the variable MUST be atomic, ie read and writen in one operation (ie a 32 bit entity: int, unsigned int, float, double)
2) Create a semaphore to lock the variable. Semaphores are usuallyn used as flags to indicate that some event has occured. In that scenario, you init the semaphore to 0. However semaphores can also be used to lock resources. In that usage pattern, you init the semaphore to 1 typically, to indicate that a resource is available. Then, as soon as you use the resource, Pend on it so the semaphore's internal count will decrement to 0 thereby locking the resource and indicating it is in use (ie locked or busy). Other tasks that want the resource also Pend, but since the internal counter is 0, are blocked. When you're done, Post to it so the counter increments once again indicating the resource is available. As soon as it is available any other Pending task will get access in order of the task priority. The downside of this approach is that if multiple tasks want the resource, the pends and posts can get out of sync effectively locking the resource. If there are just two tasks trying to read or write this works OK. Also, with this technique, data can be non-atomic since the data is locked during all accesses.
3) Finally, create a C++ class that incorporates an object of type OS_CRIT along with some variable that you'd like to protect. The OS_CRIT object is an identifier for a region you'd like to protect (eg, your variable). Next, in the class constructor, init the OS_CRIT object using OSCritInit. Then, within the class, create separate methods to read and write the variable. All access to the variable occurs thru these methods, and only these methods. But, before the methods either read or write the variable, they call OSCriticalSectionObj to operate on the critical section defined above and provide a lock. This technique is nice for a few reasons. First, it unlocks automatically when the methods go out of scope. Second it can protect non-atomic objects (variables) like structs so that all the elements of the struct can either be updated as a set while locked, or evaluated again as a synchronized set while being read. See the NNDK Prog Manual chapter on OSCritObjects, as well as the the example code at C:\Nburn\examples\RTOS\OSCrit for some basic usage ideas and add'l explanation.
1) Write the variable in ONLY one task, but read (but never modify) it in other tasks. In this case, you could substitute an ISR for either the reading or writing task. For this to work, the variable MUST be atomic, ie read and writen in one operation (ie a 32 bit entity: int, unsigned int, float, double)
2) Create a semaphore to lock the variable. Semaphores are usuallyn used as flags to indicate that some event has occured. In that scenario, you init the semaphore to 0. However semaphores can also be used to lock resources. In that usage pattern, you init the semaphore to 1 typically, to indicate that a resource is available. Then, as soon as you use the resource, Pend on it so the semaphore's internal count will decrement to 0 thereby locking the resource and indicating it is in use (ie locked or busy). Other tasks that want the resource also Pend, but since the internal counter is 0, are blocked. When you're done, Post to it so the counter increments once again indicating the resource is available. As soon as it is available any other Pending task will get access in order of the task priority. The downside of this approach is that if multiple tasks want the resource, the pends and posts can get out of sync effectively locking the resource. If there are just two tasks trying to read or write this works OK. Also, with this technique, data can be non-atomic since the data is locked during all accesses.
3) Finally, create a C++ class that incorporates an object of type OS_CRIT along with some variable that you'd like to protect. The OS_CRIT object is an identifier for a region you'd like to protect (eg, your variable). Next, in the class constructor, init the OS_CRIT object using OSCritInit. Then, within the class, create separate methods to read and write the variable. All access to the variable occurs thru these methods, and only these methods. But, before the methods either read or write the variable, they call OSCriticalSectionObj to operate on the critical section defined above and provide a lock. This technique is nice for a few reasons. First, it unlocks automatically when the methods go out of scope. Second it can protect non-atomic objects (variables) like structs so that all the elements of the struct can either be updated as a set while locked, or evaluated again as a synchronized set while being read. See the NNDK Prog Manual chapter on OSCritObjects, as well as the the example code at C:\Nburn\examples\RTOS\OSCrit for some basic usage ideas and add'l explanation.
Re: Sharing a variable within main program with another module
Ridgeglider, that is one of the best answers I have seen to that question.
Re: Sharing a variable within main program with another module
Ridgeglider's response was right on target here. Thought I would add one more method that allows read/write sharing of any objects between tasks or ISRs. There is a locking mechanism available that will block all interrupts ( except level 7 ), when interrupts are masked it will also not be possible for a task switch to occur. To enter this type of section you must call USER_ENTER_CRITICAL(), to exit call USER_EXIT_CRITICAL(). There is an internal count for these calls so multiple enters may be called but an equal amount of exit calls must be called to restore interrupts. The advantage of using these calls is that they are very quick and guarantee a section is completely locked from other ISRs and tasks. The disadvantage is that the entire system will be stalled during this section... no TimeTicks, Ethernet ISRs or Serial ISRs. Also you must treat these section like level 7 interrupts, meaning no OS functions allowed at all. These sections should be used very sparingly and any code inside these sections should be non-blocking and short. If you spend too much time in a USER_CRITICAL section bad things will happen such as RX data loss. This method should only be used if a normal OS object will not work to protect a section due to ISR sharing.